summaryrefslogtreecommitdiffstats
path: root/meta-oe/recipes-connectivity/samba/samba-3.6.24/shadow_copy2_backport.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-oe/recipes-connectivity/samba/samba-3.6.24/shadow_copy2_backport.patch')
-rw-r--r--meta-oe/recipes-connectivity/samba/samba-3.6.24/shadow_copy2_backport.patch2101
1 files changed, 2101 insertions, 0 deletions
diff --git a/meta-oe/recipes-connectivity/samba/samba-3.6.24/shadow_copy2_backport.patch b/meta-oe/recipes-connectivity/samba/samba-3.6.24/shadow_copy2_backport.patch
new file mode 100644
index 000000000..dbd10489f
--- /dev/null
+++ b/meta-oe/recipes-connectivity/samba/samba-3.6.24/shadow_copy2_backport.patch
@@ -0,0 +1,2101 @@
1Description: Backport new shadow_copy2 implementation from master
2 The shadow_copy2 vfs module in samba 3.6 doesn't work if wide links is
3 disabled. This problem is fixed by a rewrite in the master branch.
4 This patch is a backport of this new version to samba 3.6.
5 It is based on these commits in the upstream samba git:
6 dc461cade5becec21f8d1f2bb74fcf1a977a5ec2
7 617b63658b02957422359a76fd8b8e4748d228ee
8Author: Ivo De Decker <ivo.dedecker@ugent.be>
9Origin: upstream
10Bug: https://bugzilla.samba.org/show_bug.cgi?id=7287
11Forwarded: not-needed
12Last-Update: 2012-05-27
13
14--- samba-3.6.5.orig/source3/modules/vfs_shadow_copy2.c
15+++ samba-3.6.5/source3/modules/vfs_shadow_copy2.c
16@@ -1,32 +1,29 @@
17-/*
18- * implementation of an Shadow Copy module - version 2
19+/*
20+ * Third attempt at a shadow copy module
21 *
22- * Copyright (C) Andrew Tridgell 2007
23- * Copyright (C) Ed Plese 2009
24+ * Copyright (C) Andrew Tridgell 2007 (portions taken from shadow_copy2)
25+ * Copyright (C) Ed Plese 2009
26+ * Copyright (C) Volker Lendecke 2011
27+ * Copyright (C) Christian Ambach 2011
28 *
29 * This program is free software; you can redistribute it and/or modify
30 * it under the terms of the GNU General Public License as published by
31 * the Free Software Foundation; either version 2 of the License, or
32 * (at your option) any later version.
33- *
34+ *
35 * This program is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 * GNU General Public License for more details.
39- *
40+ *
41 * You should have received a copy of the GNU General Public License
42 * along with this program; if not, write to the Free Software
43 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
44 */
45
46-#include "includes.h"
47-#include "smbd/smbd.h"
48-#include "system/filesys.h"
49-#include "ntioctl.h"
50-
51 /*
52
53- This is a 2nd implemetation of a shadow copy module for exposing
54+ This is a 3rd implemetation of a shadow copy module for exposing
55 snapshots to windows clients as shadow copies. This version has the
56 following features:
57
58@@ -96,243 +93,169 @@
59 The following command would generate a correctly formatted directory name
60 for use with the default parameters:
61 date -u +@GMT-%Y.%m.%d-%H.%M.%S
62-
63 */
64
65-static int vfs_shadow_copy2_debug_level = DBGC_VFS;
66-
67-#undef DBGC_CLASS
68-#define DBGC_CLASS vfs_shadow_copy2_debug_level
69+#include "includes.h"
70+#include "system/filesys.h"
71+#include "include/ntioctl.h"
72+#include "smbd/proto.h"
73+#include <tdb.h>
74+#include "util_tdb.h"
75
76 #define GMT_NAME_LEN 24 /* length of a @GMT- name */
77-#define SHADOW_COPY2_GMT_FORMAT "@GMT-%Y.%m.%d-%H.%M.%S"
78-
79-#define SHADOW_COPY2_DEFAULT_SORT NULL
80-#define SHADOW_COPY2_DEFAULT_FORMAT "@GMT-%Y.%m.%d-%H.%M.%S"
81-#define SHADOW_COPY2_DEFAULT_LOCALTIME false
82+#define GMT_FORMAT "@GMT-%Y.%m.%d-%H.%M.%S"
83
84-/*
85- make very sure it is one of our special names
86- */
87-static inline bool shadow_copy2_match_name(const char *name, const char **gmt_start)
88+static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str,
89+ size_t **poffsets,
90+ unsigned *pnum_offsets)
91 {
92- unsigned year, month, day, hr, min, sec;
93+ unsigned num_offsets;
94+ size_t *offsets;
95 const char *p;
96- if (gmt_start) {
97- (*gmt_start) = NULL;
98- }
99- p = strstr_m(name, "@GMT-");
100- if (p == NULL) return false;
101- if (p > name && p[-1] != '/') return False;
102- if (sscanf(p, "@GMT-%04u.%02u.%02u-%02u.%02u.%02u", &year, &month,
103- &day, &hr, &min, &sec) != 6) {
104- return False;
105- }
106- if (p[24] != 0 && p[24] != '/') {
107- return False;
108- }
109- if (gmt_start) {
110- (*gmt_start) = p;
111- }
112- return True;
113-}
114
115-static char *shadow_copy2_snapshot_to_gmt(TALLOC_CTX *mem_ctx,
116- vfs_handle_struct *handle, const char *name)
117-{
118- struct tm timestamp;
119- time_t timestamp_t;
120- char gmt[GMT_NAME_LEN + 1];
121- const char *fmt;
122+ num_offsets = 0;
123
124- fmt = lp_parm_const_string(SNUM(handle->conn), "shadow",
125- "format", SHADOW_COPY2_DEFAULT_FORMAT);
126+ p = str;
127+ while ((p = strchr(p, '/')) != NULL) {
128+ num_offsets += 1;
129+ p += 1;
130+ }
131
132- ZERO_STRUCT(timestamp);
133- if (strptime(name, fmt, &timestamp) == NULL) {
134- DEBUG(10, ("shadow_copy2_snapshot_to_gmt: no match %s: %s\n",
135- fmt, name));
136- return NULL;
137+ offsets = talloc_array(mem_ctx, size_t, num_offsets);
138+ if (offsets == NULL) {
139+ return false;
140 }
141
142- DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n", fmt, name));
143- if (lp_parm_bool(SNUM(handle->conn), "shadow", "localtime",
144- SHADOW_COPY2_DEFAULT_LOCALTIME))
145- {
146- timestamp.tm_isdst = -1;
147- timestamp_t = mktime(&timestamp);
148- gmtime_r(&timestamp_t, &timestamp);
149+ p = str;
150+ num_offsets = 0;
151+ while ((p = strchr(p, '/')) != NULL) {
152+ offsets[num_offsets] = p-str;
153+ num_offsets += 1;
154+ p += 1;
155 }
156- strftime(gmt, sizeof(gmt), SHADOW_COPY2_GMT_FORMAT, &timestamp);
157
158- return talloc_strdup(mem_ctx, gmt);
159+ *poffsets = offsets;
160+ *pnum_offsets = num_offsets;
161+ return true;
162 }
163
164-/*
165- shadow copy paths can also come into the server in this form:
166-
167- /foo/bar/@GMT-XXXXX/some/file
168-
169- This function normalises the filename to be of the form:
170-
171- @GMT-XXXX/foo/bar/some/file
172- */
173-static const char *shadow_copy2_normalise_path(TALLOC_CTX *mem_ctx, const char *path, const char *gmt_start)
174+static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx,
175+ struct vfs_handle_struct *handle,
176+ time_t snapshot)
177 {
178- char *pcopy;
179- char buf[GMT_NAME_LEN];
180- size_t prefix_len;
181+ struct tm snap_tm;
182+ fstring gmt;
183+ size_t gmt_len;
184
185- if (path == gmt_start) {
186- return path;
187+ if (localtime_r(&snapshot, &snap_tm) == 0) {
188+ DEBUG(10, ("gmtime_r failed\n"));
189+ return NULL;
190 }
191-
192- prefix_len = gmt_start - path - 1;
193-
194- DEBUG(10, ("path=%s, gmt_start=%s, prefix_len=%d\n", path, gmt_start,
195- (int)prefix_len));
196-
197- /*
198- * We've got a/b/c/@GMT-YYYY.MM.DD-HH.MM.SS/d/e. convert to
199- * @GMT-YYYY.MM.DD-HH.MM.SS/a/b/c/d/e before further
200- * processing. As many VFS calls provide a const char *,
201- * unfortunately we have to make a copy.
202- */
203-
204- pcopy = talloc_strdup(talloc_tos(), path);
205- if (pcopy == NULL) {
206+ gmt_len = strftime(gmt, sizeof(gmt),
207+ lp_parm_const_string(SNUM(handle->conn), "shadow",
208+ "format", GMT_FORMAT),
209+ &snap_tm);
210+ if (gmt_len == 0) {
211+ DEBUG(10, ("strftime failed\n"));
212 return NULL;
213 }
214-
215- gmt_start = pcopy + prefix_len;
216-
217- /*
218- * Copy away "@GMT-YYYY.MM.DD-HH.MM.SS"
219- */
220- memcpy(buf, gmt_start+1, GMT_NAME_LEN);
221-
222- /*
223- * Make space for it including a trailing /
224- */
225- memmove(pcopy + GMT_NAME_LEN + 1, pcopy, prefix_len);
226-
227- /*
228- * Move in "@GMT-YYYY.MM.DD-HH.MM.SS/" at the beginning again
229- */
230- memcpy(pcopy, buf, GMT_NAME_LEN);
231- pcopy[GMT_NAME_LEN] = '/';
232-
233- DEBUG(10, ("shadow_copy2_normalise_path: %s -> %s\n", path, pcopy));
234-
235- return pcopy;
236+ return talloc_asprintf(talloc_tos(), "/%s/%s",
237+ lp_parm_const_string(
238+ SNUM(handle->conn), "shadow", "snapdir",
239+ ".snapshots"),
240+ gmt);
241 }
242
243-/*
244- convert a name to the shadow directory
245- */
246+static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx,
247+ struct vfs_handle_struct *handle,
248+ const char *name,
249+ time_t *ptimestamp,
250+ char **pstripped)
251+{
252+ struct tm tm;
253+ time_t timestamp;
254+ const char *p;
255+ char *q;
256+ char *stripped;
257+ size_t rest_len, dst_len;
258
259-#define _SHADOW2_NEXT(op, args, rtype, eret, extra) do { \
260- const char *name = fname; \
261- const char *gmt_start; \
262- if (shadow_copy2_match_name(fname, &gmt_start)) { \
263- char *name2; \
264- rtype ret; \
265- name2 = convert_shadow2_name(handle, fname, gmt_start); \
266- if (name2 == NULL) { \
267- errno = EINVAL; \
268- return eret; \
269- } \
270- name = name2; \
271- ret = SMB_VFS_NEXT_ ## op args; \
272- talloc_free(name2); \
273- if (ret != eret) extra; \
274- return ret; \
275- } else { \
276- return SMB_VFS_NEXT_ ## op args; \
277- } \
278-} while (0)
279-
280-#define _SHADOW2_NEXT_SMB_FNAME(op, args, rtype, eret, extra) do { \
281- const char *gmt_start; \
282- if (shadow_copy2_match_name(smb_fname->base_name, &gmt_start)) { \
283- char *name2; \
284- char *smb_base_name_tmp = NULL; \
285- rtype ret; \
286- name2 = convert_shadow2_name(handle, smb_fname->base_name, gmt_start); \
287- if (name2 == NULL) { \
288- errno = EINVAL; \
289- return eret; \
290- } \
291- smb_base_name_tmp = smb_fname->base_name; \
292- smb_fname->base_name = name2; \
293- ret = SMB_VFS_NEXT_ ## op args; \
294- smb_fname->base_name = smb_base_name_tmp; \
295- talloc_free(name2); \
296- if (ret != eret) extra; \
297- return ret; \
298- } else { \
299- return SMB_VFS_NEXT_ ## op args; \
300- } \
301-} while (0)
302+ p = strstr_m(name, "@GMT-");
303+ if (p == NULL) {
304+ goto no_snapshot;
305+ }
306+ if ((p > name) && (p[-1] != '/')) {
307+ goto no_snapshot;
308+ }
309+ q = strptime(p, GMT_FORMAT, &tm);
310+ if (q == NULL) {
311+ goto no_snapshot;
312+ }
313+ tm.tm_isdst = -1;
314+ timestamp = mktime(&tm);
315+ if (timestamp == (time_t)-1) {
316+ goto no_snapshot;
317+ }
318+ if ((p == name) && (q[0] == '\0')) {
319+ if (pstripped != NULL) {
320+ stripped = talloc_strdup(mem_ctx, "");
321+ if (stripped == NULL) {
322+ return false;
323+ }
324+ *pstripped = stripped;
325+ }
326+ *ptimestamp = timestamp;
327+ return true;
328+ }
329+ if (q[0] != '/') {
330+ goto no_snapshot;
331+ }
332+ q += 1;
333
334-/*
335- convert a name to the shadow directory: NTSTATUS-specific handling
336- */
337+ rest_len = strlen(q);
338+ dst_len = (p-name) + rest_len;
339+
340+ if (lp_parm_bool(SNUM(handle->conn), "shadow", "snapdirseverywhere",
341+ false)) {
342+ char *insert;
343+ bool have_insert;
344+ insert = shadow_copy2_insert_string(talloc_tos(), handle,
345+ timestamp);
346+ if (insert == NULL) {
347+ errno = ENOMEM;
348+ return false;
349+ }
350
351-#define _SHADOW2_NTSTATUS_NEXT(op, args, eret, extra) do { \
352- const char *name = fname; \
353- const char *gmt_start; \
354- if (shadow_copy2_match_name(fname, &gmt_start)) { \
355- char *name2; \
356- NTSTATUS ret; \
357- name2 = convert_shadow2_name(handle, fname, gmt_start); \
358- if (name2 == NULL) { \
359- errno = EINVAL; \
360- return eret; \
361- } \
362- name = name2; \
363- ret = SMB_VFS_NEXT_ ## op args; \
364- talloc_free(name2); \
365- if (!NT_STATUS_EQUAL(ret, eret)) extra; \
366- return ret; \
367- } else { \
368- return SMB_VFS_NEXT_ ## op args; \
369- } \
370-} while (0)
371-
372-#define SHADOW2_NTSTATUS_NEXT(op, args, eret) _SHADOW2_NTSTATUS_NEXT(op, args, eret, )
373-
374-#define SHADOW2_NEXT(op, args, rtype, eret) _SHADOW2_NEXT(op, args, rtype, eret, )
375-
376-#define SHADOW2_NEXT_SMB_FNAME(op, args, rtype, eret) _SHADOW2_NEXT_SMB_FNAME(op, args, rtype, eret, )
377-
378-#define SHADOW2_NEXT2(op, args) do { \
379- const char *gmt_start1, *gmt_start2; \
380- if (shadow_copy2_match_name(oldname, &gmt_start1) || \
381- shadow_copy2_match_name(newname, &gmt_start2)) { \
382- errno = EROFS; \
383- return -1; \
384- } else { \
385- return SMB_VFS_NEXT_ ## op args; \
386- } \
387-} while (0)
388-
389-#define SHADOW2_NEXT2_SMB_FNAME(op, args) do { \
390- const char *gmt_start1, *gmt_start2; \
391- if (shadow_copy2_match_name(smb_fname_src->base_name, &gmt_start1) || \
392- shadow_copy2_match_name(smb_fname_dst->base_name, &gmt_start2)) { \
393- errno = EROFS; \
394- return -1; \
395- } else { \
396- return SMB_VFS_NEXT_ ## op args; \
397- } \
398-} while (0)
399+ have_insert = (strstr(name, insert+1) != NULL);
400+ TALLOC_FREE(insert);
401+ if (have_insert) {
402+ goto no_snapshot;
403+ }
404+ }
405
406+ if (pstripped != NULL) {
407+ stripped = talloc_array(mem_ctx, char, dst_len+1);
408+ if (stripped == NULL) {
409+ errno = ENOMEM;
410+ return false;
411+ }
412+ if (p > name) {
413+ memcpy(stripped, name, p-name);
414+ }
415+ if (rest_len > 0) {
416+ memcpy(stripped + (p-name), q, rest_len);
417+ }
418+ stripped[dst_len] = '\0';
419+ *pstripped = stripped;
420+ }
421+ *ptimestamp = timestamp;
422+ return true;
423+no_snapshot:
424+ *ptimestamp = 0;
425+ return true;
426+}
427
428-/*
429- find the mount point of a filesystem
430- */
431-static char *find_mount_point(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle)
432+static char *shadow_copy2_find_mount_point(TALLOC_CTX *mem_ctx,
433+ vfs_handle_struct *handle)
434 {
435 char *path = talloc_strdup(mem_ctx, handle->conn->connectpath);
436 dev_t dev;
437@@ -358,164 +281,152 @@ static char *find_mount_point(TALLOC_CTX
438 }
439 }
440
441- return path;
442+ return path;
443 }
444
445-/*
446- work out the location of the snapshot for this share
447- */
448-static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle)
449-{
450- const char *snapdir;
451- char *mount_point;
452- const char *ret;
453-
454- snapdir = lp_parm_const_string(SNUM(handle->conn), "shadow", "snapdir", NULL);
455- if (snapdir == NULL) {
456- return NULL;
457- }
458- /* if its an absolute path, we're done */
459- if (*snapdir == '/') {
460- return snapdir;
461+static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx,
462+ struct vfs_handle_struct *handle,
463+ const char *name, time_t timestamp)
464+{
465+ struct smb_filename converted_fname;
466+ char *result = NULL;
467+ size_t *slashes = NULL;
468+ unsigned num_slashes;
469+ char *path = NULL;
470+ size_t pathlen;
471+ char *insert = NULL;
472+ char *converted = NULL;
473+ size_t insertlen;
474+ int i, saved_errno;
475+ size_t min_offset;
476+
477+ path = talloc_asprintf(mem_ctx, "%s/%s", handle->conn->connectpath,
478+ name);
479+ if (path == NULL) {
480+ errno = ENOMEM;
481+ goto fail;
482+ }
483+ pathlen = talloc_get_size(path)-1;
484+
485+ DEBUG(10, ("converting %s\n", path));
486+
487+ if (!shadow_copy2_find_slashes(talloc_tos(), path,
488+ &slashes, &num_slashes)) {
489+ goto fail;
490+ }
491+ insert = shadow_copy2_insert_string(talloc_tos(), handle, timestamp);
492+ if (insert == NULL) {
493+ goto fail;
494+ }
495+ insertlen = talloc_get_size(insert)-1;
496+ converted = talloc_array(mem_ctx, char, pathlen + insertlen + 1);
497+ if (converted == NULL) {
498+ goto fail;
499+ }
500+
501+ if (path[pathlen-1] != '/') {
502+ /*
503+ * Append a fake slash to find the snapshot root
504+ */
505+ size_t *tmp;
506+ tmp = talloc_realloc(talloc_tos(), slashes,
507+ size_t, num_slashes+1);
508+ if (tmp == NULL) {
509+ goto fail;
510+ }
511+ slashes = tmp;
512+ slashes[num_slashes] = pathlen;
513+ num_slashes += 1;
514 }
515
516- /* other its relative to the filesystem mount point */
517- mount_point = find_mount_point(mem_ctx, handle);
518- if (mount_point == NULL) {
519- return NULL;
520- }
521+ min_offset = 0;
522
523- ret = talloc_asprintf(mem_ctx, "%s/%s", mount_point, snapdir);
524- talloc_free(mount_point);
525- return ret;
526-}
527-
528-/*
529- work out the location of the base directory for snapshots of this share
530- */
531-static const char *shadow_copy2_find_basedir(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle)
532-{
533- const char *basedir = lp_parm_const_string(SNUM(handle->conn), "shadow", "basedir", NULL);
534+ if (!lp_parm_bool(SNUM(handle->conn), "shadow", "crossmountpoints",
535+ false)) {
536+ char *mount_point;
537
538- /* other its the filesystem mount point */
539- if (basedir == NULL) {
540- basedir = find_mount_point(mem_ctx, handle);
541+ mount_point = shadow_copy2_find_mount_point(talloc_tos(),
542+ handle);
543+ if (mount_point == NULL) {
544+ goto fail;
545+ }
546+ min_offset = strlen(mount_point);
547+ TALLOC_FREE(mount_point);
548 }
549
550- return basedir;
551-}
552+ memcpy(converted, path, pathlen+1);
553+ converted[pathlen+insertlen] = '\0';
554
555-/*
556- convert a filename from a share relative path, to a path in the
557- snapshot directory
558- */
559-static char *convert_shadow2_name(vfs_handle_struct *handle, const char *fname, const char *gmt_path)
560-{
561- TALLOC_CTX *tmp_ctx = talloc_new(handle->data);
562- const char *snapdir, *relpath, *baseoffset, *basedir;
563- size_t baselen;
564- char *ret, *prefix;
565+ ZERO_STRUCT(converted_fname);
566+ converted_fname.base_name = converted;
567
568- struct tm timestamp;
569- time_t timestamp_t;
570- char snapshot[MAXPATHLEN];
571- const char *fmt;
572+ for (i = num_slashes-1; i>=0; i--) {
573+ int ret;
574+ size_t offset;
575
576- fmt = lp_parm_const_string(SNUM(handle->conn), "shadow",
577- "format", SHADOW_COPY2_DEFAULT_FORMAT);
578+ offset = slashes[i];
579
580- snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle);
581- if (snapdir == NULL) {
582- DEBUG(2,("no snapdir found for share at %s\n", handle->conn->connectpath));
583- talloc_free(tmp_ctx);
584- return NULL;
585- }
586-
587- basedir = shadow_copy2_find_basedir(tmp_ctx, handle);
588- if (basedir == NULL) {
589- DEBUG(2,("no basedir found for share at %s\n", handle->conn->connectpath));
590- talloc_free(tmp_ctx);
591- return NULL;
592- }
593-
594- prefix = talloc_asprintf(tmp_ctx, "%s/@GMT-", snapdir);
595- if (strncmp(fname, prefix, (talloc_get_size(prefix)-1)) == 0) {
596- /* this looks like as we have already normalized it, leave it untouched*/
597- talloc_free(tmp_ctx);
598- return talloc_strdup(handle->data, fname);
599- }
600-
601- if (strncmp(fname, "@GMT-", 5) != 0) {
602- fname = shadow_copy2_normalise_path(tmp_ctx, fname, gmt_path);
603- if (fname == NULL) {
604- talloc_free(tmp_ctx);
605- return NULL;
606+ if (offset < min_offset) {
607+ errno = ENOENT;
608+ goto fail;
609 }
610- }
611
612- ZERO_STRUCT(timestamp);
613- relpath = strptime(fname, SHADOW_COPY2_GMT_FORMAT, &timestamp);
614- if (relpath == NULL) {
615- talloc_free(tmp_ctx);
616- return NULL;
617- }
618+ memcpy(converted+offset, insert, insertlen);
619
620- /* relpath is the remaining portion of the path after the @GMT-xxx */
621-
622- if (lp_parm_bool(SNUM(handle->conn), "shadow", "localtime",
623- SHADOW_COPY2_DEFAULT_LOCALTIME))
624- {
625- timestamp_t = timegm(&timestamp);
626- localtime_r(&timestamp_t, &timestamp);
627+ offset += insertlen;
628+ memcpy(converted+offset, path + slashes[i],
629+ pathlen - slashes[i]);
630+
631+ ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
632+
633+ DEBUG(10, ("Trying %s: %d (%s)\n", converted,
634+ ret, ret == 0 ? "ok" : strerror(errno)));
635+ if (ret == 0) {
636+ /* success */
637+ break;
638+ }
639+ if (errno == ENOTDIR) {
640+ /*
641+ * This is a valid condition: We appended the
642+ * .snaphots/@GMT.. to a file name. Just try
643+ * with the upper levels.
644+ */
645+ continue;
646+ }
647+ if (errno != ENOENT) {
648+ /* Other problem than "not found" */
649+ goto fail;
650+ }
651 }
652
653- strftime(snapshot, MAXPATHLEN, fmt, &timestamp);
654-
655- baselen = strlen(basedir);
656- baseoffset = handle->conn->connectpath + baselen;
657-
658- /* some sanity checks */
659- if (strncmp(basedir, handle->conn->connectpath, baselen) != 0 ||
660- (handle->conn->connectpath[baselen] != 0 && handle->conn->connectpath[baselen] != '/')) {
661- DEBUG(0,("convert_shadow2_name: basedir %s is not a parent of %s\n",
662- basedir, handle->conn->connectpath));
663- talloc_free(tmp_ctx);
664- return NULL;
665+ if (i >= 0) {
666+ /*
667+ * Found something
668+ */
669+ DEBUG(10, ("Found %s\n", converted));
670+ result = converted;
671+ converted = NULL;
672+ } else {
673+ errno = ENOENT;
674 }
675-
676- if (*relpath == '/') relpath++;
677- if (*baseoffset == '/') baseoffset++;
678-
679- ret = talloc_asprintf(handle->data, "%s/%s/%s/%s",
680- snapdir,
681- snapshot,
682- baseoffset,
683- relpath);
684- DEBUG(6,("convert_shadow2_name: '%s' -> '%s'\n", fname, ret));
685- talloc_free(tmp_ctx);
686- return ret;
687-}
688-
689-
690-/*
691- simple string hash
692- */
693-static uint32 string_hash(const char *s)
694-{
695- uint32 n = 0;
696- while (*s) {
697- n = ((n << 5) + n) ^ (uint32)(*s++);
698- }
699- return n;
700+fail:
701+ saved_errno = errno;
702+ TALLOC_FREE(converted);
703+ TALLOC_FREE(insert);
704+ TALLOC_FREE(slashes);
705+ TALLOC_FREE(path);
706+ errno = saved_errno;
707+ return result;
708 }
709
710 /*
711 modify a sbuf return to ensure that inodes in the shadow directory
712 are different from those in the main directory
713 */
714-static void convert_sbuf(vfs_handle_struct *handle, const char *fname, SMB_STRUCT_STAT *sbuf)
715+static void convert_sbuf(vfs_handle_struct *handle, const char *fname,
716+ SMB_STRUCT_STAT *sbuf)
717 {
718- if (lp_parm_bool(SNUM(handle->conn), "shadow", "fixinodes", False)) {
719+ if (lp_parm_bool(SNUM(handle->conn), "shadow", "fixinodes", False)) {
720 /* some snapshot systems, like GPFS, return the name
721 device:inode for the snapshot files as the current
722 files. That breaks the 'restore' button in the shadow copy
723@@ -526,7 +437,10 @@ static void convert_sbuf(vfs_handle_stru
724 number collision, but I can't see a better approach
725 without significant VFS changes
726 */
727- uint32_t shash = string_hash(fname) & 0xFF000000;
728+ uint32_t shash;
729+ TDB_DATA data = string_tdb_data(fname);
730+
731+ shash = tdb_jenkins_hash(&data) & 0xFF000000;
732 if (shash == 0) {
733 shash = 1;
734 }
735@@ -534,303 +448,594 @@ static void convert_sbuf(vfs_handle_stru
736 }
737 }
738
739+static SMB_STRUCT_DIR *shadow_copy2_opendir(vfs_handle_struct *handle,
740+ const char *fname,
741+ const char *mask,
742+ uint32 attr)
743+{
744+ time_t timestamp;
745+ char *stripped;
746+ SMB_STRUCT_DIR *ret;
747+ int saved_errno;
748+ char *conv;
749+
750+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
751+ &timestamp, &stripped)) {
752+ return NULL;
753+ }
754+ if (timestamp == 0) {
755+ return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr);
756+ }
757+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
758+ TALLOC_FREE(stripped);
759+ if (conv == NULL) {
760+ return NULL;
761+ }
762+ ret = SMB_VFS_NEXT_OPENDIR(handle, conv, mask, attr);
763+ saved_errno = errno;
764+ TALLOC_FREE(conv);
765+ errno = saved_errno;
766+ return ret;
767+}
768+
769 static int shadow_copy2_rename(vfs_handle_struct *handle,
770 const struct smb_filename *smb_fname_src,
771 const struct smb_filename *smb_fname_dst)
772 {
773- if (shadow_copy2_match_name(smb_fname_src->base_name, NULL)) {
774+ time_t timestamp_src, timestamp_dst;
775+
776+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
777+ smb_fname_src->base_name,
778+ &timestamp_src, NULL)) {
779+ return -1;
780+ }
781+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
782+ smb_fname_dst->base_name,
783+ &timestamp_dst, NULL)) {
784+ return -1;
785+ }
786+ if (timestamp_src != 0) {
787 errno = EXDEV;
788 return -1;
789 }
790- SHADOW2_NEXT2_SMB_FNAME(RENAME,
791- (handle, smb_fname_src, smb_fname_dst));
792+ if (timestamp_dst != 0) {
793+ errno = EROFS;
794+ return -1;
795+ }
796+ return SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
797 }
798
799 static int shadow_copy2_symlink(vfs_handle_struct *handle,
800 const char *oldname, const char *newname)
801 {
802- SHADOW2_NEXT2(SYMLINK, (handle, oldname, newname));
803-}
804+ time_t timestamp_old, timestamp_new;
805
806-static int shadow_copy2_link(vfs_handle_struct *handle,
807- const char *oldname, const char *newname)
808-{
809- SHADOW2_NEXT2(LINK, (handle, oldname, newname));
810+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
811+ &timestamp_old, NULL)) {
812+ return -1;
813+ }
814+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
815+ &timestamp_new, NULL)) {
816+ return -1;
817+ }
818+ if ((timestamp_old != 0) || (timestamp_new != 0)) {
819+ errno = EROFS;
820+ return -1;
821+ }
822+ return SMB_VFS_NEXT_SYMLINK(handle, oldname, newname);
823 }
824
825-static int shadow_copy2_open(vfs_handle_struct *handle,
826- struct smb_filename *smb_fname, files_struct *fsp,
827- int flags, mode_t mode)
828+static int shadow_copy2_link(vfs_handle_struct *handle,
829+ const char *oldname, const char *newname)
830 {
831- SHADOW2_NEXT_SMB_FNAME(OPEN,
832- (handle, smb_fname, fsp, flags, mode),
833- int, -1);
834-}
835+ time_t timestamp_old, timestamp_new;
836
837-static SMB_STRUCT_DIR *shadow_copy2_opendir(vfs_handle_struct *handle,
838- const char *fname, const char *mask, uint32 attr)
839-{
840- SHADOW2_NEXT(OPENDIR, (handle, name, mask, attr), SMB_STRUCT_DIR *, NULL);
841+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
842+ &timestamp_old, NULL)) {
843+ return -1;
844+ }
845+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
846+ &timestamp_new, NULL)) {
847+ return -1;
848+ }
849+ if ((timestamp_old != 0) || (timestamp_new != 0)) {
850+ errno = EROFS;
851+ return -1;
852+ }
853+ return SMB_VFS_NEXT_LINK(handle, oldname, newname);
854 }
855
856 static int shadow_copy2_stat(vfs_handle_struct *handle,
857 struct smb_filename *smb_fname)
858 {
859- _SHADOW2_NEXT_SMB_FNAME(STAT, (handle, smb_fname), int, -1,
860- convert_sbuf(handle, smb_fname->base_name,
861- &smb_fname->st));
862+ time_t timestamp;
863+ char *stripped, *tmp;
864+ int ret, saved_errno;
865+
866+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
867+ smb_fname->base_name,
868+ &timestamp, &stripped)) {
869+ return -1;
870+ }
871+ if (timestamp == 0) {
872+ return SMB_VFS_NEXT_STAT(handle, smb_fname);
873+ }
874+
875+ tmp = smb_fname->base_name;
876+ smb_fname->base_name = shadow_copy2_convert(
877+ talloc_tos(), handle, stripped, timestamp);
878+ TALLOC_FREE(stripped);
879+
880+ if (smb_fname->base_name == NULL) {
881+ smb_fname->base_name = tmp;
882+ return -1;
883+ }
884+
885+ ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
886+ saved_errno = errno;
887+
888+ TALLOC_FREE(smb_fname->base_name);
889+ smb_fname->base_name = tmp;
890+
891+ if (ret == 0) {
892+ convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
893+ }
894+ errno = saved_errno;
895+ return ret;
896 }
897
898 static int shadow_copy2_lstat(vfs_handle_struct *handle,
899 struct smb_filename *smb_fname)
900 {
901- _SHADOW2_NEXT_SMB_FNAME(LSTAT, (handle, smb_fname), int, -1,
902- convert_sbuf(handle, smb_fname->base_name,
903- &smb_fname->st));
904+ time_t timestamp;
905+ char *stripped, *tmp;
906+ int ret, saved_errno;
907+
908+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
909+ smb_fname->base_name,
910+ &timestamp, &stripped)) {
911+ return -1;
912+ }
913+ if (timestamp == 0) {
914+ return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
915+ }
916+
917+ tmp = smb_fname->base_name;
918+ smb_fname->base_name = shadow_copy2_convert(
919+ talloc_tos(), handle, stripped, timestamp);
920+ TALLOC_FREE(stripped);
921+
922+ if (smb_fname->base_name == NULL) {
923+ smb_fname->base_name = tmp;
924+ return -1;
925+ }
926+
927+ ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
928+ saved_errno = errno;
929+
930+ TALLOC_FREE(smb_fname->base_name);
931+ smb_fname->base_name = tmp;
932+
933+ if (ret == 0) {
934+ convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
935+ }
936+ errno = saved_errno;
937+ return ret;
938 }
939
940-static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
941+static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
942+ SMB_STRUCT_STAT *sbuf)
943 {
944- int ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
945- if (ret == 0 && shadow_copy2_match_name(fsp->fsp_name->base_name, NULL)) {
946+ time_t timestamp;
947+ int ret;
948+
949+ ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
950+ if (ret == -1) {
951+ return ret;
952+ }
953+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
954+ fsp->fsp_name->base_name,
955+ &timestamp, NULL)) {
956+ return 0;
957+ }
958+ if (timestamp != 0) {
959 convert_sbuf(handle, fsp->fsp_name->base_name, sbuf);
960 }
961+ return 0;
962+}
963+
964+static int shadow_copy2_open(vfs_handle_struct *handle,
965+ struct smb_filename *smb_fname, files_struct *fsp,
966+ int flags, mode_t mode)
967+{
968+ time_t timestamp;
969+ char *stripped, *tmp;
970+ int ret, saved_errno;
971+
972+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
973+ smb_fname->base_name,
974+ &timestamp, &stripped)) {
975+ return -1;
976+ }
977+ if (timestamp == 0) {
978+ return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
979+ }
980+
981+ tmp = smb_fname->base_name;
982+ smb_fname->base_name = shadow_copy2_convert(
983+ talloc_tos(), handle, stripped, timestamp);
984+ TALLOC_FREE(stripped);
985+
986+ if (smb_fname->base_name == NULL) {
987+ smb_fname->base_name = tmp;
988+ return -1;
989+ }
990+
991+ ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
992+ saved_errno = errno;
993+
994+ TALLOC_FREE(smb_fname->base_name);
995+ smb_fname->base_name = tmp;
996+
997+ errno = saved_errno;
998 return ret;
999 }
1000
1001 static int shadow_copy2_unlink(vfs_handle_struct *handle,
1002- const struct smb_filename *smb_fname_in)
1003+ const struct smb_filename *smb_fname)
1004 {
1005- struct smb_filename *smb_fname = NULL;
1006+ time_t timestamp;
1007+ char *stripped;
1008+ int ret, saved_errno;
1009+ struct smb_filename *conv;
1010 NTSTATUS status;
1011
1012- status = copy_smb_filename(talloc_tos(), smb_fname_in, &smb_fname);
1013+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1014+ smb_fname->base_name,
1015+ &timestamp, &stripped)) {
1016+ return -1;
1017+ }
1018+ if (timestamp == 0) {
1019+ return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1020+ }
1021+ status = copy_smb_filename(talloc_tos(), smb_fname, &conv);
1022 if (!NT_STATUS_IS_OK(status)) {
1023- errno = map_errno_from_nt_status(status);
1024+ errno = ENOMEM;
1025 return -1;
1026 }
1027-
1028- SHADOW2_NEXT_SMB_FNAME(UNLINK, (handle, smb_fname), int, -1);
1029+ conv->base_name = shadow_copy2_convert(
1030+ conv, handle, stripped, timestamp);
1031+ TALLOC_FREE(stripped);
1032+ if (conv->base_name == NULL) {
1033+ return -1;
1034+ }
1035+ ret = SMB_VFS_NEXT_UNLINK(handle, conv);
1036+ saved_errno = errno;
1037+ TALLOC_FREE(conv);
1038+ errno = saved_errno;
1039+ return ret;
1040 }
1041
1042-static int shadow_copy2_chmod(vfs_handle_struct *handle,
1043- const char *fname, mode_t mode)
1044+static int shadow_copy2_chmod(vfs_handle_struct *handle, const char *fname,
1045+ mode_t mode)
1046 {
1047- SHADOW2_NEXT(CHMOD, (handle, name, mode), int, -1);
1048+ time_t timestamp;
1049+ char *stripped;
1050+ int ret, saved_errno;
1051+ char *conv;
1052+
1053+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1054+ &timestamp, &stripped)) {
1055+ return -1;
1056+ }
1057+ if (timestamp == 0) {
1058+ return SMB_VFS_NEXT_CHMOD(handle, fname, mode);
1059+ }
1060+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1061+ TALLOC_FREE(stripped);
1062+ if (conv == NULL) {
1063+ return -1;
1064+ }
1065+ ret = SMB_VFS_NEXT_CHMOD(handle, conv, mode);
1066+ saved_errno = errno;
1067+ TALLOC_FREE(conv);
1068+ errno = saved_errno;
1069+ return ret;
1070 }
1071
1072-static int shadow_copy2_chown(vfs_handle_struct *handle,
1073- const char *fname, uid_t uid, gid_t gid)
1074+static int shadow_copy2_chown(vfs_handle_struct *handle, const char *fname,
1075+ uid_t uid, gid_t gid)
1076 {
1077- SHADOW2_NEXT(CHOWN, (handle, name, uid, gid), int, -1);
1078+ time_t timestamp;
1079+ char *stripped;
1080+ int ret, saved_errno;
1081+ char *conv;
1082+
1083+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1084+ &timestamp, &stripped)) {
1085+ return -1;
1086+ }
1087+ if (timestamp == 0) {
1088+ return SMB_VFS_NEXT_CHOWN(handle, fname, uid, gid);
1089+ }
1090+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1091+ TALLOC_FREE(stripped);
1092+ if (conv == NULL) {
1093+ return -1;
1094+ }
1095+ ret = SMB_VFS_NEXT_CHOWN(handle, conv, uid, gid);
1096+ saved_errno = errno;
1097+ TALLOC_FREE(conv);
1098+ errno = saved_errno;
1099+ return ret;
1100 }
1101
1102 static int shadow_copy2_chdir(vfs_handle_struct *handle,
1103- const char *fname)
1104+ const char *fname)
1105 {
1106- SHADOW2_NEXT(CHDIR, (handle, name), int, -1);
1107+ time_t timestamp;
1108+ char *stripped;
1109+ int ret, saved_errno;
1110+ char *conv;
1111+
1112+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1113+ &timestamp, &stripped)) {
1114+ return -1;
1115+ }
1116+ if (timestamp == 0) {
1117+ return SMB_VFS_NEXT_CHDIR(handle, fname);
1118+ }
1119+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1120+ TALLOC_FREE(stripped);
1121+ if (conv == NULL) {
1122+ return -1;
1123+ }
1124+ ret = SMB_VFS_NEXT_CHDIR(handle, conv);
1125+ saved_errno = errno;
1126+ TALLOC_FREE(conv);
1127+ errno = saved_errno;
1128+ return ret;
1129 }
1130
1131 static int shadow_copy2_ntimes(vfs_handle_struct *handle,
1132- const struct smb_filename *smb_fname_in,
1133+ const struct smb_filename *smb_fname,
1134 struct smb_file_time *ft)
1135 {
1136- struct smb_filename *smb_fname = NULL;
1137+ time_t timestamp;
1138+ char *stripped;
1139+ int ret, saved_errno;
1140+ struct smb_filename *conv;
1141 NTSTATUS status;
1142
1143- status = copy_smb_filename(talloc_tos(), smb_fname_in, &smb_fname);
1144+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1145+ smb_fname->base_name,
1146+ &timestamp, &stripped)) {
1147+ return -1;
1148+ }
1149+ if (timestamp == 0) {
1150+ return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1151+ }
1152+ status = copy_smb_filename(talloc_tos(), smb_fname, &conv);
1153 if (!NT_STATUS_IS_OK(status)) {
1154- errno = map_errno_from_nt_status(status);
1155+ errno = ENOMEM;
1156 return -1;
1157 }
1158-
1159- SHADOW2_NEXT_SMB_FNAME(NTIMES, (handle, smb_fname, ft), int, -1);
1160+ conv->base_name = shadow_copy2_convert(
1161+ conv, handle, stripped, timestamp);
1162+ TALLOC_FREE(stripped);
1163+ if (conv->base_name == NULL) {
1164+ return -1;
1165+ }
1166+ ret = SMB_VFS_NEXT_NTIMES(handle, conv, ft);
1167+ saved_errno = errno;
1168+ TALLOC_FREE(conv);
1169+ errno = saved_errno;
1170+ return ret;
1171 }
1172
1173 static int shadow_copy2_readlink(vfs_handle_struct *handle,
1174 const char *fname, char *buf, size_t bufsiz)
1175 {
1176- SHADOW2_NEXT(READLINK, (handle, name, buf, bufsiz), int, -1);
1177-}
1178+ time_t timestamp;
1179+ char *stripped;
1180+ int ret, saved_errno;
1181+ char *conv;
1182
1183-static int shadow_copy2_mknod(vfs_handle_struct *handle,
1184- const char *fname, mode_t mode, SMB_DEV_T dev)
1185-{
1186- SHADOW2_NEXT(MKNOD, (handle, name, mode, dev), int, -1);
1187+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1188+ &timestamp, &stripped)) {
1189+ return -1;
1190+ }
1191+ if (timestamp == 0) {
1192+ return SMB_VFS_NEXT_READLINK(handle, fname, buf, bufsiz);
1193+ }
1194+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1195+ TALLOC_FREE(stripped);
1196+ if (conv == NULL) {
1197+ return -1;
1198+ }
1199+ ret = SMB_VFS_NEXT_READLINK(handle, conv, buf, bufsiz);
1200+ saved_errno = errno;
1201+ TALLOC_FREE(conv);
1202+ errno = saved_errno;
1203+ return ret;
1204 }
1205
1206-static char *shadow_copy2_realpath(vfs_handle_struct *handle,
1207- const char *fname)
1208+static int shadow_copy2_mknod(vfs_handle_struct *handle,
1209+ const char *fname, mode_t mode, SMB_DEV_T dev)
1210 {
1211- const char *gmt;
1212+ time_t timestamp;
1213+ char *stripped;
1214+ int ret, saved_errno;
1215+ char *conv;
1216
1217- if (shadow_copy2_match_name(fname, &gmt)
1218- && (gmt[GMT_NAME_LEN] == '\0')) {
1219- char *copy;
1220-
1221- copy = talloc_strdup(talloc_tos(), fname);
1222- if (copy == NULL) {
1223- errno = ENOMEM;
1224- return NULL;
1225- }
1226-
1227- copy[gmt - fname] = '.';
1228- copy[gmt - fname + 1] = '\0';
1229-
1230- DEBUG(10, ("calling NEXT_REALPATH with %s\n", copy));
1231- SHADOW2_NEXT(REALPATH, (handle, name), char *,
1232- NULL);
1233+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1234+ &timestamp, &stripped)) {
1235+ return -1;
1236+ }
1237+ if (timestamp == 0) {
1238+ return SMB_VFS_NEXT_MKNOD(handle, fname, mode, dev);
1239+ }
1240+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1241+ TALLOC_FREE(stripped);
1242+ if (conv == NULL) {
1243+ return -1;
1244 }
1245- SHADOW2_NEXT(REALPATH, (handle, name), char *, NULL);
1246+ ret = SMB_VFS_NEXT_MKNOD(handle, conv, mode, dev);
1247+ saved_errno = errno;
1248+ TALLOC_FREE(conv);
1249+ errno = saved_errno;
1250+ return ret;
1251 }
1252
1253-static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle,
1254- const char *fname)
1255+static char *shadow_copy2_realpath(vfs_handle_struct *handle,
1256+ const char *fname)
1257 {
1258- TALLOC_CTX *tmp_ctx;
1259- const char *snapdir, *baseoffset, *basedir, *gmt_start;
1260- size_t baselen;
1261- char *ret;
1262+ time_t timestamp;
1263+ char *stripped = NULL;
1264+ char *tmp = NULL;
1265+ char *result = NULL;
1266+ char *inserted = NULL;
1267+ char *inserted_to, *inserted_end;
1268+ int saved_errno;
1269
1270- DEBUG(10, ("shadow_copy2_connectpath called with %s\n", fname));
1271-
1272- if (!shadow_copy2_match_name(fname, &gmt_start)) {
1273- return handle->conn->connectpath;
1274+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1275+ &timestamp, &stripped)) {
1276+ goto done;
1277 }
1278-
1279- /*
1280- * We have to create a real temporary context because we have
1281- * to put our result on talloc_tos(). Thus we can't use a
1282- * talloc_stackframe() here.
1283- */
1284- tmp_ctx = talloc_new(talloc_tos());
1285-
1286- fname = shadow_copy2_normalise_path(tmp_ctx, fname, gmt_start);
1287- if (fname == NULL) {
1288- TALLOC_FREE(tmp_ctx);
1289- return NULL;
1290+ if (timestamp == 0) {
1291+ return SMB_VFS_NEXT_REALPATH(handle, fname);
1292 }
1293
1294- snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle);
1295- if (snapdir == NULL) {
1296- DEBUG(2,("no snapdir found for share at %s\n",
1297- handle->conn->connectpath));
1298- TALLOC_FREE(tmp_ctx);
1299- return NULL;
1300+ tmp = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1301+ if (tmp == NULL) {
1302+ goto done;
1303 }
1304
1305- basedir = shadow_copy2_find_basedir(tmp_ctx, handle);
1306- if (basedir == NULL) {
1307- DEBUG(2,("no basedir found for share at %s\n",
1308- handle->conn->connectpath));
1309- TALLOC_FREE(tmp_ctx);
1310- return NULL;
1311+ result = SMB_VFS_NEXT_REALPATH(handle, tmp);
1312+ if (result == NULL) {
1313+ goto done;
1314 }
1315
1316- baselen = strlen(basedir);
1317- baseoffset = handle->conn->connectpath + baselen;
1318-
1319- /* some sanity checks */
1320- if (strncmp(basedir, handle->conn->connectpath, baselen) != 0 ||
1321- (handle->conn->connectpath[baselen] != 0
1322- && handle->conn->connectpath[baselen] != '/')) {
1323- DEBUG(0,("shadow_copy2_connectpath: basedir %s is not a "
1324- "parent of %s\n", basedir,
1325- handle->conn->connectpath));
1326- TALLOC_FREE(tmp_ctx);
1327+ /*
1328+ * Take away what we've inserted. This removes the @GMT-thingy
1329+ * completely, but will give a path under the share root.
1330+ */
1331+ inserted = shadow_copy2_insert_string(talloc_tos(), handle, timestamp);
1332+ if (inserted == NULL) {
1333+ goto done;
1334+ }
1335+ inserted_to = strstr_m(result, inserted);
1336+ if (inserted_to == NULL) {
1337+ DEBUG(2, ("SMB_VFS_NEXT_REALPATH removed %s\n", inserted));
1338+ goto done;
1339+ }
1340+ inserted_end = inserted_to + talloc_get_size(inserted) - 1;
1341+ memmove(inserted_to, inserted_end, strlen(inserted_end)+1);
1342+
1343+done:
1344+ saved_errno = errno;
1345+ TALLOC_FREE(inserted);
1346+ TALLOC_FREE(tmp);
1347+ TALLOC_FREE(stripped);
1348+ errno = saved_errno;
1349+ return result;
1350+}
1351+
1352+static char *have_snapdir(struct vfs_handle_struct *handle,
1353+ const char *path)
1354+{
1355+ struct smb_filename smb_fname;
1356+ int ret;
1357+
1358+ ZERO_STRUCT(smb_fname);
1359+ smb_fname.base_name = talloc_asprintf(
1360+ talloc_tos(), "%s/%s", path,
1361+ lp_parm_const_string(SNUM(handle->conn), "shadow", "snapdir",
1362+ ".snapshots"));
1363+ if (smb_fname.base_name == NULL) {
1364 return NULL;
1365 }
1366
1367- if (*baseoffset == '/') baseoffset++;
1368-
1369- ret = talloc_asprintf(talloc_tos(), "%s/%.*s/%s",
1370- snapdir,
1371- GMT_NAME_LEN, fname,
1372- baseoffset);
1373- DEBUG(6,("shadow_copy2_connectpath: '%s' -> '%s'\n", fname, ret));
1374- TALLOC_FREE(tmp_ctx);
1375- return ret;
1376-}
1377-
1378-static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle,
1379- const char *fname, uint32 security_info,
1380- struct security_descriptor **ppdesc)
1381-{
1382- SHADOW2_NTSTATUS_NEXT(GET_NT_ACL, (handle, name, security_info, ppdesc), NT_STATUS_ACCESS_DENIED);
1383+ ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
1384+ if ((ret == 0) && (S_ISDIR(smb_fname.st.st_ex_mode))) {
1385+ return smb_fname.base_name;
1386+ }
1387+ TALLOC_FREE(smb_fname.base_name);
1388+ return NULL;
1389 }
1390
1391-static int shadow_copy2_mkdir(vfs_handle_struct *handle, const char *fname, mode_t mode)
1392+static char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx,
1393+ struct vfs_handle_struct *handle,
1394+ struct smb_filename *smb_fname)
1395 {
1396- SHADOW2_NEXT(MKDIR, (handle, name, mode), int, -1);
1397-}
1398+ char *path, *p;
1399+ char *snapdir;
1400
1401-static int shadow_copy2_rmdir(vfs_handle_struct *handle, const char *fname)
1402-{
1403- SHADOW2_NEXT(RMDIR, (handle, name), int, -1);
1404-}
1405+ path = talloc_asprintf(mem_ctx, "%s/%s",
1406+ handle->conn->connectpath,
1407+ smb_fname->base_name);
1408+ if (path == NULL) {
1409+ return NULL;
1410+ }
1411
1412-static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname,
1413- unsigned int flags)
1414-{
1415- SHADOW2_NEXT(CHFLAGS, (handle, name, flags), int, -1);
1416-}
1417+ snapdir = have_snapdir(handle, path);
1418+ if (snapdir != NULL) {
1419+ TALLOC_FREE(path);
1420+ return snapdir;
1421+ }
1422
1423-static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
1424- const char *fname, const char *aname, void *value, size_t size)
1425-{
1426- SHADOW2_NEXT(GETXATTR, (handle, name, aname, value, size), ssize_t, -1);
1427-}
1428+ while ((p = strrchr(path, '/')) && (p > path)) {
1429
1430-static ssize_t shadow_copy2_lgetxattr(vfs_handle_struct *handle,
1431- const char *fname, const char *aname, void *value, size_t size)
1432-{
1433- SHADOW2_NEXT(LGETXATTR, (handle, name, aname, value, size), ssize_t, -1);
1434-}
1435+ p[0] = '\0';
1436
1437-static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle, const char *fname,
1438- char *list, size_t size)
1439-{
1440- SHADOW2_NEXT(LISTXATTR, (handle, name, list, size), ssize_t, -1);
1441+ snapdir = have_snapdir(handle, path);
1442+ if (snapdir != NULL) {
1443+ TALLOC_FREE(path);
1444+ return snapdir;
1445+ }
1446+ }
1447+ TALLOC_FREE(path);
1448+ return NULL;
1449 }
1450
1451-static int shadow_copy2_removexattr(struct vfs_handle_struct *handle, const char *fname,
1452- const char *aname)
1453+static bool shadow_copy2_snapshot_to_gmt(TALLOC_CTX *mem_ctx,
1454+ vfs_handle_struct *handle,
1455+ const char *name,
1456+ char *gmt, size_t gmt_len)
1457 {
1458- SHADOW2_NEXT(REMOVEXATTR, (handle, name, aname), int, -1);
1459-}
1460+ struct tm timestamp;
1461+ time_t timestamp_t;
1462+ const char *fmt;
1463
1464-static int shadow_copy2_lremovexattr(struct vfs_handle_struct *handle, const char *fname,
1465- const char *aname)
1466-{
1467- SHADOW2_NEXT(LREMOVEXATTR, (handle, name, aname), int, -1);
1468-}
1469+ fmt = lp_parm_const_string(SNUM(handle->conn), "shadow",
1470+ "format", GMT_FORMAT);
1471
1472-static int shadow_copy2_setxattr(struct vfs_handle_struct *handle, const char *fname,
1473- const char *aname, const void *value, size_t size, int flags)
1474-{
1475- SHADOW2_NEXT(SETXATTR, (handle, name, aname, value, size, flags), int, -1);
1476-}
1477+ ZERO_STRUCT(timestamp);
1478+ if (strptime(name, fmt, &timestamp) == NULL) {
1479+ DEBUG(10, ("shadow_copy2_snapshot_to_gmt: no match %s: %s\n",
1480+ fmt, name));
1481+ return false;
1482+ }
1483
1484-static int shadow_copy2_lsetxattr(struct vfs_handle_struct *handle, const char *fname,
1485- const char *aname, const void *value, size_t size, int flags)
1486-{
1487- SHADOW2_NEXT(LSETXATTR, (handle, name, aname, value, size, flags), int, -1);
1488-}
1489+ DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n", fmt, name));
1490
1491-static int shadow_copy2_chmod_acl(vfs_handle_struct *handle,
1492- const char *fname, mode_t mode)
1493-{
1494- SHADOW2_NEXT(CHMOD_ACL, (handle, name, mode), int, -1);
1495+ if (lp_parm_bool(SNUM(handle->conn), "shadow", "localtime", false)) {
1496+ timestamp.tm_isdst = -1;
1497+ timestamp_t = mktime(&timestamp);
1498+ gmtime_r(&timestamp_t, &timestamp);
1499+ }
1500+ strftime(gmt, gmt_len, GMT_FORMAT, &timestamp);
1501+ return true;
1502 }
1503
1504 static int shadow_copy2_label_cmp_asc(const void *x, const void *y)
1505 {
1506- return strncmp((char *)x, (char *)y, sizeof(SHADOW_COPY_LABEL));
1507+ return strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1508 }
1509
1510 static int shadow_copy2_label_cmp_desc(const void *x, const void *y)
1511 {
1512- return -strncmp((char *)x, (char *)y, sizeof(SHADOW_COPY_LABEL));
1513+ return -strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1514 }
1515
1516 /*
1517@@ -843,7 +1048,7 @@ static void shadow_copy2_sort_data(vfs_h
1518 const char *sort;
1519
1520 sort = lp_parm_const_string(SNUM(handle->conn), "shadow",
1521- "sort", SHADOW_COPY2_DEFAULT_SORT);
1522+ "sort", "desc");
1523 if (sort == NULL) {
1524 return;
1525 }
1526@@ -867,18 +1072,17 @@ static void shadow_copy2_sort_data(vfs_h
1527 return;
1528 }
1529
1530-static int shadow_copy2_get_shadow_copy2_data(vfs_handle_struct *handle,
1531- files_struct *fsp,
1532- struct shadow_copy_data *shadow_copy2_data,
1533- bool labels)
1534+static int shadow_copy2_get_shadow_copy_data(
1535+ vfs_handle_struct *handle, files_struct *fsp,
1536+ struct shadow_copy_data *shadow_copy2_data,
1537+ bool labels)
1538 {
1539 SMB_STRUCT_DIR *p;
1540 const char *snapdir;
1541 SMB_STRUCT_DIRENT *d;
1542- TALLOC_CTX *tmp_ctx = talloc_new(handle->data);
1543- char *snapshot;
1544+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
1545
1546- snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle);
1547+ snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle, fsp->fsp_name);
1548 if (snapdir == NULL) {
1549 DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
1550 handle->conn->connectpath));
1551@@ -901,16 +1105,23 @@ static int shadow_copy2_get_shadow_copy2
1552 shadow_copy2_data->labels = NULL;
1553
1554 while ((d = SMB_VFS_NEXT_READDIR(handle, p, NULL))) {
1555+ char snapshot[GMT_NAME_LEN+1];
1556 SHADOW_COPY_LABEL *tlabels;
1557
1558- /* ignore names not of the right form in the snapshot directory */
1559- snapshot = shadow_copy2_snapshot_to_gmt(tmp_ctx, handle,
1560- d->d_name);
1561- DEBUG(6,("shadow_copy2_get_shadow_copy2_data: %s -> %s\n",
1562- d->d_name, snapshot));
1563- if (!snapshot) {
1564+ /*
1565+ * ignore names not of the right form in the snapshot
1566+ * directory
1567+ */
1568+ if (!shadow_copy2_snapshot_to_gmt(
1569+ tmp_ctx, handle, d->d_name,
1570+ snapshot, sizeof(snapshot))) {
1571+
1572+ DEBUG(6, ("shadow_copy2_get_shadow_copy_data: "
1573+ "ignoring %s\n", d->d_name));
1574 continue;
1575 }
1576+ DEBUG(6,("shadow_copy2_get_shadow_copy_data: %s -> %s\n",
1577+ d->d_name, snapshot));
1578
1579 if (!labels) {
1580 /* the caller doesn't want the labels */
1581@@ -920,7 +1131,8 @@ static int shadow_copy2_get_shadow_copy2
1582
1583 tlabels = talloc_realloc(shadow_copy2_data,
1584 shadow_copy2_data->labels,
1585- SHADOW_COPY_LABEL, shadow_copy2_data->num_volumes+1);
1586+ SHADOW_COPY_LABEL,
1587+ shadow_copy2_data->num_volumes+1);
1588 if (tlabels == NULL) {
1589 DEBUG(0,("shadow_copy2: out of memory\n"));
1590 SMB_VFS_NEXT_CLOSEDIR(handle, p);
1591@@ -930,7 +1142,6 @@ static int shadow_copy2_get_shadow_copy2
1592
1593 strlcpy(tlabels[shadow_copy2_data->num_volumes], snapshot,
1594 sizeof(*tlabels));
1595- talloc_free(snapshot);
1596
1597 shadow_copy2_data->num_volumes++;
1598 shadow_copy2_data->labels = tlabels;
1599@@ -944,59 +1155,455 @@ static int shadow_copy2_get_shadow_copy2
1600 return 0;
1601 }
1602
1603-static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
1604- .opendir = shadow_copy2_opendir,
1605- .mkdir = shadow_copy2_mkdir,
1606- .rmdir = shadow_copy2_rmdir,
1607- .chflags = shadow_copy2_chflags,
1608- .getxattr = shadow_copy2_getxattr,
1609- .lgetxattr = shadow_copy2_lgetxattr,
1610- .listxattr = shadow_copy2_listxattr,
1611- .removexattr = shadow_copy2_removexattr,
1612- .lremovexattr = shadow_copy2_lremovexattr,
1613- .setxattr = shadow_copy2_setxattr,
1614- .lsetxattr = shadow_copy2_lsetxattr,
1615- .open_fn = shadow_copy2_open,
1616- .rename = shadow_copy2_rename,
1617- .stat = shadow_copy2_stat,
1618- .lstat = shadow_copy2_lstat,
1619- .fstat = shadow_copy2_fstat,
1620- .unlink = shadow_copy2_unlink,
1621- .chmod = shadow_copy2_chmod,
1622- .chown = shadow_copy2_chown,
1623- .chdir = shadow_copy2_chdir,
1624- .ntimes = shadow_copy2_ntimes,
1625- .symlink = shadow_copy2_symlink,
1626- .vfs_readlink = shadow_copy2_readlink,
1627- .link = shadow_copy2_link,
1628- .mknod = shadow_copy2_mknod,
1629- .realpath = shadow_copy2_realpath,
1630- .connectpath = shadow_copy2_connectpath,
1631- .get_nt_acl = shadow_copy2_get_nt_acl,
1632- .chmod_acl = shadow_copy2_chmod_acl,
1633- .get_shadow_copy_data = shadow_copy2_get_shadow_copy2_data,
1634-};
1635+static NTSTATUS shadow_copy2_fget_nt_acl(vfs_handle_struct *handle,
1636+ struct files_struct *fsp,
1637+ uint32 security_info,
1638+ struct security_descriptor **ppdesc)
1639+{
1640+ time_t timestamp;
1641+ char *stripped;
1642+ NTSTATUS status;
1643+ char *conv;
1644
1645-NTSTATUS vfs_shadow_copy2_init(void);
1646-NTSTATUS vfs_shadow_copy2_init(void)
1647+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1648+ fsp->fsp_name->base_name,
1649+ &timestamp, &stripped)) {
1650+ return map_nt_error_from_unix(errno);
1651+ }
1652+ if (timestamp == 0) {
1653+ return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
1654+ ppdesc);
1655+ }
1656+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1657+ TALLOC_FREE(stripped);
1658+ if (conv == NULL) {
1659+ return map_nt_error_from_unix(errno);
1660+ }
1661+ status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv, security_info, ppdesc);
1662+ TALLOC_FREE(conv);
1663+ return status;
1664+}
1665+
1666+static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle,
1667+ const char *fname,
1668+ uint32 security_info,
1669+ struct security_descriptor **ppdesc)
1670 {
1671- NTSTATUS ret;
1672+ time_t timestamp;
1673+ char *stripped;
1674+ NTSTATUS status;
1675+ char *conv;
1676
1677- ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "shadow_copy2",
1678- &vfs_shadow_copy2_fns);
1679+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1680+ &timestamp, &stripped)) {
1681+ return map_nt_error_from_unix(errno);
1682+ }
1683+ if (timestamp == 0) {
1684+ return SMB_VFS_NEXT_GET_NT_ACL(handle, fname, security_info,
1685+ ppdesc);
1686+ }
1687+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1688+ TALLOC_FREE(stripped);
1689+ if (conv == NULL) {
1690+ return map_nt_error_from_unix(errno);
1691+ }
1692+ status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv, security_info, ppdesc);
1693+ TALLOC_FREE(conv);
1694+ return status;
1695+}
1696
1697- if (!NT_STATUS_IS_OK(ret))
1698- return ret;
1699+static int shadow_copy2_mkdir(vfs_handle_struct *handle,
1700+ const char *fname, mode_t mode)
1701+{
1702+ time_t timestamp;
1703+ char *stripped;
1704+ int ret, saved_errno;
1705+ char *conv;
1706
1707- vfs_shadow_copy2_debug_level = debug_add_class("shadow_copy2");
1708- if (vfs_shadow_copy2_debug_level == -1) {
1709- vfs_shadow_copy2_debug_level = DBGC_VFS;
1710- DEBUG(0, ("%s: Couldn't register custom debugging class!\n",
1711- "vfs_shadow_copy2_init"));
1712- } else {
1713- DEBUG(10, ("%s: Debug class number of '%s': %d\n",
1714- "vfs_shadow_copy2_init","shadow_copy2",vfs_shadow_copy2_debug_level));
1715+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1716+ &timestamp, &stripped)) {
1717+ return -1;
1718+ }
1719+ if (timestamp == 0) {
1720+ return SMB_VFS_NEXT_MKDIR(handle, fname, mode);
1721+ }
1722+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1723+ TALLOC_FREE(stripped);
1724+ if (conv == NULL) {
1725+ return -1;
1726+ }
1727+ ret = SMB_VFS_NEXT_MKDIR(handle, conv, mode);
1728+ saved_errno = errno;
1729+ TALLOC_FREE(conv);
1730+ errno = saved_errno;
1731+ return ret;
1732+}
1733+
1734+static int shadow_copy2_rmdir(vfs_handle_struct *handle, const char *fname)
1735+{
1736+ time_t timestamp;
1737+ char *stripped;
1738+ int ret, saved_errno;
1739+ char *conv;
1740+
1741+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1742+ &timestamp, &stripped)) {
1743+ return -1;
1744 }
1745+ if (timestamp == 0) {
1746+ return SMB_VFS_NEXT_RMDIR(handle, fname);
1747+ }
1748+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1749+ TALLOC_FREE(stripped);
1750+ if (conv == NULL) {
1751+ return -1;
1752+ }
1753+ ret = SMB_VFS_NEXT_RMDIR(handle, conv);
1754+ saved_errno = errno;
1755+ TALLOC_FREE(conv);
1756+ errno = saved_errno;
1757+ return ret;
1758+}
1759+
1760+static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname,
1761+ unsigned int flags)
1762+{
1763+ time_t timestamp;
1764+ char *stripped;
1765+ int ret, saved_errno;
1766+ char *conv;
1767
1768+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1769+ &timestamp, &stripped)) {
1770+ return -1;
1771+ }
1772+ if (timestamp == 0) {
1773+ return SMB_VFS_NEXT_CHFLAGS(handle, fname, flags);
1774+ }
1775+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1776+ TALLOC_FREE(stripped);
1777+ if (conv == NULL) {
1778+ return -1;
1779+ }
1780+ ret = SMB_VFS_NEXT_CHFLAGS(handle, conv, flags);
1781+ saved_errno = errno;
1782+ TALLOC_FREE(conv);
1783+ errno = saved_errno;
1784 return ret;
1785 }
1786+
1787+static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
1788+ const char *fname, const char *aname,
1789+ void *value, size_t size)
1790+{
1791+ time_t timestamp;
1792+ char *stripped;
1793+ ssize_t ret;
1794+ int saved_errno;
1795+ char *conv;
1796+
1797+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1798+ &timestamp, &stripped)) {
1799+ return -1;
1800+ }
1801+ if (timestamp == 0) {
1802+ return SMB_VFS_NEXT_GETXATTR(handle, fname, aname, value,
1803+ size);
1804+ }
1805+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1806+ TALLOC_FREE(stripped);
1807+ if (conv == NULL) {
1808+ return -1;
1809+ }
1810+ ret = SMB_VFS_NEXT_GETXATTR(handle, conv, aname, value, size);
1811+ saved_errno = errno;
1812+ TALLOC_FREE(conv);
1813+ errno = saved_errno;
1814+ return ret;
1815+}
1816+
1817+static ssize_t shadow_copy2_lgetxattr(vfs_handle_struct *handle,
1818+ const char *fname, const char *aname,
1819+ void *value, size_t size)
1820+{
1821+ time_t timestamp;
1822+ char *stripped;
1823+ ssize_t ret;
1824+ int saved_errno;
1825+ char *conv;
1826+
1827+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1828+ &timestamp, &stripped)) {
1829+ return -1;
1830+ }
1831+ if (timestamp == 0) {
1832+ return SMB_VFS_NEXT_LGETXATTR(handle, fname, aname, value,
1833+ size);
1834+ }
1835+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1836+ TALLOC_FREE(stripped);
1837+ if (conv == NULL) {
1838+ return -1;
1839+ }
1840+ ret = SMB_VFS_NEXT_LGETXATTR(handle, conv, aname, value, size);
1841+ saved_errno = errno;
1842+ TALLOC_FREE(conv);
1843+ errno = saved_errno;
1844+ return ret;
1845+}
1846+
1847+static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle,
1848+ const char *fname,
1849+ char *list, size_t size)
1850+{
1851+ time_t timestamp;
1852+ char *stripped;
1853+ ssize_t ret;
1854+ int saved_errno;
1855+ char *conv;
1856+
1857+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1858+ &timestamp, &stripped)) {
1859+ return -1;
1860+ }
1861+ if (timestamp == 0) {
1862+ return SMB_VFS_NEXT_LISTXATTR(handle, fname, list, size);
1863+ }
1864+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1865+ TALLOC_FREE(stripped);
1866+ if (conv == NULL) {
1867+ return -1;
1868+ }
1869+ ret = SMB_VFS_NEXT_LISTXATTR(handle, conv, list, size);
1870+ saved_errno = errno;
1871+ TALLOC_FREE(conv);
1872+ errno = saved_errno;
1873+ return ret;
1874+}
1875+
1876+static int shadow_copy2_removexattr(vfs_handle_struct *handle,
1877+ const char *fname, const char *aname)
1878+{
1879+ time_t timestamp;
1880+ char *stripped;
1881+ int ret, saved_errno;
1882+ char *conv;
1883+
1884+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1885+ &timestamp, &stripped)) {
1886+ return -1;
1887+ }
1888+ if (timestamp == 0) {
1889+ return SMB_VFS_NEXT_REMOVEXATTR(handle, fname, aname);
1890+ }
1891+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1892+ TALLOC_FREE(stripped);
1893+ if (conv == NULL) {
1894+ return -1;
1895+ }
1896+ ret = SMB_VFS_NEXT_REMOVEXATTR(handle, conv, aname);
1897+ saved_errno = errno;
1898+ TALLOC_FREE(conv);
1899+ errno = saved_errno;
1900+ return ret;
1901+}
1902+
1903+static int shadow_copy2_lremovexattr(vfs_handle_struct *handle,
1904+ const char *fname, const char *aname)
1905+{
1906+ time_t timestamp;
1907+ char *stripped;
1908+ int ret, saved_errno;
1909+ char *conv;
1910+
1911+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1912+ &timestamp, &stripped)) {
1913+ return -1;
1914+ }
1915+ if (timestamp == 0) {
1916+ return SMB_VFS_NEXT_LREMOVEXATTR(handle, fname, aname);
1917+ }
1918+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1919+ TALLOC_FREE(stripped);
1920+ if (conv == NULL) {
1921+ return -1;
1922+ }
1923+ ret = SMB_VFS_NEXT_LREMOVEXATTR(handle, conv, aname);
1924+ saved_errno = errno;
1925+ TALLOC_FREE(conv);
1926+ errno = saved_errno;
1927+ return ret;
1928+}
1929+
1930+static int shadow_copy2_setxattr(struct vfs_handle_struct *handle,
1931+ const char *fname,
1932+ const char *aname, const void *value,
1933+ size_t size, int flags)
1934+{
1935+ time_t timestamp;
1936+ char *stripped;
1937+ ssize_t ret;
1938+ int saved_errno;
1939+ char *conv;
1940+
1941+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1942+ &timestamp, &stripped)) {
1943+ return -1;
1944+ }
1945+ if (timestamp == 0) {
1946+ return SMB_VFS_NEXT_SETXATTR(handle, fname, aname, value, size,
1947+ flags);
1948+ }
1949+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1950+ TALLOC_FREE(stripped);
1951+ if (conv == NULL) {
1952+ return -1;
1953+ }
1954+ ret = SMB_VFS_NEXT_SETXATTR(handle, conv, aname, value, size, flags);
1955+ saved_errno = errno;
1956+ TALLOC_FREE(conv);
1957+ errno = saved_errno;
1958+ return ret;
1959+}
1960+
1961+static int shadow_copy2_lsetxattr(struct vfs_handle_struct *handle,
1962+ const char *fname,
1963+ const char *aname, const void *value,
1964+ size_t size, int flags)
1965+{
1966+ time_t timestamp;
1967+ char *stripped;
1968+ ssize_t ret;
1969+ int saved_errno;
1970+ char *conv;
1971+
1972+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1973+ &timestamp, &stripped)) {
1974+ return -1;
1975+ }
1976+ if (timestamp == 0) {
1977+ return SMB_VFS_NEXT_LSETXATTR(handle, fname, aname, value,
1978+ size, flags);
1979+ }
1980+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1981+ TALLOC_FREE(stripped);
1982+ if (conv == NULL) {
1983+ return -1;
1984+ }
1985+ ret = SMB_VFS_NEXT_LSETXATTR(handle, conv, aname, value, size, flags);
1986+ saved_errno = errno;
1987+ TALLOC_FREE(conv);
1988+ errno = saved_errno;
1989+ return ret;
1990+}
1991+
1992+static int shadow_copy2_chmod_acl(vfs_handle_struct *handle,
1993+ const char *fname, mode_t mode)
1994+{
1995+ time_t timestamp;
1996+ char *stripped;
1997+ ssize_t ret;
1998+ int saved_errno;
1999+ char *conv;
2000+
2001+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2002+ &timestamp, &stripped)) {
2003+ return -1;
2004+ }
2005+ if (timestamp == 0) {
2006+ return SMB_VFS_NEXT_CHMOD_ACL(handle, fname, mode);
2007+ }
2008+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2009+ TALLOC_FREE(stripped);
2010+ if (conv == NULL) {
2011+ return -1;
2012+ }
2013+ ret = SMB_VFS_NEXT_CHMOD_ACL(handle, conv, mode);
2014+ saved_errno = errno;
2015+ TALLOC_FREE(conv);
2016+ errno = saved_errno;
2017+ return ret;
2018+}
2019+
2020+static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle,
2021+ const char *path,
2022+ const char *name,
2023+ TALLOC_CTX *mem_ctx,
2024+ char **found_name)
2025+{
2026+ time_t timestamp;
2027+ char *stripped;
2028+ ssize_t ret;
2029+ int saved_errno;
2030+ char *conv;
2031+
2032+ if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
2033+ &timestamp, &stripped)) {
2034+ return -1;
2035+ }
2036+ if (timestamp == 0) {
2037+ return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
2038+ mem_ctx, found_name);
2039+ }
2040+ if (stripped[0] == '\0') {
2041+ *found_name = talloc_strdup(mem_ctx, name);
2042+ if (*found_name == NULL) {
2043+ errno = ENOMEM;
2044+ return -1;
2045+ }
2046+ return 0;
2047+ }
2048+ conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2049+ TALLOC_FREE(stripped);
2050+ if (conv == NULL) {
2051+ return -1;
2052+ }
2053+ ret = SMB_VFS_NEXT_GET_REAL_FILENAME(handle, conv, name,
2054+ mem_ctx, found_name);
2055+ saved_errno = errno;
2056+ TALLOC_FREE(conv);
2057+ errno = saved_errno;
2058+ return ret;
2059+}
2060+
2061+
2062+static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
2063+ .opendir = shadow_copy2_opendir,
2064+ .rename = shadow_copy2_rename,
2065+ .link = shadow_copy2_link,
2066+ .symlink = shadow_copy2_symlink,
2067+ .stat = shadow_copy2_stat,
2068+ .lstat = shadow_copy2_lstat,
2069+ .fstat = shadow_copy2_fstat,
2070+ .open_fn = shadow_copy2_open,
2071+ .unlink = shadow_copy2_unlink,
2072+ .chmod = shadow_copy2_chmod,
2073+ .chown = shadow_copy2_chown,
2074+ .chdir = shadow_copy2_chdir,
2075+ .ntimes = shadow_copy2_ntimes,
2076+ .vfs_readlink = shadow_copy2_readlink,
2077+ .mknod = shadow_copy2_mknod,
2078+ .realpath = shadow_copy2_realpath,
2079+ .get_nt_acl = shadow_copy2_get_nt_acl,
2080+ .fget_nt_acl = shadow_copy2_fget_nt_acl,
2081+ .get_shadow_copy_data = shadow_copy2_get_shadow_copy_data,
2082+ .mkdir = shadow_copy2_mkdir,
2083+ .rmdir = shadow_copy2_rmdir,
2084+ .getxattr = shadow_copy2_getxattr,
2085+ .lgetxattr = shadow_copy2_lgetxattr,
2086+ .listxattr = shadow_copy2_listxattr,
2087+ .removexattr = shadow_copy2_removexattr,
2088+ .lremovexattr = shadow_copy2_lremovexattr,
2089+ .setxattr = shadow_copy2_setxattr,
2090+ .lsetxattr = shadow_copy2_lsetxattr,
2091+ .chmod_acl = shadow_copy2_chmod_acl,
2092+ .chflags = shadow_copy2_chflags,
2093+ .get_real_filename = shadow_copy2_get_real_filename,
2094+};
2095+
2096+NTSTATUS vfs_shadow_copy2_init(void);
2097+NTSTATUS vfs_shadow_copy2_init(void)
2098+{
2099+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2100+ "shadow_copy2", &vfs_shadow_copy2_fns);
2101+}