smbd: Remove unused [push_pull]_file_id_24
[samba.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         if (shadow_copy2_match_name(smb_fname_src->base_name, NULL)) {
539                 errno = EXDEV;
540                 return -1;
541         }
542         SHADOW2_NEXT2_SMB_FNAME(RENAME,
543                                 (handle, smb_fname_src, smb_fname_dst));
544 }
545
546 static int shadow_copy2_symlink(vfs_handle_struct *handle,
547                                 const char *oldname, const char *newname)
548 {
549         SHADOW2_NEXT2(SYMLINK, (handle, oldname, newname));
550 }
551
552 static int shadow_copy2_link(vfs_handle_struct *handle,
553                           const char *oldname, const char *newname)
554 {
555         SHADOW2_NEXT2(LINK, (handle, oldname, newname));
556 }
557
558 static int shadow_copy2_open(vfs_handle_struct *handle,
559                              struct smb_filename *smb_fname, files_struct *fsp,
560                              int flags, mode_t mode)
561 {
562         SHADOW2_NEXT_SMB_FNAME(OPEN,
563                                (handle, smb_fname, fsp, flags, mode),
564                                int, -1);
565 }
566
567 static SMB_STRUCT_DIR *shadow_copy2_opendir(vfs_handle_struct *handle,
568                           const char *fname, const char *mask, uint32 attr)
569 {
570         SHADOW2_NEXT(OPENDIR, (handle, name, mask, attr), SMB_STRUCT_DIR *, NULL);
571 }
572
573 static int shadow_copy2_stat(vfs_handle_struct *handle,
574                              struct smb_filename *smb_fname)
575 {
576         _SHADOW2_NEXT_SMB_FNAME(STAT, (handle, smb_fname), int, -1,
577                                 convert_sbuf(handle, smb_fname->base_name,
578                                              &smb_fname->st));
579 }
580
581 static int shadow_copy2_lstat(vfs_handle_struct *handle,
582                               struct smb_filename *smb_fname)
583 {
584         _SHADOW2_NEXT_SMB_FNAME(LSTAT, (handle, smb_fname), int, -1,
585                                 convert_sbuf(handle, smb_fname->base_name,
586                                              &smb_fname->st));
587 }
588
589 static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
590 {
591         int ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
592         if (ret == 0 && shadow_copy2_match_name(fsp->fsp_name->base_name, NULL)) {
593                 convert_sbuf(handle, fsp->fsp_name->base_name, sbuf);
594         }
595         return ret;
596 }
597
598 static int shadow_copy2_unlink(vfs_handle_struct *handle,
599                                const struct smb_filename *smb_fname_in)
600 {
601         struct smb_filename *smb_fname = NULL;
602         NTSTATUS status;
603
604         status = copy_smb_filename(talloc_tos(), smb_fname_in, &smb_fname);
605         if (!NT_STATUS_IS_OK(status)) {
606                 errno = map_errno_from_nt_status(status);
607                 return -1;
608         }
609
610         SHADOW2_NEXT_SMB_FNAME(UNLINK, (handle, smb_fname), int, -1);
611 }
612
613 static int shadow_copy2_chmod(vfs_handle_struct *handle,
614                        const char *fname, mode_t mode)
615 {
616         SHADOW2_NEXT(CHMOD, (handle, name, mode), int, -1);
617 }
618
619 static int shadow_copy2_chown(vfs_handle_struct *handle,
620                        const char *fname, uid_t uid, gid_t gid)
621 {
622         SHADOW2_NEXT(CHOWN, (handle, name, uid, gid), int, -1);
623 }
624
625 static int shadow_copy2_chdir(vfs_handle_struct *handle,
626                        const char *fname)
627 {
628         SHADOW2_NEXT(CHDIR, (handle, name), int, -1);
629 }
630
631 static int shadow_copy2_ntimes(vfs_handle_struct *handle,
632                                const struct smb_filename *smb_fname_in,
633                                struct smb_file_time *ft)
634 {
635         struct smb_filename *smb_fname = NULL;
636         NTSTATUS status;
637
638         status = copy_smb_filename(talloc_tos(), smb_fname_in, &smb_fname);
639         if (!NT_STATUS_IS_OK(status)) {
640                 errno = map_errno_from_nt_status(status);
641                 return -1;
642         }
643
644         SHADOW2_NEXT_SMB_FNAME(NTIMES, (handle, smb_fname, ft), int, -1);
645 }
646
647 static int shadow_copy2_readlink(vfs_handle_struct *handle,
648                                  const char *fname, char *buf, size_t bufsiz)
649 {
650         SHADOW2_NEXT(READLINK, (handle, name, buf, bufsiz), int, -1);
651 }
652
653 static int shadow_copy2_mknod(vfs_handle_struct *handle,
654                        const char *fname, mode_t mode, SMB_DEV_T dev)
655 {
656         SHADOW2_NEXT(MKNOD, (handle, name, mode, dev), int, -1);
657 }
658
659 static char *shadow_copy2_realpath(vfs_handle_struct *handle,
660                             const char *fname)
661 {
662         const char *gmt;
663
664         if (shadow_copy2_match_name(fname, &gmt)
665             && (gmt[GMT_NAME_LEN] == '\0')) {
666                 char *copy;
667
668                 copy = talloc_strdup(talloc_tos(), fname);
669                 if (copy == NULL) {
670                         errno = ENOMEM;
671                         return NULL;
672                 }
673
674                 copy[gmt - fname] = '.';
675                 copy[gmt - fname + 1] = '\0';
676
677                 DEBUG(10, ("calling NEXT_REALPATH with %s\n", copy));
678                 SHADOW2_NEXT(REALPATH, (handle, fname), char *,
679                              NULL);
680         }
681         SHADOW2_NEXT(REALPATH, (handle, name), char *, NULL);
682 }
683
684 static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle,
685                                             const char *fname)
686 {
687         TALLOC_CTX *tmp_ctx = talloc_stackframe();
688         const char *snapdir, *baseoffset, *basedir, *gmt_start;
689         size_t baselen;
690         char *ret;
691
692         DEBUG(10, ("shadow_copy2_connectpath called with %s\n", fname));
693
694         if (!shadow_copy2_match_name(fname, &gmt_start)) {
695                 return handle->conn->connectpath;
696         }
697
698         fname = shadow_copy2_normalise_path(talloc_tos(), fname, gmt_start);
699         if (fname == NULL) {
700                 TALLOC_FREE(tmp_ctx);
701                 return NULL;
702         }
703
704         snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle);
705         if (snapdir == NULL) {
706                 DEBUG(2,("no snapdir found for share at %s\n",
707                          handle->conn->connectpath));
708                 TALLOC_FREE(tmp_ctx);
709                 return NULL;
710         }
711
712         basedir = shadow_copy2_find_basedir(tmp_ctx, handle);
713         if (basedir == NULL) {
714                 DEBUG(2,("no basedir found for share at %s\n",
715                          handle->conn->connectpath));
716                 TALLOC_FREE(tmp_ctx);
717                 return NULL;
718         }
719
720         baselen = strlen(basedir);
721         baseoffset = handle->conn->connectpath + baselen;
722
723         /* some sanity checks */
724         if (strncmp(basedir, handle->conn->connectpath, baselen) != 0 ||
725             (handle->conn->connectpath[baselen] != 0
726              && handle->conn->connectpath[baselen] != '/')) {
727                 DEBUG(0,("shadow_copy2_connectpath: basedir %s is not a "
728                          "parent of %s\n", basedir,
729                          handle->conn->connectpath));
730                 TALLOC_FREE(tmp_ctx);
731                 return NULL;
732         }
733
734         if (*baseoffset == '/') baseoffset++;
735
736         ret = talloc_asprintf(talloc_tos(), "%s/%.*s/%s",
737                               snapdir,
738                               GMT_NAME_LEN, fname,
739                               baseoffset);
740         DEBUG(6,("shadow_copy2_connectpath: '%s' -> '%s'\n", fname, ret));
741         TALLOC_FREE(tmp_ctx);
742         return ret;
743 }
744
745 static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle,
746                                const char *fname, uint32 security_info,
747                                struct security_descriptor **ppdesc)
748 {
749         SHADOW2_NTSTATUS_NEXT(GET_NT_ACL, (handle, name, security_info, ppdesc), NT_STATUS_ACCESS_DENIED);
750 }
751
752 static int shadow_copy2_mkdir(vfs_handle_struct *handle,  const char *fname, mode_t mode)
753 {
754         SHADOW2_NEXT(MKDIR, (handle, name, mode), int, -1);
755 }
756
757 static int shadow_copy2_rmdir(vfs_handle_struct *handle,  const char *fname)
758 {
759         SHADOW2_NEXT(RMDIR, (handle, name), int, -1);
760 }
761
762 static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname,
763                                 unsigned int flags)
764 {
765         SHADOW2_NEXT(CHFLAGS, (handle, name, flags), int, -1);
766 }
767
768 static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
769                                   const char *fname, const char *aname, void *value, size_t size)
770 {
771         SHADOW2_NEXT(GETXATTR, (handle, name, aname, value, size), ssize_t, -1);
772 }
773
774 static ssize_t shadow_copy2_lgetxattr(vfs_handle_struct *handle,
775                                       const char *fname, const char *aname, void *value, size_t size)
776 {
777         SHADOW2_NEXT(LGETXATTR, (handle, name, aname, value, size), ssize_t, -1);
778 }
779
780 static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle, const char *fname, 
781                                       char *list, size_t size)
782 {
783         SHADOW2_NEXT(LISTXATTR, (handle, name, list, size), ssize_t, -1);
784 }
785
786 static int shadow_copy2_removexattr(struct vfs_handle_struct *handle, const char *fname, 
787                                     const char *aname)
788 {
789         SHADOW2_NEXT(REMOVEXATTR, (handle, name, aname), int, -1);
790 }
791
792 static int shadow_copy2_lremovexattr(struct vfs_handle_struct *handle, const char *fname, 
793                                      const char *aname)
794 {
795         SHADOW2_NEXT(LREMOVEXATTR, (handle, name, aname), int, -1);
796 }
797
798 static int shadow_copy2_setxattr(struct vfs_handle_struct *handle, const char *fname, 
799                                  const char *aname, const void *value, size_t size, int flags)
800 {
801         SHADOW2_NEXT(SETXATTR, (handle, name, aname, value, size, flags), int, -1);
802 }
803
804 static int shadow_copy2_lsetxattr(struct vfs_handle_struct *handle, const char *fname, 
805                                   const char *aname, const void *value, size_t size, int flags)
806 {
807         SHADOW2_NEXT(LSETXATTR, (handle, name, aname, value, size, flags), int, -1);
808 }
809
810 static int shadow_copy2_chmod_acl(vfs_handle_struct *handle,
811                            const char *fname, mode_t mode)
812 {
813         SHADOW2_NEXT(CHMOD_ACL, (handle, name, mode), int, -1);
814 }
815
816 static int shadow_copy2_label_cmp_asc(const void *x, const void *y)
817 {
818         return strncmp((char *)x, (char *)y, sizeof(SHADOW_COPY_LABEL));
819 }
820
821 static int shadow_copy2_label_cmp_desc(const void *x, const void *y)
822 {
823         return -strncmp((char *)x, (char *)y, sizeof(SHADOW_COPY_LABEL));
824 }
825
826 /*
827   sort the shadow copy data in ascending or descending order
828  */
829 static void shadow_copy2_sort_data(vfs_handle_struct *handle,
830                                    SHADOW_COPY_DATA *shadow_copy2_data)
831 {
832         int (*cmpfunc)(const void *, const void *);
833         const char *sort;
834
835         sort = lp_parm_const_string(SNUM(handle->conn), "shadow",
836                                     "sort", SHADOW_COPY2_DEFAULT_SORT);
837         if (sort == NULL) {
838                 return;
839         }
840
841         if (strcmp(sort, "asc") == 0) {
842                 cmpfunc = shadow_copy2_label_cmp_asc;
843         } else if (strcmp(sort, "desc") == 0) {
844                 cmpfunc = shadow_copy2_label_cmp_desc;
845         } else {
846                 return;
847         }
848
849         if (shadow_copy2_data && shadow_copy2_data->num_volumes > 0 &&
850             shadow_copy2_data->labels)
851         {
852                 TYPESAFE_QSORT(shadow_copy2_data->labels,
853                                shadow_copy2_data->num_volumes,
854                                cmpfunc);
855         }
856
857         return;
858 }
859
860 static int shadow_copy2_get_shadow_copy2_data(vfs_handle_struct *handle, 
861                                               files_struct *fsp, 
862                                               SHADOW_COPY_DATA *shadow_copy2_data, 
863                                               bool labels)
864 {
865         SMB_STRUCT_DIR *p;
866         const char *snapdir;
867         SMB_STRUCT_DIRENT *d;
868         TALLOC_CTX *tmp_ctx = talloc_new(handle->data);
869         char *snapshot;
870
871         snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle);
872         if (snapdir == NULL) {
873                 DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
874                          handle->conn->connectpath));
875                 errno = EINVAL;
876                 talloc_free(tmp_ctx);
877                 return -1;
878         }
879
880         p = SMB_VFS_NEXT_OPENDIR(handle, snapdir, NULL, 0);
881
882         if (!p) {
883                 DEBUG(2,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s'"
884                          " - %s\n", snapdir, strerror(errno)));
885                 talloc_free(tmp_ctx);
886                 errno = ENOSYS;
887                 return -1;
888         }
889
890         shadow_copy2_data->num_volumes = 0;
891         shadow_copy2_data->labels      = NULL;
892
893         while ((d = SMB_VFS_NEXT_READDIR(handle, p, NULL))) {
894                 SHADOW_COPY_LABEL *tlabels;
895
896                 /* ignore names not of the right form in the snapshot directory */
897                 snapshot = shadow_copy2_snapshot_to_gmt(tmp_ctx, handle,
898                                                         d->d_name);
899                 DEBUG(6,("shadow_copy2_get_shadow_copy2_data: %s -> %s\n",
900                          d->d_name, snapshot));
901                 if (!snapshot) {
902                         continue;
903                 }
904
905                 if (!labels) {
906                         /* the caller doesn't want the labels */
907                         shadow_copy2_data->num_volumes++;
908                         continue;
909                 }
910
911                 tlabels = talloc_realloc(shadow_copy2_data->mem_ctx,
912                                          shadow_copy2_data->labels,
913                                          SHADOW_COPY_LABEL, shadow_copy2_data->num_volumes+1);
914                 if (tlabels == NULL) {
915                         DEBUG(0,("shadow_copy2: out of memory\n"));
916                         SMB_VFS_NEXT_CLOSEDIR(handle, p);
917                         talloc_free(tmp_ctx);
918                         return -1;
919                 }
920
921                 strlcpy(tlabels[shadow_copy2_data->num_volumes], snapshot,
922                         sizeof(*tlabels));
923                 talloc_free(snapshot);
924
925                 shadow_copy2_data->num_volumes++;
926                 shadow_copy2_data->labels = tlabels;
927         }
928
929         SMB_VFS_NEXT_CLOSEDIR(handle,p);
930
931         shadow_copy2_sort_data(handle, shadow_copy2_data);
932
933         talloc_free(tmp_ctx);
934         return 0;
935 }
936
937 static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
938         .opendir = shadow_copy2_opendir,
939         .mkdir = shadow_copy2_mkdir,
940         .rmdir = shadow_copy2_rmdir,
941         .chflags = shadow_copy2_chflags,
942         .getxattr = shadow_copy2_getxattr,
943         .lgetxattr = shadow_copy2_lgetxattr,
944         .listxattr = shadow_copy2_listxattr,
945         .removexattr = shadow_copy2_removexattr,
946         .lremovexattr = shadow_copy2_lremovexattr,
947         .setxattr = shadow_copy2_setxattr,
948         .lsetxattr = shadow_copy2_lsetxattr,
949         .open = shadow_copy2_open,
950         .rename = shadow_copy2_rename,
951         .stat = shadow_copy2_stat,
952         .lstat = shadow_copy2_lstat,
953         .fstat = shadow_copy2_fstat,
954         .unlink = shadow_copy2_unlink,
955         .chmod = shadow_copy2_chmod,
956         .chown = shadow_copy2_chown,
957         .chdir = shadow_copy2_chdir,
958         .ntimes = shadow_copy2_ntimes,
959         .symlink = shadow_copy2_symlink,
960         .vfs_readlink = shadow_copy2_readlink,
961         .link = shadow_copy2_link,
962         .mknod = shadow_copy2_mknod,
963         .realpath = shadow_copy2_realpath,
964         .connectpath = shadow_copy2_connectpath,
965         .get_nt_acl = shadow_copy2_get_nt_acl,
966         .chmod_acl = shadow_copy2_chmod_acl,
967         .get_shadow_copy_data = shadow_copy2_get_shadow_copy2_data,
968 };
969
970 NTSTATUS vfs_shadow_copy2_init(void);
971 NTSTATUS vfs_shadow_copy2_init(void)
972 {
973         NTSTATUS ret;
974
975         ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "shadow_copy2",
976                                &vfs_shadow_copy2_fns);
977
978         if (!NT_STATUS_IS_OK(ret))
979                 return ret;
980
981         vfs_shadow_copy2_debug_level = debug_add_class("shadow_copy2");
982         if (vfs_shadow_copy2_debug_level == -1) {
983                 vfs_shadow_copy2_debug_level = DBGC_VFS;
984                 DEBUG(0, ("%s: Couldn't register custom debugging class!\n",
985                         "vfs_shadow_copy2_init"));
986         } else {
987                 DEBUG(10, ("%s: Debug class number of '%s': %d\n", 
988                         "vfs_shadow_copy2_init","shadow_copy2",vfs_shadow_copy2_debug_level));
989         }
990
991         return ret;
992 }