shadow_copy2: improve debug in shadow_copy2_convert() in snapdirseverywhere mode
[obnox/samba/samba-obnox.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         DEBUG(10, ("converting '%s'\n", name));
494
495         if (!config->snapdirseverywhere) {
496                 int ret;
497                 char *snapshot_path;
498
499                 snapshot_path = shadow_copy2_snapshot_path(talloc_tos(),
500                                                            handle,
501                                                            timestamp);
502                 if (snapshot_path == NULL) {
503                         goto fail;
504                 }
505
506                 if (config->rel_connectpath == NULL) {
507                         converted = talloc_asprintf(mem_ctx, "%s/%s",
508                                                     snapshot_path, name);
509                 } else {
510                         converted = talloc_asprintf(mem_ctx, "%s/%s/%s",
511                                                     snapshot_path,
512                                                     config->rel_connectpath,
513                                                     name);
514                 }
515                 if (converted == NULL) {
516                         goto fail;
517                 }
518
519                 ZERO_STRUCT(converted_fname);
520                 converted_fname.base_name = converted;
521
522                 ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
523                 DEBUG(10, ("Trying[not snapdirseverywhere] %s: %d (%s)\n",
524                            converted,
525                            ret, ret == 0 ? "ok" : strerror(errno)));
526                 if (ret == 0) {
527                         DEBUG(10, ("Found %s\n", converted));
528                         result = converted;
529                         converted = NULL;
530                         goto fail;
531                 } else {
532                         errno = ENOENT;
533                         goto fail;
534                 }
535                 /* never reached ... */
536         }
537
538         path = talloc_asprintf(mem_ctx, "%s/%s", handle->conn->connectpath,
539                                name);
540         if (path == NULL) {
541                 errno = ENOMEM;
542                 goto fail;
543         }
544         pathlen = talloc_get_size(path)-1;
545
546         if (!shadow_copy2_find_slashes(talloc_tos(), path,
547                                        &slashes, &num_slashes)) {
548                 goto fail;
549         }
550
551         insert = shadow_copy2_insert_string(talloc_tos(), handle, timestamp);
552         if (insert == NULL) {
553                 goto fail;
554         }
555         insertlen = talloc_get_size(insert)-1;
556
557         converted = talloc_zero_array(mem_ctx, char, pathlen + insertlen + 1);
558         if (converted == NULL) {
559                 goto fail;
560         }
561
562         if (path[pathlen-1] != '/') {
563                 /*
564                  * Append a fake slash to find the snapshot root
565                  */
566                 size_t *tmp;
567                 tmp = talloc_realloc(talloc_tos(), slashes,
568                                      size_t, num_slashes+1);
569                 if (tmp == NULL) {
570                         goto fail;
571                 }
572                 slashes = tmp;
573                 slashes[num_slashes] = pathlen;
574                 num_slashes += 1;
575         }
576
577         min_offset = 0;
578
579         if (!config->crossmountpoints) {
580                 char *mount_point;
581
582                 mount_point = shadow_copy2_find_mount_point(talloc_tos(),
583                                                             handle);
584                 if (mount_point == NULL) {
585                         goto fail;
586                 }
587                 min_offset = strlen(mount_point);
588                 TALLOC_FREE(mount_point);
589         }
590
591         memcpy(converted, path, pathlen+1);
592         converted[pathlen+insertlen] = '\0';
593
594         ZERO_STRUCT(converted_fname);
595         converted_fname.base_name = converted;
596
597         for (i = num_slashes-1; i>=0; i--) {
598                 int ret;
599                 size_t offset;
600
601                 offset = slashes[i];
602
603                 if (offset < min_offset) {
604                         errno = ENOENT;
605                         goto fail;
606                 }
607
608                 memcpy(converted+offset, insert, insertlen);
609
610                 offset += insertlen;
611                 memcpy(converted+offset, path + slashes[i],
612                        pathlen - slashes[i]);
613
614                 ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
615
616                 DEBUG(10, ("Trying[snapdirseverywhere] %s: %d (%s)\n",
617                            converted,
618                            ret, ret == 0 ? "ok" : strerror(errno)));
619                 if (ret == 0) {
620                         /* success */
621                         break;
622                 }
623                 if (errno == ENOTDIR) {
624                         /*
625                          * This is a valid condition: We appended the
626                          * .snaphots/@GMT.. to a file name. Just try
627                          * with the upper levels.
628                          */
629                         continue;
630                 }
631                 if (errno != ENOENT) {
632                         /* Other problem than "not found" */
633                         goto fail;
634                 }
635         }
636
637         if (i >= 0) {
638                 /*
639                  * Found something
640                  */
641                 DEBUG(10, ("Found %s\n", converted));
642                 result = converted;
643                 converted = NULL;
644         } else {
645                 errno = ENOENT;
646         }
647 fail:
648         saved_errno = errno;
649         TALLOC_FREE(converted);
650         TALLOC_FREE(insert);
651         TALLOC_FREE(slashes);
652         TALLOC_FREE(path);
653         errno = saved_errno;
654         return result;
655 }
656
657 /*
658   modify a sbuf return to ensure that inodes in the shadow directory
659   are different from those in the main directory
660  */
661 static void convert_sbuf(vfs_handle_struct *handle, const char *fname,
662                          SMB_STRUCT_STAT *sbuf)
663 {
664         struct shadow_copy2_config *config;
665
666         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
667                                 return);
668
669         if (config->fixinodes) {
670                 /* some snapshot systems, like GPFS, return the name
671                    device:inode for the snapshot files as the current
672                    files. That breaks the 'restore' button in the shadow copy
673                    GUI, as the client gets a sharing violation.
674
675                    This is a crude way of allowing both files to be
676                    open at once. It has a slight chance of inode
677                    number collision, but I can't see a better approach
678                    without significant VFS changes
679                 */
680                 uint32_t shash;
681
682                 shash = hash(fname, strlen(fname), 0) & 0xFF000000;
683                 if (shash == 0) {
684                         shash = 1;
685                 }
686                 sbuf->st_ex_ino ^= shash;
687         }
688 }
689
690 static DIR *shadow_copy2_opendir(vfs_handle_struct *handle,
691                                             const char *fname,
692                                             const char *mask,
693                                             uint32 attr)
694 {
695         time_t timestamp;
696         char *stripped;
697         DIR *ret;
698         int saved_errno;
699         char *conv;
700
701         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
702                                          &timestamp, &stripped)) {
703                 return NULL;
704         }
705         if (timestamp == 0) {
706                 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
707         }
708         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
709         TALLOC_FREE(stripped);
710         if (conv == NULL) {
711                 return NULL;
712         }
713         ret = SMB_VFS_NEXT_OPENDIR(handle, conv, mask, attr);
714         saved_errno = errno;
715         TALLOC_FREE(conv);
716         errno = saved_errno;
717         return ret;
718 }
719
720 static int shadow_copy2_rename(vfs_handle_struct *handle,
721                                const struct smb_filename *smb_fname_src,
722                                const struct smb_filename *smb_fname_dst)
723 {
724         time_t timestamp_src, timestamp_dst;
725
726         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
727                                          smb_fname_src->base_name,
728                                          &timestamp_src, NULL)) {
729                 return -1;
730         }
731         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
732                                          smb_fname_dst->base_name,
733                                          &timestamp_dst, NULL)) {
734                 return -1;
735         }
736         if (timestamp_src != 0) {
737                 errno = EXDEV;
738                 return -1;
739         }
740         if (timestamp_dst != 0) {
741                 errno = EROFS;
742                 return -1;
743         }
744         return SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
745 }
746
747 static int shadow_copy2_symlink(vfs_handle_struct *handle,
748                                 const char *oldname, const char *newname)
749 {
750         time_t timestamp_old, timestamp_new;
751
752         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
753                                          &timestamp_old, NULL)) {
754                 return -1;
755         }
756         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
757                                          &timestamp_new, NULL)) {
758                 return -1;
759         }
760         if ((timestamp_old != 0) || (timestamp_new != 0)) {
761                 errno = EROFS;
762                 return -1;
763         }
764         return SMB_VFS_NEXT_SYMLINK(handle, oldname, newname);
765 }
766
767 static int shadow_copy2_link(vfs_handle_struct *handle,
768                              const char *oldname, const char *newname)
769 {
770         time_t timestamp_old, timestamp_new;
771
772         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
773                                          &timestamp_old, NULL)) {
774                 return -1;
775         }
776         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
777                                          &timestamp_new, NULL)) {
778                 return -1;
779         }
780         if ((timestamp_old != 0) || (timestamp_new != 0)) {
781                 errno = EROFS;
782                 return -1;
783         }
784         return SMB_VFS_NEXT_LINK(handle, oldname, newname);
785 }
786
787 static int shadow_copy2_stat(vfs_handle_struct *handle,
788                              struct smb_filename *smb_fname)
789 {
790         time_t timestamp;
791         char *stripped, *tmp;
792         int ret, saved_errno;
793
794         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
795                                          smb_fname->base_name,
796                                          &timestamp, &stripped)) {
797                 return -1;
798         }
799         if (timestamp == 0) {
800                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
801         }
802
803         tmp = smb_fname->base_name;
804         smb_fname->base_name = shadow_copy2_convert(
805                 talloc_tos(), handle, stripped, timestamp);
806         TALLOC_FREE(stripped);
807
808         if (smb_fname->base_name == NULL) {
809                 smb_fname->base_name = tmp;
810                 return -1;
811         }
812
813         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
814         saved_errno = errno;
815
816         TALLOC_FREE(smb_fname->base_name);
817         smb_fname->base_name = tmp;
818
819         if (ret == 0) {
820                 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
821         }
822         errno = saved_errno;
823         return ret;
824 }
825
826 static int shadow_copy2_lstat(vfs_handle_struct *handle,
827                               struct smb_filename *smb_fname)
828 {
829         time_t timestamp;
830         char *stripped, *tmp;
831         int ret, saved_errno;
832
833         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
834                                          smb_fname->base_name,
835                                          &timestamp, &stripped)) {
836                 return -1;
837         }
838         if (timestamp == 0) {
839                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
840         }
841
842         tmp = smb_fname->base_name;
843         smb_fname->base_name = shadow_copy2_convert(
844                 talloc_tos(), handle, stripped, timestamp);
845         TALLOC_FREE(stripped);
846
847         if (smb_fname->base_name == NULL) {
848                 smb_fname->base_name = tmp;
849                 return -1;
850         }
851
852         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
853         saved_errno = errno;
854
855         TALLOC_FREE(smb_fname->base_name);
856         smb_fname->base_name = tmp;
857
858         if (ret == 0) {
859                 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
860         }
861         errno = saved_errno;
862         return ret;
863 }
864
865 static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
866                               SMB_STRUCT_STAT *sbuf)
867 {
868         time_t timestamp;
869         int ret;
870
871         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
872         if (ret == -1) {
873                 return ret;
874         }
875         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
876                                          fsp->fsp_name->base_name,
877                                          &timestamp, NULL)) {
878                 return 0;
879         }
880         if (timestamp != 0) {
881                 convert_sbuf(handle, fsp->fsp_name->base_name, sbuf);
882         }
883         return 0;
884 }
885
886 static int shadow_copy2_open(vfs_handle_struct *handle,
887                              struct smb_filename *smb_fname, files_struct *fsp,
888                              int flags, mode_t mode)
889 {
890         time_t timestamp;
891         char *stripped, *tmp;
892         int ret, saved_errno;
893
894         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
895                                          smb_fname->base_name,
896                                          &timestamp, &stripped)) {
897                 return -1;
898         }
899         if (timestamp == 0) {
900                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
901         }
902
903         tmp = smb_fname->base_name;
904         smb_fname->base_name = shadow_copy2_convert(
905                 talloc_tos(), handle, stripped, timestamp);
906         TALLOC_FREE(stripped);
907
908         if (smb_fname->base_name == NULL) {
909                 smb_fname->base_name = tmp;
910                 return -1;
911         }
912
913         ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
914         saved_errno = errno;
915
916         TALLOC_FREE(smb_fname->base_name);
917         smb_fname->base_name = tmp;
918
919         errno = saved_errno;
920         return ret;
921 }
922
923 static int shadow_copy2_unlink(vfs_handle_struct *handle,
924                                const struct smb_filename *smb_fname)
925 {
926         time_t timestamp;
927         char *stripped;
928         int ret, saved_errno;
929         struct smb_filename *conv;
930
931         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
932                                          smb_fname->base_name,
933                                          &timestamp, &stripped)) {
934                 return -1;
935         }
936         if (timestamp == 0) {
937                 return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
938         }
939         conv = cp_smb_filename(talloc_tos(), smb_fname);
940         if (conv == NULL) {
941                 errno = ENOMEM;
942                 return -1;
943         }
944         conv->base_name = shadow_copy2_convert(
945                 conv, handle, stripped, timestamp);
946         TALLOC_FREE(stripped);
947         if (conv->base_name == NULL) {
948                 return -1;
949         }
950         ret = SMB_VFS_NEXT_UNLINK(handle, conv);
951         saved_errno = errno;
952         TALLOC_FREE(conv);
953         errno = saved_errno;
954         return ret;
955 }
956
957 static int shadow_copy2_chmod(vfs_handle_struct *handle, const char *fname,
958                               mode_t mode)
959 {
960         time_t timestamp;
961         char *stripped;
962         int ret, saved_errno;
963         char *conv;
964
965         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
966                                          &timestamp, &stripped)) {
967                 return -1;
968         }
969         if (timestamp == 0) {
970                 return SMB_VFS_NEXT_CHMOD(handle, fname, mode);
971         }
972         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
973         TALLOC_FREE(stripped);
974         if (conv == NULL) {
975                 return -1;
976         }
977         ret = SMB_VFS_NEXT_CHMOD(handle, conv, mode);
978         saved_errno = errno;
979         TALLOC_FREE(conv);
980         errno = saved_errno;
981         return ret;
982 }
983
984 static int shadow_copy2_chown(vfs_handle_struct *handle, const char *fname,
985                               uid_t uid, gid_t gid)
986 {
987         time_t timestamp;
988         char *stripped;
989         int ret, saved_errno;
990         char *conv;
991
992         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
993                                          &timestamp, &stripped)) {
994                 return -1;
995         }
996         if (timestamp == 0) {
997                 return SMB_VFS_NEXT_CHOWN(handle, fname, uid, gid);
998         }
999         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1000         TALLOC_FREE(stripped);
1001         if (conv == NULL) {
1002                 return -1;
1003         }
1004         ret = SMB_VFS_NEXT_CHOWN(handle, conv, uid, gid);
1005         saved_errno = errno;
1006         TALLOC_FREE(conv);
1007         errno = saved_errno;
1008         return ret;
1009 }
1010
1011 static int shadow_copy2_chdir(vfs_handle_struct *handle,
1012                               const char *fname)
1013 {
1014         time_t timestamp;
1015         char *stripped;
1016         int ret, saved_errno;
1017         char *conv;
1018
1019         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1020                                          &timestamp, &stripped)) {
1021                 return -1;
1022         }
1023         if (timestamp == 0) {
1024                 return SMB_VFS_NEXT_CHDIR(handle, fname);
1025         }
1026         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1027         TALLOC_FREE(stripped);
1028         if (conv == NULL) {
1029                 return -1;
1030         }
1031         ret = SMB_VFS_NEXT_CHDIR(handle, conv);
1032         saved_errno = errno;
1033         TALLOC_FREE(conv);
1034         errno = saved_errno;
1035         return ret;
1036 }
1037
1038 static int shadow_copy2_ntimes(vfs_handle_struct *handle,
1039                                const struct smb_filename *smb_fname,
1040                                struct smb_file_time *ft)
1041 {
1042         time_t timestamp;
1043         char *stripped;
1044         int ret, saved_errno;
1045         struct smb_filename *conv;
1046
1047         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1048                                          smb_fname->base_name,
1049                                          &timestamp, &stripped)) {
1050                 return -1;
1051         }
1052         if (timestamp == 0) {
1053                 return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1054         }
1055         conv = cp_smb_filename(talloc_tos(), smb_fname);
1056         if (conv == NULL) {
1057                 errno = ENOMEM;
1058                 return -1;
1059         }
1060         conv->base_name = shadow_copy2_convert(
1061                 conv, handle, stripped, timestamp);
1062         TALLOC_FREE(stripped);
1063         if (conv->base_name == NULL) {
1064                 return -1;
1065         }
1066         ret = SMB_VFS_NEXT_NTIMES(handle, conv, ft);
1067         saved_errno = errno;
1068         TALLOC_FREE(conv);
1069         errno = saved_errno;
1070         return ret;
1071 }
1072
1073 static int shadow_copy2_readlink(vfs_handle_struct *handle,
1074                                  const char *fname, char *buf, size_t bufsiz)
1075 {
1076         time_t timestamp;
1077         char *stripped;
1078         int ret, saved_errno;
1079         char *conv;
1080
1081         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1082                                          &timestamp, &stripped)) {
1083                 return -1;
1084         }
1085         if (timestamp == 0) {
1086                 return SMB_VFS_NEXT_READLINK(handle, fname, buf, bufsiz);
1087         }
1088         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1089         TALLOC_FREE(stripped);
1090         if (conv == NULL) {
1091                 return -1;
1092         }
1093         ret = SMB_VFS_NEXT_READLINK(handle, conv, buf, bufsiz);
1094         saved_errno = errno;
1095         TALLOC_FREE(conv);
1096         errno = saved_errno;
1097         return ret;
1098 }
1099
1100 static int shadow_copy2_mknod(vfs_handle_struct *handle,
1101                               const char *fname, mode_t mode, SMB_DEV_T dev)
1102 {
1103         time_t timestamp;
1104         char *stripped;
1105         int ret, saved_errno;
1106         char *conv;
1107
1108         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1109                                          &timestamp, &stripped)) {
1110                 return -1;
1111         }
1112         if (timestamp == 0) {
1113                 return SMB_VFS_NEXT_MKNOD(handle, fname, mode, dev);
1114         }
1115         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1116         TALLOC_FREE(stripped);
1117         if (conv == NULL) {
1118                 return -1;
1119         }
1120         ret = SMB_VFS_NEXT_MKNOD(handle, conv, mode, dev);
1121         saved_errno = errno;
1122         TALLOC_FREE(conv);
1123         errno = saved_errno;
1124         return ret;
1125 }
1126
1127 static char *shadow_copy2_realpath(vfs_handle_struct *handle,
1128                                    const char *fname)
1129 {
1130         time_t timestamp;
1131         char *stripped = NULL;
1132         char *tmp = NULL;
1133         char *result = NULL;
1134         char *inserted = NULL;
1135         char *inserted_to, *inserted_end;
1136         int saved_errno;
1137
1138         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1139                                          &timestamp, &stripped)) {
1140                 goto done;
1141         }
1142         if (timestamp == 0) {
1143                 return SMB_VFS_NEXT_REALPATH(handle, fname);
1144         }
1145
1146         tmp = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1147         if (tmp == NULL) {
1148                 goto done;
1149         }
1150
1151         result = SMB_VFS_NEXT_REALPATH(handle, tmp);
1152         if (result == NULL) {
1153                 goto done;
1154         }
1155
1156         /*
1157          * Take away what we've inserted. This removes the @GMT-thingy
1158          * completely, but will give a path under the share root.
1159          */
1160         inserted = shadow_copy2_insert_string(talloc_tos(), handle, timestamp);
1161         if (inserted == NULL) {
1162                 goto done;
1163         }
1164         inserted_to = strstr_m(result, inserted);
1165         if (inserted_to == NULL) {
1166                 DEBUG(2, ("SMB_VFS_NEXT_REALPATH removed %s\n", inserted));
1167                 goto done;
1168         }
1169         inserted_end = inserted_to + talloc_get_size(inserted) - 1;
1170         memmove(inserted_to, inserted_end, strlen(inserted_end)+1);
1171
1172 done:
1173         saved_errno = errno;
1174         TALLOC_FREE(inserted);
1175         TALLOC_FREE(tmp);
1176         TALLOC_FREE(stripped);
1177         errno = saved_errno;
1178         return result;
1179 }
1180
1181 /**
1182  * Check whether a given directory contains a
1183  * snapshot directory as direct subdirectory.
1184  * If yes, return the path of the snapshot-subdir,
1185  * otherwise return NULL.
1186  */
1187 static char *have_snapdir(struct vfs_handle_struct *handle,
1188                           const char *path)
1189 {
1190         struct smb_filename smb_fname;
1191         int ret;
1192         struct shadow_copy2_config *config;
1193
1194         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1195                                 return NULL);
1196
1197         ZERO_STRUCT(smb_fname);
1198         smb_fname.base_name = talloc_asprintf(talloc_tos(), "%s/%s",
1199                                               path, config->snapdir);
1200         if (smb_fname.base_name == NULL) {
1201                 return NULL;
1202         }
1203
1204         ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
1205         if ((ret == 0) && (S_ISDIR(smb_fname.st.st_ex_mode))) {
1206                 return smb_fname.base_name;
1207         }
1208         TALLOC_FREE(smb_fname.base_name);
1209         return NULL;
1210 }
1211
1212 /**
1213  * Find the snapshot directory (if any) for the given
1214  * filename (which is relative to the share).
1215  */
1216 static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx,
1217                                              struct vfs_handle_struct *handle,
1218                                              struct smb_filename *smb_fname)
1219 {
1220         char *path, *p;
1221         const char *snapdir;
1222         struct shadow_copy2_config *config;
1223
1224         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1225                                 return NULL);
1226
1227         /*
1228          * If the non-snapdisrseverywhere mode, we should not search!
1229          */
1230         if (!config->snapdirseverywhere) {
1231                 return config->snapshot_basepath;
1232         }
1233
1234         path = talloc_asprintf(mem_ctx, "%s/%s",
1235                                handle->conn->connectpath,
1236                                smb_fname->base_name);
1237         if (path == NULL) {
1238                 return NULL;
1239         }
1240
1241         snapdir = have_snapdir(handle, path);
1242         if (snapdir != NULL) {
1243                 TALLOC_FREE(path);
1244                 return snapdir;
1245         }
1246
1247         while ((p = strrchr(path, '/')) && (p > path)) {
1248
1249                 p[0] = '\0';
1250
1251                 snapdir = have_snapdir(handle, path);
1252                 if (snapdir != NULL) {
1253                         TALLOC_FREE(path);
1254                         return snapdir;
1255                 }
1256         }
1257         TALLOC_FREE(path);
1258         return NULL;
1259 }
1260
1261 static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
1262                                          const char *name,
1263                                          char *gmt, size_t gmt_len)
1264 {
1265         struct tm timestamp;
1266         time_t timestamp_t;
1267         unsigned long int timestamp_long;
1268         const char *fmt;
1269         struct shadow_copy2_config *config;
1270
1271         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1272                                 return NULL);
1273
1274         fmt = config->gmt_format;
1275
1276         ZERO_STRUCT(timestamp);
1277         if (config->use_sscanf) {
1278                 if (sscanf(name, fmt, &timestamp_long) != 1) {
1279                         DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1280                                    "no sscanf match %s: %s\n",
1281                                    fmt, name));
1282                         return false;
1283                 }
1284                 timestamp_t = timestamp_long;
1285                 gmtime_r(&timestamp_t, &timestamp);
1286         } else {
1287                 if (strptime(name, fmt, &timestamp) == NULL) {
1288                         DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1289                                    "no match %s: %s\n",
1290                                    fmt, name));
1291                         return false;
1292                 }
1293                 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n",
1294                            fmt, name));
1295                 
1296                 if (config->use_localtime) {
1297                         timestamp.tm_isdst = -1;
1298                         timestamp_t = mktime(&timestamp);
1299                         gmtime_r(&timestamp_t, &timestamp);
1300                 }
1301         }
1302
1303         strftime(gmt, gmt_len, GMT_FORMAT, &timestamp);
1304         return true;
1305 }
1306
1307 static int shadow_copy2_label_cmp_asc(const void *x, const void *y)
1308 {
1309         return strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1310 }
1311
1312 static int shadow_copy2_label_cmp_desc(const void *x, const void *y)
1313 {
1314         return -strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1315 }
1316
1317 /*
1318   sort the shadow copy data in ascending or descending order
1319  */
1320 static void shadow_copy2_sort_data(vfs_handle_struct *handle,
1321                                    struct shadow_copy_data *shadow_copy2_data)
1322 {
1323         int (*cmpfunc)(const void *, const void *);
1324         const char *sort;
1325         struct shadow_copy2_config *config;
1326
1327         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1328                                 return);
1329
1330         sort = config->sort_order;
1331         if (sort == NULL) {
1332                 return;
1333         }
1334
1335         if (strcmp(sort, "asc") == 0) {
1336                 cmpfunc = shadow_copy2_label_cmp_asc;
1337         } else if (strcmp(sort, "desc") == 0) {
1338                 cmpfunc = shadow_copy2_label_cmp_desc;
1339         } else {
1340                 return;
1341         }
1342
1343         if (shadow_copy2_data && shadow_copy2_data->num_volumes > 0 &&
1344             shadow_copy2_data->labels)
1345         {
1346                 TYPESAFE_QSORT(shadow_copy2_data->labels,
1347                                shadow_copy2_data->num_volumes,
1348                                cmpfunc);
1349         }
1350 }
1351
1352 static int shadow_copy2_get_shadow_copy_data(
1353         vfs_handle_struct *handle, files_struct *fsp,
1354         struct shadow_copy_data *shadow_copy2_data,
1355         bool labels)
1356 {
1357         DIR *p;
1358         const char *snapdir;
1359         struct dirent *d;
1360         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1361
1362         snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle, fsp->fsp_name);
1363         if (snapdir == NULL) {
1364                 DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
1365                          handle->conn->connectpath));
1366                 errno = EINVAL;
1367                 talloc_free(tmp_ctx);
1368                 return -1;
1369         }
1370
1371         p = SMB_VFS_NEXT_OPENDIR(handle, snapdir, NULL, 0);
1372
1373         if (!p) {
1374                 DEBUG(2,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s'"
1375                          " - %s\n", snapdir, strerror(errno)));
1376                 talloc_free(tmp_ctx);
1377                 errno = ENOSYS;
1378                 return -1;
1379         }
1380
1381         shadow_copy2_data->num_volumes = 0;
1382         shadow_copy2_data->labels      = NULL;
1383
1384         while ((d = SMB_VFS_NEXT_READDIR(handle, p, NULL))) {
1385                 char snapshot[GMT_NAME_LEN+1];
1386                 SHADOW_COPY_LABEL *tlabels;
1387
1388                 /*
1389                  * ignore names not of the right form in the snapshot
1390                  * directory
1391                  */
1392                 if (!shadow_copy2_snapshot_to_gmt(
1393                             handle, d->d_name,
1394                             snapshot, sizeof(snapshot))) {
1395
1396                         DEBUG(6, ("shadow_copy2_get_shadow_copy_data: "
1397                                   "ignoring %s\n", d->d_name));
1398                         continue;
1399                 }
1400                 DEBUG(6,("shadow_copy2_get_shadow_copy_data: %s -> %s\n",
1401                          d->d_name, snapshot));
1402
1403                 if (!labels) {
1404                         /* the caller doesn't want the labels */
1405                         shadow_copy2_data->num_volumes++;
1406                         continue;
1407                 }
1408
1409                 tlabels = talloc_realloc(shadow_copy2_data,
1410                                          shadow_copy2_data->labels,
1411                                          SHADOW_COPY_LABEL,
1412                                          shadow_copy2_data->num_volumes+1);
1413                 if (tlabels == NULL) {
1414                         DEBUG(0,("shadow_copy2: out of memory\n"));
1415                         SMB_VFS_NEXT_CLOSEDIR(handle, p);
1416                         talloc_free(tmp_ctx);
1417                         return -1;
1418                 }
1419
1420                 strlcpy(tlabels[shadow_copy2_data->num_volumes], snapshot,
1421                         sizeof(*tlabels));
1422
1423                 shadow_copy2_data->num_volumes++;
1424                 shadow_copy2_data->labels = tlabels;
1425         }
1426
1427         SMB_VFS_NEXT_CLOSEDIR(handle,p);
1428
1429         shadow_copy2_sort_data(handle, shadow_copy2_data);
1430
1431         talloc_free(tmp_ctx);
1432         return 0;
1433 }
1434
1435 static NTSTATUS shadow_copy2_fget_nt_acl(vfs_handle_struct *handle,
1436                                         struct files_struct *fsp,
1437                                         uint32 security_info,
1438                                          TALLOC_CTX *mem_ctx,
1439                                         struct security_descriptor **ppdesc)
1440 {
1441         time_t timestamp;
1442         char *stripped;
1443         NTSTATUS status;
1444         char *conv;
1445
1446         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1447                                          fsp->fsp_name->base_name,
1448                                          &timestamp, &stripped)) {
1449                 return map_nt_error_from_unix(errno);
1450         }
1451         if (timestamp == 0) {
1452                 return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
1453                                                 mem_ctx,
1454                                                 ppdesc);
1455         }
1456         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1457         TALLOC_FREE(stripped);
1458         if (conv == NULL) {
1459                 return map_nt_error_from_unix(errno);
1460         }
1461         status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv, security_info,
1462                                          mem_ctx, ppdesc);
1463         TALLOC_FREE(conv);
1464         return status;
1465 }
1466
1467 static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle,
1468                                         const char *fname,
1469                                         uint32 security_info,
1470                                         TALLOC_CTX *mem_ctx,
1471                                         struct security_descriptor **ppdesc)
1472 {
1473         time_t timestamp;
1474         char *stripped;
1475         NTSTATUS status;
1476         char *conv;
1477
1478         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1479                                          &timestamp, &stripped)) {
1480                 return map_nt_error_from_unix(errno);
1481         }
1482         if (timestamp == 0) {
1483                 return SMB_VFS_NEXT_GET_NT_ACL(handle, fname, security_info,
1484                                                mem_ctx, ppdesc);
1485         }
1486         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1487         TALLOC_FREE(stripped);
1488         if (conv == NULL) {
1489                 return map_nt_error_from_unix(errno);
1490         }
1491         status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv, security_info,
1492                                          mem_ctx, ppdesc);
1493         TALLOC_FREE(conv);
1494         return status;
1495 }
1496
1497 static int shadow_copy2_mkdir(vfs_handle_struct *handle,
1498                               const char *fname, mode_t mode)
1499 {
1500         time_t timestamp;
1501         char *stripped;
1502         int ret, saved_errno;
1503         char *conv;
1504
1505         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1506                                          &timestamp, &stripped)) {
1507                 return -1;
1508         }
1509         if (timestamp == 0) {
1510                 return SMB_VFS_NEXT_MKDIR(handle, fname, mode);
1511         }
1512         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1513         TALLOC_FREE(stripped);
1514         if (conv == NULL) {
1515                 return -1;
1516         }
1517         ret = SMB_VFS_NEXT_MKDIR(handle, conv, mode);
1518         saved_errno = errno;
1519         TALLOC_FREE(conv);
1520         errno = saved_errno;
1521         return ret;
1522 }
1523
1524 static int shadow_copy2_rmdir(vfs_handle_struct *handle, const char *fname)
1525 {
1526         time_t timestamp;
1527         char *stripped;
1528         int ret, saved_errno;
1529         char *conv;
1530
1531         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1532                                          &timestamp, &stripped)) {
1533                 return -1;
1534         }
1535         if (timestamp == 0) {
1536                 return SMB_VFS_NEXT_RMDIR(handle, fname);
1537         }
1538         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1539         TALLOC_FREE(stripped);
1540         if (conv == NULL) {
1541                 return -1;
1542         }
1543         ret = SMB_VFS_NEXT_RMDIR(handle, conv);
1544         saved_errno = errno;
1545         TALLOC_FREE(conv);
1546         errno = saved_errno;
1547         return ret;
1548 }
1549
1550 static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname,
1551                                 unsigned int flags)
1552 {
1553         time_t timestamp;
1554         char *stripped;
1555         int ret, saved_errno;
1556         char *conv;
1557
1558         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1559                                          &timestamp, &stripped)) {
1560                 return -1;
1561         }
1562         if (timestamp == 0) {
1563                 return SMB_VFS_NEXT_CHFLAGS(handle, fname, flags);
1564         }
1565         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1566         TALLOC_FREE(stripped);
1567         if (conv == NULL) {
1568                 return -1;
1569         }
1570         ret = SMB_VFS_NEXT_CHFLAGS(handle, conv, flags);
1571         saved_errno = errno;
1572         TALLOC_FREE(conv);
1573         errno = saved_errno;
1574         return ret;
1575 }
1576
1577 static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
1578                                      const char *fname, const char *aname,
1579                                      void *value, size_t size)
1580 {
1581         time_t timestamp;
1582         char *stripped;
1583         ssize_t ret;
1584         int saved_errno;
1585         char *conv;
1586
1587         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1588                                          &timestamp, &stripped)) {
1589                 return -1;
1590         }
1591         if (timestamp == 0) {
1592                 return SMB_VFS_NEXT_GETXATTR(handle, fname, aname, value,
1593                                              size);
1594         }
1595         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1596         TALLOC_FREE(stripped);
1597         if (conv == NULL) {
1598                 return -1;
1599         }
1600         ret = SMB_VFS_NEXT_GETXATTR(handle, conv, aname, value, size);
1601         saved_errno = errno;
1602         TALLOC_FREE(conv);
1603         errno = saved_errno;
1604         return ret;
1605 }
1606
1607 static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle,
1608                                       const char *fname,
1609                                       char *list, size_t size)
1610 {
1611         time_t timestamp;
1612         char *stripped;
1613         ssize_t ret;
1614         int saved_errno;
1615         char *conv;
1616
1617         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1618                                          &timestamp, &stripped)) {
1619                 return -1;
1620         }
1621         if (timestamp == 0) {
1622                 return SMB_VFS_NEXT_LISTXATTR(handle, fname, list, size);
1623         }
1624         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1625         TALLOC_FREE(stripped);
1626         if (conv == NULL) {
1627                 return -1;
1628         }
1629         ret = SMB_VFS_NEXT_LISTXATTR(handle, conv, list, size);
1630         saved_errno = errno;
1631         TALLOC_FREE(conv);
1632         errno = saved_errno;
1633         return ret;
1634 }
1635
1636 static int shadow_copy2_removexattr(vfs_handle_struct *handle,
1637                                     const char *fname, const char *aname)
1638 {
1639         time_t timestamp;
1640         char *stripped;
1641         int ret, saved_errno;
1642         char *conv;
1643
1644         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1645                                          &timestamp, &stripped)) {
1646                 return -1;
1647         }
1648         if (timestamp == 0) {
1649                 return SMB_VFS_NEXT_REMOVEXATTR(handle, fname, aname);
1650         }
1651         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1652         TALLOC_FREE(stripped);
1653         if (conv == NULL) {
1654                 return -1;
1655         }
1656         ret = SMB_VFS_NEXT_REMOVEXATTR(handle, conv, aname);
1657         saved_errno = errno;
1658         TALLOC_FREE(conv);
1659         errno = saved_errno;
1660         return ret;
1661 }
1662
1663 static int shadow_copy2_setxattr(struct vfs_handle_struct *handle,
1664                                  const char *fname,
1665                                  const char *aname, const void *value,
1666                                  size_t size, int flags)
1667 {
1668         time_t timestamp;
1669         char *stripped;
1670         ssize_t ret;
1671         int saved_errno;
1672         char *conv;
1673
1674         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1675                                          &timestamp, &stripped)) {
1676                 return -1;
1677         }
1678         if (timestamp == 0) {
1679                 return SMB_VFS_NEXT_SETXATTR(handle, fname, aname, value, size,
1680                                              flags);
1681         }
1682         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1683         TALLOC_FREE(stripped);
1684         if (conv == NULL) {
1685                 return -1;
1686         }
1687         ret = SMB_VFS_NEXT_SETXATTR(handle, conv, aname, value, size, flags);
1688         saved_errno = errno;
1689         TALLOC_FREE(conv);
1690         errno = saved_errno;
1691         return ret;
1692 }
1693
1694 static int shadow_copy2_chmod_acl(vfs_handle_struct *handle,
1695                                   const char *fname, mode_t mode)
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, fname,
1704                                          &timestamp, &stripped)) {
1705                 return -1;
1706         }
1707         if (timestamp == 0) {
1708                 return SMB_VFS_NEXT_CHMOD_ACL(handle, fname, mode);
1709         }
1710         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1711         TALLOC_FREE(stripped);
1712         if (conv == NULL) {
1713                 return -1;
1714         }
1715         ret = SMB_VFS_NEXT_CHMOD_ACL(handle, conv, mode);
1716         saved_errno = errno;
1717         TALLOC_FREE(conv);
1718         errno = saved_errno;
1719         return ret;
1720 }
1721
1722 static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle,
1723                                           const char *path,
1724                                           const char *name,
1725                                           TALLOC_CTX *mem_ctx,
1726                                           char **found_name)
1727 {
1728         time_t timestamp;
1729         char *stripped;
1730         ssize_t ret;
1731         int saved_errno;
1732         char *conv;
1733
1734         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
1735                                          &timestamp, &stripped)) {
1736                 return -1;
1737         }
1738         if (timestamp == 0) {
1739                 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
1740                                                       mem_ctx, found_name);
1741         }
1742         if (stripped[0] == '\0') {
1743                 *found_name = talloc_strdup(mem_ctx, name);
1744                 if (*found_name == NULL) {
1745                         errno = ENOMEM;
1746                         return -1;
1747                 }
1748                 return 0;
1749         }
1750         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1751         TALLOC_FREE(stripped);
1752         if (conv == NULL) {
1753                 return -1;
1754         }
1755         ret = SMB_VFS_NEXT_GET_REAL_FILENAME(handle, conv, name,
1756                                              mem_ctx, found_name);
1757         saved_errno = errno;
1758         TALLOC_FREE(conv);
1759         errno = saved_errno;
1760         return ret;
1761 }
1762
1763 static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle,
1764                                        const char *path, bool small_query,
1765                                        uint64_t *bsize, uint64_t *dfree,
1766                                        uint64_t *dsize)
1767 {
1768         time_t timestamp;
1769         char *stripped;
1770         ssize_t ret;
1771         int saved_errno;
1772         char *conv;
1773
1774         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
1775                                          &timestamp, &stripped)) {
1776                 return -1;
1777         }
1778         if (timestamp == 0) {
1779                 return SMB_VFS_NEXT_DISK_FREE(handle, path, small_query,
1780                                               bsize, dfree, dsize);
1781         }
1782
1783         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1784         TALLOC_FREE(stripped);
1785         if (conv == NULL) {
1786                 return -1;
1787         }
1788
1789         ret = SMB_VFS_NEXT_DISK_FREE(handle, conv, small_query, bsize, dfree,
1790                                      dsize);
1791
1792         saved_errno = errno;
1793         TALLOC_FREE(conv);
1794         errno = saved_errno;
1795
1796         return ret;
1797 }
1798
1799 static int shadow_copy2_connect(struct vfs_handle_struct *handle,
1800                                 const char *service, const char *user)
1801 {
1802         struct shadow_copy2_config *config;
1803         int ret;
1804         const char *snapdir;
1805         const char *gmt_format;
1806         const char *sort_order;
1807         const char *basedir;
1808         const char *mount_point;
1809
1810         DEBUG(10, (__location__ ": cnum[%u], connectpath[%s]\n",
1811                    (unsigned)handle->conn->cnum,
1812                    handle->conn->connectpath));
1813
1814         ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
1815         if (ret < 0) {
1816                 return ret;
1817         }
1818
1819         config = talloc_zero(handle->conn, struct shadow_copy2_config);
1820         if (config == NULL) {
1821                 DEBUG(0, ("talloc_zero() failed\n"));
1822                 errno = ENOMEM;
1823                 return -1;
1824         }
1825
1826         gmt_format = lp_parm_const_string(SNUM(handle->conn),
1827                                           "shadow", "format",
1828                                           GMT_FORMAT);
1829         config->gmt_format = talloc_strdup(config, gmt_format);
1830         if (config->gmt_format == NULL) {
1831                 DEBUG(0, ("talloc_strdup() failed\n"));
1832                 errno = ENOMEM;
1833                 return -1;
1834         }
1835
1836         config->use_sscanf = lp_parm_bool(SNUM(handle->conn),
1837                                           "shadow", "sscanf", false);
1838
1839         config->use_localtime = lp_parm_bool(SNUM(handle->conn),
1840                                              "shadow", "localtime",
1841                                              false);
1842
1843         snapdir = lp_parm_const_string(SNUM(handle->conn),
1844                                        "shadow", "snapdir",
1845                                        ".snapshots");
1846         config->snapdir = talloc_strdup(config, snapdir);
1847         if (config->snapdir == NULL) {
1848                 DEBUG(0, ("talloc_strdup() failed\n"));
1849                 errno = ENOMEM;
1850                 return -1;
1851         }
1852
1853         config->snapdirseverywhere = lp_parm_bool(SNUM(handle->conn),
1854                                                   "shadow",
1855                                                   "snapdirseverywhere",
1856                                                   false);
1857
1858         config->crossmountpoints = lp_parm_bool(SNUM(handle->conn),
1859                                                 "shadow", "crossmountpoints",
1860                                                 false);
1861
1862         config->fixinodes = lp_parm_bool(SNUM(handle->conn),
1863                                          "shadow", "fixinodes",
1864                                          false);
1865
1866         sort_order = lp_parm_const_string(SNUM(handle->conn),
1867                                           "shadow", "sort", "desc");
1868         config->sort_order = talloc_strdup(config, sort_order);
1869         if (config->sort_order == NULL) {
1870                 DEBUG(0, ("talloc_strdup() failed\n"));
1871                 errno = ENOMEM;
1872                 return -1;
1873         }
1874
1875         mount_point = lp_parm_const_string(SNUM(handle->conn),
1876                                            "shadow", "mountpoint", NULL);
1877         if (mount_point != NULL) {
1878                 if (mount_point[0] != '/') {
1879                         DEBUG(1, (__location__ " Warning: 'mountpoint' is "
1880                                   "relative ('%s'), but it has to be an "
1881                                   "absolute path. Ignoring provided value.\n",
1882                                   mount_point));
1883                         mount_point = NULL;
1884                 } else {
1885                         char *p;
1886                         p = strstr(handle->conn->connectpath, mount_point);
1887                         if (p != handle->conn->connectpath) {
1888                                 DEBUG(1, ("Warning: mount_point (%s) is not a "
1889                                           "subdirectory of the share root "
1890                                           "(%s). Ignoring provided value.\n",
1891                                           mount_point,
1892                                           handle->conn->connectpath));
1893                                 mount_point = NULL;
1894                         }
1895                 }
1896         }
1897
1898         if (mount_point != NULL) {
1899                 config->mount_point = talloc_strdup(config, mount_point);
1900                 if (config->mount_point == NULL) {
1901                         DEBUG(0, (__location__ " talloc_strdup() failed\n"));
1902                         return -1;
1903                 }
1904         } else {
1905                 config->mount_point = shadow_copy2_find_mount_point(config,
1906                                                                     handle);
1907                 if (config->mount_point == NULL) {
1908                         DEBUG(0, (__location__ ": shadow_copy2_find_mount_point"
1909                                   " failed: %s\n", strerror(errno)));
1910                         return -1;
1911                 }
1912         }
1913
1914         basedir = lp_parm_const_string(SNUM(handle->conn),
1915                                        "shadow", "basedir", NULL);
1916
1917         if (basedir != NULL) {
1918                 if (basedir[0] != '/') {
1919                         DEBUG(1, (__location__ " Warning: 'basedir' is "
1920                                   "relative ('%s'), but it has to be an "
1921                                   "absolute path. Disabling basedir.\n",
1922                                   basedir));
1923                 } else {
1924                         char *p;
1925                         p = strstr(basedir, config->mount_point);
1926                         if (p != basedir) {
1927                                 DEBUG(1, ("Warning: basedir (%s) is not a "
1928                                           "subdirectory of the share root's "
1929                                           "mount point (%s). "
1930                                           "Disabling basedir\n",
1931                                           basedir, config->mount_point));
1932                         } else {
1933                                 config->basedir = talloc_strdup(config,
1934                                                                 basedir);
1935                                 if (config->basedir == NULL) {
1936                                         DEBUG(0, ("talloc_strdup() failed\n"));
1937                                         errno = ENOMEM;
1938                                         return -1;
1939                                 }
1940                         }
1941                 }
1942         }
1943
1944         if (config->snapdirseverywhere && config->basedir != NULL) {
1945                 DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
1946                           "with 'snapdirseverywhere'. Disabling basedir.\n"));
1947                 TALLOC_FREE(config->basedir);
1948         }
1949
1950         if (config->crossmountpoints && config->basedir != NULL) {
1951                 DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
1952                           "with 'crossmountpoints'. Disabling basedir.\n"));
1953                 TALLOC_FREE(config->basedir);
1954         }
1955
1956         if (config->basedir == NULL) {
1957                 config->basedir = config->mount_point;
1958         }
1959
1960         if (strlen(config->basedir) != strlen(handle->conn->connectpath)) {
1961                 config->rel_connectpath = talloc_strdup(config,
1962                         handle->conn->connectpath + strlen(config->basedir));
1963                 if (config->rel_connectpath == NULL) {
1964                         DEBUG(0, ("talloc_strdup() failed\n"));
1965                         errno = ENOMEM;
1966                         return -1;
1967                 }
1968         }
1969
1970         if (config->snapdir[0] == '/') {
1971                 config->snapdir_absolute = true;
1972
1973                 if (config->snapdirseverywhere == true) {
1974                         DEBUG(1, (__location__ " Warning: An absolute snapdir "
1975                                   "is incompatible with 'snapdirseverywhere', "
1976                                   "setting 'snapdirseverywhere' to false.\n"));
1977                         config->snapdirseverywhere = false;
1978                 }
1979
1980                 if (config->crossmountpoints == true) {
1981                         DEBUG(1, (__location__ " Warning: 'crossmountpoints' "
1982                                   "is not supported with an absolute snapdir. "
1983                                   "Disabling it.\n"));
1984                         config->crossmountpoints = false;
1985                 }
1986
1987                 config->snapshot_basepath = config->snapdir;
1988         } else {
1989                 config->snapshot_basepath = talloc_asprintf(config, "%s/%s",
1990                                 config->mount_point, config->snapdir);
1991                 if (config->snapshot_basepath == NULL) {
1992                         DEBUG(0, ("talloc_asprintf() failed\n"));
1993                         errno = ENOMEM;
1994                         return -1;
1995                 }
1996         }
1997
1998         DEBUG(10, ("shadow_copy2_connect: configuration:\n"
1999                    "  share root: '%s'\n"
2000                    "  basedir: '%s'\n"
2001                    "  mountpoint: '%s'\n"
2002                    "  rel share root: '%s'\n"
2003                    "  snapdir: '%s'\n"
2004                    "  snapshot base path: '%s'\n"
2005                    "  format: '%s'\n"
2006                    "  use sscanf: %s\n"
2007                    "  snapdirs everywhere: %s\n"
2008                    "  cross mountpoints: %s\n"
2009                    "  fix inodes: %s\n"
2010                    "  sort order: %s\n"
2011                    "",
2012                    handle->conn->connectpath,
2013                    config->basedir,
2014                    config->mount_point,
2015                    config->rel_connectpath,
2016                    config->snapdir,
2017                    config->snapshot_basepath,
2018                    config->gmt_format,
2019                    config->use_sscanf ? "yes" : "no",
2020                    config->snapdirseverywhere ? "yes" : "no",
2021                    config->crossmountpoints ? "yes" : "no",
2022                    config->fixinodes ? "yes" : "no",
2023                    config->sort_order
2024                    ));
2025
2026
2027         SMB_VFS_HANDLE_SET_DATA(handle, config,
2028                                 NULL, struct shadow_copy2_config,
2029                                 return -1);
2030
2031         return 0;
2032 }
2033
2034 static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
2035         .connect_fn = shadow_copy2_connect,
2036         .opendir_fn = shadow_copy2_opendir,
2037         .disk_free_fn = shadow_copy2_disk_free,
2038         .rename_fn = shadow_copy2_rename,
2039         .link_fn = shadow_copy2_link,
2040         .symlink_fn = shadow_copy2_symlink,
2041         .stat_fn = shadow_copy2_stat,
2042         .lstat_fn = shadow_copy2_lstat,
2043         .fstat_fn = shadow_copy2_fstat,
2044         .open_fn = shadow_copy2_open,
2045         .unlink_fn = shadow_copy2_unlink,
2046         .chmod_fn = shadow_copy2_chmod,
2047         .chown_fn = shadow_copy2_chown,
2048         .chdir_fn = shadow_copy2_chdir,
2049         .ntimes_fn = shadow_copy2_ntimes,
2050         .readlink_fn = shadow_copy2_readlink,
2051         .mknod_fn = shadow_copy2_mknod,
2052         .realpath_fn = shadow_copy2_realpath,
2053         .get_nt_acl_fn = shadow_copy2_get_nt_acl,
2054         .fget_nt_acl_fn = shadow_copy2_fget_nt_acl,
2055         .get_shadow_copy_data_fn = shadow_copy2_get_shadow_copy_data,
2056         .mkdir_fn = shadow_copy2_mkdir,
2057         .rmdir_fn = shadow_copy2_rmdir,
2058         .getxattr_fn = shadow_copy2_getxattr,
2059         .listxattr_fn = shadow_copy2_listxattr,
2060         .removexattr_fn = shadow_copy2_removexattr,
2061         .setxattr_fn = shadow_copy2_setxattr,
2062         .chmod_acl_fn = shadow_copy2_chmod_acl,
2063         .chflags_fn = shadow_copy2_chflags,
2064         .get_real_filename_fn = shadow_copy2_get_real_filename,
2065 };
2066
2067 NTSTATUS vfs_shadow_copy2_init(void);
2068 NTSTATUS vfs_shadow_copy2_init(void)
2069 {
2070         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2071                                 "shadow_copy2", &vfs_shadow_copy2_fns);
2072 }