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