docs: fix copy'n'paste error in vfs_shadow_copy2 manpage
[obnox/samba/samba-obnox.git] / source3 / modules / vfs_shadow_copy2.c
1 /*
2  * shadow_copy2: a shadow copy module (second implementation)
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  * Copyright (C) Michael Adam      2013
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 /*
26  * This is a second implemetation of a shadow copy module for exposing
27  * file system snapshots to windows clients as shadow copies.
28  *
29  * See the manual page for documentation.
30  */
31
32 #include "includes.h"
33 #include "smbd/smbd.h"
34 #include "system/filesys.h"
35 #include "include/ntioctl.h"
36 #include "util_tdb.h"
37
38 struct shadow_copy2_config {
39         char *gmt_format;
40         bool use_sscanf;
41         bool use_localtime;
42         char *snapdir;
43         bool snapdirseverywhere;
44         bool crossmountpoints;
45         bool fixinodes;
46         char *sort_order;
47         bool snapdir_absolute;
48         char *basedir;
49         char *mount_point;
50         char *rel_connectpath; /* share root, relative to the basedir */
51         char *snapshot_basepath; /* the absolute version of snapdir */
52 };
53
54 static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str,
55                                       size_t **poffsets,
56                                       unsigned *pnum_offsets)
57 {
58         unsigned num_offsets;
59         size_t *offsets;
60         const char *p;
61
62         num_offsets = 0;
63
64         p = str;
65         while ((p = strchr(p, '/')) != NULL) {
66                 num_offsets += 1;
67                 p += 1;
68         }
69
70         offsets = talloc_array(mem_ctx, size_t, num_offsets);
71         if (offsets == NULL) {
72                 return false;
73         }
74
75         p = str;
76         num_offsets = 0;
77         while ((p = strchr(p, '/')) != NULL) {
78                 offsets[num_offsets] = p-str;
79                 num_offsets += 1;
80                 p += 1;
81         }
82
83         *poffsets = offsets;
84         *pnum_offsets = num_offsets;
85         return true;
86 }
87
88 /**
89  * Given a timestamp, build the posix level GMT-tag string
90  * based on the configurable format.
91  */
92 static size_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct *handle,
93                                             time_t snapshot,
94                                             char *snaptime_string,
95                                             size_t len)
96 {
97         struct tm snap_tm;
98         size_t snaptime_len;
99         struct shadow_copy2_config *config;
100
101         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
102                                 return 0);
103
104         if (config->use_sscanf) {
105                 snaptime_len = snprintf(snaptime_string,
106                                         len,
107                                         config->gmt_format,
108                                         (unsigned long)snapshot);
109                 if (snaptime_len <= 0) {
110                         DEBUG(10, ("snprintf failed\n"));
111                         return snaptime_len;
112                 }
113         } else {
114                 if (config->use_localtime) {
115                         if (localtime_r(&snapshot, &snap_tm) == 0) {
116                                 DEBUG(10, ("gmtime_r failed\n"));
117                                 return -1;
118                         }
119                 } else {
120                         if (gmtime_r(&snapshot, &snap_tm) == 0) {
121                                 DEBUG(10, ("gmtime_r failed\n"));
122                                 return -1;
123                         }
124                 }
125                 snaptime_len = strftime(snaptime_string,
126                                         len,
127                                         config->gmt_format,
128                                         &snap_tm);
129                 if (snaptime_len == 0) {
130                         DEBUG(10, ("strftime failed\n"));
131                         return 0;
132                 }
133         }
134
135         return snaptime_len;
136 }
137
138 /**
139  * Given a timestamp, build the string to insert into a path
140  * as a path component for creating the local path to the
141  * snapshot at the given timestamp of the input path.
142  *
143  * In the case of a parallel snapdir (specified with an
144  * absolute path), this is the inital portion of the
145  * local path of any snapshot file. The complete path is
146  * obtained by appending the portion of the file's path
147  * below the share root's mountpoint.
148  */
149 static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx,
150                                         struct vfs_handle_struct *handle,
151                                         time_t snapshot)
152 {
153         fstring snaptime_string;
154         size_t snaptime_len = 0;
155         char *result = NULL;
156         struct shadow_copy2_config *config;
157
158         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
159                                 return NULL);
160
161         snaptime_len = shadow_copy2_posix_gmt_string(handle,
162                                                      snapshot,
163                                                      snaptime_string,
164                                                      sizeof(snaptime_string));
165         if (snaptime_len <= 0) {
166                 return NULL;
167         }
168
169         if (config->snapdir_absolute) {
170                 result = talloc_asprintf(mem_ctx, "%s/%s",
171                                          config->snapdir, snaptime_string);
172         } else {
173                 result = talloc_asprintf(mem_ctx, "/%s/%s",
174                                          config->snapdir, snaptime_string);
175         }
176         if (result == NULL) {
177                 DEBUG(1, (__location__ " talloc_asprintf failed\n"));
178         }
179
180         return result;
181 }
182
183 /**
184  * Build the posix snapshot path for the connection
185  * at the given timestamp, i.e. the absolute posix path
186  * that contains the snapshot for this file system.
187  *
188  * This only applies to classical case, i.e. not
189  * to the "snapdirseverywhere" mode.
190  */
191 static char *shadow_copy2_snapshot_path(TALLOC_CTX *mem_ctx,
192                                         struct vfs_handle_struct *handle,
193                                         time_t snapshot)
194 {
195         fstring snaptime_string;
196         size_t snaptime_len = 0;
197         char *result = NULL;
198         struct shadow_copy2_config *config;
199
200         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
201                                 return NULL);
202
203         snaptime_len = shadow_copy2_posix_gmt_string(handle,
204                                                      snapshot,
205                                                      snaptime_string,
206                                                      sizeof(snaptime_string));
207         if (snaptime_len <= 0) {
208                 return NULL;
209         }
210
211         result = talloc_asprintf(mem_ctx, "%s/%s",
212                                  config->snapshot_basepath, snaptime_string);
213         if (result == NULL) {
214                 DEBUG(1, (__location__ " talloc_asprintf failed\n"));
215         }
216
217         return result;
218 }
219
220 /**
221  * Strip a snapshot component from a filename as
222  * handed in via the smb layer.
223  * Returns the parsed timestamp and the stripped filename.
224  */
225 static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx,
226                                         struct vfs_handle_struct *handle,
227                                         const char *name,
228                                         time_t *ptimestamp,
229                                         char **pstripped)
230 {
231         struct tm tm;
232         time_t timestamp;
233         const char *p;
234         char *q;
235         char *stripped;
236         size_t rest_len, dst_len;
237         struct shadow_copy2_config *config;
238         const char *snapdir;
239         ssize_t snapdirlen;
240         ptrdiff_t len_before_gmt;
241
242         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
243                                 return false);
244
245         DEBUG(10, (__location__ ": enter path '%s'\n", name));
246
247         p = strstr_m(name, "@GMT-");
248         if (p == NULL) {
249                 DEBUG(11, ("@GMT not found\n"));
250                 goto no_snapshot;
251         }
252         if ((p > name) && (p[-1] != '/')) {
253                 /* the GMT-token does not start a path-component */
254                 DEBUG(10, ("not at start, p=%p, name=%p, p[-1]=%d\n",
255                            p, name, (int)p[-1]));
256                 goto no_snapshot;
257         }
258
259         /*
260          * Figure out whether we got an already converted string. One
261          * case where this happens is in a smb2 create call with the
262          * mxac create blob set. We do the get_acl call on
263          * fsp->fsp_name, which is already converted. We are converted
264          * if we got a file name of the form ".snapshots/@GMT-",
265          * i.e. ".snapshots/" precedes "p".
266          */
267
268         snapdir = lp_parm_const_string(SNUM(handle->conn), "shadow", "snapdir",
269                                        ".snapshots");
270         snapdirlen = strlen(snapdir);
271         len_before_gmt = p - name;
272
273         if ((len_before_gmt >= (snapdirlen + 1)) && (p[-1] == '/')) {
274                 const char *parent_snapdir = p - (snapdirlen+1);
275
276                 DEBUG(10, ("parent_snapdir = %s\n", parent_snapdir));
277
278                 if (strncmp(parent_snapdir, snapdir, snapdirlen) == 0) {
279                         DEBUG(10, ("name=%s is already converted\n", name));
280                         goto no_snapshot;
281                 }
282         }
283         q = strptime(p, GMT_FORMAT, &tm);
284         if (q == NULL) {
285                 DEBUG(10, ("strptime failed\n"));
286                 goto no_snapshot;
287         }
288         tm.tm_isdst = -1;
289         timestamp = timegm(&tm);
290         if (timestamp == (time_t)-1) {
291                 DEBUG(10, ("timestamp==-1\n"));
292                 goto no_snapshot;
293         }
294         if (q[0] == '\0') {
295                 /*
296                  * The name consists of only the GMT token or the GMT
297                  * token is at the end of the path. XP seems to send
298                  * @GMT- at the end under certain circumstances even
299                  * with a path prefix.
300                  */
301                 if (pstripped != NULL) {
302                         stripped = talloc_strndup(mem_ctx, name, p - name);
303                         if (stripped == NULL) {
304                                 return false;
305                         }
306                         *pstripped = stripped;
307                 }
308                 *ptimestamp = timestamp;
309                 return true;
310         }
311         if (q[0] != '/') {
312                 /*
313                  * It is not a complete path component, i.e. the path
314                  * component continues after the gmt-token.
315                  */
316                 DEBUG(10, ("q[0] = %d\n", (int)q[0]));
317                 goto no_snapshot;
318         }
319         q += 1;
320
321         rest_len = strlen(q);
322         dst_len = (p-name) + rest_len;
323
324         if (config->snapdirseverywhere) {
325                 char *insert;
326                 bool have_insert;
327                 insert = shadow_copy2_insert_string(talloc_tos(), handle,
328                                                     timestamp);
329                 if (insert == NULL) {
330                         errno = ENOMEM;
331                         return false;
332                 }
333
334                 DEBUG(10, (__location__ ": snapdirseverywhere mode.\n"
335                            "path '%s'.\n"
336                            "insert string '%s'\n", name, insert));
337
338                 have_insert = (strstr(name, insert+1) != NULL);
339                 DEBUG(10, ("have_insert=%d, name=%s, insert+1=%s\n",
340                            (int)have_insert, name, insert+1));
341                 if (have_insert) {
342                         DEBUG(10, (__location__ ": insert string '%s' found in "
343                                    "path '%s' found in snapdirseverywhere mode "
344                                    "==> already converted\n", insert, name));
345                         TALLOC_FREE(insert);
346                         goto no_snapshot;
347                 }
348                 TALLOC_FREE(insert);
349         } else {
350                 char *snapshot_path;
351                 char *s;
352
353                 snapshot_path = shadow_copy2_snapshot_path(talloc_tos(),
354                                                            handle,
355                                                            timestamp);
356                 if (snapshot_path == NULL) {
357                         errno = ENOMEM;
358                         return false;
359                 }
360
361                 DEBUG(10, (__location__ " path: '%s'.\n"
362                            "snapshot path: '%s'\n", name, snapshot_path));
363
364                 s = strstr(name, snapshot_path);
365                 if (s == name) {
366                         /*
367                          * this starts with "snapshot_basepath/GMT-Token"
368                          * so it is already a converted absolute
369                          * path. Don't process further.
370                          */
371                         DEBUG(10, (__location__ ": path '%s' starts with "
372                                    "snapshot path '%s' (not in "
373                                    "snapdirseverywhere mode) ==> "
374                                    "already converted\n", name, snapshot_path));
375                         talloc_free(snapshot_path);
376                         goto no_snapshot;
377                 }
378                 talloc_free(snapshot_path);
379         }
380
381         if (pstripped != NULL) {
382                 stripped = talloc_array(mem_ctx, char, dst_len+1);
383                 if (stripped == NULL) {
384                         errno = ENOMEM;
385                         return false;
386                 }
387                 if (p > name) {
388                         memcpy(stripped, name, p-name);
389                 }
390                 if (rest_len > 0) {
391                         memcpy(stripped + (p-name), q, rest_len);
392                 }
393                 stripped[dst_len] = '\0';
394                 *pstripped = stripped;
395         }
396         *ptimestamp = timestamp;
397         return true;
398 no_snapshot:
399         *ptimestamp = 0;
400         return true;
401 }
402
403 static char *shadow_copy2_find_mount_point(TALLOC_CTX *mem_ctx,
404                                            vfs_handle_struct *handle)
405 {
406         char *path = talloc_strdup(mem_ctx, handle->conn->connectpath);
407         dev_t dev;
408         struct stat st;
409         char *p;
410
411         if (stat(path, &st) != 0) {
412                 talloc_free(path);
413                 return NULL;
414         }
415
416         dev = st.st_dev;
417
418         while ((p = strrchr(path, '/')) && p > path) {
419                 *p = 0;
420                 if (stat(path, &st) != 0) {
421                         talloc_free(path);
422                         return NULL;
423                 }
424                 if (st.st_dev != dev) {
425                         *p = '/';
426                         break;
427                 }
428         }
429
430         return path;
431 }
432
433 /**
434  * Convert from a name as handed in via the SMB layer
435  * and a timestamp into the local path of the snapshot
436  * of the provided file at the provided time.
437  */
438 static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx,
439                                   struct vfs_handle_struct *handle,
440                                   const char *name, time_t timestamp)
441 {
442         struct smb_filename converted_fname;
443         char *result = NULL;
444         size_t *slashes = NULL;
445         unsigned num_slashes;
446         char *path = NULL;
447         size_t pathlen;
448         char *insert = NULL;
449         char *converted = NULL;
450         size_t insertlen;
451         int i, saved_errno;
452         size_t min_offset;
453         struct shadow_copy2_config *config;
454
455         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
456                                 return NULL);
457
458         DEBUG(10, ("converting '%s'\n", name));
459
460         if (!config->snapdirseverywhere) {
461                 int ret;
462                 char *snapshot_path;
463
464                 snapshot_path = shadow_copy2_snapshot_path(talloc_tos(),
465                                                            handle,
466                                                            timestamp);
467                 if (snapshot_path == NULL) {
468                         goto fail;
469                 }
470
471                 if (config->rel_connectpath == NULL) {
472                         converted = talloc_asprintf(mem_ctx, "%s/%s",
473                                                     snapshot_path, name);
474                 } else {
475                         converted = talloc_asprintf(mem_ctx, "%s/%s/%s",
476                                                     snapshot_path,
477                                                     config->rel_connectpath,
478                                                     name);
479                 }
480                 if (converted == NULL) {
481                         goto fail;
482                 }
483
484                 ZERO_STRUCT(converted_fname);
485                 converted_fname.base_name = converted;
486
487                 ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
488                 DEBUG(10, ("Trying[not snapdirseverywhere] %s: %d (%s)\n",
489                            converted,
490                            ret, ret == 0 ? "ok" : strerror(errno)));
491                 if (ret == 0) {
492                         DEBUG(10, ("Found %s\n", converted));
493                         result = converted;
494                         converted = NULL;
495                         goto fail;
496                 } else {
497                         errno = ENOENT;
498                         goto fail;
499                 }
500                 /* never reached ... */
501         }
502
503         if (name[0] == 0) {
504                 path = talloc_strdup(mem_ctx, handle->conn->connectpath);
505         } else {
506                 path = talloc_asprintf(
507                         mem_ctx, "%s/%s", handle->conn->connectpath, name);
508         }
509         if (path == NULL) {
510                 errno = ENOMEM;
511                 goto fail;
512         }
513         pathlen = talloc_get_size(path)-1;
514
515         if (!shadow_copy2_find_slashes(talloc_tos(), path,
516                                        &slashes, &num_slashes)) {
517                 goto fail;
518         }
519
520         insert = shadow_copy2_insert_string(talloc_tos(), handle, timestamp);
521         if (insert == NULL) {
522                 goto fail;
523         }
524         insertlen = talloc_get_size(insert)-1;
525
526         /*
527          * Note: We deliberatly don't expensively initialize the
528          * array with talloc_zero here: Putting zero into
529          * converted[pathlen+insertlen] below is sufficient, because
530          * in the following for loop, the insert string is inserted
531          * at various slash places. So the memory up to position
532          * pathlen+insertlen will always be initialized when the
533          * converted string is used.
534          */
535         converted = talloc_array(mem_ctx, char, pathlen + insertlen + 1);
536         if (converted == NULL) {
537                 goto fail;
538         }
539
540         if (path[pathlen-1] != '/') {
541                 /*
542                  * Append a fake slash to find the snapshot root
543                  */
544                 size_t *tmp;
545                 tmp = talloc_realloc(talloc_tos(), slashes,
546                                      size_t, num_slashes+1);
547                 if (tmp == NULL) {
548                         goto fail;
549                 }
550                 slashes = tmp;
551                 slashes[num_slashes] = pathlen;
552                 num_slashes += 1;
553         }
554
555         min_offset = 0;
556
557         if (!config->crossmountpoints) {
558                 min_offset = strlen(config->mount_point);
559         }
560
561         memcpy(converted, path, pathlen+1);
562         converted[pathlen+insertlen] = '\0';
563
564         ZERO_STRUCT(converted_fname);
565         converted_fname.base_name = converted;
566
567         for (i = num_slashes-1; i>=0; i--) {
568                 int ret;
569                 size_t offset;
570
571                 offset = slashes[i];
572
573                 if (offset < min_offset) {
574                         errno = ENOENT;
575                         goto fail;
576                 }
577
578                 memcpy(converted+offset, insert, insertlen);
579
580                 offset += insertlen;
581                 memcpy(converted+offset, path + slashes[i],
582                        pathlen - slashes[i]);
583
584                 ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
585
586                 DEBUG(10, ("Trying[snapdirseverywhere] %s: %d (%s)\n",
587                            converted,
588                            ret, ret == 0 ? "ok" : strerror(errno)));
589                 if (ret == 0) {
590                         /* success */
591                         break;
592                 }
593                 if (errno == ENOTDIR) {
594                         /*
595                          * This is a valid condition: We appended the
596                          * .snaphots/@GMT.. to a file name. Just try
597                          * with the upper levels.
598                          */
599                         continue;
600                 }
601                 if (errno != ENOENT) {
602                         /* Other problem than "not found" */
603                         goto fail;
604                 }
605         }
606
607         if (i >= 0) {
608                 /*
609                  * Found something
610                  */
611                 DEBUG(10, ("Found %s\n", converted));
612                 result = converted;
613                 converted = NULL;
614         } else {
615                 errno = ENOENT;
616         }
617 fail:
618         saved_errno = errno;
619         TALLOC_FREE(converted);
620         TALLOC_FREE(insert);
621         TALLOC_FREE(slashes);
622         TALLOC_FREE(path);
623         errno = saved_errno;
624         return result;
625 }
626
627 /*
628   modify a sbuf return to ensure that inodes in the shadow directory
629   are different from those in the main directory
630  */
631 static void convert_sbuf(vfs_handle_struct *handle, const char *fname,
632                          SMB_STRUCT_STAT *sbuf)
633 {
634         struct shadow_copy2_config *config;
635
636         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
637                                 return);
638
639         if (config->fixinodes) {
640                 /* some snapshot systems, like GPFS, return the name
641                    device:inode for the snapshot files as the current
642                    files. That breaks the 'restore' button in the shadow copy
643                    GUI, as the client gets a sharing violation.
644
645                    This is a crude way of allowing both files to be
646                    open at once. It has a slight chance of inode
647                    number collision, but I can't see a better approach
648                    without significant VFS changes
649                 */
650                 TDB_DATA key = { .dptr = discard_const_p(uint8_t, fname),
651                                  .dsize = strlen(fname) };
652                 uint32_t shash;
653
654                 shash = tdb_jenkins_hash(&key) & 0xFF000000;
655                 if (shash == 0) {
656                         shash = 1;
657                 }
658                 sbuf->st_ex_ino ^= shash;
659         }
660 }
661
662 static DIR *shadow_copy2_opendir(vfs_handle_struct *handle,
663                                             const char *fname,
664                                             const char *mask,
665                                             uint32_t attr)
666 {
667         time_t timestamp;
668         char *stripped;
669         DIR *ret;
670         int saved_errno;
671         char *conv;
672
673         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
674                                          &timestamp, &stripped)) {
675                 return NULL;
676         }
677         if (timestamp == 0) {
678                 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
679         }
680         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
681         TALLOC_FREE(stripped);
682         if (conv == NULL) {
683                 return NULL;
684         }
685         ret = SMB_VFS_NEXT_OPENDIR(handle, conv, mask, attr);
686         saved_errno = errno;
687         TALLOC_FREE(conv);
688         errno = saved_errno;
689         return ret;
690 }
691
692 static int shadow_copy2_rename(vfs_handle_struct *handle,
693                                const struct smb_filename *smb_fname_src,
694                                const struct smb_filename *smb_fname_dst)
695 {
696         time_t timestamp_src, timestamp_dst;
697
698         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
699                                          smb_fname_src->base_name,
700                                          &timestamp_src, NULL)) {
701                 return -1;
702         }
703         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
704                                          smb_fname_dst->base_name,
705                                          &timestamp_dst, NULL)) {
706                 return -1;
707         }
708         if (timestamp_src != 0) {
709                 errno = EXDEV;
710                 return -1;
711         }
712         if (timestamp_dst != 0) {
713                 errno = EROFS;
714                 return -1;
715         }
716         return SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
717 }
718
719 static int shadow_copy2_symlink(vfs_handle_struct *handle,
720                                 const char *oldname, const char *newname)
721 {
722         time_t timestamp_old, timestamp_new;
723
724         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
725                                          &timestamp_old, NULL)) {
726                 return -1;
727         }
728         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
729                                          &timestamp_new, NULL)) {
730                 return -1;
731         }
732         if ((timestamp_old != 0) || (timestamp_new != 0)) {
733                 errno = EROFS;
734                 return -1;
735         }
736         return SMB_VFS_NEXT_SYMLINK(handle, oldname, newname);
737 }
738
739 static int shadow_copy2_link(vfs_handle_struct *handle,
740                              const char *oldname, const char *newname)
741 {
742         time_t timestamp_old, timestamp_new;
743
744         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
745                                          &timestamp_old, NULL)) {
746                 return -1;
747         }
748         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
749                                          &timestamp_new, NULL)) {
750                 return -1;
751         }
752         if ((timestamp_old != 0) || (timestamp_new != 0)) {
753                 errno = EROFS;
754                 return -1;
755         }
756         return SMB_VFS_NEXT_LINK(handle, oldname, newname);
757 }
758
759 static int shadow_copy2_stat(vfs_handle_struct *handle,
760                              struct smb_filename *smb_fname)
761 {
762         time_t timestamp;
763         char *stripped, *tmp;
764         int ret, saved_errno;
765
766         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
767                                          smb_fname->base_name,
768                                          &timestamp, &stripped)) {
769                 return -1;
770         }
771         if (timestamp == 0) {
772                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
773         }
774
775         tmp = smb_fname->base_name;
776         smb_fname->base_name = shadow_copy2_convert(
777                 talloc_tos(), handle, stripped, timestamp);
778         TALLOC_FREE(stripped);
779
780         if (smb_fname->base_name == NULL) {
781                 smb_fname->base_name = tmp;
782                 return -1;
783         }
784
785         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
786         saved_errno = errno;
787
788         TALLOC_FREE(smb_fname->base_name);
789         smb_fname->base_name = tmp;
790
791         if (ret == 0) {
792                 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
793         }
794         errno = saved_errno;
795         return ret;
796 }
797
798 static int shadow_copy2_lstat(vfs_handle_struct *handle,
799                               struct smb_filename *smb_fname)
800 {
801         time_t timestamp;
802         char *stripped, *tmp;
803         int ret, saved_errno;
804
805         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
806                                          smb_fname->base_name,
807                                          &timestamp, &stripped)) {
808                 return -1;
809         }
810         if (timestamp == 0) {
811                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
812         }
813
814         tmp = smb_fname->base_name;
815         smb_fname->base_name = shadow_copy2_convert(
816                 talloc_tos(), handle, stripped, timestamp);
817         TALLOC_FREE(stripped);
818
819         if (smb_fname->base_name == NULL) {
820                 smb_fname->base_name = tmp;
821                 return -1;
822         }
823
824         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
825         saved_errno = errno;
826
827         TALLOC_FREE(smb_fname->base_name);
828         smb_fname->base_name = tmp;
829
830         if (ret == 0) {
831                 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
832         }
833         errno = saved_errno;
834         return ret;
835 }
836
837 static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
838                               SMB_STRUCT_STAT *sbuf)
839 {
840         time_t timestamp;
841         int ret;
842
843         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
844         if (ret == -1) {
845                 return ret;
846         }
847         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
848                                          fsp->fsp_name->base_name,
849                                          &timestamp, NULL)) {
850                 return 0;
851         }
852         if (timestamp != 0) {
853                 convert_sbuf(handle, fsp->fsp_name->base_name, sbuf);
854         }
855         return 0;
856 }
857
858 static int shadow_copy2_open(vfs_handle_struct *handle,
859                              struct smb_filename *smb_fname, files_struct *fsp,
860                              int flags, mode_t mode)
861 {
862         time_t timestamp;
863         char *stripped, *tmp;
864         int ret, saved_errno;
865
866         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
867                                          smb_fname->base_name,
868                                          &timestamp, &stripped)) {
869                 return -1;
870         }
871         if (timestamp == 0) {
872                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
873         }
874
875         tmp = smb_fname->base_name;
876         smb_fname->base_name = shadow_copy2_convert(
877                 talloc_tos(), handle, stripped, timestamp);
878         TALLOC_FREE(stripped);
879
880         if (smb_fname->base_name == NULL) {
881                 smb_fname->base_name = tmp;
882                 return -1;
883         }
884
885         ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
886         saved_errno = errno;
887
888         TALLOC_FREE(smb_fname->base_name);
889         smb_fname->base_name = tmp;
890
891         errno = saved_errno;
892         return ret;
893 }
894
895 static int shadow_copy2_unlink(vfs_handle_struct *handle,
896                                const struct smb_filename *smb_fname)
897 {
898         time_t timestamp;
899         char *stripped;
900         int ret, saved_errno;
901         struct smb_filename *conv;
902
903         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
904                                          smb_fname->base_name,
905                                          &timestamp, &stripped)) {
906                 return -1;
907         }
908         if (timestamp == 0) {
909                 return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
910         }
911         conv = cp_smb_filename(talloc_tos(), smb_fname);
912         if (conv == NULL) {
913                 errno = ENOMEM;
914                 return -1;
915         }
916         conv->base_name = shadow_copy2_convert(
917                 conv, handle, stripped, timestamp);
918         TALLOC_FREE(stripped);
919         if (conv->base_name == NULL) {
920                 return -1;
921         }
922         ret = SMB_VFS_NEXT_UNLINK(handle, conv);
923         saved_errno = errno;
924         TALLOC_FREE(conv);
925         errno = saved_errno;
926         return ret;
927 }
928
929 static int shadow_copy2_chmod(vfs_handle_struct *handle, const char *fname,
930                               mode_t mode)
931 {
932         time_t timestamp;
933         char *stripped;
934         int ret, saved_errno;
935         char *conv;
936
937         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
938                                          &timestamp, &stripped)) {
939                 return -1;
940         }
941         if (timestamp == 0) {
942                 return SMB_VFS_NEXT_CHMOD(handle, fname, mode);
943         }
944         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
945         TALLOC_FREE(stripped);
946         if (conv == NULL) {
947                 return -1;
948         }
949         ret = SMB_VFS_NEXT_CHMOD(handle, conv, mode);
950         saved_errno = errno;
951         TALLOC_FREE(conv);
952         errno = saved_errno;
953         return ret;
954 }
955
956 static int shadow_copy2_chown(vfs_handle_struct *handle, const char *fname,
957                               uid_t uid, gid_t gid)
958 {
959         time_t timestamp;
960         char *stripped;
961         int ret, saved_errno;
962         char *conv;
963
964         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
965                                          &timestamp, &stripped)) {
966                 return -1;
967         }
968         if (timestamp == 0) {
969                 return SMB_VFS_NEXT_CHOWN(handle, fname, uid, gid);
970         }
971         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
972         TALLOC_FREE(stripped);
973         if (conv == NULL) {
974                 return -1;
975         }
976         ret = SMB_VFS_NEXT_CHOWN(handle, conv, uid, gid);
977         saved_errno = errno;
978         TALLOC_FREE(conv);
979         errno = saved_errno;
980         return ret;
981 }
982
983 static int shadow_copy2_chdir(vfs_handle_struct *handle,
984                               const char *fname)
985 {
986         time_t timestamp;
987         char *stripped;
988         int ret, saved_errno;
989         char *conv;
990
991         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
992                                          &timestamp, &stripped)) {
993                 return -1;
994         }
995         if (timestamp == 0) {
996                 return SMB_VFS_NEXT_CHDIR(handle, fname);
997         }
998         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
999         TALLOC_FREE(stripped);
1000         if (conv == NULL) {
1001                 return -1;
1002         }
1003         ret = SMB_VFS_NEXT_CHDIR(handle, conv);
1004         saved_errno = errno;
1005         TALLOC_FREE(conv);
1006         errno = saved_errno;
1007         return ret;
1008 }
1009
1010 static int shadow_copy2_ntimes(vfs_handle_struct *handle,
1011                                const struct smb_filename *smb_fname,
1012                                struct smb_file_time *ft)
1013 {
1014         time_t timestamp;
1015         char *stripped;
1016         int ret, saved_errno;
1017         struct smb_filename *conv;
1018
1019         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1020                                          smb_fname->base_name,
1021                                          &timestamp, &stripped)) {
1022                 return -1;
1023         }
1024         if (timestamp == 0) {
1025                 return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1026         }
1027         conv = cp_smb_filename(talloc_tos(), smb_fname);
1028         if (conv == NULL) {
1029                 errno = ENOMEM;
1030                 return -1;
1031         }
1032         conv->base_name = shadow_copy2_convert(
1033                 conv, handle, stripped, timestamp);
1034         TALLOC_FREE(stripped);
1035         if (conv->base_name == NULL) {
1036                 return -1;
1037         }
1038         ret = SMB_VFS_NEXT_NTIMES(handle, conv, ft);
1039         saved_errno = errno;
1040         TALLOC_FREE(conv);
1041         errno = saved_errno;
1042         return ret;
1043 }
1044
1045 static int shadow_copy2_readlink(vfs_handle_struct *handle,
1046                                  const char *fname, char *buf, size_t bufsiz)
1047 {
1048         time_t timestamp;
1049         char *stripped;
1050         int ret, saved_errno;
1051         char *conv;
1052
1053         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1054                                          &timestamp, &stripped)) {
1055                 return -1;
1056         }
1057         if (timestamp == 0) {
1058                 return SMB_VFS_NEXT_READLINK(handle, fname, buf, bufsiz);
1059         }
1060         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1061         TALLOC_FREE(stripped);
1062         if (conv == NULL) {
1063                 return -1;
1064         }
1065         ret = SMB_VFS_NEXT_READLINK(handle, conv, buf, bufsiz);
1066         saved_errno = errno;
1067         TALLOC_FREE(conv);
1068         errno = saved_errno;
1069         return ret;
1070 }
1071
1072 static int shadow_copy2_mknod(vfs_handle_struct *handle,
1073                               const char *fname, mode_t mode, SMB_DEV_T dev)
1074 {
1075         time_t timestamp;
1076         char *stripped;
1077         int ret, saved_errno;
1078         char *conv;
1079
1080         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1081                                          &timestamp, &stripped)) {
1082                 return -1;
1083         }
1084         if (timestamp == 0) {
1085                 return SMB_VFS_NEXT_MKNOD(handle, fname, mode, dev);
1086         }
1087         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1088         TALLOC_FREE(stripped);
1089         if (conv == NULL) {
1090                 return -1;
1091         }
1092         ret = SMB_VFS_NEXT_MKNOD(handle, conv, mode, dev);
1093         saved_errno = errno;
1094         TALLOC_FREE(conv);
1095         errno = saved_errno;
1096         return ret;
1097 }
1098
1099 static char *shadow_copy2_realpath(vfs_handle_struct *handle,
1100                                    const char *fname)
1101 {
1102         time_t timestamp;
1103         char *stripped = NULL;
1104         char *tmp = NULL;
1105         char *result = NULL;
1106         char *inserted = NULL;
1107         char *inserted_to, *inserted_end;
1108         int saved_errno;
1109
1110         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1111                                          &timestamp, &stripped)) {
1112                 goto done;
1113         }
1114         if (timestamp == 0) {
1115                 return SMB_VFS_NEXT_REALPATH(handle, fname);
1116         }
1117
1118         tmp = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1119         if (tmp == NULL) {
1120                 goto done;
1121         }
1122
1123         result = SMB_VFS_NEXT_REALPATH(handle, tmp);
1124         if (result == NULL) {
1125                 goto done;
1126         }
1127
1128         /*
1129          * Take away what we've inserted. This removes the @GMT-thingy
1130          * completely, but will give a path under the share root.
1131          */
1132         inserted = shadow_copy2_insert_string(talloc_tos(), handle, timestamp);
1133         if (inserted == NULL) {
1134                 goto done;
1135         }
1136         inserted_to = strstr_m(result, inserted);
1137         if (inserted_to == NULL) {
1138                 DEBUG(2, ("SMB_VFS_NEXT_REALPATH removed %s\n", inserted));
1139                 goto done;
1140         }
1141         inserted_end = inserted_to + talloc_get_size(inserted) - 1;
1142         memmove(inserted_to, inserted_end, strlen(inserted_end)+1);
1143
1144 done:
1145         saved_errno = errno;
1146         TALLOC_FREE(inserted);
1147         TALLOC_FREE(tmp);
1148         TALLOC_FREE(stripped);
1149         errno = saved_errno;
1150         return result;
1151 }
1152
1153 /**
1154  * Check whether a given directory contains a
1155  * snapshot directory as direct subdirectory.
1156  * If yes, return the path of the snapshot-subdir,
1157  * otherwise return NULL.
1158  */
1159 static char *have_snapdir(struct vfs_handle_struct *handle,
1160                           const char *path)
1161 {
1162         struct smb_filename smb_fname;
1163         int ret;
1164         struct shadow_copy2_config *config;
1165
1166         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1167                                 return NULL);
1168
1169         ZERO_STRUCT(smb_fname);
1170         smb_fname.base_name = talloc_asprintf(talloc_tos(), "%s/%s",
1171                                               path, config->snapdir);
1172         if (smb_fname.base_name == NULL) {
1173                 return NULL;
1174         }
1175
1176         ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
1177         if ((ret == 0) && (S_ISDIR(smb_fname.st.st_ex_mode))) {
1178                 return smb_fname.base_name;
1179         }
1180         TALLOC_FREE(smb_fname.base_name);
1181         return NULL;
1182 }
1183
1184 static bool check_access_snapdir(struct vfs_handle_struct *handle,
1185                                 const char *path)
1186 {
1187         struct smb_filename smb_fname;
1188         int ret;
1189         NTSTATUS status;
1190
1191         ZERO_STRUCT(smb_fname);
1192         smb_fname.base_name = talloc_asprintf(talloc_tos(),
1193                                                 "%s",
1194                                                 path);
1195         if (smb_fname.base_name == NULL) {
1196                 return false;
1197         }
1198
1199         ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
1200         if (ret != 0 || !S_ISDIR(smb_fname.st.st_ex_mode)) {
1201                 TALLOC_FREE(smb_fname.base_name);
1202                 return false;
1203         }
1204
1205         status = smbd_check_access_rights(handle->conn,
1206                                         &smb_fname,
1207                                         false,
1208                                         SEC_DIR_LIST);
1209         if (!NT_STATUS_IS_OK(status)) {
1210                 DEBUG(0,("user does not have list permission "
1211                         "on snapdir %s\n",
1212                         smb_fname.base_name));
1213                 TALLOC_FREE(smb_fname.base_name);
1214                 return false;
1215         }
1216         TALLOC_FREE(smb_fname.base_name);
1217         return true;
1218 }
1219
1220 /**
1221  * Find the snapshot directory (if any) for the given
1222  * filename (which is relative to the share).
1223  */
1224 static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx,
1225                                              struct vfs_handle_struct *handle,
1226                                              struct smb_filename *smb_fname)
1227 {
1228         char *path, *p;
1229         const char *snapdir;
1230         struct shadow_copy2_config *config;
1231
1232         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1233                                 return NULL);
1234
1235         /*
1236          * If the non-snapdisrseverywhere mode, we should not search!
1237          */
1238         if (!config->snapdirseverywhere) {
1239                 return config->snapshot_basepath;
1240         }
1241
1242         path = talloc_asprintf(mem_ctx, "%s/%s",
1243                                handle->conn->connectpath,
1244                                smb_fname->base_name);
1245         if (path == NULL) {
1246                 return NULL;
1247         }
1248
1249         snapdir = have_snapdir(handle, path);
1250         if (snapdir != NULL) {
1251                 TALLOC_FREE(path);
1252                 return snapdir;
1253         }
1254
1255         while ((p = strrchr(path, '/')) && (p > path)) {
1256
1257                 p[0] = '\0';
1258
1259                 snapdir = have_snapdir(handle, path);
1260                 if (snapdir != NULL) {
1261                         TALLOC_FREE(path);
1262                         return snapdir;
1263                 }
1264         }
1265         TALLOC_FREE(path);
1266         return NULL;
1267 }
1268
1269 static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
1270                                          const char *name,
1271                                          char *gmt, size_t gmt_len)
1272 {
1273         struct tm timestamp;
1274         time_t timestamp_t;
1275         unsigned long int timestamp_long;
1276         const char *fmt;
1277         struct shadow_copy2_config *config;
1278
1279         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1280                                 return NULL);
1281
1282         fmt = config->gmt_format;
1283
1284         ZERO_STRUCT(timestamp);
1285         if (config->use_sscanf) {
1286                 if (sscanf(name, fmt, &timestamp_long) != 1) {
1287                         DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1288                                    "no sscanf match %s: %s\n",
1289                                    fmt, name));
1290                         return false;
1291                 }
1292                 timestamp_t = timestamp_long;
1293                 gmtime_r(&timestamp_t, &timestamp);
1294         } else {
1295                 if (strptime(name, fmt, &timestamp) == NULL) {
1296                         DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1297                                    "no match %s: %s\n",
1298                                    fmt, name));
1299                         return false;
1300                 }
1301                 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n",
1302                            fmt, name));
1303                 
1304                 if (config->use_localtime) {
1305                         timestamp.tm_isdst = -1;
1306                         timestamp_t = mktime(&timestamp);
1307                         gmtime_r(&timestamp_t, &timestamp);
1308                 }
1309         }
1310
1311         strftime(gmt, gmt_len, GMT_FORMAT, &timestamp);
1312         return true;
1313 }
1314
1315 static int shadow_copy2_label_cmp_asc(const void *x, const void *y)
1316 {
1317         return strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1318 }
1319
1320 static int shadow_copy2_label_cmp_desc(const void *x, const void *y)
1321 {
1322         return -strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1323 }
1324
1325 /*
1326   sort the shadow copy data in ascending or descending order
1327  */
1328 static void shadow_copy2_sort_data(vfs_handle_struct *handle,
1329                                    struct shadow_copy_data *shadow_copy2_data)
1330 {
1331         int (*cmpfunc)(const void *, const void *);
1332         const char *sort;
1333         struct shadow_copy2_config *config;
1334
1335         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1336                                 return);
1337
1338         sort = config->sort_order;
1339         if (sort == NULL) {
1340                 return;
1341         }
1342
1343         if (strcmp(sort, "asc") == 0) {
1344                 cmpfunc = shadow_copy2_label_cmp_asc;
1345         } else if (strcmp(sort, "desc") == 0) {
1346                 cmpfunc = shadow_copy2_label_cmp_desc;
1347         } else {
1348                 return;
1349         }
1350
1351         if (shadow_copy2_data && shadow_copy2_data->num_volumes > 0 &&
1352             shadow_copy2_data->labels)
1353         {
1354                 TYPESAFE_QSORT(shadow_copy2_data->labels,
1355                                shadow_copy2_data->num_volumes,
1356                                cmpfunc);
1357         }
1358 }
1359
1360 static int shadow_copy2_get_shadow_copy_data(
1361         vfs_handle_struct *handle, files_struct *fsp,
1362         struct shadow_copy_data *shadow_copy2_data,
1363         bool labels)
1364 {
1365         DIR *p;
1366         const char *snapdir;
1367         struct dirent *d;
1368         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1369         bool ret;
1370
1371         snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle, fsp->fsp_name);
1372         if (snapdir == NULL) {
1373                 DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
1374                          handle->conn->connectpath));
1375                 errno = EINVAL;
1376                 talloc_free(tmp_ctx);
1377                 return -1;
1378         }
1379         ret = check_access_snapdir(handle, snapdir);
1380         if (!ret) {
1381                 DEBUG(0,("access denied on listing snapdir %s\n", snapdir));
1382                 errno = EACCES;
1383                 talloc_free(tmp_ctx);
1384                 return -1;
1385         }
1386
1387         p = SMB_VFS_NEXT_OPENDIR(handle, snapdir, NULL, 0);
1388
1389         if (!p) {
1390                 DEBUG(2,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s'"
1391                          " - %s\n", snapdir, strerror(errno)));
1392                 talloc_free(tmp_ctx);
1393                 errno = ENOSYS;
1394                 return -1;
1395         }
1396
1397         shadow_copy2_data->num_volumes = 0;
1398         shadow_copy2_data->labels      = NULL;
1399
1400         while ((d = SMB_VFS_NEXT_READDIR(handle, p, NULL))) {
1401                 char snapshot[GMT_NAME_LEN+1];
1402                 SHADOW_COPY_LABEL *tlabels;
1403
1404                 /*
1405                  * ignore names not of the right form in the snapshot
1406                  * directory
1407                  */
1408                 if (!shadow_copy2_snapshot_to_gmt(
1409                             handle, d->d_name,
1410                             snapshot, sizeof(snapshot))) {
1411
1412                         DEBUG(6, ("shadow_copy2_get_shadow_copy_data: "
1413                                   "ignoring %s\n", d->d_name));
1414                         continue;
1415                 }
1416                 DEBUG(6,("shadow_copy2_get_shadow_copy_data: %s -> %s\n",
1417                          d->d_name, snapshot));
1418
1419                 if (!labels) {
1420                         /* the caller doesn't want the labels */
1421                         shadow_copy2_data->num_volumes++;
1422                         continue;
1423                 }
1424
1425                 tlabels = talloc_realloc(shadow_copy2_data,
1426                                          shadow_copy2_data->labels,
1427                                          SHADOW_COPY_LABEL,
1428                                          shadow_copy2_data->num_volumes+1);
1429                 if (tlabels == NULL) {
1430                         DEBUG(0,("shadow_copy2: out of memory\n"));
1431                         SMB_VFS_NEXT_CLOSEDIR(handle, p);
1432                         talloc_free(tmp_ctx);
1433                         return -1;
1434                 }
1435
1436                 strlcpy(tlabels[shadow_copy2_data->num_volumes], snapshot,
1437                         sizeof(*tlabels));
1438
1439                 shadow_copy2_data->num_volumes++;
1440                 shadow_copy2_data->labels = tlabels;
1441         }
1442
1443         SMB_VFS_NEXT_CLOSEDIR(handle,p);
1444
1445         shadow_copy2_sort_data(handle, shadow_copy2_data);
1446
1447         talloc_free(tmp_ctx);
1448         return 0;
1449 }
1450
1451 static NTSTATUS shadow_copy2_fget_nt_acl(vfs_handle_struct *handle,
1452                                         struct files_struct *fsp,
1453                                         uint32_t security_info,
1454                                          TALLOC_CTX *mem_ctx,
1455                                         struct security_descriptor **ppdesc)
1456 {
1457         time_t timestamp;
1458         char *stripped;
1459         NTSTATUS status;
1460         char *conv;
1461
1462         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1463                                          fsp->fsp_name->base_name,
1464                                          &timestamp, &stripped)) {
1465                 return map_nt_error_from_unix(errno);
1466         }
1467         if (timestamp == 0) {
1468                 return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
1469                                                 mem_ctx,
1470                                                 ppdesc);
1471         }
1472         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1473         TALLOC_FREE(stripped);
1474         if (conv == NULL) {
1475                 return map_nt_error_from_unix(errno);
1476         }
1477         status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv, security_info,
1478                                          mem_ctx, ppdesc);
1479         TALLOC_FREE(conv);
1480         return status;
1481 }
1482
1483 static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle,
1484                                         const char *fname,
1485                                         uint32_t security_info,
1486                                         TALLOC_CTX *mem_ctx,
1487                                         struct security_descriptor **ppdesc)
1488 {
1489         time_t timestamp;
1490         char *stripped;
1491         NTSTATUS status;
1492         char *conv;
1493
1494         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1495                                          &timestamp, &stripped)) {
1496                 return map_nt_error_from_unix(errno);
1497         }
1498         if (timestamp == 0) {
1499                 return SMB_VFS_NEXT_GET_NT_ACL(handle, fname, security_info,
1500                                                mem_ctx, ppdesc);
1501         }
1502         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1503         TALLOC_FREE(stripped);
1504         if (conv == NULL) {
1505                 return map_nt_error_from_unix(errno);
1506         }
1507         status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv, security_info,
1508                                          mem_ctx, ppdesc);
1509         TALLOC_FREE(conv);
1510         return status;
1511 }
1512
1513 static int shadow_copy2_mkdir(vfs_handle_struct *handle,
1514                               const char *fname, mode_t mode)
1515 {
1516         time_t timestamp;
1517         char *stripped;
1518         int ret, saved_errno;
1519         char *conv;
1520
1521         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1522                                          &timestamp, &stripped)) {
1523                 return -1;
1524         }
1525         if (timestamp == 0) {
1526                 return SMB_VFS_NEXT_MKDIR(handle, fname, mode);
1527         }
1528         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1529         TALLOC_FREE(stripped);
1530         if (conv == NULL) {
1531                 return -1;
1532         }
1533         ret = SMB_VFS_NEXT_MKDIR(handle, conv, mode);
1534         saved_errno = errno;
1535         TALLOC_FREE(conv);
1536         errno = saved_errno;
1537         return ret;
1538 }
1539
1540 static int shadow_copy2_rmdir(vfs_handle_struct *handle, const char *fname)
1541 {
1542         time_t timestamp;
1543         char *stripped;
1544         int ret, saved_errno;
1545         char *conv;
1546
1547         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1548                                          &timestamp, &stripped)) {
1549                 return -1;
1550         }
1551         if (timestamp == 0) {
1552                 return SMB_VFS_NEXT_RMDIR(handle, fname);
1553         }
1554         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1555         TALLOC_FREE(stripped);
1556         if (conv == NULL) {
1557                 return -1;
1558         }
1559         ret = SMB_VFS_NEXT_RMDIR(handle, conv);
1560         saved_errno = errno;
1561         TALLOC_FREE(conv);
1562         errno = saved_errno;
1563         return ret;
1564 }
1565
1566 static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname,
1567                                 unsigned int flags)
1568 {
1569         time_t timestamp;
1570         char *stripped;
1571         int ret, saved_errno;
1572         char *conv;
1573
1574         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1575                                          &timestamp, &stripped)) {
1576                 return -1;
1577         }
1578         if (timestamp == 0) {
1579                 return SMB_VFS_NEXT_CHFLAGS(handle, fname, flags);
1580         }
1581         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1582         TALLOC_FREE(stripped);
1583         if (conv == NULL) {
1584                 return -1;
1585         }
1586         ret = SMB_VFS_NEXT_CHFLAGS(handle, conv, flags);
1587         saved_errno = errno;
1588         TALLOC_FREE(conv);
1589         errno = saved_errno;
1590         return ret;
1591 }
1592
1593 static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
1594                                      const char *fname, const char *aname,
1595                                      void *value, size_t size)
1596 {
1597         time_t timestamp;
1598         char *stripped;
1599         ssize_t ret;
1600         int saved_errno;
1601         char *conv;
1602
1603         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1604                                          &timestamp, &stripped)) {
1605                 return -1;
1606         }
1607         if (timestamp == 0) {
1608                 return SMB_VFS_NEXT_GETXATTR(handle, fname, aname, value,
1609                                              size);
1610         }
1611         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1612         TALLOC_FREE(stripped);
1613         if (conv == NULL) {
1614                 return -1;
1615         }
1616         ret = SMB_VFS_NEXT_GETXATTR(handle, conv, aname, value, size);
1617         saved_errno = errno;
1618         TALLOC_FREE(conv);
1619         errno = saved_errno;
1620         return ret;
1621 }
1622
1623 static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle,
1624                                       const char *fname,
1625                                       char *list, size_t size)
1626 {
1627         time_t timestamp;
1628         char *stripped;
1629         ssize_t ret;
1630         int saved_errno;
1631         char *conv;
1632
1633         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1634                                          &timestamp, &stripped)) {
1635                 return -1;
1636         }
1637         if (timestamp == 0) {
1638                 return SMB_VFS_NEXT_LISTXATTR(handle, fname, list, size);
1639         }
1640         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1641         TALLOC_FREE(stripped);
1642         if (conv == NULL) {
1643                 return -1;
1644         }
1645         ret = SMB_VFS_NEXT_LISTXATTR(handle, conv, list, size);
1646         saved_errno = errno;
1647         TALLOC_FREE(conv);
1648         errno = saved_errno;
1649         return ret;
1650 }
1651
1652 static int shadow_copy2_removexattr(vfs_handle_struct *handle,
1653                                     const char *fname, const char *aname)
1654 {
1655         time_t timestamp;
1656         char *stripped;
1657         int ret, saved_errno;
1658         char *conv;
1659
1660         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1661                                          &timestamp, &stripped)) {
1662                 return -1;
1663         }
1664         if (timestamp == 0) {
1665                 return SMB_VFS_NEXT_REMOVEXATTR(handle, fname, aname);
1666         }
1667         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1668         TALLOC_FREE(stripped);
1669         if (conv == NULL) {
1670                 return -1;
1671         }
1672         ret = SMB_VFS_NEXT_REMOVEXATTR(handle, conv, aname);
1673         saved_errno = errno;
1674         TALLOC_FREE(conv);
1675         errno = saved_errno;
1676         return ret;
1677 }
1678
1679 static int shadow_copy2_setxattr(struct vfs_handle_struct *handle,
1680                                  const char *fname,
1681                                  const char *aname, const void *value,
1682                                  size_t size, int flags)
1683 {
1684         time_t timestamp;
1685         char *stripped;
1686         ssize_t ret;
1687         int saved_errno;
1688         char *conv;
1689
1690         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1691                                          &timestamp, &stripped)) {
1692                 return -1;
1693         }
1694         if (timestamp == 0) {
1695                 return SMB_VFS_NEXT_SETXATTR(handle, fname, aname, value, size,
1696                                              flags);
1697         }
1698         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1699         TALLOC_FREE(stripped);
1700         if (conv == NULL) {
1701                 return -1;
1702         }
1703         ret = SMB_VFS_NEXT_SETXATTR(handle, conv, aname, value, size, flags);
1704         saved_errno = errno;
1705         TALLOC_FREE(conv);
1706         errno = saved_errno;
1707         return ret;
1708 }
1709
1710 static int shadow_copy2_chmod_acl(vfs_handle_struct *handle,
1711                                   const char *fname, mode_t mode)
1712 {
1713         time_t timestamp;
1714         char *stripped;
1715         ssize_t ret;
1716         int saved_errno;
1717         char *conv;
1718
1719         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1720                                          &timestamp, &stripped)) {
1721                 return -1;
1722         }
1723         if (timestamp == 0) {
1724                 return SMB_VFS_NEXT_CHMOD_ACL(handle, fname, mode);
1725         }
1726         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1727         TALLOC_FREE(stripped);
1728         if (conv == NULL) {
1729                 return -1;
1730         }
1731         ret = SMB_VFS_NEXT_CHMOD_ACL(handle, conv, mode);
1732         saved_errno = errno;
1733         TALLOC_FREE(conv);
1734         errno = saved_errno;
1735         return ret;
1736 }
1737
1738 static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle,
1739                                           const char *path,
1740                                           const char *name,
1741                                           TALLOC_CTX *mem_ctx,
1742                                           char **found_name)
1743 {
1744         time_t timestamp;
1745         char *stripped;
1746         ssize_t ret;
1747         int saved_errno;
1748         char *conv;
1749
1750         DEBUG(10, ("shadow_copy2_get_real_filename called for path=[%s], "
1751                    "name=[%s]\n", path, name));
1752
1753         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
1754                                          &timestamp, &stripped)) {
1755                 DEBUG(10, ("shadow_copy2_strip_snapshot failed\n"));
1756                 return -1;
1757         }
1758         if (timestamp == 0) {
1759                 DEBUG(10, ("timestamp == 0\n"));
1760                 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
1761                                                       mem_ctx, found_name);
1762         }
1763         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1764         TALLOC_FREE(stripped);
1765         if (conv == NULL) {
1766                 DEBUG(10, ("shadow_copy2_convert failed\n"));
1767                 return -1;
1768         }
1769         DEBUG(10, ("Calling NEXT_GET_REAL_FILE_NAME for conv=[%s], "
1770                    "name=[%s]\n", conv, name));
1771         ret = SMB_VFS_NEXT_GET_REAL_FILENAME(handle, conv, name,
1772                                              mem_ctx, found_name);
1773         DEBUG(10, ("NEXT_REAL_FILE_NAME returned %d\n", (int)ret));
1774         saved_errno = errno;
1775         TALLOC_FREE(conv);
1776         errno = saved_errno;
1777         return ret;
1778 }
1779
1780 static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle,
1781                                        const char *path, uint64_t *bsize,
1782                                        uint64_t *dfree, uint64_t *dsize)
1783 {
1784         time_t timestamp;
1785         char *stripped;
1786         ssize_t ret;
1787         int saved_errno;
1788         char *conv;
1789
1790         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
1791                                          &timestamp, &stripped)) {
1792                 return -1;
1793         }
1794         if (timestamp == 0) {
1795                 return SMB_VFS_NEXT_DISK_FREE(handle, path,
1796                                               bsize, dfree, dsize);
1797         }
1798
1799         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1800         TALLOC_FREE(stripped);
1801         if (conv == NULL) {
1802                 return -1;
1803         }
1804
1805         ret = SMB_VFS_NEXT_DISK_FREE(handle, conv, bsize, dfree, dsize);
1806
1807         saved_errno = errno;
1808         TALLOC_FREE(conv);
1809         errno = saved_errno;
1810
1811         return ret;
1812 }
1813
1814 static int shadow_copy2_connect(struct vfs_handle_struct *handle,
1815                                 const char *service, const char *user)
1816 {
1817         struct shadow_copy2_config *config;
1818         int ret;
1819         const char *snapdir;
1820         const char *gmt_format;
1821         const char *sort_order;
1822         const char *basedir;
1823         const char *mount_point;
1824
1825         DEBUG(10, (__location__ ": cnum[%u], connectpath[%s]\n",
1826                    (unsigned)handle->conn->cnum,
1827                    handle->conn->connectpath));
1828
1829         ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
1830         if (ret < 0) {
1831                 return ret;
1832         }
1833
1834         config = talloc_zero(handle->conn, struct shadow_copy2_config);
1835         if (config == NULL) {
1836                 DEBUG(0, ("talloc_zero() failed\n"));
1837                 errno = ENOMEM;
1838                 return -1;
1839         }
1840
1841         gmt_format = lp_parm_const_string(SNUM(handle->conn),
1842                                           "shadow", "format",
1843                                           GMT_FORMAT);
1844         config->gmt_format = talloc_strdup(config, gmt_format);
1845         if (config->gmt_format == NULL) {
1846                 DEBUG(0, ("talloc_strdup() failed\n"));
1847                 errno = ENOMEM;
1848                 return -1;
1849         }
1850
1851         config->use_sscanf = lp_parm_bool(SNUM(handle->conn),
1852                                           "shadow", "sscanf", false);
1853
1854         config->use_localtime = lp_parm_bool(SNUM(handle->conn),
1855                                              "shadow", "localtime",
1856                                              false);
1857
1858         snapdir = lp_parm_const_string(SNUM(handle->conn),
1859                                        "shadow", "snapdir",
1860                                        ".snapshots");
1861         config->snapdir = talloc_strdup(config, snapdir);
1862         if (config->snapdir == NULL) {
1863                 DEBUG(0, ("talloc_strdup() failed\n"));
1864                 errno = ENOMEM;
1865                 return -1;
1866         }
1867
1868         config->snapdirseverywhere = lp_parm_bool(SNUM(handle->conn),
1869                                                   "shadow",
1870                                                   "snapdirseverywhere",
1871                                                   false);
1872
1873         config->crossmountpoints = lp_parm_bool(SNUM(handle->conn),
1874                                                 "shadow", "crossmountpoints",
1875                                                 false);
1876
1877         config->fixinodes = lp_parm_bool(SNUM(handle->conn),
1878                                          "shadow", "fixinodes",
1879                                          false);
1880
1881         sort_order = lp_parm_const_string(SNUM(handle->conn),
1882                                           "shadow", "sort", "desc");
1883         config->sort_order = talloc_strdup(config, sort_order);
1884         if (config->sort_order == NULL) {
1885                 DEBUG(0, ("talloc_strdup() failed\n"));
1886                 errno = ENOMEM;
1887                 return -1;
1888         }
1889
1890         mount_point = lp_parm_const_string(SNUM(handle->conn),
1891                                            "shadow", "mountpoint", NULL);
1892         if (mount_point != NULL) {
1893                 if (mount_point[0] != '/') {
1894                         DEBUG(1, (__location__ " Warning: 'mountpoint' is "
1895                                   "relative ('%s'), but it has to be an "
1896                                   "absolute path. Ignoring provided value.\n",
1897                                   mount_point));
1898                         mount_point = NULL;
1899                 } else {
1900                         char *p;
1901                         p = strstr(handle->conn->connectpath, mount_point);
1902                         if (p != handle->conn->connectpath) {
1903                                 DEBUG(1, ("Warning: mount_point (%s) is not a "
1904                                           "subdirectory of the share root "
1905                                           "(%s). Ignoring provided value.\n",
1906                                           mount_point,
1907                                           handle->conn->connectpath));
1908                                 mount_point = NULL;
1909                         }
1910                 }
1911         }
1912
1913         if (mount_point != NULL) {
1914                 config->mount_point = talloc_strdup(config, mount_point);
1915                 if (config->mount_point == NULL) {
1916                         DEBUG(0, (__location__ " talloc_strdup() failed\n"));
1917                         return -1;
1918                 }
1919         } else {
1920                 config->mount_point = shadow_copy2_find_mount_point(config,
1921                                                                     handle);
1922                 if (config->mount_point == NULL) {
1923                         DBG_WARNING("shadow_copy2_find_mount_point "
1924                                     "of the share root '%s' failed: %s\n",
1925                                     handle->conn->connectpath, strerror(errno));
1926                         return -1;
1927                 }
1928         }
1929
1930         basedir = lp_parm_const_string(SNUM(handle->conn),
1931                                        "shadow", "basedir", NULL);
1932
1933         if (basedir != NULL) {
1934                 if (basedir[0] != '/') {
1935                         DEBUG(1, (__location__ " Warning: 'basedir' is "
1936                                   "relative ('%s'), but it has to be an "
1937                                   "absolute path. Disabling basedir.\n",
1938                                   basedir));
1939                 } else {
1940                         char *p;
1941                         p = strstr(basedir, config->mount_point);
1942                         if (p != basedir) {
1943                                 DEBUG(1, ("Warning: basedir (%s) is not a "
1944                                           "subdirectory of the share root's "
1945                                           "mount point (%s). "
1946                                           "Disabling basedir\n",
1947                                           basedir, config->mount_point));
1948                         } else {
1949                                 config->basedir = talloc_strdup(config,
1950                                                                 basedir);
1951                                 if (config->basedir == NULL) {
1952                                         DEBUG(0, ("talloc_strdup() failed\n"));
1953                                         errno = ENOMEM;
1954                                         return -1;
1955                                 }
1956                         }
1957                 }
1958         }
1959
1960         if (config->snapdirseverywhere && config->basedir != NULL) {
1961                 DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
1962                           "with 'snapdirseverywhere'. Disabling basedir.\n"));
1963                 TALLOC_FREE(config->basedir);
1964         }
1965
1966         if (config->crossmountpoints && config->basedir != NULL) {
1967                 DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
1968                           "with 'crossmountpoints'. Disabling basedir.\n"));
1969                 TALLOC_FREE(config->basedir);
1970         }
1971
1972         if (config->basedir == NULL) {
1973                 config->basedir = config->mount_point;
1974         }
1975
1976         if (strlen(config->basedir) != strlen(handle->conn->connectpath)) {
1977                 config->rel_connectpath = talloc_strdup(config,
1978                         handle->conn->connectpath + strlen(config->basedir));
1979                 if (config->rel_connectpath == NULL) {
1980                         DEBUG(0, ("talloc_strdup() failed\n"));
1981                         errno = ENOMEM;
1982                         return -1;
1983                 }
1984         }
1985
1986         if (config->snapdir[0] == '/') {
1987                 config->snapdir_absolute = true;
1988
1989                 if (config->snapdirseverywhere == true) {
1990                         DEBUG(1, (__location__ " Warning: An absolute snapdir "
1991                                   "is incompatible with 'snapdirseverywhere', "
1992                                   "setting 'snapdirseverywhere' to false.\n"));
1993                         config->snapdirseverywhere = false;
1994                 }
1995
1996                 if (config->crossmountpoints == true) {
1997                         DEBUG(1, (__location__ " Warning: 'crossmountpoints' "
1998                                   "is not supported with an absolute snapdir. "
1999                                   "Disabling it.\n"));
2000                         config->crossmountpoints = false;
2001                 }
2002
2003                 config->snapshot_basepath = config->snapdir;
2004         } else {
2005                 config->snapshot_basepath = talloc_asprintf(config, "%s/%s",
2006                                 config->mount_point, config->snapdir);
2007                 if (config->snapshot_basepath == NULL) {
2008                         DEBUG(0, ("talloc_asprintf() failed\n"));
2009                         errno = ENOMEM;
2010                         return -1;
2011                 }
2012         }
2013
2014         DEBUG(10, ("shadow_copy2_connect: configuration:\n"
2015                    "  share root: '%s'\n"
2016                    "  basedir: '%s'\n"
2017                    "  mountpoint: '%s'\n"
2018                    "  rel share root: '%s'\n"
2019                    "  snapdir: '%s'\n"
2020                    "  snapshot base path: '%s'\n"
2021                    "  format: '%s'\n"
2022                    "  use sscanf: %s\n"
2023                    "  snapdirs everywhere: %s\n"
2024                    "  cross mountpoints: %s\n"
2025                    "  fix inodes: %s\n"
2026                    "  sort order: %s\n"
2027                    "",
2028                    handle->conn->connectpath,
2029                    config->basedir,
2030                    config->mount_point,
2031                    config->rel_connectpath,
2032                    config->snapdir,
2033                    config->snapshot_basepath,
2034                    config->gmt_format,
2035                    config->use_sscanf ? "yes" : "no",
2036                    config->snapdirseverywhere ? "yes" : "no",
2037                    config->crossmountpoints ? "yes" : "no",
2038                    config->fixinodes ? "yes" : "no",
2039                    config->sort_order
2040                    ));
2041
2042
2043         SMB_VFS_HANDLE_SET_DATA(handle, config,
2044                                 NULL, struct shadow_copy2_config,
2045                                 return -1);
2046
2047         return 0;
2048 }
2049
2050 static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
2051         .connect_fn = shadow_copy2_connect,
2052         .opendir_fn = shadow_copy2_opendir,
2053         .disk_free_fn = shadow_copy2_disk_free,
2054         .rename_fn = shadow_copy2_rename,
2055         .link_fn = shadow_copy2_link,
2056         .symlink_fn = shadow_copy2_symlink,
2057         .stat_fn = shadow_copy2_stat,
2058         .lstat_fn = shadow_copy2_lstat,
2059         .fstat_fn = shadow_copy2_fstat,
2060         .open_fn = shadow_copy2_open,
2061         .unlink_fn = shadow_copy2_unlink,
2062         .chmod_fn = shadow_copy2_chmod,
2063         .chown_fn = shadow_copy2_chown,
2064         .chdir_fn = shadow_copy2_chdir,
2065         .ntimes_fn = shadow_copy2_ntimes,
2066         .readlink_fn = shadow_copy2_readlink,
2067         .mknod_fn = shadow_copy2_mknod,
2068         .realpath_fn = shadow_copy2_realpath,
2069         .get_nt_acl_fn = shadow_copy2_get_nt_acl,
2070         .fget_nt_acl_fn = shadow_copy2_fget_nt_acl,
2071         .get_shadow_copy_data_fn = shadow_copy2_get_shadow_copy_data,
2072         .mkdir_fn = shadow_copy2_mkdir,
2073         .rmdir_fn = shadow_copy2_rmdir,
2074         .getxattr_fn = shadow_copy2_getxattr,
2075         .listxattr_fn = shadow_copy2_listxattr,
2076         .removexattr_fn = shadow_copy2_removexattr,
2077         .setxattr_fn = shadow_copy2_setxattr,
2078         .chmod_acl_fn = shadow_copy2_chmod_acl,
2079         .chflags_fn = shadow_copy2_chflags,
2080         .get_real_filename_fn = shadow_copy2_get_real_filename,
2081 };
2082
2083 NTSTATUS vfs_shadow_copy2_init(void);
2084 NTSTATUS vfs_shadow_copy2_init(void)
2085 {
2086         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2087                                 "shadow_copy2", &vfs_shadow_copy2_fns);
2088 }