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