shadow_copy2: add comment block explaining shadow_copy2_find_snapdir()
[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 static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str,
111                                       size_t **poffsets,
112                                       unsigned *pnum_offsets)
113 {
114         unsigned num_offsets;
115         size_t *offsets;
116         const char *p;
117
118         num_offsets = 0;
119
120         p = str;
121         while ((p = strchr(p, '/')) != NULL) {
122                 num_offsets += 1;
123                 p += 1;
124         }
125
126         offsets = talloc_array(mem_ctx, size_t, num_offsets);
127         if (offsets == NULL) {
128                 return false;
129         }
130
131         p = str;
132         num_offsets = 0;
133         while ((p = strchr(p, '/')) != NULL) {
134                 offsets[num_offsets] = p-str;
135                 num_offsets += 1;
136                 p += 1;
137         }
138
139         *poffsets = offsets;
140         *pnum_offsets = num_offsets;
141         return true;
142 }
143
144 static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx,
145                                         struct vfs_handle_struct *handle,
146                                         time_t snapshot)
147 {
148         const char *fmt;
149         struct tm snap_tm;
150         fstring snaptime_string;
151         size_t snaptime_len;
152
153         fmt = lp_parm_const_string(SNUM(handle->conn), "shadow",
154                                    "format", GMT_FORMAT);
155
156         if (lp_parm_bool(SNUM(handle->conn), "shadow", "sscanf", false)) {
157                 snaptime_len = snprintf(snaptime_string, sizeof(snaptime_string), fmt,
158                                    (unsigned long)snapshot);
159                 if (snaptime_len <= 0) {
160                         DEBUG(10, ("snprintf failed\n"));
161                         return NULL;
162                 }
163         } else {
164                 if (lp_parm_bool(SNUM(handle->conn), "shadow", "localtime", false)) {
165                         if (localtime_r(&snapshot, &snap_tm) == 0) {
166                                 DEBUG(10, ("gmtime_r failed\n"));
167                                 return NULL;
168                         }
169                 } else {
170                         if (gmtime_r(&snapshot, &snap_tm) == 0) {
171                                 DEBUG(10, ("gmtime_r failed\n"));
172                                 return NULL;
173                         }
174                 }
175                 snaptime_len = strftime(snaptime_string, sizeof(snaptime_string), fmt,
176                                    &snap_tm);
177                 if (snaptime_len == 0) {
178                         DEBUG(10, ("strftime failed\n"));
179                         return NULL;
180                 }
181         }
182         return talloc_asprintf(mem_ctx, "/%s/%s",
183                                lp_parm_const_string(
184                                        SNUM(handle->conn), "shadow", "snapdir",
185                                        ".snapshots"),
186                                snaptime_string);
187 }
188
189 /**
190  * Strip a snapshot component from an filename as
191  * handed in via the smb layer.
192  * Returns the parsed timestamp and the stripped filename.
193  */
194 static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx,
195                                         struct vfs_handle_struct *handle,
196                                         const char *name,
197                                         time_t *ptimestamp,
198                                         char **pstripped)
199 {
200         struct tm tm;
201         time_t timestamp;
202         const char *p;
203         char *q;
204         char *stripped;
205         size_t rest_len, dst_len;
206
207         p = strstr_m(name, "@GMT-");
208         if (p == NULL) {
209                 goto no_snapshot;
210         }
211         if ((p > name) && (p[-1] != '/')) {
212                 goto no_snapshot;
213         }
214         q = strptime(p, GMT_FORMAT, &tm);
215         if (q == NULL) {
216                 goto no_snapshot;
217         }
218         tm.tm_isdst = -1;
219         timestamp = timegm(&tm);
220         if (timestamp == (time_t)-1) {
221                 goto no_snapshot;
222         }
223         if ((p == name) && (q[0] == '\0')) {
224                 if (pstripped != NULL) {
225                         stripped = talloc_strdup(mem_ctx, "");
226                         if (stripped == NULL) {
227                                 return false;
228                         }
229                         *pstripped = stripped;
230                 }
231                 *ptimestamp = timestamp;
232                 return true;
233         }
234         if (q[0] != '/') {
235                 goto no_snapshot;
236         }
237         q += 1;
238
239         rest_len = strlen(q);
240         dst_len = (p-name) + rest_len;
241
242         if (lp_parm_bool(SNUM(handle->conn), "shadow", "snapdirseverywhere",
243                          false)) {
244                 char *insert;
245                 bool have_insert;
246                 insert = shadow_copy2_insert_string(talloc_tos(), handle,
247                                                     timestamp);
248                 if (insert == NULL) {
249                         errno = ENOMEM;
250                         return false;
251                 }
252
253                 have_insert = (strstr(name, insert+1) != NULL);
254                 TALLOC_FREE(insert);
255                 if (have_insert) {
256                         goto no_snapshot;
257                 }
258         }
259
260         if (pstripped != NULL) {
261                 stripped = talloc_array(mem_ctx, char, dst_len+1);
262                 if (stripped == NULL) {
263                         errno = ENOMEM;
264                         return false;
265                 }
266                 if (p > name) {
267                         memcpy(stripped, name, p-name);
268                 }
269                 if (rest_len > 0) {
270                         memcpy(stripped + (p-name), q, rest_len);
271                 }
272                 stripped[dst_len] = '\0';
273                 *pstripped = stripped;
274         }
275         *ptimestamp = timestamp;
276         return true;
277 no_snapshot:
278         *ptimestamp = 0;
279         return true;
280 }
281
282 static char *shadow_copy2_find_mount_point(TALLOC_CTX *mem_ctx,
283                                            vfs_handle_struct *handle)
284 {
285         char *path = talloc_strdup(mem_ctx, handle->conn->connectpath);
286         dev_t dev;
287         struct stat st;
288         char *p;
289
290         if (stat(path, &st) != 0) {
291                 talloc_free(path);
292                 return NULL;
293         }
294
295         dev = st.st_dev;
296
297         while ((p = strrchr(path, '/')) && p > path) {
298                 *p = 0;
299                 if (stat(path, &st) != 0) {
300                         talloc_free(path);
301                         return NULL;
302                 }
303                 if (st.st_dev != dev) {
304                         *p = '/';
305                         break;
306                 }
307         }
308
309         return path;
310 }
311
312 static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx,
313                                   struct vfs_handle_struct *handle,
314                                   const char *name, time_t timestamp)
315 {
316         struct smb_filename converted_fname;
317         char *result = NULL;
318         size_t *slashes = NULL;
319         unsigned num_slashes;
320         char *path = NULL;
321         size_t pathlen;
322         char *insert = NULL;
323         char *converted = NULL;
324         size_t insertlen;
325         int i, saved_errno;
326         size_t min_offset;
327
328         path = talloc_asprintf(mem_ctx, "%s/%s", handle->conn->connectpath,
329                                name);
330         if (path == NULL) {
331                 errno = ENOMEM;
332                 goto fail;
333         }
334         pathlen = talloc_get_size(path)-1;
335
336         DEBUG(10, ("converting %s\n", path));
337
338         if (!shadow_copy2_find_slashes(talloc_tos(), path,
339                                        &slashes, &num_slashes)) {
340                 goto fail;
341         }
342         insert = shadow_copy2_insert_string(talloc_tos(), handle, timestamp);
343         if (insert == NULL) {
344                 goto fail;
345         }
346         insertlen = talloc_get_size(insert)-1;
347         converted = talloc_array(mem_ctx, char, pathlen + insertlen + 1);
348         if (converted == NULL) {
349                 goto fail;
350         }
351
352         if (path[pathlen-1] != '/') {
353                 /*
354                  * Append a fake slash to find the snapshot root
355                  */
356                 size_t *tmp;
357                 tmp = talloc_realloc(talloc_tos(), slashes,
358                                      size_t, num_slashes+1);
359                 if (tmp == NULL) {
360                         goto fail;
361                 }
362                 slashes = tmp;
363                 slashes[num_slashes] = pathlen;
364                 num_slashes += 1;
365         }
366
367         min_offset = 0;
368
369         if (!lp_parm_bool(SNUM(handle->conn), "shadow", "crossmountpoints",
370                           false)) {
371                 char *mount_point;
372
373                 mount_point = shadow_copy2_find_mount_point(talloc_tos(),
374                                                             handle);
375                 if (mount_point == NULL) {
376                         goto fail;
377                 }
378                 min_offset = strlen(mount_point);
379                 TALLOC_FREE(mount_point);
380         }
381
382         memcpy(converted, path, pathlen+1);
383         converted[pathlen+insertlen] = '\0';
384
385         ZERO_STRUCT(converted_fname);
386         converted_fname.base_name = converted;
387
388         for (i = num_slashes-1; i>=0; i--) {
389                 int ret;
390                 size_t offset;
391
392                 offset = slashes[i];
393
394                 if (offset < min_offset) {
395                         errno = ENOENT;
396                         goto fail;
397                 }
398
399                 memcpy(converted+offset, insert, insertlen);
400
401                 offset += insertlen;
402                 memcpy(converted+offset, path + slashes[i],
403                        pathlen - slashes[i]);
404
405                 ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
406
407                 DEBUG(10, ("Trying %s: %d (%s)\n", converted,
408                            ret, ret == 0 ? "ok" : strerror(errno)));
409                 if (ret == 0) {
410                         /* success */
411                         break;
412                 }
413                 if (errno == ENOTDIR) {
414                         /*
415                          * This is a valid condition: We appended the
416                          * .snaphots/@GMT.. to a file name. Just try
417                          * with the upper levels.
418                          */
419                         continue;
420                 }
421                 if (errno != ENOENT) {
422                         /* Other problem than "not found" */
423                         goto fail;
424                 }
425         }
426
427         if (i >= 0) {
428                 /*
429                  * Found something
430                  */
431                 DEBUG(10, ("Found %s\n", converted));
432                 result = converted;
433                 converted = NULL;
434         } else {
435                 errno = ENOENT;
436         }
437 fail:
438         saved_errno = errno;
439         TALLOC_FREE(converted);
440         TALLOC_FREE(insert);
441         TALLOC_FREE(slashes);
442         TALLOC_FREE(path);
443         errno = saved_errno;
444         return result;
445 }
446
447 /*
448   modify a sbuf return to ensure that inodes in the shadow directory
449   are different from those in the main directory
450  */
451 static void convert_sbuf(vfs_handle_struct *handle, const char *fname,
452                          SMB_STRUCT_STAT *sbuf)
453 {
454         if (lp_parm_bool(SNUM(handle->conn), "shadow", "fixinodes", False)) {
455                 /* some snapshot systems, like GPFS, return the name
456                    device:inode for the snapshot files as the current
457                    files. That breaks the 'restore' button in the shadow copy
458                    GUI, as the client gets a sharing violation.
459
460                    This is a crude way of allowing both files to be
461                    open at once. It has a slight chance of inode
462                    number collision, but I can't see a better approach
463                    without significant VFS changes
464                 */
465                 uint32_t shash;
466
467                 shash = hash(fname, strlen(fname), 0) & 0xFF000000;
468                 if (shash == 0) {
469                         shash = 1;
470                 }
471                 sbuf->st_ex_ino ^= shash;
472         }
473 }
474
475 static DIR *shadow_copy2_opendir(vfs_handle_struct *handle,
476                                             const char *fname,
477                                             const char *mask,
478                                             uint32 attr)
479 {
480         time_t timestamp;
481         char *stripped;
482         DIR *ret;
483         int saved_errno;
484         char *conv;
485
486         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
487                                          &timestamp, &stripped)) {
488                 return NULL;
489         }
490         if (timestamp == 0) {
491                 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
492         }
493         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
494         TALLOC_FREE(stripped);
495         if (conv == NULL) {
496                 return NULL;
497         }
498         ret = SMB_VFS_NEXT_OPENDIR(handle, conv, mask, attr);
499         saved_errno = errno;
500         TALLOC_FREE(conv);
501         errno = saved_errno;
502         return ret;
503 }
504
505 static int shadow_copy2_rename(vfs_handle_struct *handle,
506                                const struct smb_filename *smb_fname_src,
507                                const struct smb_filename *smb_fname_dst)
508 {
509         time_t timestamp_src, timestamp_dst;
510
511         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
512                                          smb_fname_src->base_name,
513                                          &timestamp_src, NULL)) {
514                 return -1;
515         }
516         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
517                                          smb_fname_dst->base_name,
518                                          &timestamp_dst, NULL)) {
519                 return -1;
520         }
521         if (timestamp_src != 0) {
522                 errno = EXDEV;
523                 return -1;
524         }
525         if (timestamp_dst != 0) {
526                 errno = EROFS;
527                 return -1;
528         }
529         return SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
530 }
531
532 static int shadow_copy2_symlink(vfs_handle_struct *handle,
533                                 const char *oldname, const char *newname)
534 {
535         time_t timestamp_old, timestamp_new;
536
537         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
538                                          &timestamp_old, NULL)) {
539                 return -1;
540         }
541         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
542                                          &timestamp_new, NULL)) {
543                 return -1;
544         }
545         if ((timestamp_old != 0) || (timestamp_new != 0)) {
546                 errno = EROFS;
547                 return -1;
548         }
549         return SMB_VFS_NEXT_SYMLINK(handle, oldname, newname);
550 }
551
552 static int shadow_copy2_link(vfs_handle_struct *handle,
553                              const char *oldname, const char *newname)
554 {
555         time_t timestamp_old, timestamp_new;
556
557         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
558                                          &timestamp_old, NULL)) {
559                 return -1;
560         }
561         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
562                                          &timestamp_new, NULL)) {
563                 return -1;
564         }
565         if ((timestamp_old != 0) || (timestamp_new != 0)) {
566                 errno = EROFS;
567                 return -1;
568         }
569         return SMB_VFS_NEXT_LINK(handle, oldname, newname);
570 }
571
572 static int shadow_copy2_stat(vfs_handle_struct *handle,
573                              struct smb_filename *smb_fname)
574 {
575         time_t timestamp;
576         char *stripped, *tmp;
577         int ret, saved_errno;
578
579         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
580                                          smb_fname->base_name,
581                                          &timestamp, &stripped)) {
582                 return -1;
583         }
584         if (timestamp == 0) {
585                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
586         }
587
588         tmp = smb_fname->base_name;
589         smb_fname->base_name = shadow_copy2_convert(
590                 talloc_tos(), handle, stripped, timestamp);
591         TALLOC_FREE(stripped);
592
593         if (smb_fname->base_name == NULL) {
594                 smb_fname->base_name = tmp;
595                 return -1;
596         }
597
598         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
599         saved_errno = errno;
600
601         TALLOC_FREE(smb_fname->base_name);
602         smb_fname->base_name = tmp;
603
604         if (ret == 0) {
605                 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
606         }
607         errno = saved_errno;
608         return ret;
609 }
610
611 static int shadow_copy2_lstat(vfs_handle_struct *handle,
612                               struct smb_filename *smb_fname)
613 {
614         time_t timestamp;
615         char *stripped, *tmp;
616         int ret, saved_errno;
617
618         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
619                                          smb_fname->base_name,
620                                          &timestamp, &stripped)) {
621                 return -1;
622         }
623         if (timestamp == 0) {
624                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
625         }
626
627         tmp = smb_fname->base_name;
628         smb_fname->base_name = shadow_copy2_convert(
629                 talloc_tos(), handle, stripped, timestamp);
630         TALLOC_FREE(stripped);
631
632         if (smb_fname->base_name == NULL) {
633                 smb_fname->base_name = tmp;
634                 return -1;
635         }
636
637         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
638         saved_errno = errno;
639
640         TALLOC_FREE(smb_fname->base_name);
641         smb_fname->base_name = tmp;
642
643         if (ret == 0) {
644                 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
645         }
646         errno = saved_errno;
647         return ret;
648 }
649
650 static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
651                               SMB_STRUCT_STAT *sbuf)
652 {
653         time_t timestamp;
654         int ret;
655
656         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
657         if (ret == -1) {
658                 return ret;
659         }
660         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
661                                          fsp->fsp_name->base_name,
662                                          &timestamp, NULL)) {
663                 return 0;
664         }
665         if (timestamp != 0) {
666                 convert_sbuf(handle, fsp->fsp_name->base_name, sbuf);
667         }
668         return 0;
669 }
670
671 static int shadow_copy2_open(vfs_handle_struct *handle,
672                              struct smb_filename *smb_fname, files_struct *fsp,
673                              int flags, mode_t mode)
674 {
675         time_t timestamp;
676         char *stripped, *tmp;
677         int ret, saved_errno;
678
679         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
680                                          smb_fname->base_name,
681                                          &timestamp, &stripped)) {
682                 return -1;
683         }
684         if (timestamp == 0) {
685                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
686         }
687
688         tmp = smb_fname->base_name;
689         smb_fname->base_name = shadow_copy2_convert(
690                 talloc_tos(), handle, stripped, timestamp);
691         TALLOC_FREE(stripped);
692
693         if (smb_fname->base_name == NULL) {
694                 smb_fname->base_name = tmp;
695                 return -1;
696         }
697
698         ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
699         saved_errno = errno;
700
701         TALLOC_FREE(smb_fname->base_name);
702         smb_fname->base_name = tmp;
703
704         errno = saved_errno;
705         return ret;
706 }
707
708 static int shadow_copy2_unlink(vfs_handle_struct *handle,
709                                const struct smb_filename *smb_fname)
710 {
711         time_t timestamp;
712         char *stripped;
713         int ret, saved_errno;
714         struct smb_filename *conv;
715
716         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
717                                          smb_fname->base_name,
718                                          &timestamp, &stripped)) {
719                 return -1;
720         }
721         if (timestamp == 0) {
722                 return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
723         }
724         conv = cp_smb_filename(talloc_tos(), smb_fname);
725         if (conv == NULL) {
726                 errno = ENOMEM;
727                 return -1;
728         }
729         conv->base_name = shadow_copy2_convert(
730                 conv, handle, stripped, timestamp);
731         TALLOC_FREE(stripped);
732         if (conv->base_name == NULL) {
733                 return -1;
734         }
735         ret = SMB_VFS_NEXT_UNLINK(handle, conv);
736         saved_errno = errno;
737         TALLOC_FREE(conv);
738         errno = saved_errno;
739         return ret;
740 }
741
742 static int shadow_copy2_chmod(vfs_handle_struct *handle, const char *fname,
743                               mode_t mode)
744 {
745         time_t timestamp;
746         char *stripped;
747         int ret, saved_errno;
748         char *conv;
749
750         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
751                                          &timestamp, &stripped)) {
752                 return -1;
753         }
754         if (timestamp == 0) {
755                 return SMB_VFS_NEXT_CHMOD(handle, fname, mode);
756         }
757         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
758         TALLOC_FREE(stripped);
759         if (conv == NULL) {
760                 return -1;
761         }
762         ret = SMB_VFS_NEXT_CHMOD(handle, conv, mode);
763         saved_errno = errno;
764         TALLOC_FREE(conv);
765         errno = saved_errno;
766         return ret;
767 }
768
769 static int shadow_copy2_chown(vfs_handle_struct *handle, const char *fname,
770                               uid_t uid, gid_t gid)
771 {
772         time_t timestamp;
773         char *stripped;
774         int ret, saved_errno;
775         char *conv;
776
777         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
778                                          &timestamp, &stripped)) {
779                 return -1;
780         }
781         if (timestamp == 0) {
782                 return SMB_VFS_NEXT_CHOWN(handle, fname, uid, gid);
783         }
784         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
785         TALLOC_FREE(stripped);
786         if (conv == NULL) {
787                 return -1;
788         }
789         ret = SMB_VFS_NEXT_CHOWN(handle, conv, uid, gid);
790         saved_errno = errno;
791         TALLOC_FREE(conv);
792         errno = saved_errno;
793         return ret;
794 }
795
796 static int shadow_copy2_chdir(vfs_handle_struct *handle,
797                               const char *fname)
798 {
799         time_t timestamp;
800         char *stripped;
801         int ret, saved_errno;
802         char *conv;
803
804         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
805                                          &timestamp, &stripped)) {
806                 return -1;
807         }
808         if (timestamp == 0) {
809                 return SMB_VFS_NEXT_CHDIR(handle, fname);
810         }
811         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
812         TALLOC_FREE(stripped);
813         if (conv == NULL) {
814                 return -1;
815         }
816         ret = SMB_VFS_NEXT_CHDIR(handle, conv);
817         saved_errno = errno;
818         TALLOC_FREE(conv);
819         errno = saved_errno;
820         return ret;
821 }
822
823 static int shadow_copy2_ntimes(vfs_handle_struct *handle,
824                                const struct smb_filename *smb_fname,
825                                struct smb_file_time *ft)
826 {
827         time_t timestamp;
828         char *stripped;
829         int ret, saved_errno;
830         struct smb_filename *conv;
831
832         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
833                                          smb_fname->base_name,
834                                          &timestamp, &stripped)) {
835                 return -1;
836         }
837         if (timestamp == 0) {
838                 return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
839         }
840         conv = cp_smb_filename(talloc_tos(), smb_fname);
841         if (conv == NULL) {
842                 errno = ENOMEM;
843                 return -1;
844         }
845         conv->base_name = shadow_copy2_convert(
846                 conv, handle, stripped, timestamp);
847         TALLOC_FREE(stripped);
848         if (conv->base_name == NULL) {
849                 return -1;
850         }
851         ret = SMB_VFS_NEXT_NTIMES(handle, conv, ft);
852         saved_errno = errno;
853         TALLOC_FREE(conv);
854         errno = saved_errno;
855         return ret;
856 }
857
858 static int shadow_copy2_readlink(vfs_handle_struct *handle,
859                                  const char *fname, char *buf, size_t bufsiz)
860 {
861         time_t timestamp;
862         char *stripped;
863         int ret, saved_errno;
864         char *conv;
865
866         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
867                                          &timestamp, &stripped)) {
868                 return -1;
869         }
870         if (timestamp == 0) {
871                 return SMB_VFS_NEXT_READLINK(handle, fname, buf, bufsiz);
872         }
873         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
874         TALLOC_FREE(stripped);
875         if (conv == NULL) {
876                 return -1;
877         }
878         ret = SMB_VFS_NEXT_READLINK(handle, conv, buf, bufsiz);
879         saved_errno = errno;
880         TALLOC_FREE(conv);
881         errno = saved_errno;
882         return ret;
883 }
884
885 static int shadow_copy2_mknod(vfs_handle_struct *handle,
886                               const char *fname, mode_t mode, SMB_DEV_T dev)
887 {
888         time_t timestamp;
889         char *stripped;
890         int ret, saved_errno;
891         char *conv;
892
893         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
894                                          &timestamp, &stripped)) {
895                 return -1;
896         }
897         if (timestamp == 0) {
898                 return SMB_VFS_NEXT_MKNOD(handle, fname, mode, dev);
899         }
900         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
901         TALLOC_FREE(stripped);
902         if (conv == NULL) {
903                 return -1;
904         }
905         ret = SMB_VFS_NEXT_MKNOD(handle, conv, mode, dev);
906         saved_errno = errno;
907         TALLOC_FREE(conv);
908         errno = saved_errno;
909         return ret;
910 }
911
912 static char *shadow_copy2_realpath(vfs_handle_struct *handle,
913                                    const char *fname)
914 {
915         time_t timestamp;
916         char *stripped = NULL;
917         char *tmp = NULL;
918         char *result = NULL;
919         char *inserted = NULL;
920         char *inserted_to, *inserted_end;
921         int saved_errno;
922
923         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
924                                          &timestamp, &stripped)) {
925                 goto done;
926         }
927         if (timestamp == 0) {
928                 return SMB_VFS_NEXT_REALPATH(handle, fname);
929         }
930
931         tmp = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
932         if (tmp == NULL) {
933                 goto done;
934         }
935
936         result = SMB_VFS_NEXT_REALPATH(handle, tmp);
937         if (result == NULL) {
938                 goto done;
939         }
940
941         /*
942          * Take away what we've inserted. This removes the @GMT-thingy
943          * completely, but will give a path under the share root.
944          */
945         inserted = shadow_copy2_insert_string(talloc_tos(), handle, timestamp);
946         if (inserted == NULL) {
947                 goto done;
948         }
949         inserted_to = strstr_m(result, inserted);
950         if (inserted_to == NULL) {
951                 DEBUG(2, ("SMB_VFS_NEXT_REALPATH removed %s\n", inserted));
952                 goto done;
953         }
954         inserted_end = inserted_to + talloc_get_size(inserted) - 1;
955         memmove(inserted_to, inserted_end, strlen(inserted_end)+1);
956
957 done:
958         saved_errno = errno;
959         TALLOC_FREE(inserted);
960         TALLOC_FREE(tmp);
961         TALLOC_FREE(stripped);
962         errno = saved_errno;
963         return result;
964 }
965
966 /**
967  * Check whether a given directory contains a
968  * snapshot directory as direct subdirectory.
969  * If yes, return the path of the snapshot-subdir,
970  * otherwise return NULL.
971  */
972 static char *have_snapdir(struct vfs_handle_struct *handle,
973                           const char *path)
974 {
975         struct smb_filename smb_fname;
976         int ret;
977
978         ZERO_STRUCT(smb_fname);
979         smb_fname.base_name = talloc_asprintf(
980                 talloc_tos(), "%s/%s", path,
981                 lp_parm_const_string(SNUM(handle->conn), "shadow", "snapdir",
982                                      ".snapshots"));
983         if (smb_fname.base_name == NULL) {
984                 return NULL;
985         }
986
987         ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
988         if ((ret == 0) && (S_ISDIR(smb_fname.st.st_ex_mode))) {
989                 return smb_fname.base_name;
990         }
991         TALLOC_FREE(smb_fname.base_name);
992         return NULL;
993 }
994
995 /**
996  * Find the snapshot directory (if any) for the given
997  * filename (which is relative to the share).
998  */
999 static char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx,
1000                                        struct vfs_handle_struct *handle,
1001                                        struct smb_filename *smb_fname)
1002 {
1003         char *path, *p;
1004         char *snapdir;
1005
1006         path = talloc_asprintf(mem_ctx, "%s/%s",
1007                                handle->conn->connectpath,
1008                                smb_fname->base_name);
1009         if (path == NULL) {
1010                 return NULL;
1011         }
1012
1013         snapdir = have_snapdir(handle, path);
1014         if (snapdir != NULL) {
1015                 TALLOC_FREE(path);
1016                 return snapdir;
1017         }
1018
1019         while ((p = strrchr(path, '/')) && (p > path)) {
1020
1021                 p[0] = '\0';
1022
1023                 snapdir = have_snapdir(handle, path);
1024                 if (snapdir != NULL) {
1025                         TALLOC_FREE(path);
1026                         return snapdir;
1027                 }
1028         }
1029         TALLOC_FREE(path);
1030         return NULL;
1031 }
1032
1033 static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
1034                                          const char *name,
1035                                          char *gmt, size_t gmt_len)
1036 {
1037         struct tm timestamp;
1038         time_t timestamp_t;
1039         unsigned long int timestamp_long;
1040         const char *fmt;
1041
1042         fmt = lp_parm_const_string(SNUM(handle->conn), "shadow",
1043                                    "format", GMT_FORMAT);
1044
1045         ZERO_STRUCT(timestamp);
1046         if (lp_parm_bool(SNUM(handle->conn), "shadow", "sscanf", false)) {
1047                 if (sscanf(name, fmt, &timestamp_long) != 1) {
1048                         DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1049                                    "no sscanf match %s: %s\n",
1050                                    fmt, name));
1051                         return false;
1052                 }
1053                 timestamp_t = timestamp_long;
1054                 gmtime_r(&timestamp_t, &timestamp);
1055         } else {
1056                 if (strptime(name, fmt, &timestamp) == NULL) {
1057                         DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1058                                    "no match %s: %s\n",
1059                                    fmt, name));
1060                         return false;
1061                 }
1062                 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n",
1063                            fmt, name));
1064                 
1065                 if (lp_parm_bool(SNUM(handle->conn), "shadow", "localtime", false)) {
1066                         timestamp.tm_isdst = -1;
1067                         timestamp_t = mktime(&timestamp);
1068                         gmtime_r(&timestamp_t, &timestamp);
1069                 }
1070         }
1071
1072         strftime(gmt, gmt_len, GMT_FORMAT, &timestamp);
1073         return true;
1074 }
1075
1076 static int shadow_copy2_label_cmp_asc(const void *x, const void *y)
1077 {
1078         return strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1079 }
1080
1081 static int shadow_copy2_label_cmp_desc(const void *x, const void *y)
1082 {
1083         return -strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1084 }
1085
1086 /*
1087   sort the shadow copy data in ascending or descending order
1088  */
1089 static void shadow_copy2_sort_data(vfs_handle_struct *handle,
1090                                    struct shadow_copy_data *shadow_copy2_data)
1091 {
1092         int (*cmpfunc)(const void *, const void *);
1093         const char *sort;
1094
1095         sort = lp_parm_const_string(SNUM(handle->conn), "shadow",
1096                                     "sort", "desc");
1097         if (sort == NULL) {
1098                 return;
1099         }
1100
1101         if (strcmp(sort, "asc") == 0) {
1102                 cmpfunc = shadow_copy2_label_cmp_asc;
1103         } else if (strcmp(sort, "desc") == 0) {
1104                 cmpfunc = shadow_copy2_label_cmp_desc;
1105         } else {
1106                 return;
1107         }
1108
1109         if (shadow_copy2_data && shadow_copy2_data->num_volumes > 0 &&
1110             shadow_copy2_data->labels)
1111         {
1112                 TYPESAFE_QSORT(shadow_copy2_data->labels,
1113                                shadow_copy2_data->num_volumes,
1114                                cmpfunc);
1115         }
1116 }
1117
1118 static int shadow_copy2_get_shadow_copy_data(
1119         vfs_handle_struct *handle, files_struct *fsp,
1120         struct shadow_copy_data *shadow_copy2_data,
1121         bool labels)
1122 {
1123         DIR *p;
1124         const char *snapdir;
1125         struct dirent *d;
1126         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1127
1128         snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle, fsp->fsp_name);
1129         if (snapdir == NULL) {
1130                 DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
1131                          handle->conn->connectpath));
1132                 errno = EINVAL;
1133                 talloc_free(tmp_ctx);
1134                 return -1;
1135         }
1136
1137         p = SMB_VFS_NEXT_OPENDIR(handle, snapdir, NULL, 0);
1138
1139         if (!p) {
1140                 DEBUG(2,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s'"
1141                          " - %s\n", snapdir, strerror(errno)));
1142                 talloc_free(tmp_ctx);
1143                 errno = ENOSYS;
1144                 return -1;
1145         }
1146
1147         shadow_copy2_data->num_volumes = 0;
1148         shadow_copy2_data->labels      = NULL;
1149
1150         while ((d = SMB_VFS_NEXT_READDIR(handle, p, NULL))) {
1151                 char snapshot[GMT_NAME_LEN+1];
1152                 SHADOW_COPY_LABEL *tlabels;
1153
1154                 /*
1155                  * ignore names not of the right form in the snapshot
1156                  * directory
1157                  */
1158                 if (!shadow_copy2_snapshot_to_gmt(
1159                             handle, d->d_name,
1160                             snapshot, sizeof(snapshot))) {
1161
1162                         DEBUG(6, ("shadow_copy2_get_shadow_copy_data: "
1163                                   "ignoring %s\n", d->d_name));
1164                         continue;
1165                 }
1166                 DEBUG(6,("shadow_copy2_get_shadow_copy_data: %s -> %s\n",
1167                          d->d_name, snapshot));
1168
1169                 if (!labels) {
1170                         /* the caller doesn't want the labels */
1171                         shadow_copy2_data->num_volumes++;
1172                         continue;
1173                 }
1174
1175                 tlabels = talloc_realloc(shadow_copy2_data,
1176                                          shadow_copy2_data->labels,
1177                                          SHADOW_COPY_LABEL,
1178                                          shadow_copy2_data->num_volumes+1);
1179                 if (tlabels == NULL) {
1180                         DEBUG(0,("shadow_copy2: out of memory\n"));
1181                         SMB_VFS_NEXT_CLOSEDIR(handle, p);
1182                         talloc_free(tmp_ctx);
1183                         return -1;
1184                 }
1185
1186                 strlcpy(tlabels[shadow_copy2_data->num_volumes], snapshot,
1187                         sizeof(*tlabels));
1188
1189                 shadow_copy2_data->num_volumes++;
1190                 shadow_copy2_data->labels = tlabels;
1191         }
1192
1193         SMB_VFS_NEXT_CLOSEDIR(handle,p);
1194
1195         shadow_copy2_sort_data(handle, shadow_copy2_data);
1196
1197         talloc_free(tmp_ctx);
1198         return 0;
1199 }
1200
1201 static NTSTATUS shadow_copy2_fget_nt_acl(vfs_handle_struct *handle,
1202                                         struct files_struct *fsp,
1203                                         uint32 security_info,
1204                                          TALLOC_CTX *mem_ctx,
1205                                         struct security_descriptor **ppdesc)
1206 {
1207         time_t timestamp;
1208         char *stripped;
1209         NTSTATUS status;
1210         char *conv;
1211
1212         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1213                                          fsp->fsp_name->base_name,
1214                                          &timestamp, &stripped)) {
1215                 return map_nt_error_from_unix(errno);
1216         }
1217         if (timestamp == 0) {
1218                 return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
1219                                                 mem_ctx,
1220                                                 ppdesc);
1221         }
1222         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1223         TALLOC_FREE(stripped);
1224         if (conv == NULL) {
1225                 return map_nt_error_from_unix(errno);
1226         }
1227         status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv, security_info,
1228                                          mem_ctx, ppdesc);
1229         TALLOC_FREE(conv);
1230         return status;
1231 }
1232
1233 static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle,
1234                                         const char *fname,
1235                                         uint32 security_info,
1236                                         TALLOC_CTX *mem_ctx,
1237                                         struct security_descriptor **ppdesc)
1238 {
1239         time_t timestamp;
1240         char *stripped;
1241         NTSTATUS status;
1242         char *conv;
1243
1244         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1245                                          &timestamp, &stripped)) {
1246                 return map_nt_error_from_unix(errno);
1247         }
1248         if (timestamp == 0) {
1249                 return SMB_VFS_NEXT_GET_NT_ACL(handle, fname, security_info,
1250                                                mem_ctx, ppdesc);
1251         }
1252         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1253         TALLOC_FREE(stripped);
1254         if (conv == NULL) {
1255                 return map_nt_error_from_unix(errno);
1256         }
1257         status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv, security_info,
1258                                          mem_ctx, ppdesc);
1259         TALLOC_FREE(conv);
1260         return status;
1261 }
1262
1263 static int shadow_copy2_mkdir(vfs_handle_struct *handle,
1264                               const char *fname, mode_t mode)
1265 {
1266         time_t timestamp;
1267         char *stripped;
1268         int ret, saved_errno;
1269         char *conv;
1270
1271         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1272                                          &timestamp, &stripped)) {
1273                 return -1;
1274         }
1275         if (timestamp == 0) {
1276                 return SMB_VFS_NEXT_MKDIR(handle, fname, mode);
1277         }
1278         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1279         TALLOC_FREE(stripped);
1280         if (conv == NULL) {
1281                 return -1;
1282         }
1283         ret = SMB_VFS_NEXT_MKDIR(handle, conv, mode);
1284         saved_errno = errno;
1285         TALLOC_FREE(conv);
1286         errno = saved_errno;
1287         return ret;
1288 }
1289
1290 static int shadow_copy2_rmdir(vfs_handle_struct *handle, const char *fname)
1291 {
1292         time_t timestamp;
1293         char *stripped;
1294         int ret, saved_errno;
1295         char *conv;
1296
1297         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1298                                          &timestamp, &stripped)) {
1299                 return -1;
1300         }
1301         if (timestamp == 0) {
1302                 return SMB_VFS_NEXT_RMDIR(handle, fname);
1303         }
1304         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1305         TALLOC_FREE(stripped);
1306         if (conv == NULL) {
1307                 return -1;
1308         }
1309         ret = SMB_VFS_NEXT_RMDIR(handle, conv);
1310         saved_errno = errno;
1311         TALLOC_FREE(conv);
1312         errno = saved_errno;
1313         return ret;
1314 }
1315
1316 static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname,
1317                                 unsigned int flags)
1318 {
1319         time_t timestamp;
1320         char *stripped;
1321         int ret, saved_errno;
1322         char *conv;
1323
1324         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1325                                          &timestamp, &stripped)) {
1326                 return -1;
1327         }
1328         if (timestamp == 0) {
1329                 return SMB_VFS_NEXT_CHFLAGS(handle, fname, flags);
1330         }
1331         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1332         TALLOC_FREE(stripped);
1333         if (conv == NULL) {
1334                 return -1;
1335         }
1336         ret = SMB_VFS_NEXT_CHFLAGS(handle, conv, flags);
1337         saved_errno = errno;
1338         TALLOC_FREE(conv);
1339         errno = saved_errno;
1340         return ret;
1341 }
1342
1343 static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
1344                                      const char *fname, const char *aname,
1345                                      void *value, size_t size)
1346 {
1347         time_t timestamp;
1348         char *stripped;
1349         ssize_t ret;
1350         int saved_errno;
1351         char *conv;
1352
1353         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1354                                          &timestamp, &stripped)) {
1355                 return -1;
1356         }
1357         if (timestamp == 0) {
1358                 return SMB_VFS_NEXT_GETXATTR(handle, fname, aname, value,
1359                                              size);
1360         }
1361         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1362         TALLOC_FREE(stripped);
1363         if (conv == NULL) {
1364                 return -1;
1365         }
1366         ret = SMB_VFS_NEXT_GETXATTR(handle, conv, aname, value, size);
1367         saved_errno = errno;
1368         TALLOC_FREE(conv);
1369         errno = saved_errno;
1370         return ret;
1371 }
1372
1373 static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle,
1374                                       const char *fname,
1375                                       char *list, size_t size)
1376 {
1377         time_t timestamp;
1378         char *stripped;
1379         ssize_t ret;
1380         int saved_errno;
1381         char *conv;
1382
1383         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1384                                          &timestamp, &stripped)) {
1385                 return -1;
1386         }
1387         if (timestamp == 0) {
1388                 return SMB_VFS_NEXT_LISTXATTR(handle, fname, list, size);
1389         }
1390         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1391         TALLOC_FREE(stripped);
1392         if (conv == NULL) {
1393                 return -1;
1394         }
1395         ret = SMB_VFS_NEXT_LISTXATTR(handle, conv, list, size);
1396         saved_errno = errno;
1397         TALLOC_FREE(conv);
1398         errno = saved_errno;
1399         return ret;
1400 }
1401
1402 static int shadow_copy2_removexattr(vfs_handle_struct *handle,
1403                                     const char *fname, const char *aname)
1404 {
1405         time_t timestamp;
1406         char *stripped;
1407         int ret, saved_errno;
1408         char *conv;
1409
1410         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1411                                          &timestamp, &stripped)) {
1412                 return -1;
1413         }
1414         if (timestamp == 0) {
1415                 return SMB_VFS_NEXT_REMOVEXATTR(handle, fname, aname);
1416         }
1417         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1418         TALLOC_FREE(stripped);
1419         if (conv == NULL) {
1420                 return -1;
1421         }
1422         ret = SMB_VFS_NEXT_REMOVEXATTR(handle, conv, aname);
1423         saved_errno = errno;
1424         TALLOC_FREE(conv);
1425         errno = saved_errno;
1426         return ret;
1427 }
1428
1429 static int shadow_copy2_setxattr(struct vfs_handle_struct *handle,
1430                                  const char *fname,
1431                                  const char *aname, const void *value,
1432                                  size_t size, int flags)
1433 {
1434         time_t timestamp;
1435         char *stripped;
1436         ssize_t ret;
1437         int saved_errno;
1438         char *conv;
1439
1440         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1441                                          &timestamp, &stripped)) {
1442                 return -1;
1443         }
1444         if (timestamp == 0) {
1445                 return SMB_VFS_NEXT_SETXATTR(handle, fname, aname, value, size,
1446                                              flags);
1447         }
1448         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1449         TALLOC_FREE(stripped);
1450         if (conv == NULL) {
1451                 return -1;
1452         }
1453         ret = SMB_VFS_NEXT_SETXATTR(handle, conv, aname, value, size, flags);
1454         saved_errno = errno;
1455         TALLOC_FREE(conv);
1456         errno = saved_errno;
1457         return ret;
1458 }
1459
1460 static int shadow_copy2_chmod_acl(vfs_handle_struct *handle,
1461                                   const char *fname, mode_t mode)
1462 {
1463         time_t timestamp;
1464         char *stripped;
1465         ssize_t ret;
1466         int saved_errno;
1467         char *conv;
1468
1469         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1470                                          &timestamp, &stripped)) {
1471                 return -1;
1472         }
1473         if (timestamp == 0) {
1474                 return SMB_VFS_NEXT_CHMOD_ACL(handle, fname, mode);
1475         }
1476         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1477         TALLOC_FREE(stripped);
1478         if (conv == NULL) {
1479                 return -1;
1480         }
1481         ret = SMB_VFS_NEXT_CHMOD_ACL(handle, conv, mode);
1482         saved_errno = errno;
1483         TALLOC_FREE(conv);
1484         errno = saved_errno;
1485         return ret;
1486 }
1487
1488 static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle,
1489                                           const char *path,
1490                                           const char *name,
1491                                           TALLOC_CTX *mem_ctx,
1492                                           char **found_name)
1493 {
1494         time_t timestamp;
1495         char *stripped;
1496         ssize_t ret;
1497         int saved_errno;
1498         char *conv;
1499
1500         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
1501                                          &timestamp, &stripped)) {
1502                 return -1;
1503         }
1504         if (timestamp == 0) {
1505                 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
1506                                                       mem_ctx, found_name);
1507         }
1508         if (stripped[0] == '\0') {
1509                 *found_name = talloc_strdup(mem_ctx, name);
1510                 if (*found_name == NULL) {
1511                         errno = ENOMEM;
1512                         return -1;
1513                 }
1514                 return 0;
1515         }
1516         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1517         TALLOC_FREE(stripped);
1518         if (conv == NULL) {
1519                 return -1;
1520         }
1521         ret = SMB_VFS_NEXT_GET_REAL_FILENAME(handle, conv, name,
1522                                              mem_ctx, found_name);
1523         saved_errno = errno;
1524         TALLOC_FREE(conv);
1525         errno = saved_errno;
1526         return ret;
1527 }
1528
1529
1530 static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
1531         .opendir_fn = shadow_copy2_opendir,
1532         .rename_fn = shadow_copy2_rename,
1533         .link_fn = shadow_copy2_link,
1534         .symlink_fn = shadow_copy2_symlink,
1535         .stat_fn = shadow_copy2_stat,
1536         .lstat_fn = shadow_copy2_lstat,
1537         .fstat_fn = shadow_copy2_fstat,
1538         .open_fn = shadow_copy2_open,
1539         .unlink_fn = shadow_copy2_unlink,
1540         .chmod_fn = shadow_copy2_chmod,
1541         .chown_fn = shadow_copy2_chown,
1542         .chdir_fn = shadow_copy2_chdir,
1543         .ntimes_fn = shadow_copy2_ntimes,
1544         .readlink_fn = shadow_copy2_readlink,
1545         .mknod_fn = shadow_copy2_mknod,
1546         .realpath_fn = shadow_copy2_realpath,
1547         .get_nt_acl_fn = shadow_copy2_get_nt_acl,
1548         .fget_nt_acl_fn = shadow_copy2_fget_nt_acl,
1549         .get_shadow_copy_data_fn = shadow_copy2_get_shadow_copy_data,
1550         .mkdir_fn = shadow_copy2_mkdir,
1551         .rmdir_fn = shadow_copy2_rmdir,
1552         .getxattr_fn = shadow_copy2_getxattr,
1553         .listxattr_fn = shadow_copy2_listxattr,
1554         .removexattr_fn = shadow_copy2_removexattr,
1555         .setxattr_fn = shadow_copy2_setxattr,
1556         .chmod_acl_fn = shadow_copy2_chmod_acl,
1557         .chflags_fn = shadow_copy2_chflags,
1558         .get_real_filename_fn = shadow_copy2_get_real_filename,
1559 };
1560
1561 NTSTATUS vfs_shadow_copy2_init(void);
1562 NTSTATUS vfs_shadow_copy2_init(void)
1563 {
1564         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1565                                 "shadow_copy2", &vfs_shadow_copy2_fns);
1566 }