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