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