diff options
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.patch | 2101 |
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 @@ | |||
1 | Description: 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 | ||
8 | Author: Ivo De Decker <ivo.dedecker@ugent.be> | ||
9 | Origin: upstream | ||
10 | Bug: https://bugzilla.samba.org/show_bug.cgi?id=7287 | ||
11 | Forwarded: not-needed | ||
12 | Last-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, ×tamp) == 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(×tamp); | ||
148 | - gmtime_r(×tamp_t, ×tamp); | ||
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, ×tamp); | ||
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, ×tamp); | ||
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(×tamp); | ||
626 | - localtime_r(×tamp_t, ×tamp); | ||
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, ×tamp); | ||
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 | + ×tamp, &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 | + ×tamp_src, NULL)) { | ||
779 | + return -1; | ||
780 | + } | ||
781 | + if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, | ||
782 | + smb_fname_dst->base_name, | ||
783 | + ×tamp_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 | + ×tamp_old, NULL)) { | ||
812 | + return -1; | ||
813 | + } | ||
814 | + if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname, | ||
815 | + ×tamp_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 | + ×tamp_old, NULL)) { | ||
843 | + return -1; | ||
844 | + } | ||
845 | + if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname, | ||
846 | + ×tamp_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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, 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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, &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, ×tamp) == 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(×tamp); | ||
1498 | + gmtime_r(×tamp_t, ×tamp); | ||
1499 | + } | ||
1500 | + strftime(gmt, gmt_len, GMT_FORMAT, ×tamp); | ||
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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, &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 | + ×tamp, &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 | +} | ||