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