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