s3: Plumb smb_filename through SMB_VFS_UNLINK
[kai/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  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *  
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *  
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include "includes.h"
22
23 /*
24
25   This is a 2nd implemetation of a shadow copy module for exposing
26   snapshots to windows clients as shadow copies. This version has the
27   following features:
28
29      1) you don't need to populate your shares with symlinks to the
30      snapshots. This can be very important when you have thousands of
31      shares, or use [homes]
32
33      2) the inode number of the files is altered so it is different
34      from the original. This allows the 'restore' button to work
35      without a sharing violation
36
37   Module options:
38
39       shadow:snapdir = <directory where snapshots are kept>
40
41       This is the directory containing the @GMT-* snapshot directories. If it is an absolute
42       path it is used as-is. If it is a relative path, then it is taken relative to the mount
43       point of the filesystem that the root of this share is on
44
45       shadow:basedir = <base directory that snapshots are from>
46
47       This is an optional parameter that specifies the directory that
48       the snapshots are relative to. It defaults to the filesystem
49       mount point
50
51       shadow:fixinodes = yes/no
52
53       If you enable shadow:fixinodes then this module will modify the
54       apparent inode number of files in the snapshot directories using
55       a hash of the files path. This is needed for snapshot systems
56       where the snapshots have the same device:inode number as the
57       original files (such as happens with GPFS snapshots). If you
58       don't set this option then the 'restore' button in the shadow
59       copy UI will fail with a sharing violation.
60
61   Note that the directory names in the snapshot directory must take the form
62   @GMT-YYYY.MM.DD-HH.MM.SS
63   
64   The following command would generate a correctly formatted directory name:
65      date -u +@GMT-%Y.%m.%d-%H.%M.%S
66   
67  */
68
69 static int vfs_shadow_copy2_debug_level = DBGC_VFS;
70
71 #undef DBGC_CLASS
72 #define DBGC_CLASS vfs_shadow_copy2_debug_level
73
74 #define GMT_NAME_LEN 24 /* length of a @GMT- name */
75
76 /*
77   make very sure it is one of our special names 
78  */
79 static inline bool shadow_copy2_match_name(const char *name)
80 {
81         unsigned year, month, day, hr, min, sec;
82         if (name[0] != '@') return False;
83         if (strncmp(name, "@GMT-", 5) != 0) return False;
84         if (sscanf(name, "@GMT-%04u.%02u.%02u-%02u.%02u.%02u", &year, &month,
85                    &day, &hr, &min, &sec) != 6) {
86                 return False;
87         }
88         if (name[24] != 0 && name[24] != '/') {
89                 return False;
90         }
91         return True;
92 }
93
94 /*
95   convert a name to the shadow directory
96  */
97
98 #define _SHADOW2_NEXT(op, args, rtype, eret, extra) do { \
99         const char *name = fname; \
100         if (shadow_copy2_match_name(fname)) { \
101                 char *name2; \
102                 rtype ret; \
103                 name2 = convert_shadow2_name(handle, fname); \
104                 if (name2 == NULL) { \
105                         errno = EINVAL; \
106                         return eret; \
107                 } \
108                 name = name2; \
109                 ret = SMB_VFS_NEXT_ ## op args; \
110                 talloc_free(name2); \
111                 if (ret != eret) extra; \
112                 return ret; \
113         } else { \
114                 return SMB_VFS_NEXT_ ## op args; \
115         } \
116 } while (0)
117
118 #define _SHADOW2_NEXT_SMB_FNAME(op, args, rtype, eret, extra) do { \
119         if (shadow_copy2_match_name(smb_fname->base_name)) { \
120                 char *name2; \
121                 char *smb_base_name_tmp = NULL; \
122                 rtype ret; \
123                 name2 = convert_shadow2_name(handle, smb_fname->base_name); \
124                 if (name2 == NULL) { \
125                         errno = EINVAL; \
126                         return eret; \
127                 } \
128                 smb_base_name_tmp = smb_fname->base_name; \
129                 smb_fname->base_name = name2; \
130                 ret = SMB_VFS_NEXT_ ## op args; \
131                 smb_fname->base_name = smb_base_name_tmp; \
132                 talloc_free(name2); \
133                 if (ret != eret) extra; \
134                 return ret; \
135         } else { \
136                 return SMB_VFS_NEXT_ ## op args; \
137         } \
138 } while (0)
139
140 /*
141   convert a name to the shadow directory: NTSTATUS-specific handling
142  */
143
144 #define _SHADOW2_NTSTATUS_NEXT(op, args, eret, extra) do { \
145         const char *name = fname; \
146         if (shadow_copy2_match_name(fname)) { \
147                 char *name2; \
148                 NTSTATUS ret; \
149                 name2 = convert_shadow2_name(handle, fname); \
150                 if (name2 == NULL) { \
151                         errno = EINVAL; \
152                         return eret; \
153                 } \
154                 name = name2; \
155                 ret = SMB_VFS_NEXT_ ## op args; \
156                 talloc_free(name2); \
157                 if (!NT_STATUS_EQUAL(ret, eret)) extra; \
158                 return ret; \
159         } else { \
160                 return SMB_VFS_NEXT_ ## op args; \
161         } \
162 } while (0)
163
164 #define SHADOW2_NTSTATUS_NEXT(op, args, eret) _SHADOW2_NTSTATUS_NEXT(op, args, eret, )
165
166 #define SHADOW2_NEXT(op, args, rtype, eret) _SHADOW2_NEXT(op, args, rtype, eret, )
167
168 #define SHADOW2_NEXT_SMB_FNAME(op, args, rtype, eret) _SHADOW2_NEXT_SMB_FNAME(op, args, rtype, eret, )
169
170 #define SHADOW2_NEXT2(op, args) do { \
171         if (shadow_copy2_match_name(oldname) || shadow_copy2_match_name(newname)) { \
172                 errno = EROFS; \
173                 return -1; \
174         } else { \
175                 return SMB_VFS_NEXT_ ## op args; \
176         } \
177 } while (0)
178
179 #define SHADOW2_NEXT2_SMB_FNAME(op, args) do { \
180         if (shadow_copy2_match_name(smb_fname_src->base_name) || \
181             shadow_copy2_match_name(smb_fname_dst->base_name)) { \
182                 errno = EROFS; \
183                 return -1; \
184         } else { \
185                 return SMB_VFS_NEXT_ ## op args; \
186         } \
187 } while (0)
188
189
190 /*
191   find the mount point of a filesystem
192  */
193 static char *find_mount_point(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle)
194 {
195         char *path = talloc_strdup(mem_ctx, handle->conn->connectpath);
196         dev_t dev;
197         struct stat st;
198         char *p;
199
200         if (stat(path, &st) != 0) {
201                 talloc_free(path);
202                 return NULL;
203         }
204
205         dev = st.st_dev;
206
207         while ((p = strrchr(path, '/')) && p > path) {
208                 *p = 0;
209                 if (stat(path, &st) != 0) {
210                         talloc_free(path);
211                         return NULL;
212                 }
213                 if (st.st_dev != dev) {
214                         *p = '/';
215                         break;
216                 }
217         }
218
219         return path;    
220 }
221
222 /*
223   work out the location of the snapshot for this share
224  */
225 static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle)
226 {
227         const char *snapdir;
228         char *mount_point;
229         const char *ret;
230
231         snapdir = lp_parm_const_string(SNUM(handle->conn), "shadow", "snapdir", NULL);
232         if (snapdir == NULL) {
233                 return NULL;
234         }
235         /* if its an absolute path, we're done */
236         if (*snapdir == '/') {
237                 return snapdir;
238         }
239
240         /* other its relative to the filesystem mount point */
241         mount_point = find_mount_point(mem_ctx, handle);
242         if (mount_point == NULL) {
243                 return NULL;
244         }
245
246         ret = talloc_asprintf(mem_ctx, "%s/%s", mount_point, snapdir);
247         talloc_free(mount_point);
248         return ret;
249 }
250
251 /*
252   work out the location of the base directory for snapshots of this share
253  */
254 static const char *shadow_copy2_find_basedir(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle)
255 {
256         const char *basedir = lp_parm_const_string(SNUM(handle->conn), "shadow", "basedir", NULL);
257
258         /* other its the filesystem mount point */
259         if (basedir == NULL) {
260                 basedir = find_mount_point(mem_ctx, handle);
261         }
262
263         return basedir;
264 }
265
266 /*
267   convert a filename from a share relative path, to a path in the
268   snapshot directory
269  */
270 static char *convert_shadow2_name(vfs_handle_struct *handle, const char *fname)
271 {
272         TALLOC_CTX *tmp_ctx = talloc_new(handle->data);
273         const char *snapdir, *relpath, *baseoffset, *basedir;
274         size_t baselen;
275         char *ret;
276
277         snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle);
278         if (snapdir == NULL) {
279                 DEBUG(2,("no snapdir found for share at %s\n", handle->conn->connectpath));
280                 talloc_free(tmp_ctx);
281                 return NULL;
282         }
283
284         basedir = shadow_copy2_find_basedir(tmp_ctx, handle);
285         if (basedir == NULL) {
286                 DEBUG(2,("no basedir found for share at %s\n", handle->conn->connectpath));
287                 talloc_free(tmp_ctx);
288                 return NULL;
289         }
290
291         relpath = fname + GMT_NAME_LEN;
292         baselen = strlen(basedir);
293         baseoffset = handle->conn->connectpath + baselen;
294
295         /* some sanity checks */
296         if (strncmp(basedir, handle->conn->connectpath, baselen) != 0 ||
297             (handle->conn->connectpath[baselen] != 0 && handle->conn->connectpath[baselen] != '/')) {
298                 DEBUG(0,("convert_shadow2_name: basedir %s is not a parent of %s\n",
299                          basedir, handle->conn->connectpath));
300                 talloc_free(tmp_ctx);
301                 return NULL;
302         }
303
304         if (*relpath == '/') relpath++;
305         if (*baseoffset == '/') baseoffset++;
306
307         ret = talloc_asprintf(handle->data, "%s/%.*s/%s/%s", 
308                               snapdir, 
309                               GMT_NAME_LEN, fname, 
310                               baseoffset, 
311                               relpath);
312         DEBUG(6,("convert_shadow2_name: '%s' -> '%s'\n", fname, ret));
313         talloc_free(tmp_ctx);
314         return ret;
315 }
316
317
318 /*
319   simple string hash
320  */
321 static uint32 string_hash(const char *s)
322 {
323         uint32 n = 0;
324         while (*s) {
325                 n = ((n << 5) + n) ^ (uint32)(*s++);
326         }
327         return n;
328 }
329
330 /*
331   modify a sbuf return to ensure that inodes in the shadow directory
332   are different from those in the main directory
333  */
334 static void convert_sbuf(vfs_handle_struct *handle, const char *fname, SMB_STRUCT_STAT *sbuf)
335 {
336         if (lp_parm_bool(SNUM(handle->conn), "shadow", "fixinodes", False)) {           
337                 /* some snapshot systems, like GPFS, return the name
338                    device:inode for the snapshot files as the current
339                    files. That breaks the 'restore' button in the shadow copy
340                    GUI, as the client gets a sharing violation.
341
342                    This is a crude way of allowing both files to be
343                    open at once. It has a slight chance of inode
344                    number collision, but I can't see a better approach
345                    without significant VFS changes
346                 */
347                 uint32_t shash = string_hash(fname) & 0xFF000000;
348                 if (shash == 0) {
349                         shash = 1;
350                 }
351                 sbuf->st_ex_ino ^= shash;
352         }
353 }
354
355 static int shadow_copy2_rename(vfs_handle_struct *handle,
356                                const struct smb_filename *smb_fname_src,
357                                const struct smb_filename *smb_fname_dst)
358 {
359         SHADOW2_NEXT2_SMB_FNAME(RENAME,
360                                 (handle, smb_fname_src, smb_fname_dst));
361 }
362
363 static int shadow_copy2_symlink(vfs_handle_struct *handle,
364                                 const char *oldname, const char *newname)
365 {
366         SHADOW2_NEXT2(SYMLINK, (handle, oldname, newname));
367 }
368
369 static int shadow_copy2_link(vfs_handle_struct *handle,
370                           const char *oldname, const char *newname)
371 {
372         SHADOW2_NEXT2(LINK, (handle, oldname, newname));
373 }
374
375 static int shadow_copy2_open(vfs_handle_struct *handle,
376                              struct smb_filename *smb_fname, files_struct *fsp,
377                              int flags, mode_t mode)
378 {
379         SHADOW2_NEXT_SMB_FNAME(OPEN,
380                                (handle, smb_fname, fsp, flags, mode),
381                                int, -1);
382 }
383
384 static SMB_STRUCT_DIR *shadow_copy2_opendir(vfs_handle_struct *handle,
385                           const char *fname, const char *mask, uint32 attr)
386 {
387         SHADOW2_NEXT(OPENDIR, (handle, name, mask, attr), SMB_STRUCT_DIR *, NULL);
388 }
389
390 static int shadow_copy2_stat(vfs_handle_struct *handle,
391                              struct smb_filename *smb_fname)
392 {
393         _SHADOW2_NEXT_SMB_FNAME(STAT, (handle, smb_fname), int, -1,
394                                 convert_sbuf(handle, smb_fname->base_name,
395                                              &smb_fname->st));
396 }
397
398 static int shadow_copy2_lstat(vfs_handle_struct *handle,
399                               struct smb_filename *smb_fname)
400 {
401         _SHADOW2_NEXT_SMB_FNAME(LSTAT, (handle, smb_fname), int, -1,
402                                 convert_sbuf(handle, smb_fname->base_name,
403                                              &smb_fname->st));
404 }
405
406 static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
407 {
408         int ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
409         if (ret == 0 && shadow_copy2_match_name(fsp->fsp_name)) {
410                 convert_sbuf(handle, fsp->fsp_name, sbuf);
411         }
412         return ret;
413 }
414
415 static int shadow_copy2_unlink(vfs_handle_struct *handle,
416                                const struct smb_filename *smb_fname_in)
417 {
418         struct smb_filename *smb_fname = NULL;
419         NTSTATUS status;
420
421         status = copy_smb_filename(talloc_tos(), smb_fname_in, &smb_fname);
422         if (!NT_STATUS_IS_OK(status)) {
423                 errno = map_errno_from_nt_status(status);
424                 return -1;
425         }
426
427         SHADOW2_NEXT_SMB_FNAME(UNLINK, (handle, smb_fname), int, -1);
428 }
429
430 static int shadow_copy2_chmod(vfs_handle_struct *handle,
431                        const char *fname, mode_t mode)
432 {
433         SHADOW2_NEXT(CHMOD, (handle, name, mode), int, -1);
434 }
435
436 static int shadow_copy2_chown(vfs_handle_struct *handle,
437                        const char *fname, uid_t uid, gid_t gid)
438 {
439         SHADOW2_NEXT(CHOWN, (handle, name, uid, gid), int, -1);
440 }
441
442 static int shadow_copy2_chdir(vfs_handle_struct *handle,
443                        const char *fname)
444 {
445         SHADOW2_NEXT(CHDIR, (handle, name), int, -1);
446 }
447
448 static int shadow_copy2_ntimes(vfs_handle_struct *handle,
449                        const char *fname, struct smb_file_time *ft)
450 {
451         SHADOW2_NEXT(NTIMES, (handle, name, ft), int, -1);
452 }
453
454 static int shadow_copy2_readlink(vfs_handle_struct *handle,
455                                  const char *fname, char *buf, size_t bufsiz)
456 {
457         SHADOW2_NEXT(READLINK, (handle, name, buf, bufsiz), int, -1);
458 }
459
460 static int shadow_copy2_mknod(vfs_handle_struct *handle,
461                        const char *fname, mode_t mode, SMB_DEV_T dev)
462 {
463         SHADOW2_NEXT(MKNOD, (handle, name, mode, dev), int, -1);
464 }
465
466 static char *shadow_copy2_realpath(vfs_handle_struct *handle,
467                             const char *fname, char *resolved_path)
468 {
469         SHADOW2_NEXT(REALPATH, (handle, name, resolved_path), char *, NULL);
470 }
471
472 static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle,
473                                             const char *fname)
474 {
475         TALLOC_CTX *tmp_ctx = talloc_stackframe();
476         const char *snapdir, *baseoffset, *basedir;
477         size_t baselen;
478         char *ret;
479
480         if (!shadow_copy2_match_name(fname)) {
481                 return handle->conn->connectpath;
482         }
483
484         snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle);
485         if (snapdir == NULL) {
486                 DEBUG(2,("no snapdir found for share at %s\n",
487                          handle->conn->connectpath));
488                 TALLOC_FREE(tmp_ctx);
489                 return NULL;
490         }
491
492         basedir = shadow_copy2_find_basedir(tmp_ctx, handle);
493         if (basedir == NULL) {
494                 DEBUG(2,("no basedir found for share at %s\n",
495                          handle->conn->connectpath));
496                 TALLOC_FREE(tmp_ctx);
497                 return NULL;
498         }
499
500         baselen = strlen(basedir);
501         baseoffset = handle->conn->connectpath + baselen;
502
503         /* some sanity checks */
504         if (strncmp(basedir, handle->conn->connectpath, baselen) != 0 ||
505             (handle->conn->connectpath[baselen] != 0
506              && handle->conn->connectpath[baselen] != '/')) {
507                 DEBUG(0,("shadow_copy2_connectpath: basedir %s is not a "
508                          "parent of %s\n", basedir,
509                          handle->conn->connectpath));
510                 TALLOC_FREE(tmp_ctx);
511                 return NULL;
512         }
513
514         if (*baseoffset == '/') baseoffset++;
515
516         ret = talloc_asprintf(talloc_tos(), "%s/%.*s/%s",
517                               snapdir,
518                               GMT_NAME_LEN, fname,
519                               baseoffset);
520         DEBUG(6,("shadow_copy2_connectpath: '%s' -> '%s'\n", fname, ret));
521         TALLOC_FREE(tmp_ctx);
522         return ret;
523 }
524
525 static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle,
526                                const char *fname, uint32 security_info,
527                                struct security_descriptor **ppdesc)
528 {
529         SHADOW2_NTSTATUS_NEXT(GET_NT_ACL, (handle, name, security_info, ppdesc), NT_STATUS_ACCESS_DENIED);
530 }
531
532 static int shadow_copy2_mkdir(vfs_handle_struct *handle,  const char *fname, mode_t mode)
533 {
534         SHADOW2_NEXT(MKDIR, (handle, name, mode), int, -1);
535 }
536
537 static int shadow_copy2_rmdir(vfs_handle_struct *handle,  const char *fname)
538 {
539         SHADOW2_NEXT(RMDIR, (handle, name), int, -1);
540 }
541
542 static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname, int flags)
543 {
544         SHADOW2_NEXT(CHFLAGS, (handle, name, flags), int, -1);
545 }
546
547 static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
548                                   const char *fname, const char *aname, void *value, size_t size)
549 {
550         SHADOW2_NEXT(GETXATTR, (handle, name, aname, value, size), ssize_t, -1);
551 }
552
553 static ssize_t shadow_copy2_lgetxattr(vfs_handle_struct *handle,
554                                       const char *fname, const char *aname, void *value, size_t size)
555 {
556         SHADOW2_NEXT(LGETXATTR, (handle, name, aname, value, size), ssize_t, -1);
557 }
558
559 static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle, const char *fname, 
560                                       char *list, size_t size)
561 {
562         SHADOW2_NEXT(LISTXATTR, (handle, name, list, size), ssize_t, -1);
563 }
564
565 static int shadow_copy2_removexattr(struct vfs_handle_struct *handle, const char *fname, 
566                                     const char *aname)
567 {
568         SHADOW2_NEXT(REMOVEXATTR, (handle, name, aname), int, -1);
569 }
570
571 static int shadow_copy2_lremovexattr(struct vfs_handle_struct *handle, const char *fname, 
572                                      const char *aname)
573 {
574         SHADOW2_NEXT(LREMOVEXATTR, (handle, name, aname), int, -1);
575 }
576
577 static int shadow_copy2_setxattr(struct vfs_handle_struct *handle, const char *fname, 
578                                  const char *aname, const void *value, size_t size, int flags)
579 {
580         SHADOW2_NEXT(SETXATTR, (handle, name, aname, value, size, flags), int, -1);
581 }
582
583 static int shadow_copy2_lsetxattr(struct vfs_handle_struct *handle, const char *fname, 
584                                   const char *aname, const void *value, size_t size, int flags)
585 {
586         SHADOW2_NEXT(LSETXATTR, (handle, name, aname, value, size, flags), int, -1);
587 }
588
589 static int shadow_copy2_chmod_acl(vfs_handle_struct *handle,
590                            const char *fname, mode_t mode)
591 {
592         /* If the underlying VFS doesn't have ACL support... */
593         if (!handle->vfs_next.ops.chmod_acl) {
594                 errno = ENOSYS;
595                 return -1;
596         }
597         SHADOW2_NEXT(CHMOD_ACL, (handle, name, mode), int, -1);
598 }
599
600 static int shadow_copy2_get_shadow_copy2_data(vfs_handle_struct *handle, 
601                                               files_struct *fsp, 
602                                               SHADOW_COPY_DATA *shadow_copy2_data, 
603                                               bool labels)
604 {
605         SMB_STRUCT_DIR *p;
606         const char *snapdir;
607         SMB_STRUCT_DIRENT *d;
608         TALLOC_CTX *tmp_ctx = talloc_new(handle->data);
609
610         snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle);
611         if (snapdir == NULL) {
612                 DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
613                          handle->conn->connectpath));
614                 errno = EINVAL;
615                 talloc_free(tmp_ctx);
616                 return -1;
617         }
618
619         p = SMB_VFS_NEXT_OPENDIR(handle, snapdir, NULL, 0);
620
621         if (!p) {
622                 DEBUG(2,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s'"
623                          " - %s\n", snapdir, strerror(errno)));
624                 talloc_free(tmp_ctx);
625                 errno = ENOSYS;
626                 return -1;
627         }
628
629         talloc_free(tmp_ctx);
630
631         shadow_copy2_data->num_volumes = 0;
632         shadow_copy2_data->labels      = NULL;
633
634         while ((d = SMB_VFS_NEXT_READDIR(handle, p, NULL))) {
635                 SHADOW_COPY_LABEL *tlabels;
636
637                 /* ignore names not of the right form in the snapshot directory */
638                 if (!shadow_copy2_match_name(d->d_name)) {
639                         continue;
640                 }
641
642                 if (!labels) {
643                         /* the caller doesn't want the labels */
644                         shadow_copy2_data->num_volumes++;
645                         continue;
646                 }
647
648                 tlabels = talloc_realloc(shadow_copy2_data->mem_ctx,
649                                          shadow_copy2_data->labels,
650                                          SHADOW_COPY_LABEL, shadow_copy2_data->num_volumes+1);
651                 if (tlabels == NULL) {
652                         DEBUG(0,("shadow_copy2: out of memory\n"));
653                         SMB_VFS_NEXT_CLOSEDIR(handle, p);
654                         return -1;
655                 }
656
657                 strlcpy(tlabels[shadow_copy2_data->num_volumes], d->d_name, sizeof(*tlabels));
658                 shadow_copy2_data->num_volumes++;
659                 shadow_copy2_data->labels = tlabels;
660         }
661
662         SMB_VFS_NEXT_CLOSEDIR(handle,p);
663         return 0;
664 }
665
666 /* VFS operations structure */
667
668 static vfs_op_tuple shadow_copy2_ops[] = {
669         {SMB_VFS_OP(shadow_copy2_opendir),  SMB_VFS_OP_OPENDIR,  SMB_VFS_LAYER_TRANSPARENT},
670
671         /* directory operations */
672         {SMB_VFS_OP(shadow_copy2_mkdir),       SMB_VFS_OP_MKDIR,       SMB_VFS_LAYER_TRANSPARENT},
673         {SMB_VFS_OP(shadow_copy2_rmdir),       SMB_VFS_OP_RMDIR,       SMB_VFS_LAYER_TRANSPARENT},
674
675         /* xattr and flags operations */
676         {SMB_VFS_OP(shadow_copy2_chflags),     SMB_VFS_OP_CHFLAGS,     SMB_VFS_LAYER_TRANSPARENT},
677         {SMB_VFS_OP(shadow_copy2_getxattr),    SMB_VFS_OP_GETXATTR,    SMB_VFS_LAYER_TRANSPARENT},
678         {SMB_VFS_OP(shadow_copy2_lgetxattr),   SMB_VFS_OP_LGETXATTR,   SMB_VFS_LAYER_TRANSPARENT},
679         {SMB_VFS_OP(shadow_copy2_listxattr),   SMB_VFS_OP_LISTXATTR,   SMB_VFS_LAYER_TRANSPARENT},
680         {SMB_VFS_OP(shadow_copy2_removexattr), SMB_VFS_OP_REMOVEXATTR, SMB_VFS_LAYER_TRANSPARENT},
681         {SMB_VFS_OP(shadow_copy2_lremovexattr),SMB_VFS_OP_LREMOVEXATTR,SMB_VFS_LAYER_TRANSPARENT},
682         {SMB_VFS_OP(shadow_copy2_setxattr),    SMB_VFS_OP_SETXATTR,    SMB_VFS_LAYER_TRANSPARENT},
683         {SMB_VFS_OP(shadow_copy2_lsetxattr),   SMB_VFS_OP_LSETXATTR,   SMB_VFS_LAYER_TRANSPARENT},
684
685         /* File operations */
686         {SMB_VFS_OP(shadow_copy2_open),       SMB_VFS_OP_OPEN,     SMB_VFS_LAYER_TRANSPARENT},
687         {SMB_VFS_OP(shadow_copy2_rename),     SMB_VFS_OP_RENAME,   SMB_VFS_LAYER_TRANSPARENT},
688         {SMB_VFS_OP(shadow_copy2_stat),       SMB_VFS_OP_STAT,     SMB_VFS_LAYER_TRANSPARENT},
689         {SMB_VFS_OP(shadow_copy2_lstat),      SMB_VFS_OP_LSTAT,    SMB_VFS_LAYER_TRANSPARENT},
690         {SMB_VFS_OP(shadow_copy2_fstat),      SMB_VFS_OP_FSTAT,    SMB_VFS_LAYER_TRANSPARENT},
691         {SMB_VFS_OP(shadow_copy2_unlink),     SMB_VFS_OP_UNLINK,   SMB_VFS_LAYER_TRANSPARENT},
692         {SMB_VFS_OP(shadow_copy2_chmod),      SMB_VFS_OP_CHMOD,    SMB_VFS_LAYER_TRANSPARENT},
693         {SMB_VFS_OP(shadow_copy2_chown),      SMB_VFS_OP_CHOWN,    SMB_VFS_LAYER_TRANSPARENT},
694         {SMB_VFS_OP(shadow_copy2_chdir),      SMB_VFS_OP_CHDIR,    SMB_VFS_LAYER_TRANSPARENT},
695         {SMB_VFS_OP(shadow_copy2_ntimes),     SMB_VFS_OP_NTIMES,   SMB_VFS_LAYER_TRANSPARENT},
696         {SMB_VFS_OP(shadow_copy2_symlink),    SMB_VFS_OP_SYMLINK,  SMB_VFS_LAYER_TRANSPARENT},
697         {SMB_VFS_OP(shadow_copy2_readlink),   SMB_VFS_OP_READLINK, SMB_VFS_LAYER_TRANSPARENT},
698         {SMB_VFS_OP(shadow_copy2_link),       SMB_VFS_OP_LINK,     SMB_VFS_LAYER_TRANSPARENT},
699         {SMB_VFS_OP(shadow_copy2_mknod),      SMB_VFS_OP_MKNOD,    SMB_VFS_LAYER_TRANSPARENT},
700         {SMB_VFS_OP(shadow_copy2_realpath),   SMB_VFS_OP_REALPATH, SMB_VFS_LAYER_TRANSPARENT},
701         {SMB_VFS_OP(shadow_copy2_connectpath), SMB_VFS_OP_CONNECTPATH, SMB_VFS_LAYER_OPAQUE},
702
703         /* NT File ACL operations */
704         {SMB_VFS_OP(shadow_copy2_get_nt_acl), SMB_VFS_OP_GET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT},
705
706         /* POSIX ACL operations */
707         {SMB_VFS_OP(shadow_copy2_chmod_acl), SMB_VFS_OP_CHMOD_ACL, SMB_VFS_LAYER_TRANSPARENT},
708
709         /* special shadown copy op */
710         {SMB_VFS_OP(shadow_copy2_get_shadow_copy2_data), 
711          SMB_VFS_OP_GET_SHADOW_COPY_DATA,SMB_VFS_LAYER_OPAQUE},
712
713         {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
714 };
715
716 NTSTATUS vfs_shadow_copy2_init(void);
717 NTSTATUS vfs_shadow_copy2_init(void)
718 {
719         NTSTATUS ret;
720
721         ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "shadow_copy2", shadow_copy2_ops);
722
723         if (!NT_STATUS_IS_OK(ret))
724                 return ret;
725
726         vfs_shadow_copy2_debug_level = debug_add_class("shadow_copy2");
727         if (vfs_shadow_copy2_debug_level == -1) {
728                 vfs_shadow_copy2_debug_level = DBGC_VFS;
729                 DEBUG(0, ("%s: Couldn't register custom debugging class!\n",
730                         "vfs_shadow_copy2_init"));
731         } else {
732                 DEBUG(10, ("%s: Debug class number of '%s': %d\n", 
733                         "vfs_shadow_copy2_init","shadow_copy2",vfs_shadow_copy2_debug_level));
734         }
735
736         return ret;
737 }