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