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