s3-vfs: Remove unused llistxattr call from VFS modules, system.c and configure
[kai/samba-autobuild/.git] / source3 / modules / vfs_shadow_copy2.c
1 /*
2  * Third attempt at a shadow copy module
3  *
4  * Copyright (C) Andrew Tridgell   2007 (portions taken from shadow_copy2)
5  * Copyright (C) Ed Plese          2009
6  * Copyright (C) Volker Lendecke   2011
7  * Copyright (C) Christian Ambach  2011
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23
24 /*
25
26   This is a 3rd implemetation of a shadow copy module for exposing
27   snapshots to windows clients as shadow copies. This version has the
28   following features:
29
30      1) you don't need to populate your shares with symlinks to the
31      snapshots. This can be very important when you have thousands of
32      shares, or use [homes]
33
34      2) the inode number of the files is altered so it is different
35      from the original. This allows the 'restore' button to work
36      without a sharing violation
37
38      3) shadow copy results can be sorted before being sent to the
39      client.  This is beneficial for filesystems that don't read
40      directories alphabetically (the default unix).
41
42      4) vanity naming for snapshots. Snapshots can be named in any
43      format compatible with str[fp]time conversions.
44
45      5) time stamps in snapshot names can be represented in localtime
46      rather than UTC.
47
48   Module options:
49
50       shadow:snapdir = <directory where snapshots are kept>
51
52       This is the directory containing the @GMT-* snapshot directories. If it is an absolute
53       path it is used as-is. If it is a relative path, then it is taken relative to the mount
54       point of the filesystem that the root of this share is on
55
56       shadow:basedir = <base directory that snapshots are from>
57
58       This is an optional parameter that specifies the directory that
59       the snapshots are relative to. It defaults to the filesystem
60       mount point
61
62       shadow:fixinodes = yes/no
63
64       If you enable shadow:fixinodes then this module will modify the
65       apparent inode number of files in the snapshot directories using
66       a hash of the files path. This is needed for snapshot systems
67       where the snapshots have the same device:inode number as the
68       original files (such as happens with GPFS snapshots). If you
69       don't set this option then the 'restore' button in the shadow
70       copy UI will fail with a sharing violation.
71
72       shadow:sort = asc/desc, or not specified for unsorted (default)
73
74       This is an optional parameter that specifies that the shadow
75       copy directories should be sorted before sending them to the
76       client.  This can be beneficial as unix filesystems are usually
77       not listed alphabetically sorted.  If enabled, you typically
78       want to specify descending order.
79
80       shadow:format = <format specification for snapshot names>
81
82       This is an optional parameter that specifies the format
83       specification for the naming of snapshots.  The format must
84       be compatible with the conversion specifications recognized
85       by str[fp]time.  The default value is "@GMT-%Y.%m.%d-%H.%M.%S".
86
87       shadow: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 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         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         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_listxattr(struct vfs_handle_struct *handle,
1325                                       const char *fname,
1326                                       char *list, 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_LISTXATTR(handle, fname, list, size);
1340         }
1341         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1342         TALLOC_FREE(stripped);
1343         if (conv == NULL) {
1344                 return -1;
1345         }
1346         ret = SMB_VFS_NEXT_LISTXATTR(handle, conv, list, size);
1347         saved_errno = errno;
1348         TALLOC_FREE(conv);
1349         errno = saved_errno;
1350         return ret;
1351 }
1352
1353 static int shadow_copy2_removexattr(vfs_handle_struct *handle,
1354                                     const char *fname, const char *aname)
1355 {
1356         time_t timestamp;
1357         char *stripped;
1358         int ret, saved_errno;
1359         char *conv;
1360
1361         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1362                                          &timestamp, &stripped)) {
1363                 return -1;
1364         }
1365         if (timestamp == 0) {
1366                 return SMB_VFS_NEXT_REMOVEXATTR(handle, fname, aname);
1367         }
1368         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1369         TALLOC_FREE(stripped);
1370         if (conv == NULL) {
1371                 return -1;
1372         }
1373         ret = SMB_VFS_NEXT_REMOVEXATTR(handle, conv, aname);
1374         saved_errno = errno;
1375         TALLOC_FREE(conv);
1376         errno = saved_errno;
1377         return ret;
1378 }
1379
1380 static int shadow_copy2_lremovexattr(vfs_handle_struct *handle,
1381                                      const char *fname, const char *aname)
1382 {
1383         time_t timestamp;
1384         char *stripped;
1385         int ret, saved_errno;
1386         char *conv;
1387
1388         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1389                                          &timestamp, &stripped)) {
1390                 return -1;
1391         }
1392         if (timestamp == 0) {
1393                 return SMB_VFS_NEXT_LREMOVEXATTR(handle, fname, aname);
1394         }
1395         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1396         TALLOC_FREE(stripped);
1397         if (conv == NULL) {
1398                 return -1;
1399         }
1400         ret = SMB_VFS_NEXT_LREMOVEXATTR(handle, conv, aname);
1401         saved_errno = errno;
1402         TALLOC_FREE(conv);
1403         errno = saved_errno;
1404         return ret;
1405 }
1406
1407 static int shadow_copy2_setxattr(struct vfs_handle_struct *handle,
1408                                  const char *fname,
1409                                  const char *aname, const void *value,
1410                                  size_t size, int flags)
1411 {
1412         time_t timestamp;
1413         char *stripped;
1414         ssize_t ret;
1415         int 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_SETXATTR(handle, fname, aname, value, size,
1424                                              flags);
1425         }
1426         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1427         TALLOC_FREE(stripped);
1428         if (conv == NULL) {
1429                 return -1;
1430         }
1431         ret = SMB_VFS_NEXT_SETXATTR(handle, conv, aname, value, size, flags);
1432         saved_errno = errno;
1433         TALLOC_FREE(conv);
1434         errno = saved_errno;
1435         return ret;
1436 }
1437
1438 static int shadow_copy2_lsetxattr(struct vfs_handle_struct *handle,
1439                                   const char *fname,
1440                                   const char *aname, const void *value,
1441                                   size_t size, int flags)
1442 {
1443         time_t timestamp;
1444         char *stripped;
1445         ssize_t ret;
1446         int saved_errno;
1447         char *conv;
1448
1449         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1450                                          &timestamp, &stripped)) {
1451                 return -1;
1452         }
1453         if (timestamp == 0) {
1454                 return SMB_VFS_NEXT_LSETXATTR(handle, fname, aname, value,
1455                                               size, flags);
1456         }
1457         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1458         TALLOC_FREE(stripped);
1459         if (conv == NULL) {
1460                 return -1;
1461         }
1462         ret = SMB_VFS_NEXT_LSETXATTR(handle, conv, aname, value, size, flags);
1463         saved_errno = errno;
1464         TALLOC_FREE(conv);
1465         errno = saved_errno;
1466         return ret;
1467 }
1468
1469 static int shadow_copy2_chmod_acl(vfs_handle_struct *handle,
1470                                   const char *fname, mode_t mode)
1471 {
1472         time_t timestamp;
1473         char *stripped;
1474         ssize_t ret;
1475         int saved_errno;
1476         char *conv;
1477
1478         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1479                                          &timestamp, &stripped)) {
1480                 return -1;
1481         }
1482         if (timestamp == 0) {
1483                 return SMB_VFS_NEXT_CHMOD_ACL(handle, fname, mode);
1484         }
1485         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1486         TALLOC_FREE(stripped);
1487         if (conv == NULL) {
1488                 return -1;
1489         }
1490         ret = SMB_VFS_NEXT_CHMOD_ACL(handle, conv, mode);
1491         saved_errno = errno;
1492         TALLOC_FREE(conv);
1493         errno = saved_errno;
1494         return ret;
1495 }
1496
1497 static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle,
1498                                           const char *path,
1499                                           const char *name,
1500                                           TALLOC_CTX *mem_ctx,
1501                                           char **found_name)
1502 {
1503         time_t timestamp;
1504         char *stripped;
1505         ssize_t ret;
1506         int saved_errno;
1507         char *conv;
1508
1509         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
1510                                          &timestamp, &stripped)) {
1511                 return -1;
1512         }
1513         if (timestamp == 0) {
1514                 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
1515                                                       mem_ctx, found_name);
1516         }
1517         if (stripped[0] == '\0') {
1518                 *found_name = talloc_strdup(mem_ctx, name);
1519                 if (*found_name == NULL) {
1520                         errno = ENOMEM;
1521                         return -1;
1522                 }
1523                 return 0;
1524         }
1525         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1526         TALLOC_FREE(stripped);
1527         if (conv == NULL) {
1528                 return -1;
1529         }
1530         ret = SMB_VFS_NEXT_GET_REAL_FILENAME(handle, conv, name,
1531                                              mem_ctx, found_name);
1532         saved_errno = errno;
1533         TALLOC_FREE(conv);
1534         errno = saved_errno;
1535         return ret;
1536 }
1537
1538
1539 static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
1540         .opendir_fn = shadow_copy2_opendir,
1541         .rename_fn = shadow_copy2_rename,
1542         .link_fn = shadow_copy2_link,
1543         .symlink_fn = shadow_copy2_symlink,
1544         .stat_fn = shadow_copy2_stat,
1545         .lstat_fn = shadow_copy2_lstat,
1546         .fstat_fn = shadow_copy2_fstat,
1547         .open_fn = shadow_copy2_open,
1548         .unlink_fn = shadow_copy2_unlink,
1549         .chmod_fn = shadow_copy2_chmod,
1550         .chown_fn = shadow_copy2_chown,
1551         .chdir_fn = shadow_copy2_chdir,
1552         .ntimes_fn = shadow_copy2_ntimes,
1553         .readlink_fn = shadow_copy2_readlink,
1554         .mknod_fn = shadow_copy2_mknod,
1555         .realpath_fn = shadow_copy2_realpath,
1556         .get_nt_acl_fn = shadow_copy2_get_nt_acl,
1557         .fget_nt_acl_fn = shadow_copy2_fget_nt_acl,
1558         .get_shadow_copy_data_fn = shadow_copy2_get_shadow_copy_data,
1559         .mkdir_fn = shadow_copy2_mkdir,
1560         .rmdir_fn = shadow_copy2_rmdir,
1561         .getxattr_fn = shadow_copy2_getxattr,
1562         .listxattr_fn = shadow_copy2_listxattr,
1563         .removexattr_fn = shadow_copy2_removexattr,
1564         .lremovexattr_fn = shadow_copy2_lremovexattr,
1565         .setxattr_fn = shadow_copy2_setxattr,
1566         .lsetxattr_fn = shadow_copy2_lsetxattr,
1567         .chmod_acl_fn = shadow_copy2_chmod_acl,
1568         .chflags_fn = shadow_copy2_chflags,
1569         .get_real_filename_fn = shadow_copy2_get_real_filename,
1570 };
1571
1572 NTSTATUS vfs_shadow_copy2_init(void);
1573 NTSTATUS vfs_shadow_copy2_init(void)
1574 {
1575         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
1576                                 "shadow_copy2", &vfs_shadow_copy2_fns);
1577 }