s3:winbind: remove the method SET_MAPPING from winbind's API
[ira/wip.git] / source3 / modules / vfs_shadow_copy2.c
1 /* 
2  * implementation of an Shadow Copy module - version 2
3  *
4  * Copyright (C) Andrew Tridgell     2007
5  * Copyright (C) Ed Plese            2009
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *  
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *  
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #include "includes.h"
23
24 /*
25
26   This is a 2nd implemetation of a shadow copy module for exposing
27   snapshots to windows clients as shadow copies. This version has the
28   following features:
29
30      1) you don't need to populate your shares with symlinks to the
31      snapshots. This can be very important when you have thousands of
32      shares, or use [homes]
33
34      2) the inode number of the files is altered so it is different
35      from the original. This allows the 'restore' button to work
36      without a sharing violation
37
38      3) shadow copy results can be sorted before being sent to the
39      client.  This is beneficial for filesystems that don't read
40      directories alphabetically (the default unix).
41
42      4) vanity naming for snapshots. Snapshots can be named in any
43      format compatible with str[fp]time conversions.
44
45      5) time stamps in snapshot names can be represented in localtime
46      rather than UTC.
47
48   Module options:
49
50       shadow:snapdir = <directory where snapshots are kept>
51
52       This is the directory containing the @GMT-* snapshot directories. If it is an absolute
53       path it is used as-is. If it is a relative path, then it is taken relative to the mount
54       point of the filesystem that the root of this share is on
55
56       shadow:basedir = <base directory that snapshots are from>
57
58       This is an optional parameter that specifies the directory that
59       the snapshots are relative to. It defaults to the filesystem
60       mount point
61
62       shadow:fixinodes = yes/no
63
64       If you enable shadow:fixinodes then this module will modify the
65       apparent inode number of files in the snapshot directories using
66       a hash of the files path. This is needed for snapshot systems
67       where the snapshots have the same device:inode number as the
68       original files (such as happens with GPFS snapshots). If you
69       don't set this option then the 'restore' button in the shadow
70       copy UI will fail with a sharing violation.
71
72       shadow:sort = asc/desc, or not specified for unsorted (default)
73
74       This is an optional parameter that specifies that the shadow
75       copy directories should be sorted before sending them to the
76       client.  This can be beneficial as unix filesystems are usually
77       not listed alphabetically sorted.  If enabled, you typically
78       want to specify descending order.
79
80       shadow:format = <format specification for snapshot names>
81
82       This is an optional parameter that specifies the format
83       specification for the naming of snapshots.  The format must
84       be compatible with the conversion specifications recognized
85       by str[fp]time.  The default value is "@GMT-%Y.%m.%d-%H.%M.%S".
86
87       shadow:localtime = yes/no (default is no)
88
89       This is an optional parameter that indicates whether the
90       snapshot names are in UTC/GMT or the local time.
91
92
93   The following command would generate a correctly formatted directory name
94   for use with the default parameters:
95      date -u +@GMT-%Y.%m.%d-%H.%M.%S
96   
97  */
98
99 static int vfs_shadow_copy2_debug_level = DBGC_VFS;
100
101 #undef DBGC_CLASS
102 #define DBGC_CLASS vfs_shadow_copy2_debug_level
103
104 #define GMT_NAME_LEN 24 /* length of a @GMT- name */
105 #define SHADOW_COPY2_GMT_FORMAT "@GMT-%Y.%m.%d-%H.%M.%S"
106
107 #define SHADOW_COPY2_DEFAULT_SORT NULL
108 #define SHADOW_COPY2_DEFAULT_FORMAT "@GMT-%Y.%m.%d-%H.%M.%S"
109 #define SHADOW_COPY2_DEFAULT_LOCALTIME false
110
111 /*
112   make very sure it is one of our special names 
113  */
114 static inline bool shadow_copy2_match_name(const char *name, const char **gmt_start)
115 {
116         unsigned year, month, day, hr, min, sec;
117         const char *p;
118         if (gmt_start) {
119                 (*gmt_start) = NULL;
120         }
121         p = strstr_m(name, "@GMT-");
122         if (p == NULL) return false;
123         if (p > name && p[-1] != '/') return False;
124         if (sscanf(p, "@GMT-%04u.%02u.%02u-%02u.%02u.%02u", &year, &month,
125                    &day, &hr, &min, &sec) != 6) {
126                 return False;
127         }
128         if (p[24] != 0 && p[24] != '/') {
129                 return False;
130         }
131         if (gmt_start) {
132                 (*gmt_start) = p;
133         }
134         return True;
135 }
136
137 static char *shadow_copy2_snapshot_to_gmt(TALLOC_CTX *mem_ctx,
138                                 vfs_handle_struct *handle, const char *name)
139 {
140         struct tm timestamp;
141         time_t timestamp_t;
142         char gmt[GMT_NAME_LEN + 1];
143         const char *fmt;
144
145         fmt = lp_parm_const_string(SNUM(handle->conn), "shadow",
146                                    "format", SHADOW_COPY2_DEFAULT_FORMAT);
147
148         ZERO_STRUCT(timestamp);
149         if (strptime(name, fmt, &timestamp) == NULL) {
150                 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: no match %s: %s\n",
151                            fmt, name));
152                 return NULL;
153         }
154
155         DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n", fmt, name));
156         if (lp_parm_bool(SNUM(handle->conn), "shadow", "localtime",
157                          SHADOW_COPY2_DEFAULT_LOCALTIME))
158         {
159                 timestamp.tm_isdst = -1;
160                 timestamp_t = mktime(&timestamp);
161                 gmtime_r(&timestamp_t, &timestamp);
162         }
163         strftime(gmt, sizeof(gmt), SHADOW_COPY2_GMT_FORMAT, &timestamp);
164
165         return talloc_strdup(mem_ctx, gmt);
166 }
167
168 /*
169   shadow copy paths can also come into the server in this form:
170
171     /foo/bar/@GMT-XXXXX/some/file
172
173   This function normalises the filename to be of the form:
174
175     @GMT-XXXX/foo/bar/some/file
176  */
177 static const char *shadow_copy2_normalise_path(TALLOC_CTX *mem_ctx, const char *path, const char *gmt_start)
178 {
179         char *pcopy;
180         char buf[GMT_NAME_LEN];
181         size_t prefix_len;
182
183         if (path == gmt_start) {
184                 return path;
185         }
186
187         prefix_len = gmt_start - path - 1;
188
189         DEBUG(10, ("path=%s, gmt_start=%s, prefix_len=%d\n", path, gmt_start,
190                    (int)prefix_len));
191
192         /*
193          * We've got a/b/c/@GMT-YYYY.MM.DD-HH.MM.SS/d/e. convert to
194          * @GMT-YYYY.MM.DD-HH.MM.SS/a/b/c/d/e before further
195          * processing. As many VFS calls provide a const char *,
196          * unfortunately we have to make a copy.
197          */
198
199         pcopy = talloc_strdup(talloc_tos(), path);
200         if (pcopy == NULL) {
201                 return NULL;
202         }
203
204         gmt_start = pcopy + prefix_len;
205
206         /*
207          * Copy away "@GMT-YYYY.MM.DD-HH.MM.SS"
208          */
209         memcpy(buf, gmt_start+1, GMT_NAME_LEN);
210
211         /*
212          * Make space for it including a trailing /
213          */
214         memmove(pcopy + GMT_NAME_LEN + 1, pcopy, prefix_len);
215
216         /*
217          * Move in "@GMT-YYYY.MM.DD-HH.MM.SS/" at the beginning again
218          */
219         memcpy(pcopy, buf, GMT_NAME_LEN);
220         pcopy[GMT_NAME_LEN] = '/';
221
222         DEBUG(10, ("shadow_copy2_normalise_path: %s -> %s\n", path, pcopy));
223
224         return pcopy;
225 }
226
227 /*
228   convert a name to the shadow directory
229  */
230
231 #define _SHADOW2_NEXT(op, args, rtype, eret, extra) do { \
232         const char *name = fname; \
233         const char *gmt_start; \
234         if (shadow_copy2_match_name(fname, &gmt_start)) {       \
235                 char *name2; \
236                 rtype ret; \
237                 name2 = convert_shadow2_name(handle, fname, gmt_start); \
238                 if (name2 == NULL) { \
239                         errno = EINVAL; \
240                         return eret; \
241                 } \
242                 name = name2; \
243                 ret = SMB_VFS_NEXT_ ## op args; \
244                 talloc_free(name2); \
245                 if (ret != eret) extra; \
246                 return ret; \
247         } else { \
248                 return SMB_VFS_NEXT_ ## op args; \
249         } \
250 } while (0)
251
252 #define _SHADOW2_NEXT_SMB_FNAME(op, args, rtype, eret, extra) do { \
253                 const char *gmt_start; \
254                 if (shadow_copy2_match_name(smb_fname->base_name, &gmt_start)) {        \
255                 char *name2; \
256                 char *smb_base_name_tmp = NULL; \
257                 rtype ret; \
258                 name2 = convert_shadow2_name(handle, smb_fname->base_name, gmt_start); \
259                 if (name2 == NULL) { \
260                         errno = EINVAL; \
261                         return eret; \
262                 } \
263                 smb_base_name_tmp = smb_fname->base_name; \
264                 smb_fname->base_name = name2; \
265                 ret = SMB_VFS_NEXT_ ## op args; \
266                 smb_fname->base_name = smb_base_name_tmp; \
267                 talloc_free(name2); \
268                 if (ret != eret) extra; \
269                 return ret; \
270         } else { \
271                 return SMB_VFS_NEXT_ ## op args; \
272         } \
273 } while (0)
274
275 /*
276   convert a name to the shadow directory: NTSTATUS-specific handling
277  */
278
279 #define _SHADOW2_NTSTATUS_NEXT(op, args, eret, extra) do { \
280         const char *name = fname; \
281         const char *gmt_start; \
282         if (shadow_copy2_match_name(fname, &gmt_start)) {       \
283                 char *name2; \
284                 NTSTATUS ret; \
285                 name2 = convert_shadow2_name(handle, fname, gmt_start); \
286                 if (name2 == NULL) { \
287                         errno = EINVAL; \
288                         return eret; \
289                 } \
290                 name = name2; \
291                 ret = SMB_VFS_NEXT_ ## op args; \
292                 talloc_free(name2); \
293                 if (!NT_STATUS_EQUAL(ret, eret)) extra; \
294                 return ret; \
295         } else { \
296                 return SMB_VFS_NEXT_ ## op args; \
297         } \
298 } while (0)
299
300 #define SHADOW2_NTSTATUS_NEXT(op, args, eret) _SHADOW2_NTSTATUS_NEXT(op, args, eret, )
301
302 #define SHADOW2_NEXT(op, args, rtype, eret) _SHADOW2_NEXT(op, args, rtype, eret, )
303
304 #define SHADOW2_NEXT_SMB_FNAME(op, args, rtype, eret) _SHADOW2_NEXT_SMB_FNAME(op, args, rtype, eret, )
305
306 #define SHADOW2_NEXT2(op, args) do { \
307         const char *gmt_start1, *gmt_start2; \
308         if (shadow_copy2_match_name(oldname, &gmt_start1) || \
309             shadow_copy2_match_name(newname, &gmt_start2)) {    \
310                 errno = EROFS; \
311                 return -1; \
312         } else { \
313                 return SMB_VFS_NEXT_ ## op args; \
314         } \
315 } while (0)
316
317 #define SHADOW2_NEXT2_SMB_FNAME(op, args) do { \
318         const char *gmt_start1, *gmt_start2; \
319         if (shadow_copy2_match_name(smb_fname_src->base_name, &gmt_start1) || \
320             shadow_copy2_match_name(smb_fname_dst->base_name, &gmt_start2)) { \
321                 errno = EROFS; \
322                 return -1; \
323         } else { \
324                 return SMB_VFS_NEXT_ ## op args; \
325         } \
326 } while (0)
327
328
329 /*
330   find the mount point of a filesystem
331  */
332 static char *find_mount_point(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle)
333 {
334         char *path = talloc_strdup(mem_ctx, handle->conn->connectpath);
335         dev_t dev;
336         struct stat st;
337         char *p;
338
339         if (stat(path, &st) != 0) {
340                 talloc_free(path);
341                 return NULL;
342         }
343
344         dev = st.st_dev;
345
346         while ((p = strrchr(path, '/')) && p > path) {
347                 *p = 0;
348                 if (stat(path, &st) != 0) {
349                         talloc_free(path);
350                         return NULL;
351                 }
352                 if (st.st_dev != dev) {
353                         *p = '/';
354                         break;
355                 }
356         }
357
358         return path;    
359 }
360
361 /*
362   work out the location of the snapshot for this share
363  */
364 static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle)
365 {
366         const char *snapdir;
367         char *mount_point;
368         const char *ret;
369
370         snapdir = lp_parm_const_string(SNUM(handle->conn), "shadow", "snapdir", NULL);
371         if (snapdir == NULL) {
372                 return NULL;
373         }
374         /* if its an absolute path, we're done */
375         if (*snapdir == '/') {
376                 return snapdir;
377         }
378
379         /* other its relative to the filesystem mount point */
380         mount_point = find_mount_point(mem_ctx, handle);
381         if (mount_point == NULL) {
382                 return NULL;
383         }
384
385         ret = talloc_asprintf(mem_ctx, "%s/%s", mount_point, snapdir);
386         talloc_free(mount_point);
387         return ret;
388 }
389
390 /*
391   work out the location of the base directory for snapshots of this share
392  */
393 static const char *shadow_copy2_find_basedir(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle)
394 {
395         const char *basedir = lp_parm_const_string(SNUM(handle->conn), "shadow", "basedir", NULL);
396
397         /* other its the filesystem mount point */
398         if (basedir == NULL) {
399                 basedir = find_mount_point(mem_ctx, handle);
400         }
401
402         return basedir;
403 }
404
405 /*
406   convert a filename from a share relative path, to a path in the
407   snapshot directory
408  */
409 static char *convert_shadow2_name(vfs_handle_struct *handle, const char *fname, const char *gmt_path)
410 {
411         TALLOC_CTX *tmp_ctx = talloc_new(handle->data);
412         const char *snapdir, *relpath, *baseoffset, *basedir;
413         size_t baselen;
414         char *ret, *prefix;
415
416         struct tm timestamp;
417         time_t timestamp_t;
418         char snapshot[MAXPATHLEN];
419         const char *fmt;
420
421         fmt = lp_parm_const_string(SNUM(handle->conn), "shadow",
422                                    "format", SHADOW_COPY2_DEFAULT_FORMAT);
423
424         snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle);
425         if (snapdir == NULL) {
426                 DEBUG(2,("no snapdir found for share at %s\n", handle->conn->connectpath));
427                 talloc_free(tmp_ctx);
428                 return NULL;
429         }
430
431         basedir = shadow_copy2_find_basedir(tmp_ctx, handle);
432         if (basedir == NULL) {
433                 DEBUG(2,("no basedir found for share at %s\n", handle->conn->connectpath));
434                 talloc_free(tmp_ctx);
435                 return NULL;
436         }
437
438         prefix = talloc_asprintf(tmp_ctx, "%s/@GMT-", snapdir);
439         if (strncmp(fname, prefix, (talloc_get_size(prefix)-1)) == 0) {
440                 /* this looks like as we have already normalized it, leave it untouched*/
441                 talloc_free(tmp_ctx);
442                 return talloc_strdup(handle->data, fname);
443         }
444
445         if (strncmp(fname, "@GMT-", 5) != 0) {
446                 fname = shadow_copy2_normalise_path(tmp_ctx, fname, gmt_path);
447                 if (fname == NULL) {
448                         talloc_free(tmp_ctx);
449                         return NULL;
450                 }
451         }
452
453         ZERO_STRUCT(timestamp);
454         relpath = strptime(fname, SHADOW_COPY2_GMT_FORMAT, &timestamp);
455         if (relpath == NULL) {
456                 talloc_free(tmp_ctx);
457                 return NULL;
458         }
459
460         /* relpath is the remaining portion of the path after the @GMT-xxx */
461
462         if (lp_parm_bool(SNUM(handle->conn), "shadow", "localtime",
463                          SHADOW_COPY2_DEFAULT_LOCALTIME))
464         {
465                 timestamp_t = timegm(&timestamp);
466                 localtime_r(&timestamp_t, &timestamp);
467         }
468
469         strftime(snapshot, MAXPATHLEN, fmt, &timestamp);
470
471         baselen = strlen(basedir);
472         baseoffset = handle->conn->connectpath + baselen;
473
474         /* some sanity checks */
475         if (strncmp(basedir, handle->conn->connectpath, baselen) != 0 ||
476             (handle->conn->connectpath[baselen] != 0 && handle->conn->connectpath[baselen] != '/')) {
477                 DEBUG(0,("convert_shadow2_name: basedir %s is not a parent of %s\n",
478                          basedir, handle->conn->connectpath));
479                 talloc_free(tmp_ctx);
480                 return NULL;
481         }
482
483         if (*relpath == '/') relpath++;
484         if (*baseoffset == '/') baseoffset++;
485
486         ret = talloc_asprintf(handle->data, "%s/%s/%s/%s",
487                               snapdir, 
488                               snapshot,
489                               baseoffset, 
490                               relpath);
491         DEBUG(6,("convert_shadow2_name: '%s' -> '%s'\n", fname, ret));
492         talloc_free(tmp_ctx);
493         return ret;
494 }
495
496
497 /*
498   simple string hash
499  */
500 static uint32 string_hash(const char *s)
501 {
502         uint32 n = 0;
503         while (*s) {
504                 n = ((n << 5) + n) ^ (uint32)(*s++);
505         }
506         return n;
507 }
508
509 /*
510   modify a sbuf return to ensure that inodes in the shadow directory
511   are different from those in the main directory
512  */
513 static void convert_sbuf(vfs_handle_struct *handle, const char *fname, SMB_STRUCT_STAT *sbuf)
514 {
515         if (lp_parm_bool(SNUM(handle->conn), "shadow", "fixinodes", False)) {           
516                 /* some snapshot systems, like GPFS, return the name
517                    device:inode for the snapshot files as the current
518                    files. That breaks the 'restore' button in the shadow copy
519                    GUI, as the client gets a sharing violation.
520
521                    This is a crude way of allowing both files to be
522                    open at once. It has a slight chance of inode
523                    number collision, but I can't see a better approach
524                    without significant VFS changes
525                 */
526                 uint32_t shash = string_hash(fname) & 0xFF000000;
527                 if (shash == 0) {
528                         shash = 1;
529                 }
530                 sbuf->st_ex_ino ^= shash;
531         }
532 }
533
534 static int shadow_copy2_rename(vfs_handle_struct *handle,
535                                const struct smb_filename *smb_fname_src,
536                                const struct smb_filename *smb_fname_dst)
537 {
538         SHADOW2_NEXT2_SMB_FNAME(RENAME,
539                                 (handle, smb_fname_src, smb_fname_dst));
540 }
541
542 static int shadow_copy2_symlink(vfs_handle_struct *handle,
543                                 const char *oldname, const char *newname)
544 {
545         SHADOW2_NEXT2(SYMLINK, (handle, oldname, newname));
546 }
547
548 static int shadow_copy2_link(vfs_handle_struct *handle,
549                           const char *oldname, const char *newname)
550 {
551         SHADOW2_NEXT2(LINK, (handle, oldname, newname));
552 }
553
554 static int shadow_copy2_open(vfs_handle_struct *handle,
555                              struct smb_filename *smb_fname, files_struct *fsp,
556                              int flags, mode_t mode)
557 {
558         SHADOW2_NEXT_SMB_FNAME(OPEN,
559                                (handle, smb_fname, fsp, flags, mode),
560                                int, -1);
561 }
562
563 static SMB_STRUCT_DIR *shadow_copy2_opendir(vfs_handle_struct *handle,
564                           const char *fname, const char *mask, uint32 attr)
565 {
566         SHADOW2_NEXT(OPENDIR, (handle, name, mask, attr), SMB_STRUCT_DIR *, NULL);
567 }
568
569 static int shadow_copy2_stat(vfs_handle_struct *handle,
570                              struct smb_filename *smb_fname)
571 {
572         _SHADOW2_NEXT_SMB_FNAME(STAT, (handle, smb_fname), int, -1,
573                                 convert_sbuf(handle, smb_fname->base_name,
574                                              &smb_fname->st));
575 }
576
577 static int shadow_copy2_lstat(vfs_handle_struct *handle,
578                               struct smb_filename *smb_fname)
579 {
580         _SHADOW2_NEXT_SMB_FNAME(LSTAT, (handle, smb_fname), int, -1,
581                                 convert_sbuf(handle, smb_fname->base_name,
582                                              &smb_fname->st));
583 }
584
585 static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
586 {
587         int ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
588         if (ret == 0 && shadow_copy2_match_name(fsp->fsp_name->base_name, NULL)) {
589                 convert_sbuf(handle, fsp->fsp_name->base_name, sbuf);
590         }
591         return ret;
592 }
593
594 static int shadow_copy2_unlink(vfs_handle_struct *handle,
595                                const struct smb_filename *smb_fname_in)
596 {
597         struct smb_filename *smb_fname = NULL;
598         NTSTATUS status;
599
600         status = copy_smb_filename(talloc_tos(), smb_fname_in, &smb_fname);
601         if (!NT_STATUS_IS_OK(status)) {
602                 errno = map_errno_from_nt_status(status);
603                 return -1;
604         }
605
606         SHADOW2_NEXT_SMB_FNAME(UNLINK, (handle, smb_fname), int, -1);
607 }
608
609 static int shadow_copy2_chmod(vfs_handle_struct *handle,
610                        const char *fname, mode_t mode)
611 {
612         SHADOW2_NEXT(CHMOD, (handle, name, mode), int, -1);
613 }
614
615 static int shadow_copy2_chown(vfs_handle_struct *handle,
616                        const char *fname, uid_t uid, gid_t gid)
617 {
618         SHADOW2_NEXT(CHOWN, (handle, name, uid, gid), int, -1);
619 }
620
621 static int shadow_copy2_chdir(vfs_handle_struct *handle,
622                        const char *fname)
623 {
624         SHADOW2_NEXT(CHDIR, (handle, name), int, -1);
625 }
626
627 static int shadow_copy2_ntimes(vfs_handle_struct *handle,
628                                const struct smb_filename *smb_fname_in,
629                                struct smb_file_time *ft)
630 {
631         struct smb_filename *smb_fname = NULL;
632         NTSTATUS status;
633
634         status = copy_smb_filename(talloc_tos(), smb_fname_in, &smb_fname);
635         if (!NT_STATUS_IS_OK(status)) {
636                 errno = map_errno_from_nt_status(status);
637                 return -1;
638         }
639
640         SHADOW2_NEXT_SMB_FNAME(NTIMES, (handle, smb_fname, ft), int, -1);
641 }
642
643 static int shadow_copy2_readlink(vfs_handle_struct *handle,
644                                  const char *fname, char *buf, size_t bufsiz)
645 {
646         SHADOW2_NEXT(READLINK, (handle, name, buf, bufsiz), int, -1);
647 }
648
649 static int shadow_copy2_mknod(vfs_handle_struct *handle,
650                        const char *fname, mode_t mode, SMB_DEV_T dev)
651 {
652         SHADOW2_NEXT(MKNOD, (handle, name, mode, dev), int, -1);
653 }
654
655 static char *shadow_copy2_realpath(vfs_handle_struct *handle,
656                             const char *fname, char *resolved_path)
657 {
658         const char *gmt;
659
660         if (shadow_copy2_match_name(fname, &gmt)
661             && (gmt[GMT_NAME_LEN] == '\0')) {
662                 char *copy;
663
664                 copy = talloc_strdup(talloc_tos(), fname);
665                 if (copy == NULL) {
666                         errno = ENOMEM;
667                         return NULL;
668                 }
669
670                 copy[gmt - fname] = '.';
671                 copy[gmt - fname + 1] = '\0';
672
673                 DEBUG(10, ("calling NEXT_REALPATH with %s\n", copy));
674                 SHADOW2_NEXT(REALPATH, (handle, name, resolved_path), char *,
675                              NULL);
676         }
677         SHADOW2_NEXT(REALPATH, (handle, name, resolved_path), char *, NULL);
678 }
679
680 static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle,
681                                             const char *fname)
682 {
683         TALLOC_CTX *tmp_ctx = talloc_stackframe();
684         const char *snapdir, *baseoffset, *basedir, *gmt_start;
685         size_t baselen;
686         char *ret;
687
688         DEBUG(10, ("shadow_copy2_connectpath called with %s\n", fname));
689
690         if (!shadow_copy2_match_name(fname, &gmt_start)) {
691                 return handle->conn->connectpath;
692         }
693
694         fname = shadow_copy2_normalise_path(talloc_tos(), fname, gmt_start);
695         if (fname == NULL) {
696                 TALLOC_FREE(tmp_ctx);
697                 return NULL;
698         }
699
700         snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle);
701         if (snapdir == NULL) {
702                 DEBUG(2,("no snapdir found for share at %s\n",
703                          handle->conn->connectpath));
704                 TALLOC_FREE(tmp_ctx);
705                 return NULL;
706         }
707
708         basedir = shadow_copy2_find_basedir(tmp_ctx, handle);
709         if (basedir == NULL) {
710                 DEBUG(2,("no basedir found for share at %s\n",
711                          handle->conn->connectpath));
712                 TALLOC_FREE(tmp_ctx);
713                 return NULL;
714         }
715
716         baselen = strlen(basedir);
717         baseoffset = handle->conn->connectpath + baselen;
718
719         /* some sanity checks */
720         if (strncmp(basedir, handle->conn->connectpath, baselen) != 0 ||
721             (handle->conn->connectpath[baselen] != 0
722              && handle->conn->connectpath[baselen] != '/')) {
723                 DEBUG(0,("shadow_copy2_connectpath: basedir %s is not a "
724                          "parent of %s\n", basedir,
725                          handle->conn->connectpath));
726                 TALLOC_FREE(tmp_ctx);
727                 return NULL;
728         }
729
730         if (*baseoffset == '/') baseoffset++;
731
732         ret = talloc_asprintf(talloc_tos(), "%s/%.*s/%s",
733                               snapdir,
734                               GMT_NAME_LEN, fname,
735                               baseoffset);
736         DEBUG(6,("shadow_copy2_connectpath: '%s' -> '%s'\n", fname, ret));
737         TALLOC_FREE(tmp_ctx);
738         return ret;
739 }
740
741 static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle,
742                                const char *fname, uint32 security_info,
743                                struct security_descriptor **ppdesc)
744 {
745         SHADOW2_NTSTATUS_NEXT(GET_NT_ACL, (handle, name, security_info, ppdesc), NT_STATUS_ACCESS_DENIED);
746 }
747
748 static int shadow_copy2_mkdir(vfs_handle_struct *handle,  const char *fname, mode_t mode)
749 {
750         SHADOW2_NEXT(MKDIR, (handle, name, mode), int, -1);
751 }
752
753 static int shadow_copy2_rmdir(vfs_handle_struct *handle,  const char *fname)
754 {
755         SHADOW2_NEXT(RMDIR, (handle, name), int, -1);
756 }
757
758 static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname,
759                                 unsigned int flags)
760 {
761         SHADOW2_NEXT(CHFLAGS, (handle, name, flags), int, -1);
762 }
763
764 static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
765                                   const char *fname, const char *aname, void *value, size_t size)
766 {
767         SHADOW2_NEXT(GETXATTR, (handle, name, aname, value, size), ssize_t, -1);
768 }
769
770 static ssize_t shadow_copy2_lgetxattr(vfs_handle_struct *handle,
771                                       const char *fname, const char *aname, void *value, size_t size)
772 {
773         SHADOW2_NEXT(LGETXATTR, (handle, name, aname, value, size), ssize_t, -1);
774 }
775
776 static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle, const char *fname, 
777                                       char *list, size_t size)
778 {
779         SHADOW2_NEXT(LISTXATTR, (handle, name, list, size), ssize_t, -1);
780 }
781
782 static int shadow_copy2_removexattr(struct vfs_handle_struct *handle, const char *fname, 
783                                     const char *aname)
784 {
785         SHADOW2_NEXT(REMOVEXATTR, (handle, name, aname), int, -1);
786 }
787
788 static int shadow_copy2_lremovexattr(struct vfs_handle_struct *handle, const char *fname, 
789                                      const char *aname)
790 {
791         SHADOW2_NEXT(LREMOVEXATTR, (handle, name, aname), int, -1);
792 }
793
794 static int shadow_copy2_setxattr(struct vfs_handle_struct *handle, const char *fname, 
795                                  const char *aname, const void *value, size_t size, int flags)
796 {
797         SHADOW2_NEXT(SETXATTR, (handle, name, aname, value, size, flags), int, -1);
798 }
799
800 static int shadow_copy2_lsetxattr(struct vfs_handle_struct *handle, const char *fname, 
801                                   const char *aname, const void *value, size_t size, int flags)
802 {
803         SHADOW2_NEXT(LSETXATTR, (handle, name, aname, value, size, flags), int, -1);
804 }
805
806 static int shadow_copy2_chmod_acl(vfs_handle_struct *handle,
807                            const char *fname, mode_t mode)
808 {
809         SHADOW2_NEXT(CHMOD_ACL, (handle, name, mode), int, -1);
810 }
811
812 static int shadow_copy2_label_cmp_asc(const void *x, const void *y)
813 {
814         return strncmp((char *)x, (char *)y, sizeof(SHADOW_COPY_LABEL));
815 }
816
817 static int shadow_copy2_label_cmp_desc(const void *x, const void *y)
818 {
819         return -strncmp((char *)x, (char *)y, sizeof(SHADOW_COPY_LABEL));
820 }
821
822 /*
823   sort the shadow copy data in ascending or descending order
824  */
825 static void shadow_copy2_sort_data(vfs_handle_struct *handle,
826                                    SHADOW_COPY_DATA *shadow_copy2_data)
827 {
828         int (*cmpfunc)(const void *, const void *);
829         const char *sort;
830
831         sort = lp_parm_const_string(SNUM(handle->conn), "shadow",
832                                     "sort", SHADOW_COPY2_DEFAULT_SORT);
833         if (sort == NULL) {
834                 return;
835         }
836
837         if (strcmp(sort, "asc") == 0) {
838                 cmpfunc = shadow_copy2_label_cmp_asc;
839         } else if (strcmp(sort, "desc") == 0) {
840                 cmpfunc = shadow_copy2_label_cmp_desc;
841         } else {
842                 return;
843         }
844
845         if (shadow_copy2_data && shadow_copy2_data->num_volumes > 0 &&
846             shadow_copy2_data->labels)
847         {
848                 TYPESAFE_QSORT(shadow_copy2_data->labels,
849                                shadow_copy2_data->num_volumes,
850                                cmpfunc);
851         }
852
853         return;
854 }
855
856 static int shadow_copy2_get_shadow_copy2_data(vfs_handle_struct *handle, 
857                                               files_struct *fsp, 
858                                               SHADOW_COPY_DATA *shadow_copy2_data, 
859                                               bool labels)
860 {
861         SMB_STRUCT_DIR *p;
862         const char *snapdir;
863         SMB_STRUCT_DIRENT *d;
864         TALLOC_CTX *tmp_ctx = talloc_new(handle->data);
865         char *snapshot;
866
867         snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle);
868         if (snapdir == NULL) {
869                 DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
870                          handle->conn->connectpath));
871                 errno = EINVAL;
872                 talloc_free(tmp_ctx);
873                 return -1;
874         }
875
876         p = SMB_VFS_NEXT_OPENDIR(handle, snapdir, NULL, 0);
877
878         if (!p) {
879                 DEBUG(2,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s'"
880                          " - %s\n", snapdir, strerror(errno)));
881                 talloc_free(tmp_ctx);
882                 errno = ENOSYS;
883                 return -1;
884         }
885
886         shadow_copy2_data->num_volumes = 0;
887         shadow_copy2_data->labels      = NULL;
888
889         while ((d = SMB_VFS_NEXT_READDIR(handle, p, NULL))) {
890                 SHADOW_COPY_LABEL *tlabels;
891
892                 /* ignore names not of the right form in the snapshot directory */
893                 snapshot = shadow_copy2_snapshot_to_gmt(tmp_ctx, handle,
894                                                         d->d_name);
895                 DEBUG(6,("shadow_copy2_get_shadow_copy2_data: %s -> %s\n",
896                          d->d_name, snapshot));
897                 if (!snapshot) {
898                         continue;
899                 }
900
901                 if (!labels) {
902                         /* the caller doesn't want the labels */
903                         shadow_copy2_data->num_volumes++;
904                         continue;
905                 }
906
907                 tlabels = talloc_realloc(shadow_copy2_data->mem_ctx,
908                                          shadow_copy2_data->labels,
909                                          SHADOW_COPY_LABEL, shadow_copy2_data->num_volumes+1);
910                 if (tlabels == NULL) {
911                         DEBUG(0,("shadow_copy2: out of memory\n"));
912                         SMB_VFS_NEXT_CLOSEDIR(handle, p);
913                         talloc_free(tmp_ctx);
914                         return -1;
915                 }
916
917                 strlcpy(tlabels[shadow_copy2_data->num_volumes], snapshot,
918                         sizeof(*tlabels));
919                 talloc_free(snapshot);
920
921                 shadow_copy2_data->num_volumes++;
922                 shadow_copy2_data->labels = tlabels;
923         }
924
925         SMB_VFS_NEXT_CLOSEDIR(handle,p);
926
927         shadow_copy2_sort_data(handle, shadow_copy2_data);
928
929         talloc_free(tmp_ctx);
930         return 0;
931 }
932
933 static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
934         .opendir = shadow_copy2_opendir,
935         .mkdir = shadow_copy2_mkdir,
936         .rmdir = shadow_copy2_rmdir,
937         .chflags = shadow_copy2_chflags,
938         .getxattr = shadow_copy2_getxattr,
939         .lgetxattr = shadow_copy2_lgetxattr,
940         .listxattr = shadow_copy2_listxattr,
941         .removexattr = shadow_copy2_removexattr,
942         .lremovexattr = shadow_copy2_lremovexattr,
943         .setxattr = shadow_copy2_setxattr,
944         .lsetxattr = shadow_copy2_lsetxattr,
945         .open = shadow_copy2_open,
946         .rename = shadow_copy2_rename,
947         .stat = shadow_copy2_stat,
948         .lstat = shadow_copy2_lstat,
949         .fstat = shadow_copy2_fstat,
950         .unlink = shadow_copy2_unlink,
951         .chmod = shadow_copy2_chmod,
952         .chown = shadow_copy2_chown,
953         .chdir = shadow_copy2_chdir,
954         .ntimes = shadow_copy2_ntimes,
955         .symlink = shadow_copy2_symlink,
956         .vfs_readlink = shadow_copy2_readlink,
957         .link = shadow_copy2_link,
958         .mknod = shadow_copy2_mknod,
959         .realpath = shadow_copy2_realpath,
960         .connectpath = shadow_copy2_connectpath,
961         .get_nt_acl = shadow_copy2_get_nt_acl,
962         .chmod_acl = shadow_copy2_chmod_acl,
963         .get_shadow_copy_data = shadow_copy2_get_shadow_copy2_data,
964 };
965
966 NTSTATUS vfs_shadow_copy2_init(void);
967 NTSTATUS vfs_shadow_copy2_init(void)
968 {
969         NTSTATUS ret;
970
971         ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "shadow_copy2",
972                                &vfs_shadow_copy2_fns);
973
974         if (!NT_STATUS_IS_OK(ret))
975                 return ret;
976
977         vfs_shadow_copy2_debug_level = debug_add_class("shadow_copy2");
978         if (vfs_shadow_copy2_debug_level == -1) {
979                 vfs_shadow_copy2_debug_level = DBGC_VFS;
980                 DEBUG(0, ("%s: Couldn't register custom debugging class!\n",
981                         "vfs_shadow_copy2_init"));
982         } else {
983                 DEBUG(10, ("%s: Debug class number of '%s': %d\n", 
984                         "vfs_shadow_copy2_init","shadow_copy2",vfs_shadow_copy2_debug_level));
985         }
986
987         return ret;
988 }