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