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