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