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