vfs_shadow_copy2: fix case where snapshots are outside the share
[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  * Also return the path in the snapshot corresponding
438  * to the file's share root.
439  */
440 static char *shadow_copy2_do_convert(TALLOC_CTX *mem_ctx,
441                                      struct vfs_handle_struct *handle,
442                                      const char *name, time_t timestamp,
443                                      size_t *snaproot_len)
444 {
445         struct smb_filename converted_fname;
446         char *result = NULL;
447         size_t *slashes = NULL;
448         unsigned num_slashes;
449         char *path = NULL;
450         size_t pathlen;
451         char *insert = NULL;
452         char *converted = NULL;
453         size_t insertlen, connectlen = 0;
454         int i, saved_errno;
455         size_t min_offset;
456         struct shadow_copy2_config *config;
457         size_t in_share_offset = 0;
458
459         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
460                                 return NULL);
461
462         DEBUG(10, ("converting '%s'\n", name));
463
464         if (!config->snapdirseverywhere) {
465                 int ret;
466                 char *snapshot_path;
467
468                 snapshot_path = shadow_copy2_snapshot_path(talloc_tos(),
469                                                            handle,
470                                                            timestamp);
471                 if (snapshot_path == NULL) {
472                         goto fail;
473                 }
474
475                 if (config->rel_connectpath == NULL) {
476                         converted = talloc_asprintf(mem_ctx, "%s/%s",
477                                                     snapshot_path, name);
478                 } else {
479                         converted = talloc_asprintf(mem_ctx, "%s/%s/%s",
480                                                     snapshot_path,
481                                                     config->rel_connectpath,
482                                                     name);
483                 }
484                 if (converted == NULL) {
485                         goto fail;
486                 }
487
488                 ZERO_STRUCT(converted_fname);
489                 converted_fname.base_name = converted;
490
491                 ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
492                 DEBUG(10, ("Trying[not snapdirseverywhere] %s: %d (%s)\n",
493                            converted,
494                            ret, ret == 0 ? "ok" : strerror(errno)));
495                 if (ret == 0) {
496                         DEBUG(10, ("Found %s\n", converted));
497                         result = converted;
498                         converted = NULL;
499                         if (snaproot_len != NULL) {
500                                 *snaproot_len = strlen(snapshot_path);
501                                 if (config->rel_connectpath != NULL) {
502                                         *snaproot_len +=
503                                             strlen(config->rel_connectpath) + 1;
504                                 }
505                         }
506                         goto fail;
507                 } else {
508                         errno = ENOENT;
509                         goto fail;
510                 }
511                 /* never reached ... */
512         }
513
514         connectlen = strlen(handle->conn->connectpath);
515         if (name[0] == 0) {
516                 path = talloc_strdup(mem_ctx, handle->conn->connectpath);
517         } else {
518                 path = talloc_asprintf(
519                         mem_ctx, "%s/%s", handle->conn->connectpath, name);
520         }
521         if (path == NULL) {
522                 errno = ENOMEM;
523                 goto fail;
524         }
525         pathlen = talloc_get_size(path)-1;
526
527         if (!shadow_copy2_find_slashes(talloc_tos(), path,
528                                        &slashes, &num_slashes)) {
529                 goto fail;
530         }
531
532         insert = shadow_copy2_insert_string(talloc_tos(), handle, timestamp);
533         if (insert == NULL) {
534                 goto fail;
535         }
536         insertlen = talloc_get_size(insert)-1;
537
538         /*
539          * Note: We deliberatly don't expensively initialize the
540          * array with talloc_zero here: Putting zero into
541          * converted[pathlen+insertlen] below is sufficient, because
542          * in the following for loop, the insert string is inserted
543          * at various slash places. So the memory up to position
544          * pathlen+insertlen will always be initialized when the
545          * converted string is used.
546          */
547         converted = talloc_array(mem_ctx, char, pathlen + insertlen + 1);
548         if (converted == NULL) {
549                 goto fail;
550         }
551
552         if (path[pathlen-1] != '/') {
553                 /*
554                  * Append a fake slash to find the snapshot root
555                  */
556                 size_t *tmp;
557                 tmp = talloc_realloc(talloc_tos(), slashes,
558                                      size_t, num_slashes+1);
559                 if (tmp == NULL) {
560                         goto fail;
561                 }
562                 slashes = tmp;
563                 slashes[num_slashes] = pathlen;
564                 num_slashes += 1;
565         }
566
567         min_offset = 0;
568
569         if (!config->crossmountpoints) {
570                 min_offset = strlen(config->mount_point);
571         }
572
573         memcpy(converted, path, pathlen+1);
574         converted[pathlen+insertlen] = '\0';
575
576         ZERO_STRUCT(converted_fname);
577         converted_fname.base_name = converted;
578
579         for (i = num_slashes-1; i>=0; i--) {
580                 int ret;
581                 size_t offset;
582
583                 offset = slashes[i];
584
585                 if (offset < min_offset) {
586                         errno = ENOENT;
587                         goto fail;
588                 }
589
590                 if (offset >= connectlen) {
591                         in_share_offset = offset;
592                 }
593
594                 memcpy(converted+offset, insert, insertlen);
595
596                 offset += insertlen;
597                 memcpy(converted+offset, path + slashes[i],
598                        pathlen - slashes[i]);
599
600                 ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
601
602                 DEBUG(10, ("Trying[snapdirseverywhere] %s: %d (%s)\n",
603                            converted,
604                            ret, ret == 0 ? "ok" : strerror(errno)));
605                 if (ret == 0) {
606                         /* success */
607                         if (snaproot_len != NULL) {
608                                 *snaproot_len = in_share_offset + insertlen;
609                         }
610                         break;
611                 }
612                 if (errno == ENOTDIR) {
613                         /*
614                          * This is a valid condition: We appended the
615                          * .snaphots/@GMT.. to a file name. Just try
616                          * with the upper levels.
617                          */
618                         continue;
619                 }
620                 if (errno != ENOENT) {
621                         /* Other problem than "not found" */
622                         goto fail;
623                 }
624         }
625
626         if (i >= 0) {
627                 /*
628                  * Found something
629                  */
630                 DEBUG(10, ("Found %s\n", converted));
631                 result = converted;
632                 converted = NULL;
633         } else {
634                 errno = ENOENT;
635         }
636 fail:
637         saved_errno = errno;
638         TALLOC_FREE(converted);
639         TALLOC_FREE(insert);
640         TALLOC_FREE(slashes);
641         TALLOC_FREE(path);
642         errno = saved_errno;
643         return result;
644 }
645
646 /**
647  * Convert from a name as handed in via the SMB layer
648  * and a timestamp into the local path of the snapshot
649  * of the provided file at the provided time.
650  */
651 static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx,
652                                   struct vfs_handle_struct *handle,
653                                   const char *name, time_t timestamp)
654 {
655         return shadow_copy2_do_convert(mem_ctx, handle, name, timestamp, NULL);
656 }
657
658 /*
659   modify a sbuf return to ensure that inodes in the shadow directory
660   are different from those in the main directory
661  */
662 static void convert_sbuf(vfs_handle_struct *handle, const char *fname,
663                          SMB_STRUCT_STAT *sbuf)
664 {
665         struct shadow_copy2_config *config;
666
667         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
668                                 return);
669
670         if (config->fixinodes) {
671                 /* some snapshot systems, like GPFS, return the name
672                    device:inode for the snapshot files as the current
673                    files. That breaks the 'restore' button in the shadow copy
674                    GUI, as the client gets a sharing violation.
675
676                    This is a crude way of allowing both files to be
677                    open at once. It has a slight chance of inode
678                    number collision, but I can't see a better approach
679                    without significant VFS changes
680                 */
681                 TDB_DATA key = { .dptr = discard_const_p(uint8_t, fname),
682                                  .dsize = strlen(fname) };
683                 uint32_t shash;
684
685                 shash = tdb_jenkins_hash(&key) & 0xFF000000;
686                 if (shash == 0) {
687                         shash = 1;
688                 }
689                 sbuf->st_ex_ino ^= shash;
690         }
691 }
692
693 static DIR *shadow_copy2_opendir(vfs_handle_struct *handle,
694                                             const char *fname,
695                                             const char *mask,
696                                             uint32_t attr)
697 {
698         time_t timestamp;
699         char *stripped;
700         DIR *ret;
701         int saved_errno;
702         char *conv;
703
704         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
705                                          &timestamp, &stripped)) {
706                 return NULL;
707         }
708         if (timestamp == 0) {
709                 return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
710         }
711         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
712         TALLOC_FREE(stripped);
713         if (conv == NULL) {
714                 return NULL;
715         }
716         ret = SMB_VFS_NEXT_OPENDIR(handle, conv, mask, attr);
717         saved_errno = errno;
718         TALLOC_FREE(conv);
719         errno = saved_errno;
720         return ret;
721 }
722
723 static int shadow_copy2_rename(vfs_handle_struct *handle,
724                                const struct smb_filename *smb_fname_src,
725                                const struct smb_filename *smb_fname_dst)
726 {
727         time_t timestamp_src, timestamp_dst;
728
729         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
730                                          smb_fname_src->base_name,
731                                          &timestamp_src, NULL)) {
732                 return -1;
733         }
734         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
735                                          smb_fname_dst->base_name,
736                                          &timestamp_dst, NULL)) {
737                 return -1;
738         }
739         if (timestamp_src != 0) {
740                 errno = EXDEV;
741                 return -1;
742         }
743         if (timestamp_dst != 0) {
744                 errno = EROFS;
745                 return -1;
746         }
747         return SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
748 }
749
750 static int shadow_copy2_symlink(vfs_handle_struct *handle,
751                                 const char *oldname, const char *newname)
752 {
753         time_t timestamp_old, timestamp_new;
754
755         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
756                                          &timestamp_old, NULL)) {
757                 return -1;
758         }
759         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
760                                          &timestamp_new, NULL)) {
761                 return -1;
762         }
763         if ((timestamp_old != 0) || (timestamp_new != 0)) {
764                 errno = EROFS;
765                 return -1;
766         }
767         return SMB_VFS_NEXT_SYMLINK(handle, oldname, newname);
768 }
769
770 static int shadow_copy2_link(vfs_handle_struct *handle,
771                              const char *oldname, const char *newname)
772 {
773         time_t timestamp_old, timestamp_new;
774
775         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
776                                          &timestamp_old, NULL)) {
777                 return -1;
778         }
779         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
780                                          &timestamp_new, NULL)) {
781                 return -1;
782         }
783         if ((timestamp_old != 0) || (timestamp_new != 0)) {
784                 errno = EROFS;
785                 return -1;
786         }
787         return SMB_VFS_NEXT_LINK(handle, oldname, newname);
788 }
789
790 static int shadow_copy2_stat(vfs_handle_struct *handle,
791                              struct smb_filename *smb_fname)
792 {
793         time_t timestamp;
794         char *stripped, *tmp;
795         int ret, saved_errno;
796
797         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
798                                          smb_fname->base_name,
799                                          &timestamp, &stripped)) {
800                 return -1;
801         }
802         if (timestamp == 0) {
803                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
804         }
805
806         tmp = smb_fname->base_name;
807         smb_fname->base_name = shadow_copy2_convert(
808                 talloc_tos(), handle, stripped, timestamp);
809         TALLOC_FREE(stripped);
810
811         if (smb_fname->base_name == NULL) {
812                 smb_fname->base_name = tmp;
813                 return -1;
814         }
815
816         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
817         saved_errno = errno;
818
819         TALLOC_FREE(smb_fname->base_name);
820         smb_fname->base_name = tmp;
821
822         if (ret == 0) {
823                 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
824         }
825         errno = saved_errno;
826         return ret;
827 }
828
829 static int shadow_copy2_lstat(vfs_handle_struct *handle,
830                               struct smb_filename *smb_fname)
831 {
832         time_t timestamp;
833         char *stripped, *tmp;
834         int ret, saved_errno;
835
836         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
837                                          smb_fname->base_name,
838                                          &timestamp, &stripped)) {
839                 return -1;
840         }
841         if (timestamp == 0) {
842                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
843         }
844
845         tmp = smb_fname->base_name;
846         smb_fname->base_name = shadow_copy2_convert(
847                 talloc_tos(), handle, stripped, timestamp);
848         TALLOC_FREE(stripped);
849
850         if (smb_fname->base_name == NULL) {
851                 smb_fname->base_name = tmp;
852                 return -1;
853         }
854
855         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
856         saved_errno = errno;
857
858         TALLOC_FREE(smb_fname->base_name);
859         smb_fname->base_name = tmp;
860
861         if (ret == 0) {
862                 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
863         }
864         errno = saved_errno;
865         return ret;
866 }
867
868 static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
869                               SMB_STRUCT_STAT *sbuf)
870 {
871         time_t timestamp;
872         int ret;
873
874         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
875         if (ret == -1) {
876                 return ret;
877         }
878         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
879                                          fsp->fsp_name->base_name,
880                                          &timestamp, NULL)) {
881                 return 0;
882         }
883         if (timestamp != 0) {
884                 convert_sbuf(handle, fsp->fsp_name->base_name, sbuf);
885         }
886         return 0;
887 }
888
889 static int shadow_copy2_open(vfs_handle_struct *handle,
890                              struct smb_filename *smb_fname, files_struct *fsp,
891                              int flags, mode_t mode)
892 {
893         time_t timestamp;
894         char *stripped, *tmp;
895         int ret, saved_errno;
896
897         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
898                                          smb_fname->base_name,
899                                          &timestamp, &stripped)) {
900                 return -1;
901         }
902         if (timestamp == 0) {
903                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
904         }
905
906         tmp = smb_fname->base_name;
907         smb_fname->base_name = shadow_copy2_convert(
908                 talloc_tos(), handle, stripped, timestamp);
909         TALLOC_FREE(stripped);
910
911         if (smb_fname->base_name == NULL) {
912                 smb_fname->base_name = tmp;
913                 return -1;
914         }
915
916         ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
917         saved_errno = errno;
918
919         TALLOC_FREE(smb_fname->base_name);
920         smb_fname->base_name = tmp;
921
922         errno = saved_errno;
923         return ret;
924 }
925
926 static int shadow_copy2_unlink(vfs_handle_struct *handle,
927                                const struct smb_filename *smb_fname)
928 {
929         time_t timestamp;
930         char *stripped;
931         int ret, saved_errno;
932         struct smb_filename *conv;
933
934         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
935                                          smb_fname->base_name,
936                                          &timestamp, &stripped)) {
937                 return -1;
938         }
939         if (timestamp == 0) {
940                 return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
941         }
942         conv = cp_smb_filename(talloc_tos(), smb_fname);
943         if (conv == NULL) {
944                 errno = ENOMEM;
945                 return -1;
946         }
947         conv->base_name = shadow_copy2_convert(
948                 conv, handle, stripped, timestamp);
949         TALLOC_FREE(stripped);
950         if (conv->base_name == NULL) {
951                 return -1;
952         }
953         ret = SMB_VFS_NEXT_UNLINK(handle, conv);
954         saved_errno = errno;
955         TALLOC_FREE(conv);
956         errno = saved_errno;
957         return ret;
958 }
959
960 static int shadow_copy2_chmod(vfs_handle_struct *handle, const char *fname,
961                               mode_t mode)
962 {
963         time_t timestamp;
964         char *stripped;
965         int ret, saved_errno;
966         char *conv;
967
968         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
969                                          &timestamp, &stripped)) {
970                 return -1;
971         }
972         if (timestamp == 0) {
973                 return SMB_VFS_NEXT_CHMOD(handle, fname, mode);
974         }
975         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
976         TALLOC_FREE(stripped);
977         if (conv == NULL) {
978                 return -1;
979         }
980         ret = SMB_VFS_NEXT_CHMOD(handle, conv, mode);
981         saved_errno = errno;
982         TALLOC_FREE(conv);
983         errno = saved_errno;
984         return ret;
985 }
986
987 static int shadow_copy2_chown(vfs_handle_struct *handle, const char *fname,
988                               uid_t uid, gid_t gid)
989 {
990         time_t timestamp;
991         char *stripped;
992         int ret, saved_errno;
993         char *conv;
994
995         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
996                                          &timestamp, &stripped)) {
997                 return -1;
998         }
999         if (timestamp == 0) {
1000                 return SMB_VFS_NEXT_CHOWN(handle, fname, uid, gid);
1001         }
1002         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1003         TALLOC_FREE(stripped);
1004         if (conv == NULL) {
1005                 return -1;
1006         }
1007         ret = SMB_VFS_NEXT_CHOWN(handle, conv, uid, gid);
1008         saved_errno = errno;
1009         TALLOC_FREE(conv);
1010         errno = saved_errno;
1011         return ret;
1012 }
1013
1014 static int shadow_copy2_chdir(vfs_handle_struct *handle,
1015                               const char *fname)
1016 {
1017         time_t timestamp;
1018         char *stripped;
1019         int ret, saved_errno;
1020         char *conv;
1021
1022         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1023                                          &timestamp, &stripped)) {
1024                 return -1;
1025         }
1026         if (timestamp == 0) {
1027                 return SMB_VFS_NEXT_CHDIR(handle, fname);
1028         }
1029         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1030         TALLOC_FREE(stripped);
1031         if (conv == NULL) {
1032                 return -1;
1033         }
1034         ret = SMB_VFS_NEXT_CHDIR(handle, conv);
1035         saved_errno = errno;
1036         TALLOC_FREE(conv);
1037         errno = saved_errno;
1038         return ret;
1039 }
1040
1041 static int shadow_copy2_ntimes(vfs_handle_struct *handle,
1042                                const struct smb_filename *smb_fname,
1043                                struct smb_file_time *ft)
1044 {
1045         time_t timestamp;
1046         char *stripped;
1047         int ret, saved_errno;
1048         struct smb_filename *conv;
1049
1050         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1051                                          smb_fname->base_name,
1052                                          &timestamp, &stripped)) {
1053                 return -1;
1054         }
1055         if (timestamp == 0) {
1056                 return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1057         }
1058         conv = cp_smb_filename(talloc_tos(), smb_fname);
1059         if (conv == NULL) {
1060                 errno = ENOMEM;
1061                 return -1;
1062         }
1063         conv->base_name = shadow_copy2_convert(
1064                 conv, handle, stripped, timestamp);
1065         TALLOC_FREE(stripped);
1066         if (conv->base_name == NULL) {
1067                 return -1;
1068         }
1069         ret = SMB_VFS_NEXT_NTIMES(handle, conv, ft);
1070         saved_errno = errno;
1071         TALLOC_FREE(conv);
1072         errno = saved_errno;
1073         return ret;
1074 }
1075
1076 static int shadow_copy2_readlink(vfs_handle_struct *handle,
1077                                  const char *fname, char *buf, size_t bufsiz)
1078 {
1079         time_t timestamp;
1080         char *stripped;
1081         int ret, saved_errno;
1082         char *conv;
1083
1084         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1085                                          &timestamp, &stripped)) {
1086                 return -1;
1087         }
1088         if (timestamp == 0) {
1089                 return SMB_VFS_NEXT_READLINK(handle, fname, buf, bufsiz);
1090         }
1091         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1092         TALLOC_FREE(stripped);
1093         if (conv == NULL) {
1094                 return -1;
1095         }
1096         ret = SMB_VFS_NEXT_READLINK(handle, conv, buf, bufsiz);
1097         saved_errno = errno;
1098         TALLOC_FREE(conv);
1099         errno = saved_errno;
1100         return ret;
1101 }
1102
1103 static int shadow_copy2_mknod(vfs_handle_struct *handle,
1104                               const char *fname, mode_t mode, SMB_DEV_T dev)
1105 {
1106         time_t timestamp;
1107         char *stripped;
1108         int ret, saved_errno;
1109         char *conv;
1110
1111         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1112                                          &timestamp, &stripped)) {
1113                 return -1;
1114         }
1115         if (timestamp == 0) {
1116                 return SMB_VFS_NEXT_MKNOD(handle, fname, mode, dev);
1117         }
1118         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1119         TALLOC_FREE(stripped);
1120         if (conv == NULL) {
1121                 return -1;
1122         }
1123         ret = SMB_VFS_NEXT_MKNOD(handle, conv, mode, dev);
1124         saved_errno = errno;
1125         TALLOC_FREE(conv);
1126         errno = saved_errno;
1127         return ret;
1128 }
1129
1130 static char *shadow_copy2_realpath(vfs_handle_struct *handle,
1131                                    const char *fname)
1132 {
1133         time_t timestamp;
1134         char *stripped = NULL;
1135         char *tmp = NULL;
1136         char *result = NULL;
1137         int saved_errno;
1138
1139         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1140                                          &timestamp, &stripped)) {
1141                 goto done;
1142         }
1143         if (timestamp == 0) {
1144                 return SMB_VFS_NEXT_REALPATH(handle, fname);
1145         }
1146
1147         tmp = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1148         if (tmp == NULL) {
1149                 goto done;
1150         }
1151
1152         result = SMB_VFS_NEXT_REALPATH(handle, tmp);
1153
1154 done:
1155         saved_errno = errno;
1156         TALLOC_FREE(tmp);
1157         TALLOC_FREE(stripped);
1158         errno = saved_errno;
1159         return result;
1160 }
1161
1162 /**
1163  * Check whether a given directory contains a
1164  * snapshot directory as direct subdirectory.
1165  * If yes, return the path of the snapshot-subdir,
1166  * otherwise return NULL.
1167  */
1168 static char *have_snapdir(struct vfs_handle_struct *handle,
1169                           const char *path)
1170 {
1171         struct smb_filename smb_fname;
1172         int ret;
1173         struct shadow_copy2_config *config;
1174
1175         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1176                                 return NULL);
1177
1178         ZERO_STRUCT(smb_fname);
1179         smb_fname.base_name = talloc_asprintf(talloc_tos(), "%s/%s",
1180                                               path, config->snapdir);
1181         if (smb_fname.base_name == NULL) {
1182                 return NULL;
1183         }
1184
1185         ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
1186         if ((ret == 0) && (S_ISDIR(smb_fname.st.st_ex_mode))) {
1187                 return smb_fname.base_name;
1188         }
1189         TALLOC_FREE(smb_fname.base_name);
1190         return NULL;
1191 }
1192
1193 static bool check_access_snapdir(struct vfs_handle_struct *handle,
1194                                 const char *path)
1195 {
1196         struct smb_filename smb_fname;
1197         int ret;
1198         NTSTATUS status;
1199
1200         ZERO_STRUCT(smb_fname);
1201         smb_fname.base_name = talloc_asprintf(talloc_tos(),
1202                                                 "%s",
1203                                                 path);
1204         if (smb_fname.base_name == NULL) {
1205                 return false;
1206         }
1207
1208         ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
1209         if (ret != 0 || !S_ISDIR(smb_fname.st.st_ex_mode)) {
1210                 TALLOC_FREE(smb_fname.base_name);
1211                 return false;
1212         }
1213
1214         status = smbd_check_access_rights(handle->conn,
1215                                         &smb_fname,
1216                                         false,
1217                                         SEC_DIR_LIST);
1218         if (!NT_STATUS_IS_OK(status)) {
1219                 DEBUG(0,("user does not have list permission "
1220                         "on snapdir %s\n",
1221                         smb_fname.base_name));
1222                 TALLOC_FREE(smb_fname.base_name);
1223                 return false;
1224         }
1225         TALLOC_FREE(smb_fname.base_name);
1226         return true;
1227 }
1228
1229 /**
1230  * Find the snapshot directory (if any) for the given
1231  * filename (which is relative to the share).
1232  */
1233 static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx,
1234                                              struct vfs_handle_struct *handle,
1235                                              struct smb_filename *smb_fname)
1236 {
1237         char *path, *p;
1238         const char *snapdir;
1239         struct shadow_copy2_config *config;
1240
1241         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1242                                 return NULL);
1243
1244         /*
1245          * If the non-snapdisrseverywhere mode, we should not search!
1246          */
1247         if (!config->snapdirseverywhere) {
1248                 return config->snapshot_basepath;
1249         }
1250
1251         path = talloc_asprintf(mem_ctx, "%s/%s",
1252                                handle->conn->connectpath,
1253                                smb_fname->base_name);
1254         if (path == NULL) {
1255                 return NULL;
1256         }
1257
1258         snapdir = have_snapdir(handle, path);
1259         if (snapdir != NULL) {
1260                 TALLOC_FREE(path);
1261                 return snapdir;
1262         }
1263
1264         while ((p = strrchr(path, '/')) && (p > path)) {
1265
1266                 p[0] = '\0';
1267
1268                 snapdir = have_snapdir(handle, path);
1269                 if (snapdir != NULL) {
1270                         TALLOC_FREE(path);
1271                         return snapdir;
1272                 }
1273         }
1274         TALLOC_FREE(path);
1275         return NULL;
1276 }
1277
1278 static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
1279                                          const char *name,
1280                                          char *gmt, size_t gmt_len)
1281 {
1282         struct tm timestamp;
1283         time_t timestamp_t;
1284         unsigned long int timestamp_long;
1285         const char *fmt;
1286         struct shadow_copy2_config *config;
1287
1288         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1289                                 return NULL);
1290
1291         fmt = config->gmt_format;
1292
1293         ZERO_STRUCT(timestamp);
1294         if (config->use_sscanf) {
1295                 if (sscanf(name, fmt, &timestamp_long) != 1) {
1296                         DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1297                                    "no sscanf match %s: %s\n",
1298                                    fmt, name));
1299                         return false;
1300                 }
1301                 timestamp_t = timestamp_long;
1302                 gmtime_r(&timestamp_t, &timestamp);
1303         } else {
1304                 if (strptime(name, fmt, &timestamp) == NULL) {
1305                         DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1306                                    "no match %s: %s\n",
1307                                    fmt, name));
1308                         return false;
1309                 }
1310                 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n",
1311                            fmt, name));
1312                 
1313                 if (config->use_localtime) {
1314                         timestamp.tm_isdst = -1;
1315                         timestamp_t = mktime(&timestamp);
1316                         gmtime_r(&timestamp_t, &timestamp);
1317                 }
1318         }
1319
1320         strftime(gmt, gmt_len, GMT_FORMAT, &timestamp);
1321         return true;
1322 }
1323
1324 static int shadow_copy2_label_cmp_asc(const void *x, const void *y)
1325 {
1326         return strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1327 }
1328
1329 static int shadow_copy2_label_cmp_desc(const void *x, const void *y)
1330 {
1331         return -strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1332 }
1333
1334 /*
1335   sort the shadow copy data in ascending or descending order
1336  */
1337 static void shadow_copy2_sort_data(vfs_handle_struct *handle,
1338                                    struct shadow_copy_data *shadow_copy2_data)
1339 {
1340         int (*cmpfunc)(const void *, const void *);
1341         const char *sort;
1342         struct shadow_copy2_config *config;
1343
1344         SMB_VFS_HANDLE_GET_DATA(handle, config, struct shadow_copy2_config,
1345                                 return);
1346
1347         sort = config->sort_order;
1348         if (sort == NULL) {
1349                 return;
1350         }
1351
1352         if (strcmp(sort, "asc") == 0) {
1353                 cmpfunc = shadow_copy2_label_cmp_asc;
1354         } else if (strcmp(sort, "desc") == 0) {
1355                 cmpfunc = shadow_copy2_label_cmp_desc;
1356         } else {
1357                 return;
1358         }
1359
1360         if (shadow_copy2_data && shadow_copy2_data->num_volumes > 0 &&
1361             shadow_copy2_data->labels)
1362         {
1363                 TYPESAFE_QSORT(shadow_copy2_data->labels,
1364                                shadow_copy2_data->num_volumes,
1365                                cmpfunc);
1366         }
1367 }
1368
1369 static int shadow_copy2_get_shadow_copy_data(
1370         vfs_handle_struct *handle, files_struct *fsp,
1371         struct shadow_copy_data *shadow_copy2_data,
1372         bool labels)
1373 {
1374         DIR *p;
1375         const char *snapdir;
1376         struct dirent *d;
1377         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1378         bool ret;
1379
1380         snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle, fsp->fsp_name);
1381         if (snapdir == NULL) {
1382                 DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
1383                          handle->conn->connectpath));
1384                 errno = EINVAL;
1385                 talloc_free(tmp_ctx);
1386                 return -1;
1387         }
1388         ret = check_access_snapdir(handle, snapdir);
1389         if (!ret) {
1390                 DEBUG(0,("access denied on listing snapdir %s\n", snapdir));
1391                 errno = EACCES;
1392                 talloc_free(tmp_ctx);
1393                 return -1;
1394         }
1395
1396         p = SMB_VFS_NEXT_OPENDIR(handle, snapdir, NULL, 0);
1397
1398         if (!p) {
1399                 DEBUG(2,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s'"
1400                          " - %s\n", snapdir, strerror(errno)));
1401                 talloc_free(tmp_ctx);
1402                 errno = ENOSYS;
1403                 return -1;
1404         }
1405
1406         shadow_copy2_data->num_volumes = 0;
1407         shadow_copy2_data->labels      = NULL;
1408
1409         while ((d = SMB_VFS_NEXT_READDIR(handle, p, NULL))) {
1410                 char snapshot[GMT_NAME_LEN+1];
1411                 SHADOW_COPY_LABEL *tlabels;
1412
1413                 /*
1414                  * ignore names not of the right form in the snapshot
1415                  * directory
1416                  */
1417                 if (!shadow_copy2_snapshot_to_gmt(
1418                             handle, d->d_name,
1419                             snapshot, sizeof(snapshot))) {
1420
1421                         DEBUG(6, ("shadow_copy2_get_shadow_copy_data: "
1422                                   "ignoring %s\n", d->d_name));
1423                         continue;
1424                 }
1425                 DEBUG(6,("shadow_copy2_get_shadow_copy_data: %s -> %s\n",
1426                          d->d_name, snapshot));
1427
1428                 if (!labels) {
1429                         /* the caller doesn't want the labels */
1430                         shadow_copy2_data->num_volumes++;
1431                         continue;
1432                 }
1433
1434                 tlabels = talloc_realloc(shadow_copy2_data,
1435                                          shadow_copy2_data->labels,
1436                                          SHADOW_COPY_LABEL,
1437                                          shadow_copy2_data->num_volumes+1);
1438                 if (tlabels == NULL) {
1439                         DEBUG(0,("shadow_copy2: out of memory\n"));
1440                         SMB_VFS_NEXT_CLOSEDIR(handle, p);
1441                         talloc_free(tmp_ctx);
1442                         return -1;
1443                 }
1444
1445                 strlcpy(tlabels[shadow_copy2_data->num_volumes], snapshot,
1446                         sizeof(*tlabels));
1447
1448                 shadow_copy2_data->num_volumes++;
1449                 shadow_copy2_data->labels = tlabels;
1450         }
1451
1452         SMB_VFS_NEXT_CLOSEDIR(handle,p);
1453
1454         shadow_copy2_sort_data(handle, shadow_copy2_data);
1455
1456         talloc_free(tmp_ctx);
1457         return 0;
1458 }
1459
1460 static NTSTATUS shadow_copy2_fget_nt_acl(vfs_handle_struct *handle,
1461                                         struct files_struct *fsp,
1462                                         uint32_t security_info,
1463                                          TALLOC_CTX *mem_ctx,
1464                                         struct security_descriptor **ppdesc)
1465 {
1466         time_t timestamp;
1467         char *stripped;
1468         NTSTATUS status;
1469         char *conv;
1470
1471         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1472                                          fsp->fsp_name->base_name,
1473                                          &timestamp, &stripped)) {
1474                 return map_nt_error_from_unix(errno);
1475         }
1476         if (timestamp == 0) {
1477                 return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
1478                                                 mem_ctx,
1479                                                 ppdesc);
1480         }
1481         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1482         TALLOC_FREE(stripped);
1483         if (conv == NULL) {
1484                 return map_nt_error_from_unix(errno);
1485         }
1486         status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv, security_info,
1487                                          mem_ctx, ppdesc);
1488         TALLOC_FREE(conv);
1489         return status;
1490 }
1491
1492 static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle,
1493                                         const char *fname,
1494                                         uint32_t security_info,
1495                                         TALLOC_CTX *mem_ctx,
1496                                         struct security_descriptor **ppdesc)
1497 {
1498         time_t timestamp;
1499         char *stripped;
1500         NTSTATUS status;
1501         char *conv;
1502
1503         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1504                                          &timestamp, &stripped)) {
1505                 return map_nt_error_from_unix(errno);
1506         }
1507         if (timestamp == 0) {
1508                 return SMB_VFS_NEXT_GET_NT_ACL(handle, fname, security_info,
1509                                                mem_ctx, ppdesc);
1510         }
1511         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1512         TALLOC_FREE(stripped);
1513         if (conv == NULL) {
1514                 return map_nt_error_from_unix(errno);
1515         }
1516         status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv, security_info,
1517                                          mem_ctx, ppdesc);
1518         TALLOC_FREE(conv);
1519         return status;
1520 }
1521
1522 static int shadow_copy2_mkdir(vfs_handle_struct *handle,
1523                               const char *fname, mode_t mode)
1524 {
1525         time_t timestamp;
1526         char *stripped;
1527         int ret, saved_errno;
1528         char *conv;
1529
1530         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1531                                          &timestamp, &stripped)) {
1532                 return -1;
1533         }
1534         if (timestamp == 0) {
1535                 return SMB_VFS_NEXT_MKDIR(handle, fname, mode);
1536         }
1537         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1538         TALLOC_FREE(stripped);
1539         if (conv == NULL) {
1540                 return -1;
1541         }
1542         ret = SMB_VFS_NEXT_MKDIR(handle, conv, mode);
1543         saved_errno = errno;
1544         TALLOC_FREE(conv);
1545         errno = saved_errno;
1546         return ret;
1547 }
1548
1549 static int shadow_copy2_rmdir(vfs_handle_struct *handle, const char *fname)
1550 {
1551         time_t timestamp;
1552         char *stripped;
1553         int ret, saved_errno;
1554         char *conv;
1555
1556         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1557                                          &timestamp, &stripped)) {
1558                 return -1;
1559         }
1560         if (timestamp == 0) {
1561                 return SMB_VFS_NEXT_RMDIR(handle, fname);
1562         }
1563         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1564         TALLOC_FREE(stripped);
1565         if (conv == NULL) {
1566                 return -1;
1567         }
1568         ret = SMB_VFS_NEXT_RMDIR(handle, conv);
1569         saved_errno = errno;
1570         TALLOC_FREE(conv);
1571         errno = saved_errno;
1572         return ret;
1573 }
1574
1575 static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname,
1576                                 unsigned int flags)
1577 {
1578         time_t timestamp;
1579         char *stripped;
1580         int ret, saved_errno;
1581         char *conv;
1582
1583         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1584                                          &timestamp, &stripped)) {
1585                 return -1;
1586         }
1587         if (timestamp == 0) {
1588                 return SMB_VFS_NEXT_CHFLAGS(handle, fname, flags);
1589         }
1590         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1591         TALLOC_FREE(stripped);
1592         if (conv == NULL) {
1593                 return -1;
1594         }
1595         ret = SMB_VFS_NEXT_CHFLAGS(handle, conv, flags);
1596         saved_errno = errno;
1597         TALLOC_FREE(conv);
1598         errno = saved_errno;
1599         return ret;
1600 }
1601
1602 static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
1603                                      const char *fname, const char *aname,
1604                                      void *value, size_t size)
1605 {
1606         time_t timestamp;
1607         char *stripped;
1608         ssize_t ret;
1609         int saved_errno;
1610         char *conv;
1611
1612         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1613                                          &timestamp, &stripped)) {
1614                 return -1;
1615         }
1616         if (timestamp == 0) {
1617                 return SMB_VFS_NEXT_GETXATTR(handle, fname, aname, value,
1618                                              size);
1619         }
1620         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1621         TALLOC_FREE(stripped);
1622         if (conv == NULL) {
1623                 return -1;
1624         }
1625         ret = SMB_VFS_NEXT_GETXATTR(handle, conv, aname, value, size);
1626         saved_errno = errno;
1627         TALLOC_FREE(conv);
1628         errno = saved_errno;
1629         return ret;
1630 }
1631
1632 static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle,
1633                                       const char *fname,
1634                                       char *list, size_t size)
1635 {
1636         time_t timestamp;
1637         char *stripped;
1638         ssize_t ret;
1639         int saved_errno;
1640         char *conv;
1641
1642         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1643                                          &timestamp, &stripped)) {
1644                 return -1;
1645         }
1646         if (timestamp == 0) {
1647                 return SMB_VFS_NEXT_LISTXATTR(handle, fname, list, size);
1648         }
1649         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1650         TALLOC_FREE(stripped);
1651         if (conv == NULL) {
1652                 return -1;
1653         }
1654         ret = SMB_VFS_NEXT_LISTXATTR(handle, conv, list, size);
1655         saved_errno = errno;
1656         TALLOC_FREE(conv);
1657         errno = saved_errno;
1658         return ret;
1659 }
1660
1661 static int shadow_copy2_removexattr(vfs_handle_struct *handle,
1662                                     const char *fname, const char *aname)
1663 {
1664         time_t timestamp;
1665         char *stripped;
1666         int ret, saved_errno;
1667         char *conv;
1668
1669         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1670                                          &timestamp, &stripped)) {
1671                 return -1;
1672         }
1673         if (timestamp == 0) {
1674                 return SMB_VFS_NEXT_REMOVEXATTR(handle, fname, aname);
1675         }
1676         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1677         TALLOC_FREE(stripped);
1678         if (conv == NULL) {
1679                 return -1;
1680         }
1681         ret = SMB_VFS_NEXT_REMOVEXATTR(handle, conv, aname);
1682         saved_errno = errno;
1683         TALLOC_FREE(conv);
1684         errno = saved_errno;
1685         return ret;
1686 }
1687
1688 static int shadow_copy2_setxattr(struct vfs_handle_struct *handle,
1689                                  const char *fname,
1690                                  const char *aname, const void *value,
1691                                  size_t size, int flags)
1692 {
1693         time_t timestamp;
1694         char *stripped;
1695         ssize_t ret;
1696         int saved_errno;
1697         char *conv;
1698
1699         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1700                                          &timestamp, &stripped)) {
1701                 return -1;
1702         }
1703         if (timestamp == 0) {
1704                 return SMB_VFS_NEXT_SETXATTR(handle, fname, aname, value, size,
1705                                              flags);
1706         }
1707         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1708         TALLOC_FREE(stripped);
1709         if (conv == NULL) {
1710                 return -1;
1711         }
1712         ret = SMB_VFS_NEXT_SETXATTR(handle, conv, aname, value, size, flags);
1713         saved_errno = errno;
1714         TALLOC_FREE(conv);
1715         errno = saved_errno;
1716         return ret;
1717 }
1718
1719 static int shadow_copy2_chmod_acl(vfs_handle_struct *handle,
1720                                   const char *fname, mode_t mode)
1721 {
1722         time_t timestamp;
1723         char *stripped;
1724         ssize_t ret;
1725         int saved_errno;
1726         char *conv;
1727
1728         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1729                                          &timestamp, &stripped)) {
1730                 return -1;
1731         }
1732         if (timestamp == 0) {
1733                 return SMB_VFS_NEXT_CHMOD_ACL(handle, fname, mode);
1734         }
1735         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1736         TALLOC_FREE(stripped);
1737         if (conv == NULL) {
1738                 return -1;
1739         }
1740         ret = SMB_VFS_NEXT_CHMOD_ACL(handle, conv, mode);
1741         saved_errno = errno;
1742         TALLOC_FREE(conv);
1743         errno = saved_errno;
1744         return ret;
1745 }
1746
1747 static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle,
1748                                           const char *path,
1749                                           const char *name,
1750                                           TALLOC_CTX *mem_ctx,
1751                                           char **found_name)
1752 {
1753         time_t timestamp;
1754         char *stripped;
1755         ssize_t ret;
1756         int saved_errno;
1757         char *conv;
1758
1759         DEBUG(10, ("shadow_copy2_get_real_filename called for path=[%s], "
1760                    "name=[%s]\n", path, name));
1761
1762         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
1763                                          &timestamp, &stripped)) {
1764                 DEBUG(10, ("shadow_copy2_strip_snapshot failed\n"));
1765                 return -1;
1766         }
1767         if (timestamp == 0) {
1768                 DEBUG(10, ("timestamp == 0\n"));
1769                 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
1770                                                       mem_ctx, found_name);
1771         }
1772         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1773         TALLOC_FREE(stripped);
1774         if (conv == NULL) {
1775                 DEBUG(10, ("shadow_copy2_convert failed\n"));
1776                 return -1;
1777         }
1778         DEBUG(10, ("Calling NEXT_GET_REAL_FILE_NAME for conv=[%s], "
1779                    "name=[%s]\n", conv, name));
1780         ret = SMB_VFS_NEXT_GET_REAL_FILENAME(handle, conv, name,
1781                                              mem_ctx, found_name);
1782         DEBUG(10, ("NEXT_REAL_FILE_NAME returned %d\n", (int)ret));
1783         saved_errno = errno;
1784         TALLOC_FREE(conv);
1785         errno = saved_errno;
1786         return ret;
1787 }
1788
1789 static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle,
1790                                             const char *fname)
1791 {
1792         time_t timestamp;
1793         char *stripped = NULL;
1794         char *tmp = NULL;
1795         char *result = NULL;
1796         int saved_errno;
1797         size_t rootpath_len = 0;
1798
1799         DBG_DEBUG("Calc connect path for [%s]\n", fname);
1800
1801         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1802                                          &timestamp, &stripped)) {
1803                 goto done;
1804         }
1805         if (timestamp == 0) {
1806                 return SMB_VFS_NEXT_CONNECTPATH(handle, fname);
1807         }
1808
1809         tmp = shadow_copy2_do_convert(talloc_tos(), handle, stripped, timestamp,
1810                                       &rootpath_len);
1811         if (tmp == NULL) {
1812                 goto done;
1813         }
1814
1815         DBG_DEBUG("converted path is [%s] root path is [%.*s]\n", tmp,
1816                   (int)rootpath_len, tmp);
1817
1818         tmp[rootpath_len] = '\0';
1819         result = SMB_VFS_NEXT_REALPATH(handle, tmp);
1820         if (result == NULL) {
1821                 goto done;
1822         }
1823
1824         DBG_DEBUG("connect path is [%s]\n", result);
1825
1826 done:
1827         saved_errno = errno;
1828         TALLOC_FREE(tmp);
1829         TALLOC_FREE(stripped);
1830         errno = saved_errno;
1831         return result;
1832 }
1833
1834 static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle,
1835                                        const char *path, uint64_t *bsize,
1836                                        uint64_t *dfree, uint64_t *dsize)
1837 {
1838         time_t timestamp;
1839         char *stripped;
1840         ssize_t ret;
1841         int saved_errno;
1842         char *conv;
1843
1844         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
1845                                          &timestamp, &stripped)) {
1846                 return -1;
1847         }
1848         if (timestamp == 0) {
1849                 return SMB_VFS_NEXT_DISK_FREE(handle, path,
1850                                               bsize, dfree, dsize);
1851         }
1852
1853         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1854         TALLOC_FREE(stripped);
1855         if (conv == NULL) {
1856                 return -1;
1857         }
1858
1859         ret = SMB_VFS_NEXT_DISK_FREE(handle, conv, bsize, dfree, dsize);
1860
1861         saved_errno = errno;
1862         TALLOC_FREE(conv);
1863         errno = saved_errno;
1864
1865         return ret;
1866 }
1867
1868 static int shadow_copy2_connect(struct vfs_handle_struct *handle,
1869                                 const char *service, const char *user)
1870 {
1871         struct shadow_copy2_config *config;
1872         int ret;
1873         const char *snapdir;
1874         const char *gmt_format;
1875         const char *sort_order;
1876         const char *basedir;
1877         const char *mount_point;
1878
1879         DEBUG(10, (__location__ ": cnum[%u], connectpath[%s]\n",
1880                    (unsigned)handle->conn->cnum,
1881                    handle->conn->connectpath));
1882
1883         ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
1884         if (ret < 0) {
1885                 return ret;
1886         }
1887
1888         config = talloc_zero(handle->conn, struct shadow_copy2_config);
1889         if (config == NULL) {
1890                 DEBUG(0, ("talloc_zero() failed\n"));
1891                 errno = ENOMEM;
1892                 return -1;
1893         }
1894
1895         gmt_format = lp_parm_const_string(SNUM(handle->conn),
1896                                           "shadow", "format",
1897                                           GMT_FORMAT);
1898         config->gmt_format = talloc_strdup(config, gmt_format);
1899         if (config->gmt_format == NULL) {
1900                 DEBUG(0, ("talloc_strdup() failed\n"));
1901                 errno = ENOMEM;
1902                 return -1;
1903         }
1904
1905         config->use_sscanf = lp_parm_bool(SNUM(handle->conn),
1906                                           "shadow", "sscanf", false);
1907
1908         config->use_localtime = lp_parm_bool(SNUM(handle->conn),
1909                                              "shadow", "localtime",
1910                                              false);
1911
1912         snapdir = lp_parm_const_string(SNUM(handle->conn),
1913                                        "shadow", "snapdir",
1914                                        ".snapshots");
1915         config->snapdir = talloc_strdup(config, snapdir);
1916         if (config->snapdir == NULL) {
1917                 DEBUG(0, ("talloc_strdup() failed\n"));
1918                 errno = ENOMEM;
1919                 return -1;
1920         }
1921
1922         config->snapdirseverywhere = lp_parm_bool(SNUM(handle->conn),
1923                                                   "shadow",
1924                                                   "snapdirseverywhere",
1925                                                   false);
1926
1927         config->crossmountpoints = lp_parm_bool(SNUM(handle->conn),
1928                                                 "shadow", "crossmountpoints",
1929                                                 false);
1930
1931         config->fixinodes = lp_parm_bool(SNUM(handle->conn),
1932                                          "shadow", "fixinodes",
1933                                          false);
1934
1935         sort_order = lp_parm_const_string(SNUM(handle->conn),
1936                                           "shadow", "sort", "desc");
1937         config->sort_order = talloc_strdup(config, sort_order);
1938         if (config->sort_order == NULL) {
1939                 DEBUG(0, ("talloc_strdup() failed\n"));
1940                 errno = ENOMEM;
1941                 return -1;
1942         }
1943
1944         mount_point = lp_parm_const_string(SNUM(handle->conn),
1945                                            "shadow", "mountpoint", NULL);
1946         if (mount_point != NULL) {
1947                 if (mount_point[0] != '/') {
1948                         DEBUG(1, (__location__ " Warning: 'mountpoint' is "
1949                                   "relative ('%s'), but it has to be an "
1950                                   "absolute path. Ignoring provided value.\n",
1951                                   mount_point));
1952                         mount_point = NULL;
1953                 } else {
1954                         char *p;
1955                         p = strstr(handle->conn->connectpath, mount_point);
1956                         if (p != handle->conn->connectpath) {
1957                                 DBG_WARNING("Warning: the share root (%s) is "
1958                                             "not a subdirectory of the "
1959                                             "specified mountpoint (%s). "
1960                                             "Ignoring provided value.\n",
1961                                             handle->conn->connectpath,
1962                                             mount_point);
1963                                 mount_point = NULL;
1964                         }
1965                 }
1966         }
1967
1968         if (mount_point != NULL) {
1969                 config->mount_point = talloc_strdup(config, mount_point);
1970                 if (config->mount_point == NULL) {
1971                         DEBUG(0, (__location__ " talloc_strdup() failed\n"));
1972                         return -1;
1973                 }
1974         } else {
1975                 config->mount_point = shadow_copy2_find_mount_point(config,
1976                                                                     handle);
1977                 if (config->mount_point == NULL) {
1978                         DBG_WARNING("shadow_copy2_find_mount_point "
1979                                     "of the share root '%s' failed: %s\n",
1980                                     handle->conn->connectpath, strerror(errno));
1981                         return -1;
1982                 }
1983         }
1984
1985         basedir = lp_parm_const_string(SNUM(handle->conn),
1986                                        "shadow", "basedir", NULL);
1987
1988         if (basedir != NULL) {
1989                 if (basedir[0] != '/') {
1990                         DEBUG(1, (__location__ " Warning: 'basedir' is "
1991                                   "relative ('%s'), but it has to be an "
1992                                   "absolute path. Disabling basedir.\n",
1993                                   basedir));
1994                 } else {
1995                         char *p;
1996                         p = strstr(basedir, config->mount_point);
1997                         if (p != basedir) {
1998                                 DEBUG(1, ("Warning: basedir (%s) is not a "
1999                                           "subdirectory of the share root's "
2000                                           "mount point (%s). "
2001                                           "Disabling basedir\n",
2002                                           basedir, config->mount_point));
2003                         } else {
2004                                 config->basedir = talloc_strdup(config,
2005                                                                 basedir);
2006                                 if (config->basedir == NULL) {
2007                                         DEBUG(0, ("talloc_strdup() failed\n"));
2008                                         errno = ENOMEM;
2009                                         return -1;
2010                                 }
2011                         }
2012                 }
2013         }
2014
2015         if (config->snapdirseverywhere && config->basedir != NULL) {
2016                 DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
2017                           "with 'snapdirseverywhere'. Disabling basedir.\n"));
2018                 TALLOC_FREE(config->basedir);
2019         }
2020
2021         if (config->crossmountpoints && config->basedir != NULL) {
2022                 DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
2023                           "with 'crossmountpoints'. Disabling basedir.\n"));
2024                 TALLOC_FREE(config->basedir);
2025         }
2026
2027         if (config->basedir == NULL) {
2028                 config->basedir = config->mount_point;
2029         }
2030
2031         if (strlen(config->basedir) != strlen(handle->conn->connectpath)) {
2032                 config->rel_connectpath = talloc_strdup(config,
2033                         handle->conn->connectpath + strlen(config->basedir));
2034                 if (config->rel_connectpath == NULL) {
2035                         DEBUG(0, ("talloc_strdup() failed\n"));
2036                         errno = ENOMEM;
2037                         return -1;
2038                 }
2039         }
2040
2041         if (config->snapdir[0] == '/') {
2042                 config->snapdir_absolute = true;
2043
2044                 if (config->snapdirseverywhere == true) {
2045                         DEBUG(1, (__location__ " Warning: An absolute snapdir "
2046                                   "is incompatible with 'snapdirseverywhere', "
2047                                   "setting 'snapdirseverywhere' to false.\n"));
2048                         config->snapdirseverywhere = false;
2049                 }
2050
2051                 if (config->crossmountpoints == true) {
2052                         DEBUG(1, (__location__ " Warning: 'crossmountpoints' "
2053                                   "is not supported with an absolute snapdir. "
2054                                   "Disabling it.\n"));
2055                         config->crossmountpoints = false;
2056                 }
2057
2058                 config->snapshot_basepath = config->snapdir;
2059         } else {
2060                 config->snapshot_basepath = talloc_asprintf(config, "%s/%s",
2061                                 config->mount_point, config->snapdir);
2062                 if (config->snapshot_basepath == NULL) {
2063                         DEBUG(0, ("talloc_asprintf() failed\n"));
2064                         errno = ENOMEM;
2065                         return -1;
2066                 }
2067         }
2068
2069         DEBUG(10, ("shadow_copy2_connect: configuration:\n"
2070                    "  share root: '%s'\n"
2071                    "  basedir: '%s'\n"
2072                    "  mountpoint: '%s'\n"
2073                    "  rel share root: '%s'\n"
2074                    "  snapdir: '%s'\n"
2075                    "  snapshot base path: '%s'\n"
2076                    "  format: '%s'\n"
2077                    "  use sscanf: %s\n"
2078                    "  snapdirs everywhere: %s\n"
2079                    "  cross mountpoints: %s\n"
2080                    "  fix inodes: %s\n"
2081                    "  sort order: %s\n"
2082                    "",
2083                    handle->conn->connectpath,
2084                    config->basedir,
2085                    config->mount_point,
2086                    config->rel_connectpath,
2087                    config->snapdir,
2088                    config->snapshot_basepath,
2089                    config->gmt_format,
2090                    config->use_sscanf ? "yes" : "no",
2091                    config->snapdirseverywhere ? "yes" : "no",
2092                    config->crossmountpoints ? "yes" : "no",
2093                    config->fixinodes ? "yes" : "no",
2094                    config->sort_order
2095                    ));
2096
2097
2098         SMB_VFS_HANDLE_SET_DATA(handle, config,
2099                                 NULL, struct shadow_copy2_config,
2100                                 return -1);
2101
2102         return 0;
2103 }
2104
2105 static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
2106         .connect_fn = shadow_copy2_connect,
2107         .opendir_fn = shadow_copy2_opendir,
2108         .disk_free_fn = shadow_copy2_disk_free,
2109         .rename_fn = shadow_copy2_rename,
2110         .link_fn = shadow_copy2_link,
2111         .symlink_fn = shadow_copy2_symlink,
2112         .stat_fn = shadow_copy2_stat,
2113         .lstat_fn = shadow_copy2_lstat,
2114         .fstat_fn = shadow_copy2_fstat,
2115         .open_fn = shadow_copy2_open,
2116         .unlink_fn = shadow_copy2_unlink,
2117         .chmod_fn = shadow_copy2_chmod,
2118         .chown_fn = shadow_copy2_chown,
2119         .chdir_fn = shadow_copy2_chdir,
2120         .ntimes_fn = shadow_copy2_ntimes,
2121         .readlink_fn = shadow_copy2_readlink,
2122         .mknod_fn = shadow_copy2_mknod,
2123         .realpath_fn = shadow_copy2_realpath,
2124         .get_nt_acl_fn = shadow_copy2_get_nt_acl,
2125         .fget_nt_acl_fn = shadow_copy2_fget_nt_acl,
2126         .get_shadow_copy_data_fn = shadow_copy2_get_shadow_copy_data,
2127         .mkdir_fn = shadow_copy2_mkdir,
2128         .rmdir_fn = shadow_copy2_rmdir,
2129         .getxattr_fn = shadow_copy2_getxattr,
2130         .listxattr_fn = shadow_copy2_listxattr,
2131         .removexattr_fn = shadow_copy2_removexattr,
2132         .setxattr_fn = shadow_copy2_setxattr,
2133         .chmod_acl_fn = shadow_copy2_chmod_acl,
2134         .chflags_fn = shadow_copy2_chflags,
2135         .get_real_filename_fn = shadow_copy2_get_real_filename,
2136         .connectpath_fn = shadow_copy2_connectpath,
2137 };
2138
2139 NTSTATUS vfs_shadow_copy2_init(void);
2140 NTSTATUS vfs_shadow_copy2_init(void)
2141 {
2142         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2143                                 "shadow_copy2", &vfs_shadow_copy2_fns);
2144 }