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