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