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