30eaaa41924968261e6b893488f303e0f78e8235
[metze/samba/wip.git] / source3 / modules / vfs_shadow_copy2.c
1 /*
2  * shadow_copy2: a shadow copy module (second implementation)
3  *
4  * Copyright (C) Andrew Tridgell   2007 (portions taken from shadow_copy2)
5  * Copyright (C) Ed Plese          2009
6  * Copyright (C) Volker Lendecke   2011
7  * Copyright (C) Christian Ambach  2011
8  * Copyright (C) Michael Adam      2013
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 /*
26  * This is a second implemetation of a shadow copy module for exposing
27  * file system snapshots to windows clients as shadow copies.
28  *
29  * See the manual page for documentation.
30  */
31
32 #include "includes.h"
33 #include "system/filesys.h"
34 #include "include/ntioctl.h"
35 #include <ccan/hash/hash.h>
36 #include "util_tdb.h"
37
38 struct shadow_copy2_config {
39         char *gmt_format;
40         bool use_sscanf;
41         bool use_localtime;
42         char *snapdir;
43         bool snapdirseverywhere;
44         bool crossmountpoints;
45         bool fixinodes;
46         char *sort_order;
47         bool snapdir_absolute;
48         char *basedir;
49         char *mount_point;
50         char *rel_connectpath; /* share root, relative to the basedir */
51         char *snapshot_basepath; /* the absolute version of snapdir */
52 };
53
54 static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str,
55                                       size_t **poffsets,
56                                       unsigned *pnum_offsets)
57 {
58         unsigned num_offsets;
59         size_t *offsets;
60         const char *p;
61
62         num_offsets = 0;
63
64         p = str;
65         while ((p = strchr(p, '/')) != NULL) {
66                 num_offsets += 1;
67                 p += 1;
68         }
69
70         offsets = talloc_array(mem_ctx, size_t, num_offsets);
71         if (offsets == NULL) {
72                 return false;
73         }
74
75         p = str;
76         num_offsets = 0;
77         while ((p = strchr(p, '/')) != NULL) {
78                 offsets[num_offsets] = p-str;
79                 num_offsets += 1;
80                 p += 1;
81         }
82
83         *poffsets = offsets;
84         *pnum_offsets = num_offsets;
85         return true;
86 }
87
88 /**
89  * Given a timestamp, build the posix level GMT-tag string
90  * based on the configurable format.
91  */
92 static size_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct *handle,
93                                             time_t snapshot,
94                                             char *snaptime_string,
95                                             size_t len)
96 {
97         struct tm snap_tm;
98         size_t snaptime_len;
99         struct shadow_copy2_config *config;
100
101         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
102                                 return 0);
103
104         if (config->use_sscanf) {
105                 snaptime_len = snprintf(snaptime_string,
106                                         len,
107                                         config->gmt_format,
108                                         (unsigned long)snapshot);
109                 if (snaptime_len <= 0) {
110                         DEBUG(10, ("snprintf failed\n"));
111                         return snaptime_len;
112                 }
113         } else {
114                 if (config->use_localtime) {
115                         if (localtime_r(&snapshot, &snap_tm) == 0) {
116                                 DEBUG(10, ("gmtime_r failed\n"));
117                                 return -1;
118                         }
119                 } else {
120                         if (gmtime_r(&snapshot, &snap_tm) == 0) {
121                                 DEBUG(10, ("gmtime_r failed\n"));
122                                 return -1;
123                         }
124                 }
125                 snaptime_len = strftime(snaptime_string,
126                                         len,
127                                         config->gmt_format,
128                                         &snap_tm);
129                 if (snaptime_len == 0) {
130                         DEBUG(10, ("strftime failed\n"));
131                         return 0;
132                 }
133         }
134
135         return snaptime_len;
136 }
137
138 /**
139  * Given a timestamp, build the string to insert into a path
140  * as a path component for creating the local path to the
141  * snapshot at the given timestamp of the input path.
142  *
143  * In the case of a parallel snapdir (specified with an
144  * absolute path), this is the inital portion of the
145  * local path of any snapshot file. The complete path is
146  * obtained by appending the portion of the file's path
147  * below the share root's mountpoint.
148  */
149 static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx,
150                                         struct vfs_handle_struct *handle,
151                                         time_t snapshot)
152 {
153         fstring snaptime_string;
154         size_t snaptime_len = 0;
155         char *result = NULL;
156         struct shadow_copy2_config *config;
157
158         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
159                                 return NULL);
160
161         snaptime_len = shadow_copy2_posix_gmt_string(handle,
162                                                      snapshot,
163                                                      snaptime_string,
164                                                      sizeof(snaptime_string));
165         if (snaptime_len <= 0) {
166                 return NULL;
167         }
168
169         if (config->snapdir_absolute) {
170                 result = talloc_asprintf(mem_ctx, "%s/%s",
171                                          config->snapdir, snaptime_string);
172         } else {
173                 result = talloc_asprintf(mem_ctx, "/%s/%s",
174                                          config->snapdir, snaptime_string);
175         }
176         if (result == NULL) {
177                 DEBUG(1, (__location__ " talloc_asprintf failed\n"));
178         }
179
180         return result;
181 }
182
183 /**
184  * Build the posix snapshot path for the connection
185  * at the given timestamp, i.e. the absolute posix path
186  * that contains the snapshot for this file system.
187  *
188  * This only applies to classical case, i.e. not
189  * to the "snapdirseverywhere" mode.
190  */
191 static char *shadow_copy2_snapshot_path(TALLOC_CTX *mem_ctx,
192                                         struct vfs_handle_struct *handle,
193                                         time_t snapshot)
194 {
195         fstring snaptime_string;
196         size_t snaptime_len = 0;
197         char *result = NULL;
198         struct shadow_copy2_config *config;
199
200         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
201                                 return NULL);
202
203         snaptime_len = shadow_copy2_posix_gmt_string(handle,
204                                                      snapshot,
205                                                      snaptime_string,
206                                                      sizeof(snaptime_string));
207         if (snaptime_len <= 0) {
208                 return NULL;
209         }
210
211         result = talloc_asprintf(mem_ctx, "%s/%s",
212                                  config->snapshot_basepath, snaptime_string);
213         if (result == NULL) {
214                 DEBUG(1, (__location__ " talloc_asprintf failed\n"));
215         }
216
217         return result;
218 }
219
220 /**
221  * Strip a snapshot component from a filename as
222  * handed in via the smb layer.
223  * Returns the parsed timestamp and the stripped filename.
224  */
225 static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx,
226                                         struct vfs_handle_struct *handle,
227                                         const char *name,
228                                         time_t *ptimestamp,
229                                         char **pstripped)
230 {
231         struct tm tm;
232         time_t timestamp;
233         const char *p;
234         char *q;
235         char *stripped;
236         size_t rest_len, dst_len;
237         struct shadow_copy2_config *config;
238
239         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
240                                 return false);
241
242         DEBUG(10, (__location__ ": enter path '%s'\n", name));
243
244         p = strstr_m(name, "@GMT-");
245         if (p == NULL) {
246                 goto no_snapshot;
247         }
248         if ((p > name) && (p[-1] != '/')) {
249                 /* the GMT-token does not start a path-component */
250                 goto no_snapshot;
251         }
252         q = strptime(p, GMT_FORMAT, &tm);
253         if (q == NULL) {
254                 goto no_snapshot;
255         }
256         tm.tm_isdst = -1;
257         timestamp = timegm(&tm);
258         if (timestamp == (time_t)-1) {
259                 goto no_snapshot;
260         }
261         if ((p == name) && (q[0] == '\0')) {
262                 /* the name consists of only the GMT token */
263                 if (pstripped != NULL) {
264                         stripped = talloc_strdup(mem_ctx, "");
265                         if (stripped == NULL) {
266                                 return false;
267                         }
268                         *pstripped = stripped;
269                 }
270                 *ptimestamp = timestamp;
271                 return true;
272         }
273         if (q[0] != '/') {
274                 /*
275                  * The GMT token is either at the end of the path
276                  * or it is not a complete path component, i.e. the
277                  * path component continues after the gmt-token.
278                  *
279                  * TODO: Is this correct? Or would the GMT tag as the
280                  * last component be a valid input?
281                  */
282                 goto no_snapshot;
283         }
284         q += 1;
285
286         rest_len = strlen(q);
287         dst_len = (p-name) + rest_len;
288
289         if (config->snapdirseverywhere) {
290                 char *insert;
291                 bool have_insert;
292                 insert = shadow_copy2_insert_string(talloc_tos(), handle,
293                                                     timestamp);
294                 if (insert == NULL) {
295                         errno = ENOMEM;
296                         return false;
297                 }
298
299                 DEBUG(10, (__location__ ": snapdirseverywhere mode.\n"
300                            "path '%s'.\n"
301                            "insert string '%s'\n", name, insert));
302
303                 have_insert = (strstr(name, insert+1) != NULL);
304                 if (have_insert) {
305                         DEBUG(10, (__location__ ": insert string '%s' found in "
306                                    "path '%s' found in snapdirseverywhere mode "
307                                    "==> already converted\n", insert, name));
308                         TALLOC_FREE(insert);
309                         goto no_snapshot;
310                 }
311                 TALLOC_FREE(insert);
312         } else {
313                 char *snapshot_path;
314                 char *s;
315
316                 snapshot_path = shadow_copy2_snapshot_path(talloc_tos(),
317                                                            handle,
318                                                            timestamp);
319                 if (snapshot_path == NULL) {
320                         errno = ENOMEM;
321                         return false;
322                 }
323
324                 DEBUG(10, (__location__ " path: '%s'.\n"
325                            "snapshot path: '%s'\n", name, snapshot_path));
326
327                 s = strstr(name, snapshot_path);
328                 if (s == name) {
329                         /*
330                          * this starts with "snapshot_basepath/GMT-Token"
331                          * so it is already a converted absolute
332                          * path. Don't process further.
333                          */
334                         DEBUG(10, (__location__ ": path '%s' starts with "
335                                    "snapshot path '%s' (not in "
336                                    "snapdirseverywhere mode) ==> "
337                                    "already converted\n", name, snapshot_path));
338                         talloc_free(snapshot_path);
339                         goto no_snapshot;
340                 }
341                 talloc_free(snapshot_path);
342         }
343
344         if (pstripped != NULL) {
345                 stripped = talloc_array(mem_ctx, char, dst_len+1);
346                 if (stripped == NULL) {
347                         errno = ENOMEM;
348                         return false;
349                 }
350                 if (p > name) {
351                         memcpy(stripped, name, p-name);
352                 }
353                 if (rest_len > 0) {
354                         memcpy(stripped + (p-name), q, rest_len);
355                 }
356                 stripped[dst_len] = '\0';
357                 *pstripped = stripped;
358         }
359         *ptimestamp = timestamp;
360         return true;
361 no_snapshot:
362         *ptimestamp = 0;
363         return true;
364 }
365
366 static char *shadow_copy2_find_mount_point(TALLOC_CTX *mem_ctx,
367                                            vfs_handle_struct *handle)
368 {
369         char *path = talloc_strdup(mem_ctx, handle->conn->connectpath);
370         dev_t dev;
371         struct stat st;
372         char *p;
373
374         if (stat(path, &st) != 0) {
375                 talloc_free(path);
376                 return NULL;
377         }
378
379         dev = st.st_dev;
380
381         while ((p = strrchr(path, '/')) && p > path) {
382                 *p = 0;
383                 if (stat(path, &st) != 0) {
384                         talloc_free(path);
385                         return NULL;
386                 }
387                 if (st.st_dev != dev) {
388                         *p = '/';
389                         break;
390                 }
391         }
392
393         return path;
394 }
395
396 /**
397  * Convert from a name as handed in via the SMB layer
398  * and a timestamp into the local path of the snapshot
399  * of the provided file at the provided time.
400  */
401 static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx,
402                                   struct vfs_handle_struct *handle,
403                                   const char *name, time_t timestamp)
404 {
405         struct smb_filename converted_fname;
406         char *result = NULL;
407         size_t *slashes = NULL;
408         unsigned num_slashes;
409         char *path = NULL;
410         size_t pathlen;
411         char *insert = NULL;
412         char *converted = NULL;
413         size_t insertlen;
414         int i, saved_errno;
415         size_t min_offset;
416         struct shadow_copy2_config *config;
417
418         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
419                                 return NULL);
420
421         DEBUG(10, ("converting '%s'\n", name));
422
423         if (!config->snapdirseverywhere) {
424                 int ret;
425                 char *snapshot_path;
426
427                 snapshot_path = shadow_copy2_snapshot_path(talloc_tos(),
428                                                            handle,
429                                                            timestamp);
430                 if (snapshot_path == NULL) {
431                         goto fail;
432                 }
433
434                 if (config->rel_connectpath == NULL) {
435                         converted = talloc_asprintf(mem_ctx, "%s/%s",
436                                                     snapshot_path, name);
437                 } else {
438                         converted = talloc_asprintf(mem_ctx, "%s/%s/%s",
439                                                     snapshot_path,
440                                                     config->rel_connectpath,
441                                                     name);
442                 }
443                 if (converted == NULL) {
444                         goto fail;
445                 }
446
447                 ZERO_STRUCT(converted_fname);
448                 converted_fname.base_name = converted;
449
450                 ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
451                 DEBUG(10, ("Trying[not snapdirseverywhere] %s: %d (%s)\n",
452                            converted,
453                            ret, ret == 0 ? "ok" : strerror(errno)));
454                 if (ret == 0) {
455                         DEBUG(10, ("Found %s\n", converted));
456                         result = converted;
457                         converted = NULL;
458                         goto fail;
459                 } else {
460                         errno = ENOENT;
461                         goto fail;
462                 }
463                 /* never reached ... */
464         }
465
466         path = talloc_asprintf(mem_ctx, "%s/%s", handle->conn->connectpath,
467                                name);
468         if (path == NULL) {
469                 errno = ENOMEM;
470                 goto fail;
471         }
472         pathlen = talloc_get_size(path)-1;
473
474         if (!shadow_copy2_find_slashes(talloc_tos(), path,
475                                        &slashes, &num_slashes)) {
476                 goto fail;
477         }
478
479         insert = shadow_copy2_insert_string(talloc_tos(), handle, timestamp);
480         if (insert == NULL) {
481                 goto fail;
482         }
483         insertlen = talloc_get_size(insert)-1;
484
485         /*
486          * Note: We deliberatly don't expensively initialize the
487          * array with talloc_zero here: Putting zero into
488          * converted[pathlen+insertlen] below is sufficient, because
489          * in the following for loop, the insert string is inserted
490          * at various slash places. So the memory up to position
491          * pathlen+insertlen will always be initialized when the
492          * converted string is used.
493          */
494         converted = talloc_array(mem_ctx, char, pathlen + insertlen + 1);
495         if (converted == NULL) {
496                 goto fail;
497         }
498
499         if (path[pathlen-1] != '/') {
500                 /*
501                  * Append a fake slash to find the snapshot root
502                  */
503                 size_t *tmp;
504                 tmp = talloc_realloc(talloc_tos(), slashes,
505                                      size_t, num_slashes+1);
506                 if (tmp == NULL) {
507                         goto fail;
508                 }
509                 slashes = tmp;
510                 slashes[num_slashes] = pathlen;
511                 num_slashes += 1;
512         }
513
514         min_offset = 0;
515
516         if (!config->crossmountpoints) {
517                 min_offset = strlen(config->mount_point);
518         }
519
520         memcpy(converted, path, pathlen+1);
521         converted[pathlen+insertlen] = '\0';
522
523         ZERO_STRUCT(converted_fname);
524         converted_fname.base_name = converted;
525
526         for (i = num_slashes-1; i>=0; i--) {
527                 int ret;
528                 size_t offset;
529
530                 offset = slashes[i];
531
532                 if (offset < min_offset) {
533                         errno = ENOENT;
534                         goto fail;
535                 }
536
537                 memcpy(converted+offset, insert, insertlen);
538
539                 offset += insertlen;
540                 memcpy(converted+offset, path + slashes[i],
541                        pathlen - slashes[i]);
542
543                 ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
544
545                 DEBUG(10, ("Trying[snapdirseverywhere] %s: %d (%s)\n",
546                            converted,
547                            ret, ret == 0 ? "ok" : strerror(errno)));
548                 if (ret == 0) {
549                         /* success */
550                         break;
551                 }
552                 if (errno == ENOTDIR) {
553                         /*
554                          * This is a valid condition: We appended the
555                          * .snaphots/@GMT.. to a file name. Just try
556                          * with the upper levels.
557                          */
558                         continue;
559                 }
560                 if (errno != ENOENT) {
561                         /* Other problem than "not found" */
562                         goto fail;
563                 }
564         }
565
566         if (i >= 0) {
567                 /*
568                  * Found something
569                  */
570                 DEBUG(10, ("Found %s\n", converted));
571                 result = converted;
572                 converted = NULL;
573         } else {
574                 errno = ENOENT;
575         }
576 fail:
577         saved_errno = errno;
578         TALLOC_FREE(converted);
579         TALLOC_FREE(insert);
580         TALLOC_FREE(slashes);
581         TALLOC_FREE(path);
582         errno = saved_errno;
583         return result;
584 }
585
586 /*
587   modify a sbuf return to ensure that inodes in the shadow directory
588   are different from those in the main directory
589  */
590 static void convert_sbuf(vfs_handle_struct *handle, const char *fname,
591                          SMB_STRUCT_STAT *sbuf)
592 {
593         struct shadow_copy2_config *config;
594
595         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
596                                 return);
597
598         if (config->fixinodes) {
599                 /* some snapshot systems, like GPFS, return the name
600                    device:inode for the snapshot files as the current
601                    files. That breaks the 'restore' button in the shadow copy
602                    GUI, as the client gets a sharing violation.
603
604                    This is a crude way of allowing both files to be
605                    open at once. It has a slight chance of inode
606                    number collision, but I can't see a better approach
607                    without significant VFS changes
608                 */
609                 uint32_t shash;
610
611                 shash = hash(fname, strlen(fname), 0) & 0xFF000000;
612                 if (shash == 0) {
613                         shash = 1;
614                 }
615                 sbuf->st_ex_ino ^= shash;
616         }
617 }
618
619 static DIR *shadow_copy2_opendir(vfs_handle_struct *handle,
620                                             const char *fname,
621                                             const char *mask,
622                                             uint32 attr)
623 {
624         time_t timestamp;
625         char *stripped;
626         DIR *ret;
627         int saved_errno;
628         char *conv;
629
630         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
631                                          &timestamp, &stripped)) {
632                 return NULL;
633         }
634         if (timestamp == 0) {
635                 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
636         }
637         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
638         TALLOC_FREE(stripped);
639         if (conv == NULL) {
640                 return NULL;
641         }
642         ret = SMB_VFS_NEXT_OPENDIR(handle, conv, mask, attr);
643         saved_errno = errno;
644         TALLOC_FREE(conv);
645         errno = saved_errno;
646         return ret;
647 }
648
649 static int shadow_copy2_rename(vfs_handle_struct *handle,
650                                const struct smb_filename *smb_fname_src,
651                                const struct smb_filename *smb_fname_dst)
652 {
653         time_t timestamp_src, timestamp_dst;
654
655         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
656                                          smb_fname_src->base_name,
657                                          &timestamp_src, NULL)) {
658                 return -1;
659         }
660         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
661                                          smb_fname_dst->base_name,
662                                          &timestamp_dst, NULL)) {
663                 return -1;
664         }
665         if (timestamp_src != 0) {
666                 errno = EXDEV;
667                 return -1;
668         }
669         if (timestamp_dst != 0) {
670                 errno = EROFS;
671                 return -1;
672         }
673         return SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
674 }
675
676 static int shadow_copy2_symlink(vfs_handle_struct *handle,
677                                 const char *oldname, const char *newname)
678 {
679         time_t timestamp_old, timestamp_new;
680
681         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
682                                          &timestamp_old, NULL)) {
683                 return -1;
684         }
685         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
686                                          &timestamp_new, NULL)) {
687                 return -1;
688         }
689         if ((timestamp_old != 0) || (timestamp_new != 0)) {
690                 errno = EROFS;
691                 return -1;
692         }
693         return SMB_VFS_NEXT_SYMLINK(handle, oldname, newname);
694 }
695
696 static int shadow_copy2_link(vfs_handle_struct *handle,
697                              const char *oldname, const char *newname)
698 {
699         time_t timestamp_old, timestamp_new;
700
701         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
702                                          &timestamp_old, NULL)) {
703                 return -1;
704         }
705         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
706                                          &timestamp_new, NULL)) {
707                 return -1;
708         }
709         if ((timestamp_old != 0) || (timestamp_new != 0)) {
710                 errno = EROFS;
711                 return -1;
712         }
713         return SMB_VFS_NEXT_LINK(handle, oldname, newname);
714 }
715
716 static int shadow_copy2_stat(vfs_handle_struct *handle,
717                              struct smb_filename *smb_fname)
718 {
719         time_t timestamp;
720         char *stripped, *tmp;
721         int ret, saved_errno;
722
723         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
724                                          smb_fname->base_name,
725                                          &timestamp, &stripped)) {
726                 return -1;
727         }
728         if (timestamp == 0) {
729                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
730         }
731
732         tmp = smb_fname->base_name;
733         smb_fname->base_name = shadow_copy2_convert(
734                 talloc_tos(), handle, stripped, timestamp);
735         TALLOC_FREE(stripped);
736
737         if (smb_fname->base_name == NULL) {
738                 smb_fname->base_name = tmp;
739                 return -1;
740         }
741
742         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
743         saved_errno = errno;
744
745         TALLOC_FREE(smb_fname->base_name);
746         smb_fname->base_name = tmp;
747
748         if (ret == 0) {
749                 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
750         }
751         errno = saved_errno;
752         return ret;
753 }
754
755 static int shadow_copy2_lstat(vfs_handle_struct *handle,
756                               struct smb_filename *smb_fname)
757 {
758         time_t timestamp;
759         char *stripped, *tmp;
760         int ret, saved_errno;
761
762         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
763                                          smb_fname->base_name,
764                                          &timestamp, &stripped)) {
765                 return -1;
766         }
767         if (timestamp == 0) {
768                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
769         }
770
771         tmp = smb_fname->base_name;
772         smb_fname->base_name = shadow_copy2_convert(
773                 talloc_tos(), handle, stripped, timestamp);
774         TALLOC_FREE(stripped);
775
776         if (smb_fname->base_name == NULL) {
777                 smb_fname->base_name = tmp;
778                 return -1;
779         }
780
781         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
782         saved_errno = errno;
783
784         TALLOC_FREE(smb_fname->base_name);
785         smb_fname->base_name = tmp;
786
787         if (ret == 0) {
788                 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
789         }
790         errno = saved_errno;
791         return ret;
792 }
793
794 static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
795                               SMB_STRUCT_STAT *sbuf)
796 {
797         time_t timestamp;
798         int ret;
799
800         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
801         if (ret == -1) {
802                 return ret;
803         }
804         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
805                                          fsp->fsp_name->base_name,
806                                          &timestamp, NULL)) {
807                 return 0;
808         }
809         if (timestamp != 0) {
810                 convert_sbuf(handle, fsp->fsp_name->base_name, sbuf);
811         }
812         return 0;
813 }
814
815 static int shadow_copy2_open(vfs_handle_struct *handle,
816                              struct smb_filename *smb_fname, files_struct *fsp,
817                              int flags, mode_t mode)
818 {
819         time_t timestamp;
820         char *stripped, *tmp;
821         int ret, saved_errno;
822
823         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
824                                          smb_fname->base_name,
825                                          &timestamp, &stripped)) {
826                 return -1;
827         }
828         if (timestamp == 0) {
829                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
830         }
831
832         tmp = smb_fname->base_name;
833         smb_fname->base_name = shadow_copy2_convert(
834                 talloc_tos(), handle, stripped, timestamp);
835         TALLOC_FREE(stripped);
836
837         if (smb_fname->base_name == NULL) {
838                 smb_fname->base_name = tmp;
839                 return -1;
840         }
841
842         ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
843         saved_errno = errno;
844
845         TALLOC_FREE(smb_fname->base_name);
846         smb_fname->base_name = tmp;
847
848         errno = saved_errno;
849         return ret;
850 }
851
852 static int shadow_copy2_unlink(vfs_handle_struct *handle,
853                                const struct smb_filename *smb_fname)
854 {
855         time_t timestamp;
856         char *stripped;
857         int ret, saved_errno;
858         struct smb_filename *conv;
859
860         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
861                                          smb_fname->base_name,
862                                          &timestamp, &stripped)) {
863                 return -1;
864         }
865         if (timestamp == 0) {
866                 return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
867         }
868         conv = cp_smb_filename(talloc_tos(), smb_fname);
869         if (conv == NULL) {
870                 errno = ENOMEM;
871                 return -1;
872         }
873         conv->base_name = shadow_copy2_convert(
874                 conv, handle, stripped, timestamp);
875         TALLOC_FREE(stripped);
876         if (conv->base_name == NULL) {
877                 return -1;
878         }
879         ret = SMB_VFS_NEXT_UNLINK(handle, conv);
880         saved_errno = errno;
881         TALLOC_FREE(conv);
882         errno = saved_errno;
883         return ret;
884 }
885
886 static int shadow_copy2_chmod(vfs_handle_struct *handle, const char *fname,
887                               mode_t mode)
888 {
889         time_t timestamp;
890         char *stripped;
891         int ret, saved_errno;
892         char *conv;
893
894         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
895                                          &timestamp, &stripped)) {
896                 return -1;
897         }
898         if (timestamp == 0) {
899                 return SMB_VFS_NEXT_CHMOD(handle, fname, mode);
900         }
901         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
902         TALLOC_FREE(stripped);
903         if (conv == NULL) {
904                 return -1;
905         }
906         ret = SMB_VFS_NEXT_CHMOD(handle, conv, mode);
907         saved_errno = errno;
908         TALLOC_FREE(conv);
909         errno = saved_errno;
910         return ret;
911 }
912
913 static int shadow_copy2_chown(vfs_handle_struct *handle, const char *fname,
914                               uid_t uid, gid_t gid)
915 {
916         time_t timestamp;
917         char *stripped;
918         int ret, saved_errno;
919         char *conv;
920
921         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
922                                          &timestamp, &stripped)) {
923                 return -1;
924         }
925         if (timestamp == 0) {
926                 return SMB_VFS_NEXT_CHOWN(handle, fname, uid, gid);
927         }
928         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
929         TALLOC_FREE(stripped);
930         if (conv == NULL) {
931                 return -1;
932         }
933         ret = SMB_VFS_NEXT_CHOWN(handle, conv, uid, gid);
934         saved_errno = errno;
935         TALLOC_FREE(conv);
936         errno = saved_errno;
937         return ret;
938 }
939
940 static int shadow_copy2_chdir(vfs_handle_struct *handle,
941                               const char *fname)
942 {
943         time_t timestamp;
944         char *stripped;
945         int ret, saved_errno;
946         char *conv;
947
948         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
949                                          &timestamp, &stripped)) {
950                 return -1;
951         }
952         if (timestamp == 0) {
953                 return SMB_VFS_NEXT_CHDIR(handle, fname);
954         }
955         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
956         TALLOC_FREE(stripped);
957         if (conv == NULL) {
958                 return -1;
959         }
960         ret = SMB_VFS_NEXT_CHDIR(handle, conv);
961         saved_errno = errno;
962         TALLOC_FREE(conv);
963         errno = saved_errno;
964         return ret;
965 }
966
967 static int shadow_copy2_ntimes(vfs_handle_struct *handle,
968                                const struct smb_filename *smb_fname,
969                                struct smb_file_time *ft)
970 {
971         time_t timestamp;
972         char *stripped;
973         int ret, saved_errno;
974         struct smb_filename *conv;
975
976         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
977                                          smb_fname->base_name,
978                                          &timestamp, &stripped)) {
979                 return -1;
980         }
981         if (timestamp == 0) {
982                 return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
983         }
984         conv = cp_smb_filename(talloc_tos(), smb_fname);
985         if (conv == NULL) {
986                 errno = ENOMEM;
987                 return -1;
988         }
989         conv->base_name = shadow_copy2_convert(
990                 conv, handle, stripped, timestamp);
991         TALLOC_FREE(stripped);
992         if (conv->base_name == NULL) {
993                 return -1;
994         }
995         ret = SMB_VFS_NEXT_NTIMES(handle, conv, ft);
996         saved_errno = errno;
997         TALLOC_FREE(conv);
998         errno = saved_errno;
999         return ret;
1000 }
1001
1002 static int shadow_copy2_readlink(vfs_handle_struct *handle,
1003                                  const char *fname, char *buf, size_t bufsiz)
1004 {
1005         time_t timestamp;
1006         char *stripped;
1007         int ret, saved_errno;
1008         char *conv;
1009
1010         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1011                                          &timestamp, &stripped)) {
1012                 return -1;
1013         }
1014         if (timestamp == 0) {
1015                 return SMB_VFS_NEXT_READLINK(handle, fname, buf, bufsiz);
1016         }
1017         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1018         TALLOC_FREE(stripped);
1019         if (conv == NULL) {
1020                 return -1;
1021         }
1022         ret = SMB_VFS_NEXT_READLINK(handle, conv, buf, bufsiz);
1023         saved_errno = errno;
1024         TALLOC_FREE(conv);
1025         errno = saved_errno;
1026         return ret;
1027 }
1028
1029 static int shadow_copy2_mknod(vfs_handle_struct *handle,
1030                               const char *fname, mode_t mode, SMB_DEV_T dev)
1031 {
1032         time_t timestamp;
1033         char *stripped;
1034         int ret, saved_errno;
1035         char *conv;
1036
1037         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1038                                          &timestamp, &stripped)) {
1039                 return -1;
1040         }
1041         if (timestamp == 0) {
1042                 return SMB_VFS_NEXT_MKNOD(handle, fname, mode, dev);
1043         }
1044         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1045         TALLOC_FREE(stripped);
1046         if (conv == NULL) {
1047                 return -1;
1048         }
1049         ret = SMB_VFS_NEXT_MKNOD(handle, conv, mode, dev);
1050         saved_errno = errno;
1051         TALLOC_FREE(conv);
1052         errno = saved_errno;
1053         return ret;
1054 }
1055
1056 static char *shadow_copy2_realpath(vfs_handle_struct *handle,
1057                                    const char *fname)
1058 {
1059         time_t timestamp;
1060         char *stripped = NULL;
1061         char *tmp = NULL;
1062         char *result = NULL;
1063         char *inserted = NULL;
1064         char *inserted_to, *inserted_end;
1065         int saved_errno;
1066
1067         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1068                                          &timestamp, &stripped)) {
1069                 goto done;
1070         }
1071         if (timestamp == 0) {
1072                 return SMB_VFS_NEXT_REALPATH(handle, fname);
1073         }
1074
1075         tmp = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1076         if (tmp == NULL) {
1077                 goto done;
1078         }
1079
1080         result = SMB_VFS_NEXT_REALPATH(handle, tmp);
1081         if (result == NULL) {
1082                 goto done;
1083         }
1084
1085         /*
1086          * Take away what we've inserted. This removes the @GMT-thingy
1087          * completely, but will give a path under the share root.
1088          */
1089         inserted = shadow_copy2_insert_string(talloc_tos(), handle, timestamp);
1090         if (inserted == NULL) {
1091                 goto done;
1092         }
1093         inserted_to = strstr_m(result, inserted);
1094         if (inserted_to == NULL) {
1095                 DEBUG(2, ("SMB_VFS_NEXT_REALPATH removed %s\n", inserted));
1096                 goto done;
1097         }
1098         inserted_end = inserted_to + talloc_get_size(inserted) - 1;
1099         memmove(inserted_to, inserted_end, strlen(inserted_end)+1);
1100
1101 done:
1102         saved_errno = errno;
1103         TALLOC_FREE(inserted);
1104         TALLOC_FREE(tmp);
1105         TALLOC_FREE(stripped);
1106         errno = saved_errno;
1107         return result;
1108 }
1109
1110 /**
1111  * Check whether a given directory contains a
1112  * snapshot directory as direct subdirectory.
1113  * If yes, return the path of the snapshot-subdir,
1114  * otherwise return NULL.
1115  */
1116 static char *have_snapdir(struct vfs_handle_struct *handle,
1117                           const char *path)
1118 {
1119         struct smb_filename smb_fname;
1120         int ret;
1121         struct shadow_copy2_config *config;
1122
1123         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1124                                 return NULL);
1125
1126         ZERO_STRUCT(smb_fname);
1127         smb_fname.base_name = talloc_asprintf(talloc_tos(), "%s/%s",
1128                                               path, config->snapdir);
1129         if (smb_fname.base_name == NULL) {
1130                 return NULL;
1131         }
1132
1133         ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
1134         if ((ret == 0) && (S_ISDIR(smb_fname.st.st_ex_mode))) {
1135                 return smb_fname.base_name;
1136         }
1137         TALLOC_FREE(smb_fname.base_name);
1138         return NULL;
1139 }
1140
1141 /**
1142  * Find the snapshot directory (if any) for the given
1143  * filename (which is relative to the share).
1144  */
1145 static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx,
1146                                              struct vfs_handle_struct *handle,
1147                                              struct smb_filename *smb_fname)
1148 {
1149         char *path, *p;
1150         const char *snapdir;
1151         struct shadow_copy2_config *config;
1152
1153         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1154                                 return NULL);
1155
1156         /*
1157          * If the non-snapdisrseverywhere mode, we should not search!
1158          */
1159         if (!config->snapdirseverywhere) {
1160                 return config->snapshot_basepath;
1161         }
1162
1163         path = talloc_asprintf(mem_ctx, "%s/%s",
1164                                handle->conn->connectpath,
1165                                smb_fname->base_name);
1166         if (path == NULL) {
1167                 return NULL;
1168         }
1169
1170         snapdir = have_snapdir(handle, path);
1171         if (snapdir != NULL) {
1172                 TALLOC_FREE(path);
1173                 return snapdir;
1174         }
1175
1176         while ((p = strrchr(path, '/')) && (p > path)) {
1177
1178                 p[0] = '\0';
1179
1180                 snapdir = have_snapdir(handle, path);
1181                 if (snapdir != NULL) {
1182                         TALLOC_FREE(path);
1183                         return snapdir;
1184                 }
1185         }
1186         TALLOC_FREE(path);
1187         return NULL;
1188 }
1189
1190 static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
1191                                          const char *name,
1192                                          char *gmt, size_t gmt_len)
1193 {
1194         struct tm timestamp;
1195         time_t timestamp_t;
1196         unsigned long int timestamp_long;
1197         const char *fmt;
1198         struct shadow_copy2_config *config;
1199
1200         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1201                                 return NULL);
1202
1203         fmt = config->gmt_format;
1204
1205         ZERO_STRUCT(timestamp);
1206         if (config->use_sscanf) {
1207                 if (sscanf(name, fmt, &timestamp_long) != 1) {
1208                         DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1209                                    "no sscanf match %s: %s\n",
1210                                    fmt, name));
1211                         return false;
1212                 }
1213                 timestamp_t = timestamp_long;
1214                 gmtime_r(&timestamp_t, &timestamp);
1215         } else {
1216                 if (strptime(name, fmt, &timestamp) == NULL) {
1217                         DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1218                                    "no match %s: %s\n",
1219                                    fmt, name));
1220                         return false;
1221                 }
1222                 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n",
1223                            fmt, name));
1224                 
1225                 if (config->use_localtime) {
1226                         timestamp.tm_isdst = -1;
1227                         timestamp_t = mktime(&timestamp);
1228                         gmtime_r(&timestamp_t, &timestamp);
1229                 }
1230         }
1231
1232         strftime(gmt, gmt_len, GMT_FORMAT, &timestamp);
1233         return true;
1234 }
1235
1236 static int shadow_copy2_label_cmp_asc(const void *x, const void *y)
1237 {
1238         return strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1239 }
1240
1241 static int shadow_copy2_label_cmp_desc(const void *x, const void *y)
1242 {
1243         return -strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1244 }
1245
1246 /*
1247   sort the shadow copy data in ascending or descending order
1248  */
1249 static void shadow_copy2_sort_data(vfs_handle_struct *handle,
1250                                    struct shadow_copy_data *shadow_copy2_data)
1251 {
1252         int (*cmpfunc)(const void *, const void *);
1253         const char *sort;
1254         struct shadow_copy2_config *config;
1255
1256         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1257                                 return);
1258
1259         sort = config->sort_order;
1260         if (sort == NULL) {
1261                 return;
1262         }
1263
1264         if (strcmp(sort, "asc") == 0) {
1265                 cmpfunc = shadow_copy2_label_cmp_asc;
1266         } else if (strcmp(sort, "desc") == 0) {
1267                 cmpfunc = shadow_copy2_label_cmp_desc;
1268         } else {
1269                 return;
1270         }
1271
1272         if (shadow_copy2_data && shadow_copy2_data->num_volumes > 0 &&
1273             shadow_copy2_data->labels)
1274         {
1275                 TYPESAFE_QSORT(shadow_copy2_data->labels,
1276                                shadow_copy2_data->num_volumes,
1277                                cmpfunc);
1278         }
1279 }
1280
1281 static int shadow_copy2_get_shadow_copy_data(
1282         vfs_handle_struct *handle, files_struct *fsp,
1283         struct shadow_copy_data *shadow_copy2_data,
1284         bool labels)
1285 {
1286         DIR *p;
1287         const char *snapdir;
1288         struct dirent *d;
1289         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1290
1291         snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle, fsp->fsp_name);
1292         if (snapdir == NULL) {
1293                 DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
1294                          handle->conn->connectpath));
1295                 errno = EINVAL;
1296                 talloc_free(tmp_ctx);
1297                 return -1;
1298         }
1299
1300         p = SMB_VFS_NEXT_OPENDIR(handle, snapdir, NULL, 0);
1301
1302         if (!p) {
1303                 DEBUG(2,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s'"
1304                          " - %s\n", snapdir, strerror(errno)));
1305                 talloc_free(tmp_ctx);
1306                 errno = ENOSYS;
1307                 return -1;
1308         }
1309
1310         shadow_copy2_data->num_volumes = 0;
1311         shadow_copy2_data->labels      = NULL;
1312
1313         while ((d = SMB_VFS_NEXT_READDIR(handle, p, NULL))) {
1314                 char snapshot[GMT_NAME_LEN+1];
1315                 SHADOW_COPY_LABEL *tlabels;
1316
1317                 /*
1318                  * ignore names not of the right form in the snapshot
1319                  * directory
1320                  */
1321                 if (!shadow_copy2_snapshot_to_gmt(
1322                             handle, d->d_name,
1323                             snapshot, sizeof(snapshot))) {
1324
1325                         DEBUG(6, ("shadow_copy2_get_shadow_copy_data: "
1326                                   "ignoring %s\n", d->d_name));
1327                         continue;
1328                 }
1329                 DEBUG(6,("shadow_copy2_get_shadow_copy_data: %s -> %s\n",
1330                          d->d_name, snapshot));
1331
1332                 if (!labels) {
1333                         /* the caller doesn't want the labels */
1334                         shadow_copy2_data->num_volumes++;
1335                         continue;
1336                 }
1337
1338                 tlabels = talloc_realloc(shadow_copy2_data,
1339                                          shadow_copy2_data->labels,
1340                                          SHADOW_COPY_LABEL,
1341                                          shadow_copy2_data->num_volumes+1);
1342                 if (tlabels == NULL) {
1343                         DEBUG(0,("shadow_copy2: out of memory\n"));
1344                         SMB_VFS_NEXT_CLOSEDIR(handle, p);
1345                         talloc_free(tmp_ctx);
1346                         return -1;
1347                 }
1348
1349                 strlcpy(tlabels[shadow_copy2_data->num_volumes], snapshot,
1350                         sizeof(*tlabels));
1351
1352                 shadow_copy2_data->num_volumes++;
1353                 shadow_copy2_data->labels = tlabels;
1354         }
1355
1356         SMB_VFS_NEXT_CLOSEDIR(handle,p);
1357
1358         shadow_copy2_sort_data(handle, shadow_copy2_data);
1359
1360         talloc_free(tmp_ctx);
1361         return 0;
1362 }
1363
1364 static NTSTATUS shadow_copy2_fget_nt_acl(vfs_handle_struct *handle,
1365                                         struct files_struct *fsp,
1366                                         uint32 security_info,
1367                                          TALLOC_CTX *mem_ctx,
1368                                         struct security_descriptor **ppdesc)
1369 {
1370         time_t timestamp;
1371         char *stripped;
1372         NTSTATUS status;
1373         char *conv;
1374
1375         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1376                                          fsp->fsp_name->base_name,
1377                                          &timestamp, &stripped)) {
1378                 return map_nt_error_from_unix(errno);
1379         }
1380         if (timestamp == 0) {
1381                 return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
1382                                                 mem_ctx,
1383                                                 ppdesc);
1384         }
1385         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1386         TALLOC_FREE(stripped);
1387         if (conv == NULL) {
1388                 return map_nt_error_from_unix(errno);
1389         }
1390         status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv, security_info,
1391                                          mem_ctx, ppdesc);
1392         TALLOC_FREE(conv);
1393         return status;
1394 }
1395
1396 static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle,
1397                                         const char *fname,
1398                                         uint32 security_info,
1399                                         TALLOC_CTX *mem_ctx,
1400                                         struct security_descriptor **ppdesc)
1401 {
1402         time_t timestamp;
1403         char *stripped;
1404         NTSTATUS status;
1405         char *conv;
1406
1407         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1408                                          &timestamp, &stripped)) {
1409                 return map_nt_error_from_unix(errno);
1410         }
1411         if (timestamp == 0) {
1412                 return SMB_VFS_NEXT_GET_NT_ACL(handle, fname, security_info,
1413                                                mem_ctx, ppdesc);
1414         }
1415         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1416         TALLOC_FREE(stripped);
1417         if (conv == NULL) {
1418                 return map_nt_error_from_unix(errno);
1419         }
1420         status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv, security_info,
1421                                          mem_ctx, ppdesc);
1422         TALLOC_FREE(conv);
1423         return status;
1424 }
1425
1426 static int shadow_copy2_mkdir(vfs_handle_struct *handle,
1427                               const char *fname, mode_t mode)
1428 {
1429         time_t timestamp;
1430         char *stripped;
1431         int ret, saved_errno;
1432         char *conv;
1433
1434         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1435                                          &timestamp, &stripped)) {
1436                 return -1;
1437         }
1438         if (timestamp == 0) {
1439                 return SMB_VFS_NEXT_MKDIR(handle, fname, mode);
1440         }
1441         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1442         TALLOC_FREE(stripped);
1443         if (conv == NULL) {
1444                 return -1;
1445         }
1446         ret = SMB_VFS_NEXT_MKDIR(handle, conv, mode);
1447         saved_errno = errno;
1448         TALLOC_FREE(conv);
1449         errno = saved_errno;
1450         return ret;
1451 }
1452
1453 static int shadow_copy2_rmdir(vfs_handle_struct *handle, const char *fname)
1454 {
1455         time_t timestamp;
1456         char *stripped;
1457         int ret, saved_errno;
1458         char *conv;
1459
1460         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1461                                          &timestamp, &stripped)) {
1462                 return -1;
1463         }
1464         if (timestamp == 0) {
1465                 return SMB_VFS_NEXT_RMDIR(handle, fname);
1466         }
1467         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1468         TALLOC_FREE(stripped);
1469         if (conv == NULL) {
1470                 return -1;
1471         }
1472         ret = SMB_VFS_NEXT_RMDIR(handle, conv);
1473         saved_errno = errno;
1474         TALLOC_FREE(conv);
1475         errno = saved_errno;
1476         return ret;
1477 }
1478
1479 static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname,
1480                                 unsigned int flags)
1481 {
1482         time_t timestamp;
1483         char *stripped;
1484         int ret, saved_errno;
1485         char *conv;
1486
1487         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1488                                          &timestamp, &stripped)) {
1489                 return -1;
1490         }
1491         if (timestamp == 0) {
1492                 return SMB_VFS_NEXT_CHFLAGS(handle, fname, flags);
1493         }
1494         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1495         TALLOC_FREE(stripped);
1496         if (conv == NULL) {
1497                 return -1;
1498         }
1499         ret = SMB_VFS_NEXT_CHFLAGS(handle, conv, flags);
1500         saved_errno = errno;
1501         TALLOC_FREE(conv);
1502         errno = saved_errno;
1503         return ret;
1504 }
1505
1506 static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
1507                                      const char *fname, const char *aname,
1508                                      void *value, size_t size)
1509 {
1510         time_t timestamp;
1511         char *stripped;
1512         ssize_t ret;
1513         int saved_errno;
1514         char *conv;
1515
1516         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1517                                          &timestamp, &stripped)) {
1518                 return -1;
1519         }
1520         if (timestamp == 0) {
1521                 return SMB_VFS_NEXT_GETXATTR(handle, fname, aname, value,
1522                                              size);
1523         }
1524         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1525         TALLOC_FREE(stripped);
1526         if (conv == NULL) {
1527                 return -1;
1528         }
1529         ret = SMB_VFS_NEXT_GETXATTR(handle, conv, aname, value, size);
1530         saved_errno = errno;
1531         TALLOC_FREE(conv);
1532         errno = saved_errno;
1533         return ret;
1534 }
1535
1536 static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle,
1537                                       const char *fname,
1538                                       char *list, size_t size)
1539 {
1540         time_t timestamp;
1541         char *stripped;
1542         ssize_t ret;
1543         int saved_errno;
1544         char *conv;
1545
1546         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1547                                          &timestamp, &stripped)) {
1548                 return -1;
1549         }
1550         if (timestamp == 0) {
1551                 return SMB_VFS_NEXT_LISTXATTR(handle, fname, list, size);
1552         }
1553         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1554         TALLOC_FREE(stripped);
1555         if (conv == NULL) {
1556                 return -1;
1557         }
1558         ret = SMB_VFS_NEXT_LISTXATTR(handle, conv, list, size);
1559         saved_errno = errno;
1560         TALLOC_FREE(conv);
1561         errno = saved_errno;
1562         return ret;
1563 }
1564
1565 static int shadow_copy2_removexattr(vfs_handle_struct *handle,
1566                                     const char *fname, const char *aname)
1567 {
1568         time_t timestamp;
1569         char *stripped;
1570         int ret, saved_errno;
1571         char *conv;
1572
1573         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1574                                          &timestamp, &stripped)) {
1575                 return -1;
1576         }
1577         if (timestamp == 0) {
1578                 return SMB_VFS_NEXT_REMOVEXATTR(handle, fname, aname);
1579         }
1580         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1581         TALLOC_FREE(stripped);
1582         if (conv == NULL) {
1583                 return -1;
1584         }
1585         ret = SMB_VFS_NEXT_REMOVEXATTR(handle, conv, aname);
1586         saved_errno = errno;
1587         TALLOC_FREE(conv);
1588         errno = saved_errno;
1589         return ret;
1590 }
1591
1592 static int shadow_copy2_setxattr(struct vfs_handle_struct *handle,
1593                                  const char *fname,
1594                                  const char *aname, const void *value,
1595                                  size_t size, int flags)
1596 {
1597         time_t timestamp;
1598         char *stripped;
1599         ssize_t ret;
1600         int saved_errno;
1601         char *conv;
1602
1603         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1604                                          &timestamp, &stripped)) {
1605                 return -1;
1606         }
1607         if (timestamp == 0) {
1608                 return SMB_VFS_NEXT_SETXATTR(handle, fname, aname, value, size,
1609                                              flags);
1610         }
1611         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1612         TALLOC_FREE(stripped);
1613         if (conv == NULL) {
1614                 return -1;
1615         }
1616         ret = SMB_VFS_NEXT_SETXATTR(handle, conv, aname, value, size, flags);
1617         saved_errno = errno;
1618         TALLOC_FREE(conv);
1619         errno = saved_errno;
1620         return ret;
1621 }
1622
1623 static int shadow_copy2_chmod_acl(vfs_handle_struct *handle,
1624                                   const char *fname, mode_t mode)
1625 {
1626         time_t timestamp;
1627         char *stripped;
1628         ssize_t ret;
1629         int saved_errno;
1630         char *conv;
1631
1632         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1633                                          &timestamp, &stripped)) {
1634                 return -1;
1635         }
1636         if (timestamp == 0) {
1637                 return SMB_VFS_NEXT_CHMOD_ACL(handle, fname, mode);
1638         }
1639         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1640         TALLOC_FREE(stripped);
1641         if (conv == NULL) {
1642                 return -1;
1643         }
1644         ret = SMB_VFS_NEXT_CHMOD_ACL(handle, conv, mode);
1645         saved_errno = errno;
1646         TALLOC_FREE(conv);
1647         errno = saved_errno;
1648         return ret;
1649 }
1650
1651 static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle,
1652                                           const char *path,
1653                                           const char *name,
1654                                           TALLOC_CTX *mem_ctx,
1655                                           char **found_name)
1656 {
1657         time_t timestamp;
1658         char *stripped;
1659         ssize_t ret;
1660         int saved_errno;
1661         char *conv;
1662
1663         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
1664                                          &timestamp, &stripped)) {
1665                 return -1;
1666         }
1667         if (timestamp == 0) {
1668                 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
1669                                                       mem_ctx, found_name);
1670         }
1671         if (stripped[0] == '\0') {
1672                 *found_name = talloc_strdup(mem_ctx, name);
1673                 if (*found_name == NULL) {
1674                         errno = ENOMEM;
1675                         return -1;
1676                 }
1677                 return 0;
1678         }
1679         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1680         TALLOC_FREE(stripped);
1681         if (conv == NULL) {
1682                 return -1;
1683         }
1684         ret = SMB_VFS_NEXT_GET_REAL_FILENAME(handle, conv, name,
1685                                              mem_ctx, found_name);
1686         saved_errno = errno;
1687         TALLOC_FREE(conv);
1688         errno = saved_errno;
1689         return ret;
1690 }
1691
1692 static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle,
1693                                        const char *path, bool small_query,
1694                                        uint64_t *bsize, uint64_t *dfree,
1695                                        uint64_t *dsize)
1696 {
1697         time_t timestamp;
1698         char *stripped;
1699         ssize_t ret;
1700         int saved_errno;
1701         char *conv;
1702
1703         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
1704                                          &timestamp, &stripped)) {
1705                 return -1;
1706         }
1707         if (timestamp == 0) {
1708                 return SMB_VFS_NEXT_DISK_FREE(handle, path, small_query,
1709                                               bsize, dfree, dsize);
1710         }
1711
1712         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1713         TALLOC_FREE(stripped);
1714         if (conv == NULL) {
1715                 return -1;
1716         }
1717
1718         ret = SMB_VFS_NEXT_DISK_FREE(handle, conv, small_query, bsize, dfree,
1719                                      dsize);
1720
1721         saved_errno = errno;
1722         TALLOC_FREE(conv);
1723         errno = saved_errno;
1724
1725         return ret;
1726 }
1727
1728 static int shadow_copy2_connect(struct vfs_handle_struct *handle,
1729                                 const char *service, const char *user)
1730 {
1731         struct shadow_copy2_config *config;
1732         int ret;
1733         const char *snapdir;
1734         const char *gmt_format;
1735         const char *sort_order;
1736         const char *basedir;
1737         const char *mount_point;
1738
1739         DEBUG(10, (__location__ ": cnum[%u], connectpath[%s]\n",
1740                    (unsigned)handle->conn->cnum,
1741                    handle->conn->connectpath));
1742
1743         ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
1744         if (ret < 0) {
1745                 return ret;
1746         }
1747
1748         config = talloc_zero(handle->conn, struct shadow_copy2_config);
1749         if (config == NULL) {
1750                 DEBUG(0, ("talloc_zero() failed\n"));
1751                 errno = ENOMEM;
1752                 return -1;
1753         }
1754
1755         gmt_format = lp_parm_const_string(SNUM(handle->conn),
1756                                           "shadow", "format",
1757                                           GMT_FORMAT);
1758         config->gmt_format = talloc_strdup(config, gmt_format);
1759         if (config->gmt_format == NULL) {
1760                 DEBUG(0, ("talloc_strdup() failed\n"));
1761                 errno = ENOMEM;
1762                 return -1;
1763         }
1764
1765         config->use_sscanf = lp_parm_bool(SNUM(handle->conn),
1766                                           "shadow", "sscanf", false);
1767
1768         config->use_localtime = lp_parm_bool(SNUM(handle->conn),
1769                                              "shadow", "localtime",
1770                                              false);
1771
1772         snapdir = lp_parm_const_string(SNUM(handle->conn),
1773                                        "shadow", "snapdir",
1774                                        ".snapshots");
1775         config->snapdir = talloc_strdup(config, snapdir);
1776         if (config->snapdir == NULL) {
1777                 DEBUG(0, ("talloc_strdup() failed\n"));
1778                 errno = ENOMEM;
1779                 return -1;
1780         }
1781
1782         config->snapdirseverywhere = lp_parm_bool(SNUM(handle->conn),
1783                                                   "shadow",
1784                                                   "snapdirseverywhere",
1785                                                   false);
1786
1787         config->crossmountpoints = lp_parm_bool(SNUM(handle->conn),
1788                                                 "shadow", "crossmountpoints",
1789                                                 false);
1790
1791         config->fixinodes = lp_parm_bool(SNUM(handle->conn),
1792                                          "shadow", "fixinodes",
1793                                          false);
1794
1795         sort_order = lp_parm_const_string(SNUM(handle->conn),
1796                                           "shadow", "sort", "desc");
1797         config->sort_order = talloc_strdup(config, sort_order);
1798         if (config->sort_order == NULL) {
1799                 DEBUG(0, ("talloc_strdup() failed\n"));
1800                 errno = ENOMEM;
1801                 return -1;
1802         }
1803
1804         mount_point = lp_parm_const_string(SNUM(handle->conn),
1805                                            "shadow", "mountpoint", NULL);
1806         if (mount_point != NULL) {
1807                 if (mount_point[0] != '/') {
1808                         DEBUG(1, (__location__ " Warning: 'mountpoint' is "
1809                                   "relative ('%s'), but it has to be an "
1810                                   "absolute path. Ignoring provided value.\n",
1811                                   mount_point));
1812                         mount_point = NULL;
1813                 } else {
1814                         char *p;
1815                         p = strstr(handle->conn->connectpath, mount_point);
1816                         if (p != handle->conn->connectpath) {
1817                                 DEBUG(1, ("Warning: mount_point (%s) is not a "
1818                                           "subdirectory of the share root "
1819                                           "(%s). Ignoring provided value.\n",
1820                                           mount_point,
1821                                           handle->conn->connectpath));
1822                                 mount_point = NULL;
1823                         }
1824                 }
1825         }
1826
1827         if (mount_point != NULL) {
1828                 config->mount_point = talloc_strdup(config, mount_point);
1829                 if (config->mount_point == NULL) {
1830                         DEBUG(0, (__location__ " talloc_strdup() failed\n"));
1831                         return -1;
1832                 }
1833         } else {
1834                 config->mount_point = shadow_copy2_find_mount_point(config,
1835                                                                     handle);
1836                 if (config->mount_point == NULL) {
1837                         DEBUG(0, (__location__ ": shadow_copy2_find_mount_point"
1838                                   " failed: %s\n", strerror(errno)));
1839                         return -1;
1840                 }
1841         }
1842
1843         basedir = lp_parm_const_string(SNUM(handle->conn),
1844                                        "shadow", "basedir", NULL);
1845
1846         if (basedir != NULL) {
1847                 if (basedir[0] != '/') {
1848                         DEBUG(1, (__location__ " Warning: 'basedir' is "
1849                                   "relative ('%s'), but it has to be an "
1850                                   "absolute path. Disabling basedir.\n",
1851                                   basedir));
1852                 } else {
1853                         char *p;
1854                         p = strstr(basedir, config->mount_point);
1855                         if (p != basedir) {
1856                                 DEBUG(1, ("Warning: basedir (%s) is not a "
1857                                           "subdirectory of the share root's "
1858                                           "mount point (%s). "
1859                                           "Disabling basedir\n",
1860                                           basedir, config->mount_point));
1861                         } else {
1862                                 config->basedir = talloc_strdup(config,
1863                                                                 basedir);
1864                                 if (config->basedir == NULL) {
1865                                         DEBUG(0, ("talloc_strdup() failed\n"));
1866                                         errno = ENOMEM;
1867                                         return -1;
1868                                 }
1869                         }
1870                 }
1871         }
1872
1873         if (config->snapdirseverywhere && config->basedir != NULL) {
1874                 DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
1875                           "with 'snapdirseverywhere'. Disabling basedir.\n"));
1876                 TALLOC_FREE(config->basedir);
1877         }
1878
1879         if (config->crossmountpoints && config->basedir != NULL) {
1880                 DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
1881                           "with 'crossmountpoints'. Disabling basedir.\n"));
1882                 TALLOC_FREE(config->basedir);
1883         }
1884
1885         if (config->basedir == NULL) {
1886                 config->basedir = config->mount_point;
1887         }
1888
1889         if (strlen(config->basedir) != strlen(handle->conn->connectpath)) {
1890                 config->rel_connectpath = talloc_strdup(config,
1891                         handle->conn->connectpath + strlen(config->basedir));
1892                 if (config->rel_connectpath == NULL) {
1893                         DEBUG(0, ("talloc_strdup() failed\n"));
1894                         errno = ENOMEM;
1895                         return -1;
1896                 }
1897         }
1898
1899         if (config->snapdir[0] == '/') {
1900                 config->snapdir_absolute = true;
1901
1902                 if (config->snapdirseverywhere == true) {
1903                         DEBUG(1, (__location__ " Warning: An absolute snapdir "
1904                                   "is incompatible with 'snapdirseverywhere', "
1905                                   "setting 'snapdirseverywhere' to false.\n"));
1906                         config->snapdirseverywhere = false;
1907                 }
1908
1909                 if (config->crossmountpoints == true) {
1910                         DEBUG(1, (__location__ " Warning: 'crossmountpoints' "
1911                                   "is not supported with an absolute snapdir. "
1912                                   "Disabling it.\n"));
1913                         config->crossmountpoints = false;
1914                 }
1915
1916                 config->snapshot_basepath = config->snapdir;
1917         } else {
1918                 config->snapshot_basepath = talloc_asprintf(config, "%s/%s",
1919                                 config->mount_point, config->snapdir);
1920                 if (config->snapshot_basepath == NULL) {
1921                         DEBUG(0, ("talloc_asprintf() failed\n"));
1922                         errno = ENOMEM;
1923                         return -1;
1924                 }
1925         }
1926
1927         DEBUG(10, ("shadow_copy2_connect: configuration:\n"
1928                    "  share root: '%s'\n"
1929                    "  basedir: '%s'\n"
1930                    "  mountpoint: '%s'\n"
1931                    "  rel share root: '%s'\n"
1932                    "  snapdir: '%s'\n"
1933                    "  snapshot base path: '%s'\n"
1934                    "  format: '%s'\n"
1935                    "  use sscanf: %s\n"
1936                    "  snapdirs everywhere: %s\n"
1937                    "  cross mountpoints: %s\n"
1938                    "  fix inodes: %s\n"
1939                    "  sort order: %s\n"
1940                    "",
1941                    handle->conn->connectpath,
1942                    config->basedir,
1943                    config->mount_point,
1944                    config->rel_connectpath,
1945                    config->snapdir,
1946                    config->snapshot_basepath,
1947                    config->gmt_format,
1948                    config->use_sscanf ? "yes" : "no",
1949                    config->snapdirseverywhere ? "yes" : "no",
1950                    config->crossmountpoints ? "yes" : "no",
1951                    config->fixinodes ? "yes" : "no",
1952                    config->sort_order
1953                    ));
1954
1955
1956         SMB_VFS_HANDLE_SET_DATA(handle, config,
1957                                 NULL, struct shadow_copy2_config,
1958                                 return -1);
1959
1960         return 0;
1961 }
1962
1963 static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
1964         .connect_fn = shadow_copy2_connect,
1965         .opendir_fn = shadow_copy2_opendir,
1966         .disk_free_fn = shadow_copy2_disk_free,
1967         .rename_fn = shadow_copy2_rename,
1968         .link_fn = shadow_copy2_link,
1969         .symlink_fn = shadow_copy2_symlink,
1970         .stat_fn = shadow_copy2_stat,
1971         .lstat_fn = shadow_copy2_lstat,
1972         .fstat_fn = shadow_copy2_fstat,
1973         .open_fn = shadow_copy2_open,
1974         .unlink_fn = shadow_copy2_unlink,
1975         .chmod_fn = shadow_copy2_chmod,
1976         .chown_fn = shadow_copy2_chown,
1977         .chdir_fn = shadow_copy2_chdir,
1978         .ntimes_fn = shadow_copy2_ntimes,
1979         .readlink_fn = shadow_copy2_readlink,
1980         .mknod_fn = shadow_copy2_mknod,
1981         .realpath_fn = shadow_copy2_realpath,
1982         .get_nt_acl_fn = shadow_copy2_get_nt_acl,
1983         .fget_nt_acl_fn = shadow_copy2_fget_nt_acl,
1984         .get_shadow_copy_data_fn = shadow_copy2_get_shadow_copy_data,
1985         .mkdir_fn = shadow_copy2_mkdir,
1986         .rmdir_fn = shadow_copy2_rmdir,
1987         .getxattr_fn = shadow_copy2_getxattr,
1988         .listxattr_fn = shadow_copy2_listxattr,
1989         .removexattr_fn = shadow_copy2_removexattr,
1990         .setxattr_fn = shadow_copy2_setxattr,
1991         .chmod_acl_fn = shadow_copy2_chmod_acl,
1992         .chflags_fn = shadow_copy2_chflags,
1993         .get_real_filename_fn = shadow_copy2_get_real_filename,
1994 };
1995
1996 NTSTATUS vfs_shadow_copy2_init(void);
1997 NTSTATUS vfs_shadow_copy2_init(void)
1998 {
1999         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2000                                 "shadow_copy2", &vfs_shadow_copy2_fns);
2001 }