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