Line data Source code
1 : /*
2 : * shadow_copy2: a shadow copy module (second implementation)
3 : *
4 : * Copyright (C) Andrew Tridgell 2007 (portions taken from shadow_copy2)
5 : * Copyright (C) Ed Plese 2009
6 : * Copyright (C) Volker Lendecke 2011
7 : * Copyright (C) Christian Ambach 2011
8 : * Copyright (C) Michael Adam 2013
9 : * Copyright (C) Rajesh Joseph 2016
10 : *
11 : * This program is free software; you can redistribute it and/or modify
12 : * it under the terms of the GNU General Public License as published by
13 : * the Free Software Foundation; either version 2 of the License, or
14 : * (at your option) any later version.
15 : *
16 : * This program is distributed in the hope that it will be useful,
17 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : * GNU General Public License for more details.
20 : *
21 : * You should have received a copy of the GNU General Public License
22 : * along with this program; if not, write to the Free Software
23 : * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 : */
25 :
26 : /*
27 : * This is a second implemetation of a shadow copy module for exposing
28 : * file system snapshots to windows clients as shadow copies.
29 : *
30 : * See the manual page for documentation.
31 : */
32 :
33 : #include "includes.h"
34 : #include "smbd/smbd.h"
35 : #include "system/filesys.h"
36 : #include "include/ntioctl.h"
37 : #include "util_tdb.h"
38 : #include "lib/util_path.h"
39 : #include "libcli/security/security.h"
40 : #include "lib/util/tevent_unix.h"
41 :
42 : struct shadow_copy2_config {
43 : char *gmt_format;
44 : bool use_sscanf;
45 : bool use_localtime;
46 : char *snapdir;
47 : char *delimiter;
48 : bool snapdirseverywhere;
49 : bool crossmountpoints;
50 : bool fixinodes;
51 : char *sort_order;
52 : bool snapdir_absolute;
53 : char *mount_point;
54 : char *rel_connectpath; /* share root, relative to a snapshot root */
55 : char *snapshot_basepath; /* the absolute version of snapdir */
56 : };
57 :
58 : /* Data-structure to hold the list of snap entries */
59 : struct shadow_copy2_snapentry {
60 : char *snapname;
61 : char *time_fmt;
62 : struct shadow_copy2_snapentry *next;
63 : struct shadow_copy2_snapentry *prev;
64 : };
65 :
66 : struct shadow_copy2_snaplist_info {
67 : struct shadow_copy2_snapentry *snaplist; /* snapshot list */
68 : regex_t *regex; /* Regex to filter snaps */
69 : time_t fetch_time; /* snaplist update time */
70 : };
71 :
72 :
73 : /*
74 : * shadow_copy2 private structure. This structure will be
75 : * used to keep module specific information
76 : */
77 : struct shadow_copy2_private {
78 : struct shadow_copy2_config *config;
79 : struct shadow_copy2_snaplist_info *snaps;
80 : char *shadow_cwd; /* Absolute $cwd path. */
81 : /* Absolute connectpath - can vary depending on $cwd. */
82 : char *shadow_connectpath;
83 : /* talloc'ed realpath return. */
84 : struct smb_filename *shadow_realpath;
85 : };
86 :
87 : static int shadow_copy2_get_shadow_copy_data(
88 : vfs_handle_struct *handle, files_struct *fsp,
89 : struct shadow_copy_data *shadow_copy2_data,
90 : bool labels);
91 :
92 : /**
93 : *This function will create a new snapshot list entry and
94 : * return to the caller. This entry will also be added to
95 : * the global snapshot list.
96 : *
97 : * @param[in] priv shadow_copy2 specific data structure
98 : * @return Newly created snapshot entry or NULL on failure
99 : */
100 0 : static struct shadow_copy2_snapentry *shadow_copy2_create_snapentry(
101 : struct shadow_copy2_private *priv)
102 : {
103 0 : struct shadow_copy2_snapentry *tmpentry = NULL;
104 :
105 0 : tmpentry = talloc_zero(priv->snaps, struct shadow_copy2_snapentry);
106 0 : if (tmpentry == NULL) {
107 0 : DBG_ERR("talloc_zero() failed\n");
108 0 : errno = ENOMEM;
109 0 : return NULL;
110 : }
111 :
112 0 : DLIST_ADD(priv->snaps->snaplist, tmpentry);
113 :
114 0 : return tmpentry;
115 : }
116 :
117 : /**
118 : *This function will delete the entire snaplist and reset
119 : * priv->snaps->snaplist to NULL.
120 : *
121 : * @param[in] priv shadow_copye specific data structure
122 : */
123 0 : static void shadow_copy2_delete_snaplist(struct shadow_copy2_private *priv)
124 : {
125 0 : struct shadow_copy2_snapentry *tmp = NULL;
126 :
127 0 : while ((tmp = priv->snaps->snaplist) != NULL) {
128 0 : DLIST_REMOVE(priv->snaps->snaplist, tmp);
129 0 : talloc_free(tmp);
130 : }
131 0 : }
132 :
133 : /**
134 : * Given a timestamp this function searches the global snapshot list
135 : * and returns the complete snapshot directory name saved in the entry.
136 : *
137 : * @param[in] priv shadow_copy2 specific structure
138 : * @param[in] timestamp timestamp corresponding to one of the snapshot
139 : * @param[out] snap_str buffer to copy the actual snapshot name
140 : * @param[in] len length of snap_str buffer
141 : *
142 : * @return Length of actual snapshot name, and -1 on failure
143 : */
144 0 : static ssize_t shadow_copy2_saved_snapname(struct shadow_copy2_private *priv,
145 : struct tm *timestamp,
146 : char *snap_str, size_t len)
147 : {
148 0 : ssize_t snaptime_len = -1;
149 0 : struct shadow_copy2_snapentry *entry = NULL;
150 :
151 0 : snaptime_len = strftime(snap_str, len, GMT_FORMAT, timestamp);
152 0 : if (snaptime_len == 0) {
153 0 : DBG_ERR("strftime failed\n");
154 0 : return -1;
155 : }
156 :
157 0 : snaptime_len = -1;
158 :
159 0 : for (entry = priv->snaps->snaplist; entry; entry = entry->next) {
160 0 : if (strcmp(entry->time_fmt, snap_str) == 0) {
161 0 : snaptime_len = snprintf(snap_str, len, "%s",
162 : entry->snapname);
163 0 : return snaptime_len;
164 : }
165 : }
166 :
167 0 : snap_str[0] = 0;
168 0 : return snaptime_len;
169 : }
170 :
171 :
172 : /**
173 : * This function will check if snaplist is updated or not. If snaplist
174 : * is empty then it will create a new list. Each time snaplist is updated
175 : * the time is recorded. If the snapshot time is greater than the snaplist
176 : * update time then chances are we are working on an older list. Then discard
177 : * the old list and fetch a new snaplist.
178 : *
179 : * @param[in] handle VFS handle struct
180 : * @param[in] snap_time time of snapshot
181 : *
182 : * @return true if the list is updated else false
183 : */
184 0 : static bool shadow_copy2_update_snaplist(struct vfs_handle_struct *handle,
185 : time_t snap_time)
186 : {
187 0 : int ret = -1;
188 0 : bool snaplist_updated = false;
189 0 : struct files_struct fsp = {0};
190 0 : struct smb_filename smb_fname = {0};
191 0 : double seconds = 0.0;
192 0 : struct shadow_copy2_private *priv = NULL;
193 :
194 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
195 : return false);
196 :
197 0 : seconds = difftime(snap_time, priv->snaps->fetch_time);
198 :
199 : /*
200 : * Fetch the snapshot list if either the snaplist is empty or the
201 : * required snapshot time is greater than the last fetched snaplist
202 : * time.
203 : */
204 0 : if (seconds > 0 || (priv->snaps->snaplist == NULL)) {
205 0 : smb_fname.base_name = discard_const_p(char, ".");
206 0 : fsp.fsp_name = &smb_fname;
207 :
208 0 : ret = shadow_copy2_get_shadow_copy_data(handle, &fsp,
209 : NULL, false);
210 0 : if (ret == 0) {
211 0 : snaplist_updated = true;
212 : } else {
213 0 : DBG_ERR("Failed to get shadow copy data\n");
214 : }
215 :
216 : }
217 :
218 0 : return snaplist_updated;
219 : }
220 :
221 0 : static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str,
222 : size_t **poffsets,
223 : unsigned *pnum_offsets)
224 : {
225 : unsigned num_offsets;
226 : size_t *offsets;
227 : const char *p;
228 :
229 0 : num_offsets = 0;
230 :
231 0 : p = str;
232 0 : while ((p = strchr(p, '/')) != NULL) {
233 0 : num_offsets += 1;
234 0 : p += 1;
235 : }
236 :
237 0 : offsets = talloc_array(mem_ctx, size_t, num_offsets);
238 0 : if (offsets == NULL) {
239 0 : return false;
240 : }
241 :
242 0 : p = str;
243 0 : num_offsets = 0;
244 0 : while ((p = strchr(p, '/')) != NULL) {
245 0 : offsets[num_offsets] = p-str;
246 0 : num_offsets += 1;
247 0 : p += 1;
248 : }
249 :
250 0 : *poffsets = offsets;
251 0 : *pnum_offsets = num_offsets;
252 0 : return true;
253 : }
254 :
255 : /**
256 : * Given a timestamp, build the posix level GMT-tag string
257 : * based on the configurable format.
258 : */
259 0 : static ssize_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct *handle,
260 : time_t snapshot,
261 : char *snaptime_string,
262 : size_t len)
263 : {
264 : struct tm snap_tm;
265 : ssize_t snaptime_len;
266 : struct shadow_copy2_config *config;
267 : struct shadow_copy2_private *priv;
268 :
269 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
270 : return 0);
271 :
272 0 : config = priv->config;
273 :
274 0 : if (config->use_sscanf) {
275 0 : snaptime_len = snprintf(snaptime_string,
276 : len,
277 0 : config->gmt_format,
278 : (unsigned long)snapshot);
279 0 : if (snaptime_len <= 0) {
280 0 : DEBUG(10, ("snprintf failed\n"));
281 0 : return -1;
282 : }
283 : } else {
284 0 : if (config->use_localtime) {
285 0 : if (localtime_r(&snapshot, &snap_tm) == 0) {
286 0 : DEBUG(10, ("gmtime_r failed\n"));
287 0 : return -1;
288 : }
289 : } else {
290 0 : if (gmtime_r(&snapshot, &snap_tm) == 0) {
291 0 : DEBUG(10, ("gmtime_r failed\n"));
292 0 : return -1;
293 : }
294 : }
295 :
296 0 : if (priv->snaps->regex != NULL) {
297 0 : snaptime_len = shadow_copy2_saved_snapname(priv,
298 : &snap_tm, snaptime_string, len);
299 0 : if (snaptime_len >= 0)
300 0 : return snaptime_len;
301 :
302 : /*
303 : * If we fail to find the snapshot name, chances are
304 : * that we have not updated our snaplist. Make sure the
305 : * snaplist is updated.
306 : */
307 0 : if (!shadow_copy2_update_snaplist(handle, snapshot)) {
308 0 : DBG_DEBUG("shadow_copy2_update_snaplist "
309 : "failed\n");
310 0 : return -1;
311 : }
312 :
313 0 : return shadow_copy2_saved_snapname(priv,
314 : &snap_tm, snaptime_string, len);
315 : }
316 :
317 0 : snaptime_len = strftime(snaptime_string,
318 : len,
319 0 : config->gmt_format,
320 : &snap_tm);
321 0 : if (snaptime_len == 0) {
322 0 : DEBUG(10, ("strftime failed\n"));
323 0 : return -1;
324 : }
325 : }
326 :
327 0 : return snaptime_len;
328 : }
329 :
330 : /**
331 : * Given a timestamp, build the string to insert into a path
332 : * as a path component for creating the local path to the
333 : * snapshot at the given timestamp of the input path.
334 : *
335 : * In the case of a parallel snapdir (specified with an
336 : * absolute path), this is the initial portion of the
337 : * local path of any snapshot file. The complete path is
338 : * obtained by appending the portion of the file's path
339 : * below the share root's mountpoint.
340 : */
341 0 : static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx,
342 : struct vfs_handle_struct *handle,
343 : time_t snapshot)
344 : {
345 : fstring snaptime_string;
346 0 : ssize_t snaptime_len = 0;
347 0 : char *result = NULL;
348 : struct shadow_copy2_config *config;
349 : struct shadow_copy2_private *priv;
350 :
351 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
352 : return NULL);
353 :
354 0 : config = priv->config;
355 :
356 0 : snaptime_len = shadow_copy2_posix_gmt_string(handle,
357 : snapshot,
358 : snaptime_string,
359 : sizeof(snaptime_string));
360 0 : if (snaptime_len <= 0) {
361 0 : return NULL;
362 : }
363 :
364 0 : if (config->snapdir_absolute) {
365 0 : result = talloc_asprintf(mem_ctx, "%s/%s",
366 : config->snapdir, snaptime_string);
367 : } else {
368 0 : result = talloc_asprintf(mem_ctx, "/%s/%s",
369 : config->snapdir, snaptime_string);
370 : }
371 0 : if (result == NULL) {
372 0 : DEBUG(1, (__location__ " talloc_asprintf failed\n"));
373 : }
374 :
375 0 : return result;
376 : }
377 :
378 : /**
379 : * Build the posix snapshot path for the connection
380 : * at the given timestamp, i.e. the absolute posix path
381 : * that contains the snapshot for this file system.
382 : *
383 : * This only applies to classical case, i.e. not
384 : * to the "snapdirseverywhere" mode.
385 : */
386 0 : static char *shadow_copy2_snapshot_path(TALLOC_CTX *mem_ctx,
387 : struct vfs_handle_struct *handle,
388 : time_t snapshot)
389 : {
390 : fstring snaptime_string;
391 0 : ssize_t snaptime_len = 0;
392 0 : char *result = NULL;
393 : struct shadow_copy2_private *priv;
394 :
395 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
396 : return NULL);
397 :
398 0 : snaptime_len = shadow_copy2_posix_gmt_string(handle,
399 : snapshot,
400 : snaptime_string,
401 : sizeof(snaptime_string));
402 0 : if (snaptime_len <= 0) {
403 0 : return NULL;
404 : }
405 :
406 0 : result = talloc_asprintf(mem_ctx, "%s/%s",
407 0 : priv->config->snapshot_basepath, snaptime_string);
408 0 : if (result == NULL) {
409 0 : DEBUG(1, (__location__ " talloc_asprintf failed\n"));
410 : }
411 :
412 0 : return result;
413 : }
414 :
415 0 : static char *make_path_absolute(TALLOC_CTX *mem_ctx,
416 : struct shadow_copy2_private *priv,
417 : const char *name)
418 : {
419 0 : char *newpath = NULL;
420 0 : char *abs_path = NULL;
421 :
422 0 : if (name[0] != '/') {
423 0 : newpath = talloc_asprintf(mem_ctx,
424 : "%s/%s",
425 : priv->shadow_cwd,
426 : name);
427 0 : if (newpath == NULL) {
428 0 : return NULL;
429 : }
430 0 : name = newpath;
431 : }
432 0 : abs_path = canonicalize_absolute_path(mem_ctx, name);
433 0 : TALLOC_FREE(newpath);
434 0 : return abs_path;
435 : }
436 :
437 : /* Return a $cwd-relative path. */
438 0 : static bool make_relative_path(const char *cwd, char *abs_path)
439 : {
440 0 : size_t cwd_len = strlen(cwd);
441 0 : size_t abs_len = strlen(abs_path);
442 :
443 0 : if (abs_len < cwd_len) {
444 0 : return false;
445 : }
446 0 : if (memcmp(abs_path, cwd, cwd_len) != 0) {
447 0 : return false;
448 : }
449 : /* The cwd_len != 1 case is for $cwd == '/' */
450 0 : if (cwd_len != 1 &&
451 0 : abs_path[cwd_len] != '/' &&
452 0 : abs_path[cwd_len] != '\0')
453 : {
454 0 : return false;
455 : }
456 0 : if (abs_path[cwd_len] == '/') {
457 0 : cwd_len++;
458 : }
459 0 : memmove(abs_path, &abs_path[cwd_len], abs_len + 1 - cwd_len);
460 0 : return true;
461 : }
462 :
463 : static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
464 : const char *name,
465 : char *gmt, size_t gmt_len);
466 :
467 : /*
468 : * Check if an incoming filename is already a snapshot converted pathname.
469 : *
470 : * If so, it returns the pathname truncated at the snapshot point which
471 : * will be used as the connectpath.
472 : */
473 :
474 0 : static int check_for_converted_path(TALLOC_CTX *mem_ctx,
475 : struct vfs_handle_struct *handle,
476 : struct shadow_copy2_private *priv,
477 : char *abs_path,
478 : bool *ppath_already_converted,
479 : char **pconnectpath)
480 : {
481 0 : size_t snapdirlen = 0;
482 0 : char *p = strstr_m(abs_path, priv->config->snapdir);
483 0 : char *q = NULL;
484 0 : char *connect_path = NULL;
485 : char snapshot[GMT_NAME_LEN+1];
486 :
487 0 : *ppath_already_converted = false;
488 :
489 0 : if (p == NULL) {
490 : /* Must at least contain shadow:snapdir. */
491 0 : return 0;
492 : }
493 :
494 0 : if (priv->config->snapdir[0] == '/' &&
495 : p != abs_path) {
496 : /* Absolute shadow:snapdir must be at the start. */
497 0 : return 0;
498 : }
499 :
500 0 : snapdirlen = strlen(priv->config->snapdir);
501 0 : if (p[snapdirlen] != '/') {
502 : /* shadow:snapdir must end as a separate component. */
503 0 : return 0;
504 : }
505 :
506 0 : if (p > abs_path && p[-1] != '/') {
507 : /* shadow:snapdir must start as a separate component. */
508 0 : return 0;
509 : }
510 :
511 0 : p += snapdirlen;
512 0 : p++; /* Move past the / */
513 :
514 : /*
515 : * Need to return up to the next path
516 : * component after the time.
517 : * This will be used as the connectpath.
518 : */
519 0 : q = strchr(p, '/');
520 0 : if (q == NULL) {
521 : /*
522 : * No next path component.
523 : * Use entire string.
524 : */
525 0 : connect_path = talloc_strdup(mem_ctx,
526 : abs_path);
527 : } else {
528 0 : connect_path = talloc_strndup(mem_ctx,
529 : abs_path,
530 0 : q - abs_path);
531 : }
532 0 : if (connect_path == NULL) {
533 0 : return ENOMEM;
534 : }
535 :
536 : /*
537 : * Point p at the same offset in connect_path as
538 : * it is in abs_path.
539 : */
540 :
541 0 : p = &connect_path[p - abs_path];
542 :
543 : /*
544 : * Now ensure there is a time string at p.
545 : * The SMB-format @GMT-token string is returned
546 : * in snapshot.
547 : */
548 :
549 0 : if (!shadow_copy2_snapshot_to_gmt(handle,
550 : p,
551 : snapshot,
552 : sizeof(snapshot))) {
553 0 : TALLOC_FREE(connect_path);
554 0 : return 0;
555 : }
556 :
557 0 : if (pconnectpath != NULL) {
558 0 : *pconnectpath = connect_path;
559 : }
560 :
561 0 : *ppath_already_converted = true;
562 :
563 0 : DBG_DEBUG("path |%s| is already converted. "
564 : "connect path = |%s|\n",
565 : abs_path,
566 : connect_path);
567 :
568 0 : return 0;
569 : }
570 :
571 : /**
572 : * This function does two things.
573 : *
574 : * 1). Checks if an incoming filename is already a
575 : * snapshot converted pathname.
576 : * If so, it returns the pathname truncated
577 : * at the snapshot point which will be used
578 : * as the connectpath, and then does an early return.
579 : *
580 : * 2). Checks if an incoming filename contains an
581 : * SMB-layer @GMT- style timestamp.
582 : * If so, it strips the timestamp, and returns
583 : * both the timestamp and the stripped path
584 : * (making it cwd-relative).
585 : */
586 :
587 0 : static bool _shadow_copy2_strip_snapshot_internal(TALLOC_CTX *mem_ctx,
588 : struct vfs_handle_struct *handle,
589 : const struct smb_filename *smb_fname,
590 : time_t *ptimestamp,
591 : char **pstripped,
592 : char **psnappath,
593 : bool *_already_converted,
594 : const char *function)
595 : {
596 0 : char *stripped = NULL;
597 : struct shadow_copy2_private *priv;
598 0 : char *abs_path = NULL;
599 0 : bool ret = true;
600 0 : bool already_converted = false;
601 0 : int err = 0;
602 :
603 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
604 : return false);
605 :
606 0 : DBG_DEBUG("[from %s()] Path '%s'\n",
607 : function, smb_fname_str_dbg(smb_fname));
608 :
609 0 : if (_already_converted != NULL) {
610 0 : *_already_converted = false;
611 : }
612 :
613 0 : abs_path = make_path_absolute(mem_ctx, priv, smb_fname->base_name);
614 0 : if (abs_path == NULL) {
615 0 : ret = false;
616 0 : goto out;
617 : }
618 :
619 0 : DBG_DEBUG("abs path '%s'\n", abs_path);
620 :
621 0 : err = check_for_converted_path(mem_ctx,
622 : handle,
623 : priv,
624 : abs_path,
625 : &already_converted,
626 : psnappath);
627 0 : if (err != 0) {
628 : /* error in conversion. */
629 0 : ret = false;
630 0 : goto out;
631 : }
632 :
633 0 : if (already_converted) {
634 0 : if (_already_converted != NULL) {
635 0 : *_already_converted = true;
636 : }
637 0 : goto out;
638 : }
639 :
640 0 : if (smb_fname->twrp == 0) {
641 0 : goto out;
642 : }
643 :
644 0 : if (ptimestamp != NULL) {
645 0 : *ptimestamp = nt_time_to_unix(smb_fname->twrp);
646 : }
647 :
648 0 : if (pstripped != NULL) {
649 0 : stripped = talloc_strdup(mem_ctx, abs_path);
650 0 : if (stripped == NULL) {
651 0 : ret = false;
652 0 : goto out;
653 : }
654 :
655 0 : if (smb_fname->base_name[0] != '/') {
656 0 : ret = make_relative_path(priv->shadow_cwd, stripped);
657 0 : if (!ret) {
658 0 : DBG_DEBUG("Path '%s' "
659 : "doesn't start with cwd '%s'\n",
660 : stripped, priv->shadow_cwd);
661 0 : ret = false;
662 0 : errno = ENOENT;
663 0 : goto out;
664 : }
665 : }
666 0 : *pstripped = stripped;
667 : }
668 :
669 0 : ret = true;
670 :
671 0 : out:
672 0 : TALLOC_FREE(abs_path);
673 0 : return ret;
674 : }
675 :
676 : #define shadow_copy2_strip_snapshot_internal(mem_ctx, handle, orig_name, \
677 : ptimestamp, pstripped, psnappath, _already_converted) \
678 : _shadow_copy2_strip_snapshot_internal((mem_ctx), (handle), (orig_name), \
679 : (ptimestamp), (pstripped), (psnappath), (_already_converted), \
680 : __FUNCTION__)
681 :
682 0 : static bool _shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx,
683 : struct vfs_handle_struct *handle,
684 : const struct smb_filename *orig_name,
685 : time_t *ptimestamp,
686 : char **pstripped,
687 : const char *function)
688 : {
689 0 : return _shadow_copy2_strip_snapshot_internal(mem_ctx,
690 : handle,
691 : orig_name,
692 : ptimestamp,
693 : pstripped,
694 : NULL,
695 : NULL,
696 : function);
697 : }
698 :
699 : #define shadow_copy2_strip_snapshot(mem_ctx, handle, orig_name, \
700 : ptimestamp, pstripped) \
701 : _shadow_copy2_strip_snapshot((mem_ctx), (handle), (orig_name), \
702 : (ptimestamp), (pstripped), __FUNCTION__)
703 :
704 0 : static bool _shadow_copy2_strip_snapshot_converted(TALLOC_CTX *mem_ctx,
705 : struct vfs_handle_struct *handle,
706 : const struct smb_filename *orig_name,
707 : time_t *ptimestamp,
708 : char **pstripped,
709 : bool *is_converted,
710 : const char *function)
711 : {
712 0 : return _shadow_copy2_strip_snapshot_internal(mem_ctx,
713 : handle,
714 : orig_name,
715 : ptimestamp,
716 : pstripped,
717 : NULL,
718 : is_converted,
719 : function);
720 : }
721 :
722 : #define shadow_copy2_strip_snapshot_converted(mem_ctx, handle, orig_name, \
723 : ptimestamp, pstripped, is_converted) \
724 : _shadow_copy2_strip_snapshot_converted((mem_ctx), (handle), (orig_name), \
725 : (ptimestamp), (pstripped), (is_converted), __FUNCTION__)
726 :
727 0 : static char *shadow_copy2_find_mount_point(TALLOC_CTX *mem_ctx,
728 : vfs_handle_struct *handle)
729 : {
730 0 : char *path = talloc_strdup(mem_ctx, handle->conn->connectpath);
731 : dev_t dev;
732 : struct stat st;
733 : char *p;
734 :
735 0 : if (stat(path, &st) != 0) {
736 0 : talloc_free(path);
737 0 : return NULL;
738 : }
739 :
740 0 : dev = st.st_dev;
741 :
742 0 : while ((p = strrchr(path, '/')) && p > path) {
743 0 : *p = 0;
744 0 : if (stat(path, &st) != 0) {
745 0 : talloc_free(path);
746 0 : return NULL;
747 : }
748 0 : if (st.st_dev != dev) {
749 0 : *p = '/';
750 0 : break;
751 : }
752 : }
753 :
754 0 : return path;
755 : }
756 :
757 : /**
758 : * Convert from a name as handed in via the SMB layer
759 : * and a timestamp into the local path of the snapshot
760 : * of the provided file at the provided time.
761 : * Also return the path in the snapshot corresponding
762 : * to the file's share root.
763 : */
764 0 : static char *shadow_copy2_do_convert(TALLOC_CTX *mem_ctx,
765 : struct vfs_handle_struct *handle,
766 : const char *name, time_t timestamp,
767 : size_t *snaproot_len)
768 : {
769 : struct smb_filename converted_fname;
770 0 : char *result = NULL;
771 0 : size_t *slashes = NULL;
772 : unsigned num_slashes;
773 0 : char *path = NULL;
774 : size_t pathlen;
775 0 : char *insert = NULL;
776 0 : char *converted = NULL;
777 0 : size_t insertlen, connectlen = 0;
778 0 : int saved_errno = 0;
779 : int i;
780 : size_t min_offset;
781 : struct shadow_copy2_config *config;
782 : struct shadow_copy2_private *priv;
783 0 : size_t in_share_offset = 0;
784 :
785 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
786 : return NULL);
787 :
788 0 : config = priv->config;
789 :
790 0 : DEBUG(10, ("converting '%s'\n", name));
791 :
792 0 : if (!config->snapdirseverywhere) {
793 : int ret;
794 : char *snapshot_path;
795 :
796 0 : snapshot_path = shadow_copy2_snapshot_path(talloc_tos(),
797 : handle,
798 : timestamp);
799 0 : if (snapshot_path == NULL) {
800 0 : goto fail;
801 : }
802 :
803 0 : if (config->rel_connectpath == NULL) {
804 0 : converted = talloc_asprintf(mem_ctx, "%s/%s",
805 : snapshot_path, name);
806 : } else {
807 0 : converted = talloc_asprintf(mem_ctx, "%s/%s/%s",
808 : snapshot_path,
809 : config->rel_connectpath,
810 : name);
811 : }
812 0 : if (converted == NULL) {
813 0 : goto fail;
814 : }
815 :
816 0 : ZERO_STRUCT(converted_fname);
817 0 : converted_fname.base_name = converted;
818 :
819 0 : ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
820 0 : DEBUG(10, ("Trying[not snapdirseverywhere] %s: %d (%s)\n",
821 : converted,
822 : ret, ret == 0 ? "ok" : strerror(errno)));
823 0 : if (ret == 0) {
824 0 : DEBUG(10, ("Found %s\n", converted));
825 0 : result = converted;
826 0 : converted = NULL;
827 0 : if (snaproot_len != NULL) {
828 0 : *snaproot_len = strlen(snapshot_path);
829 0 : if (config->rel_connectpath != NULL) {
830 0 : *snaproot_len +=
831 0 : strlen(config->rel_connectpath) + 1;
832 : }
833 : }
834 0 : goto fail;
835 : } else {
836 0 : errno = ENOENT;
837 0 : goto fail;
838 : }
839 : /* never reached ... */
840 : }
841 :
842 0 : connectlen = strlen(handle->conn->connectpath);
843 0 : if (name[0] == 0) {
844 0 : path = talloc_strdup(mem_ctx, handle->conn->connectpath);
845 : } else {
846 0 : path = talloc_asprintf(
847 0 : mem_ctx, "%s/%s", handle->conn->connectpath, name);
848 : }
849 0 : if (path == NULL) {
850 0 : errno = ENOMEM;
851 0 : goto fail;
852 : }
853 0 : pathlen = talloc_get_size(path)-1;
854 :
855 0 : if (!shadow_copy2_find_slashes(talloc_tos(), path,
856 : &slashes, &num_slashes)) {
857 0 : goto fail;
858 : }
859 :
860 0 : insert = shadow_copy2_insert_string(talloc_tos(), handle, timestamp);
861 0 : if (insert == NULL) {
862 0 : goto fail;
863 : }
864 0 : insertlen = talloc_get_size(insert)-1;
865 :
866 : /*
867 : * Note: We deliberatly don't expensively initialize the
868 : * array with talloc_zero here: Putting zero into
869 : * converted[pathlen+insertlen] below is sufficient, because
870 : * in the following for loop, the insert string is inserted
871 : * at various slash places. So the memory up to position
872 : * pathlen+insertlen will always be initialized when the
873 : * converted string is used.
874 : */
875 0 : converted = talloc_array(mem_ctx, char, pathlen + insertlen + 1);
876 0 : if (converted == NULL) {
877 0 : goto fail;
878 : }
879 :
880 0 : if (path[pathlen-1] != '/') {
881 : /*
882 : * Append a fake slash to find the snapshot root
883 : */
884 : size_t *tmp;
885 0 : tmp = talloc_realloc(talloc_tos(), slashes,
886 : size_t, num_slashes+1);
887 0 : if (tmp == NULL) {
888 0 : goto fail;
889 : }
890 0 : slashes = tmp;
891 0 : slashes[num_slashes] = pathlen;
892 0 : num_slashes += 1;
893 : }
894 :
895 0 : min_offset = 0;
896 :
897 0 : if (!config->crossmountpoints) {
898 0 : min_offset = strlen(config->mount_point);
899 : }
900 :
901 0 : memcpy(converted, path, pathlen+1);
902 0 : converted[pathlen+insertlen] = '\0';
903 :
904 0 : ZERO_STRUCT(converted_fname);
905 0 : converted_fname.base_name = converted;
906 :
907 0 : for (i = num_slashes-1; i>=0; i--) {
908 : int ret;
909 : size_t offset;
910 :
911 0 : offset = slashes[i];
912 :
913 0 : if (offset < min_offset) {
914 0 : errno = ENOENT;
915 0 : goto fail;
916 : }
917 :
918 0 : if (offset >= connectlen) {
919 0 : in_share_offset = offset;
920 : }
921 :
922 0 : memcpy(converted+offset, insert, insertlen);
923 :
924 0 : offset += insertlen;
925 0 : memcpy(converted+offset, path + slashes[i],
926 0 : pathlen - slashes[i]);
927 :
928 0 : ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
929 :
930 0 : DEBUG(10, ("Trying[snapdirseverywhere] %s: %d (%s)\n",
931 : converted,
932 : ret, ret == 0 ? "ok" : strerror(errno)));
933 0 : if (ret == 0) {
934 : /* success */
935 0 : if (snaproot_len != NULL) {
936 0 : *snaproot_len = in_share_offset + insertlen;
937 : }
938 0 : break;
939 : }
940 0 : if (errno == ENOTDIR) {
941 : /*
942 : * This is a valid condition: We appended the
943 : * .snapshots/@GMT.. to a file name. Just try
944 : * with the upper levels.
945 : */
946 0 : continue;
947 : }
948 0 : if (errno != ENOENT) {
949 : /* Other problem than "not found" */
950 0 : goto fail;
951 : }
952 : }
953 :
954 0 : if (i >= 0) {
955 : /*
956 : * Found something
957 : */
958 0 : DEBUG(10, ("Found %s\n", converted));
959 0 : result = converted;
960 0 : converted = NULL;
961 : } else {
962 0 : errno = ENOENT;
963 : }
964 0 : fail:
965 0 : if (result == NULL) {
966 0 : saved_errno = errno;
967 : }
968 0 : TALLOC_FREE(converted);
969 0 : TALLOC_FREE(insert);
970 0 : TALLOC_FREE(slashes);
971 0 : TALLOC_FREE(path);
972 0 : if (saved_errno != 0) {
973 0 : errno = saved_errno;
974 : }
975 0 : return result;
976 : }
977 :
978 : /**
979 : * Convert from a name as handed in via the SMB layer
980 : * and a timestamp into the local path of the snapshot
981 : * of the provided file at the provided time.
982 : */
983 0 : static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx,
984 : struct vfs_handle_struct *handle,
985 : const char *name, time_t timestamp)
986 : {
987 0 : return shadow_copy2_do_convert(mem_ctx, handle, name, timestamp, NULL);
988 : }
989 :
990 : /*
991 : modify a sbuf return to ensure that inodes in the shadow directory
992 : are different from those in the main directory
993 : */
994 0 : static void convert_sbuf(vfs_handle_struct *handle, const char *fname,
995 : SMB_STRUCT_STAT *sbuf)
996 : {
997 : struct shadow_copy2_private *priv;
998 :
999 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1000 : return);
1001 :
1002 0 : if (priv->config->fixinodes) {
1003 : /* some snapshot systems, like GPFS, return the same
1004 : device:inode for the snapshot files as the current
1005 : files. That breaks the 'restore' button in the shadow copy
1006 : GUI, as the client gets a sharing violation.
1007 :
1008 : This is a crude way of allowing both files to be
1009 : open at once. It has a slight chance of inode
1010 : number collision, but I can't see a better approach
1011 : without significant VFS changes
1012 : */
1013 0 : TDB_DATA key = { .dptr = discard_const_p(uint8_t, fname),
1014 0 : .dsize = strlen(fname) };
1015 : uint32_t shash;
1016 :
1017 0 : shash = tdb_jenkins_hash(&key) & 0xFF000000;
1018 0 : if (shash == 0) {
1019 0 : shash = 1;
1020 : }
1021 0 : sbuf->st_ex_ino ^= shash;
1022 : }
1023 : }
1024 :
1025 0 : static int shadow_copy2_renameat(vfs_handle_struct *handle,
1026 : files_struct *srcfsp,
1027 : const struct smb_filename *smb_fname_src,
1028 : files_struct *dstfsp,
1029 : const struct smb_filename *smb_fname_dst)
1030 : {
1031 0 : time_t timestamp_src = 0;
1032 0 : time_t timestamp_dst = 0;
1033 0 : char *snappath_src = NULL;
1034 0 : char *snappath_dst = NULL;
1035 :
1036 0 : if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle,
1037 : smb_fname_src,
1038 : ×tamp_src, NULL, &snappath_src,
1039 : NULL)) {
1040 0 : return -1;
1041 : }
1042 0 : if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle,
1043 : smb_fname_dst,
1044 : ×tamp_dst, NULL, &snappath_dst,
1045 : NULL)) {
1046 0 : return -1;
1047 : }
1048 0 : if (timestamp_src != 0) {
1049 0 : errno = EXDEV;
1050 0 : return -1;
1051 : }
1052 0 : if (timestamp_dst != 0) {
1053 0 : errno = EROFS;
1054 0 : return -1;
1055 : }
1056 : /*
1057 : * Don't allow rename on already converted paths.
1058 : */
1059 0 : if (snappath_src != NULL) {
1060 0 : errno = EXDEV;
1061 0 : return -1;
1062 : }
1063 0 : if (snappath_dst != NULL) {
1064 0 : errno = EROFS;
1065 0 : return -1;
1066 : }
1067 0 : return SMB_VFS_NEXT_RENAMEAT(handle,
1068 : srcfsp,
1069 : smb_fname_src,
1070 : dstfsp,
1071 : smb_fname_dst);
1072 : }
1073 :
1074 0 : static int shadow_copy2_symlinkat(vfs_handle_struct *handle,
1075 : const struct smb_filename *link_contents,
1076 : struct files_struct *dirfsp,
1077 : const struct smb_filename *new_smb_fname)
1078 : {
1079 0 : time_t timestamp_old = 0;
1080 0 : time_t timestamp_new = 0;
1081 0 : char *snappath_old = NULL;
1082 0 : char *snappath_new = NULL;
1083 :
1084 0 : if (!shadow_copy2_strip_snapshot_internal(talloc_tos(),
1085 : handle,
1086 : link_contents,
1087 : ×tamp_old,
1088 : NULL,
1089 : &snappath_old,
1090 : NULL)) {
1091 0 : return -1;
1092 : }
1093 0 : if (!shadow_copy2_strip_snapshot_internal(talloc_tos(),
1094 : handle,
1095 : new_smb_fname,
1096 : ×tamp_new,
1097 : NULL,
1098 : &snappath_new,
1099 : NULL)) {
1100 0 : return -1;
1101 : }
1102 0 : if ((timestamp_old != 0) || (timestamp_new != 0)) {
1103 0 : errno = EROFS;
1104 0 : return -1;
1105 : }
1106 : /*
1107 : * Don't allow symlinks on already converted paths.
1108 : */
1109 0 : if ((snappath_old != NULL) || (snappath_new != NULL)) {
1110 0 : errno = EROFS;
1111 0 : return -1;
1112 : }
1113 0 : return SMB_VFS_NEXT_SYMLINKAT(handle,
1114 : link_contents,
1115 : dirfsp,
1116 : new_smb_fname);
1117 : }
1118 :
1119 0 : static int shadow_copy2_linkat(vfs_handle_struct *handle,
1120 : files_struct *srcfsp,
1121 : const struct smb_filename *old_smb_fname,
1122 : files_struct *dstfsp,
1123 : const struct smb_filename *new_smb_fname,
1124 : int flags)
1125 : {
1126 0 : time_t timestamp_old = 0;
1127 0 : time_t timestamp_new = 0;
1128 0 : char *snappath_old = NULL;
1129 0 : char *snappath_new = NULL;
1130 :
1131 0 : if (!shadow_copy2_strip_snapshot_internal(talloc_tos(),
1132 : handle,
1133 : old_smb_fname,
1134 : ×tamp_old,
1135 : NULL,
1136 : &snappath_old,
1137 : NULL)) {
1138 0 : return -1;
1139 : }
1140 0 : if (!shadow_copy2_strip_snapshot_internal(talloc_tos(),
1141 : handle,
1142 : new_smb_fname,
1143 : ×tamp_new,
1144 : NULL,
1145 : &snappath_new,
1146 : NULL)) {
1147 0 : return -1;
1148 : }
1149 0 : if ((timestamp_old != 0) || (timestamp_new != 0)) {
1150 0 : errno = EROFS;
1151 0 : return -1;
1152 : }
1153 : /*
1154 : * Don't allow links on already converted paths.
1155 : */
1156 0 : if ((snappath_old != NULL) || (snappath_new != NULL)) {
1157 0 : errno = EROFS;
1158 0 : return -1;
1159 : }
1160 0 : return SMB_VFS_NEXT_LINKAT(handle,
1161 : srcfsp,
1162 : old_smb_fname,
1163 : dstfsp,
1164 : new_smb_fname,
1165 : flags);
1166 : }
1167 :
1168 0 : static int shadow_copy2_stat(vfs_handle_struct *handle,
1169 : struct smb_filename *smb_fname)
1170 : {
1171 0 : struct shadow_copy2_private *priv = NULL;
1172 0 : time_t timestamp = 0;
1173 0 : char *stripped = NULL;
1174 0 : bool converted = false;
1175 0 : char *abspath = NULL;
1176 : char *tmp;
1177 0 : int ret = 0;
1178 :
1179 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1180 : return -1);
1181 :
1182 0 : if (!shadow_copy2_strip_snapshot_converted(talloc_tos(),
1183 : handle,
1184 : smb_fname,
1185 : ×tamp,
1186 : &stripped,
1187 : &converted)) {
1188 0 : return -1;
1189 : }
1190 0 : if (timestamp == 0) {
1191 0 : TALLOC_FREE(stripped);
1192 0 : ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
1193 0 : if (ret != 0) {
1194 0 : return ret;
1195 : }
1196 0 : if (!converted) {
1197 0 : return 0;
1198 : }
1199 :
1200 0 : abspath = make_path_absolute(talloc_tos(),
1201 : priv,
1202 0 : smb_fname->base_name);
1203 0 : if (abspath == NULL) {
1204 0 : return -1;
1205 : }
1206 :
1207 0 : convert_sbuf(handle, abspath, &smb_fname->st);
1208 0 : TALLOC_FREE(abspath);
1209 0 : return 0;
1210 : }
1211 :
1212 0 : tmp = smb_fname->base_name;
1213 0 : smb_fname->base_name = shadow_copy2_convert(
1214 : talloc_tos(), handle, stripped, timestamp);
1215 0 : TALLOC_FREE(stripped);
1216 :
1217 0 : if (smb_fname->base_name == NULL) {
1218 0 : smb_fname->base_name = tmp;
1219 0 : return -1;
1220 : }
1221 :
1222 0 : ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
1223 0 : if (ret != 0) {
1224 0 : goto out;
1225 : }
1226 :
1227 0 : abspath = make_path_absolute(talloc_tos(),
1228 : priv,
1229 0 : smb_fname->base_name);
1230 0 : if (abspath == NULL) {
1231 0 : ret = -1;
1232 0 : goto out;
1233 : }
1234 :
1235 0 : convert_sbuf(handle, abspath, &smb_fname->st);
1236 0 : TALLOC_FREE(abspath);
1237 :
1238 0 : out:
1239 0 : TALLOC_FREE(smb_fname->base_name);
1240 0 : smb_fname->base_name = tmp;
1241 :
1242 0 : return ret;
1243 : }
1244 :
1245 0 : static int shadow_copy2_lstat(vfs_handle_struct *handle,
1246 : struct smb_filename *smb_fname)
1247 : {
1248 0 : struct shadow_copy2_private *priv = NULL;
1249 0 : time_t timestamp = 0;
1250 0 : char *stripped = NULL;
1251 0 : bool converted = false;
1252 0 : char *abspath = NULL;
1253 : char *tmp;
1254 0 : int ret = 0;
1255 :
1256 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1257 : return -1);
1258 :
1259 0 : if (!shadow_copy2_strip_snapshot_converted(talloc_tos(),
1260 : handle,
1261 : smb_fname,
1262 : ×tamp,
1263 : &stripped,
1264 : &converted)) {
1265 0 : return -1;
1266 : }
1267 0 : if (timestamp == 0) {
1268 0 : TALLOC_FREE(stripped);
1269 0 : ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1270 0 : if (ret != 0) {
1271 0 : return ret;
1272 : }
1273 0 : if (!converted) {
1274 0 : return 0;
1275 : }
1276 :
1277 0 : abspath = make_path_absolute(talloc_tos(),
1278 : priv,
1279 0 : smb_fname->base_name);
1280 0 : if (abspath == NULL) {
1281 0 : return -1;
1282 : }
1283 :
1284 0 : convert_sbuf(handle, abspath, &smb_fname->st);
1285 0 : TALLOC_FREE(abspath);
1286 0 : return 0;
1287 : }
1288 :
1289 0 : tmp = smb_fname->base_name;
1290 0 : smb_fname->base_name = shadow_copy2_convert(
1291 : talloc_tos(), handle, stripped, timestamp);
1292 0 : TALLOC_FREE(stripped);
1293 :
1294 0 : if (smb_fname->base_name == NULL) {
1295 0 : smb_fname->base_name = tmp;
1296 0 : return -1;
1297 : }
1298 :
1299 0 : ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1300 0 : if (ret != 0) {
1301 0 : goto out;
1302 : }
1303 :
1304 0 : abspath = make_path_absolute(talloc_tos(),
1305 : priv,
1306 0 : smb_fname->base_name);
1307 0 : if (abspath == NULL) {
1308 0 : ret = -1;
1309 0 : goto out;
1310 : }
1311 :
1312 0 : convert_sbuf(handle, abspath, &smb_fname->st);
1313 0 : TALLOC_FREE(abspath);
1314 :
1315 0 : out:
1316 0 : TALLOC_FREE(smb_fname->base_name);
1317 0 : smb_fname->base_name = tmp;
1318 :
1319 0 : return ret;
1320 : }
1321 :
1322 0 : static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
1323 : SMB_STRUCT_STAT *sbuf)
1324 : {
1325 0 : struct shadow_copy2_private *priv = NULL;
1326 0 : time_t timestamp = 0;
1327 0 : struct smb_filename *orig_smb_fname = NULL;
1328 : struct smb_filename vss_smb_fname;
1329 0 : struct smb_filename *orig_base_smb_fname = NULL;
1330 : struct smb_filename vss_base_smb_fname;
1331 0 : char *stripped = NULL;
1332 0 : char *abspath = NULL;
1333 0 : bool converted = false;
1334 : bool ok;
1335 : int ret;
1336 :
1337 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1338 : return -1);
1339 :
1340 0 : ok = shadow_copy2_strip_snapshot_converted(talloc_tos(),
1341 : handle,
1342 : fsp->fsp_name,
1343 : ×tamp,
1344 : &stripped,
1345 : &converted);
1346 0 : if (!ok) {
1347 0 : return -1;
1348 : }
1349 :
1350 0 : if (timestamp == 0) {
1351 0 : TALLOC_FREE(stripped);
1352 0 : ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1353 0 : if (ret != 0) {
1354 0 : return ret;
1355 : }
1356 0 : if (!converted) {
1357 0 : return 0;
1358 : }
1359 :
1360 0 : abspath = make_path_absolute(talloc_tos(),
1361 : priv,
1362 0 : fsp->fsp_name->base_name);
1363 0 : if (abspath == NULL) {
1364 0 : return -1;
1365 : }
1366 :
1367 0 : convert_sbuf(handle, abspath, sbuf);
1368 0 : TALLOC_FREE(abspath);
1369 0 : return 0;
1370 : }
1371 :
1372 0 : vss_smb_fname = *fsp->fsp_name;
1373 0 : vss_smb_fname.base_name = shadow_copy2_convert(talloc_tos(),
1374 : handle,
1375 : stripped,
1376 : timestamp);
1377 0 : TALLOC_FREE(stripped);
1378 0 : if (vss_smb_fname.base_name == NULL) {
1379 0 : return -1;
1380 : }
1381 :
1382 0 : orig_smb_fname = fsp->fsp_name;
1383 0 : fsp->fsp_name = &vss_smb_fname;
1384 :
1385 0 : if (fsp_is_alternate_stream(fsp)) {
1386 0 : vss_base_smb_fname = *fsp->base_fsp->fsp_name;
1387 0 : vss_base_smb_fname.base_name = vss_smb_fname.base_name;
1388 0 : orig_base_smb_fname = fsp->base_fsp->fsp_name;
1389 0 : fsp->base_fsp->fsp_name = &vss_base_smb_fname;
1390 : }
1391 :
1392 0 : ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1393 0 : if (ret != 0) {
1394 0 : goto out;
1395 : }
1396 :
1397 0 : abspath = make_path_absolute(talloc_tos(),
1398 : priv,
1399 0 : fsp->fsp_name->base_name);
1400 0 : if (abspath == NULL) {
1401 0 : ret = -1;
1402 0 : goto out;
1403 : }
1404 :
1405 0 : convert_sbuf(handle, abspath, sbuf);
1406 0 : TALLOC_FREE(abspath);
1407 :
1408 0 : out:
1409 0 : fsp->fsp_name = orig_smb_fname;
1410 0 : if (fsp_is_alternate_stream(fsp)) {
1411 0 : fsp->base_fsp->fsp_name = orig_base_smb_fname;
1412 : }
1413 :
1414 0 : return ret;
1415 : }
1416 :
1417 0 : static int shadow_copy2_fstatat(
1418 : struct vfs_handle_struct *handle,
1419 : const struct files_struct *dirfsp,
1420 : const struct smb_filename *smb_fname_in,
1421 : SMB_STRUCT_STAT *sbuf,
1422 : int flags)
1423 : {
1424 0 : struct shadow_copy2_private *priv = NULL;
1425 0 : struct smb_filename *smb_fname = NULL;
1426 0 : time_t timestamp = 0;
1427 0 : char *stripped = NULL;
1428 0 : char *abspath = NULL;
1429 0 : bool converted = false;
1430 : int ret;
1431 : bool ok;
1432 :
1433 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1434 : return -1);
1435 :
1436 0 : smb_fname = full_path_from_dirfsp_atname(talloc_tos(),
1437 : dirfsp,
1438 : smb_fname_in);
1439 0 : if (smb_fname == NULL) {
1440 0 : errno = ENOMEM;
1441 0 : return -1;
1442 : }
1443 :
1444 0 : ok = shadow_copy2_strip_snapshot_converted(talloc_tos(),
1445 : handle,
1446 : smb_fname,
1447 : ×tamp,
1448 : &stripped,
1449 : &converted);
1450 0 : if (!ok) {
1451 0 : return -1;
1452 : }
1453 0 : if (timestamp == 0) {
1454 0 : TALLOC_FREE(stripped);
1455 0 : ret = SMB_VFS_NEXT_FSTATAT(
1456 : handle, dirfsp, smb_fname_in, sbuf, flags);
1457 0 : if (ret != 0) {
1458 0 : return ret;
1459 : }
1460 0 : if (!converted) {
1461 0 : return 0;
1462 : }
1463 :
1464 0 : abspath = make_path_absolute(
1465 0 : talloc_tos(), priv, smb_fname->base_name);
1466 0 : if (abspath == NULL) {
1467 0 : errno = ENOMEM;
1468 0 : return -1;
1469 : }
1470 :
1471 0 : convert_sbuf(handle, abspath, sbuf);
1472 0 : TALLOC_FREE(abspath);
1473 0 : return 0;
1474 : }
1475 :
1476 0 : smb_fname->base_name = shadow_copy2_convert(
1477 : smb_fname, handle, stripped, timestamp);
1478 0 : TALLOC_FREE(stripped);
1479 0 : if (smb_fname->base_name == NULL) {
1480 0 : TALLOC_FREE(smb_fname);
1481 0 : errno = ENOMEM;
1482 0 : return -1;
1483 : }
1484 :
1485 0 : ret = SMB_VFS_NEXT_FSTATAT(handle,
1486 : dirfsp,
1487 : smb_fname,
1488 : sbuf,
1489 : flags);
1490 0 : if (ret != 0) {
1491 0 : int saved_errno = errno;
1492 0 : TALLOC_FREE(smb_fname);
1493 0 : errno = saved_errno;
1494 0 : return -1;
1495 : }
1496 :
1497 0 : abspath = make_path_absolute(
1498 0 : talloc_tos(), priv, smb_fname->base_name);
1499 0 : if (abspath == NULL) {
1500 0 : TALLOC_FREE(smb_fname);
1501 0 : errno = ENOMEM;
1502 0 : return -1;
1503 : }
1504 :
1505 0 : convert_sbuf(handle, abspath, sbuf);
1506 0 : TALLOC_FREE(abspath);
1507 :
1508 0 : TALLOC_FREE(smb_fname);
1509 :
1510 0 : return 0;
1511 : }
1512 :
1513 0 : static struct smb_filename *shadow_copy2_openat_name(
1514 : TALLOC_CTX *mem_ctx,
1515 : const struct files_struct *dirfsp,
1516 : const struct files_struct *fsp,
1517 : const struct smb_filename *smb_fname_in)
1518 : {
1519 0 : struct smb_filename *result = NULL;
1520 :
1521 0 : if (fsp->base_fsp != NULL) {
1522 0 : struct smb_filename *base_fname = fsp->base_fsp->fsp_name;
1523 :
1524 0 : if (smb_fname_in->base_name[0] == '/') {
1525 : /*
1526 : * Special-case stream names from streams_depot
1527 : */
1528 0 : result = cp_smb_filename(mem_ctx, smb_fname_in);
1529 : } else {
1530 :
1531 0 : SMB_ASSERT(is_named_stream(smb_fname_in));
1532 :
1533 0 : result = synthetic_smb_fname(mem_ctx,
1534 0 : base_fname->base_name,
1535 0 : smb_fname_in->stream_name,
1536 : &smb_fname_in->st,
1537 : smb_fname_in->twrp,
1538 : smb_fname_in->flags);
1539 : }
1540 : } else {
1541 0 : result = full_path_from_dirfsp_atname(
1542 : mem_ctx, dirfsp, smb_fname_in);
1543 : }
1544 :
1545 0 : return result;
1546 : }
1547 :
1548 0 : static int shadow_copy2_openat(vfs_handle_struct *handle,
1549 : const struct files_struct *dirfsp,
1550 : const struct smb_filename *smb_fname_in,
1551 : struct files_struct *fsp,
1552 : const struct vfs_open_how *_how)
1553 : {
1554 0 : struct vfs_open_how how = *_how;
1555 0 : struct smb_filename *smb_fname = NULL;
1556 0 : time_t timestamp = 0;
1557 0 : char *stripped = NULL;
1558 0 : bool is_converted = false;
1559 0 : int saved_errno = 0;
1560 : int ret;
1561 : bool ok;
1562 :
1563 0 : if (how.resolve != 0) {
1564 0 : errno = ENOSYS;
1565 0 : return -1;
1566 : }
1567 :
1568 0 : smb_fname = shadow_copy2_openat_name(
1569 : talloc_tos(), dirfsp, fsp, smb_fname_in);
1570 0 : if (smb_fname == NULL) {
1571 0 : errno = ENOMEM;
1572 0 : return -1;
1573 : }
1574 :
1575 0 : ok = shadow_copy2_strip_snapshot_converted(talloc_tos(),
1576 : handle,
1577 : smb_fname,
1578 : ×tamp,
1579 : &stripped,
1580 : &is_converted);
1581 0 : if (!ok) {
1582 0 : return -1;
1583 : }
1584 0 : if (timestamp == 0) {
1585 0 : if (is_converted) {
1586 : /*
1587 : * Just pave over the user requested mode and use
1588 : * O_RDONLY. Later attempts by the client to write on
1589 : * the handle will fail in the pwrite() syscall with
1590 : * EINVAL which we carefully map to EROFS. In sum, this
1591 : * matches Windows behaviour.
1592 : */
1593 0 : how.flags &= ~(O_WRONLY | O_RDWR | O_CREAT);
1594 : }
1595 0 : return SMB_VFS_NEXT_OPENAT(handle,
1596 : dirfsp,
1597 : smb_fname_in,
1598 : fsp,
1599 : &how);
1600 : }
1601 :
1602 0 : smb_fname->base_name = shadow_copy2_convert(smb_fname,
1603 : handle,
1604 : stripped,
1605 : timestamp);
1606 0 : if (smb_fname->base_name == NULL) {
1607 0 : int err = errno;
1608 0 : TALLOC_FREE(stripped);
1609 0 : TALLOC_FREE(smb_fname);
1610 0 : errno = err;
1611 0 : return -1;
1612 : }
1613 0 : TALLOC_FREE(stripped);
1614 :
1615 : /*
1616 : * Just pave over the user requested mode and use O_RDONLY. Later
1617 : * attempts by the client to write on the handle will fail in the
1618 : * pwrite() syscall with EINVAL which we carefully map to EROFS. In sum,
1619 : * this matches Windows behaviour.
1620 : */
1621 0 : how.flags &= ~(O_WRONLY | O_RDWR | O_CREAT);
1622 :
1623 0 : ret = SMB_VFS_NEXT_OPENAT(handle,
1624 : dirfsp,
1625 : smb_fname,
1626 : fsp,
1627 : &how);
1628 0 : if (ret == -1) {
1629 0 : saved_errno = errno;
1630 : }
1631 :
1632 0 : TALLOC_FREE(smb_fname);
1633 :
1634 0 : if (saved_errno != 0) {
1635 0 : errno = saved_errno;
1636 : }
1637 0 : return ret;
1638 : }
1639 :
1640 0 : static int shadow_copy2_unlinkat(vfs_handle_struct *handle,
1641 : struct files_struct *dirfsp,
1642 : const struct smb_filename *smb_fname,
1643 : int flags)
1644 : {
1645 0 : time_t timestamp = 0;
1646 :
1647 0 : if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1648 : smb_fname,
1649 : ×tamp, NULL)) {
1650 0 : return -1;
1651 : }
1652 0 : if (timestamp != 0) {
1653 0 : errno = EROFS;
1654 0 : return -1;
1655 : }
1656 0 : return SMB_VFS_NEXT_UNLINKAT(handle,
1657 : dirfsp,
1658 : smb_fname,
1659 : flags);
1660 : }
1661 :
1662 0 : static int shadow_copy2_fchmod(vfs_handle_struct *handle,
1663 : struct files_struct *fsp,
1664 : mode_t mode)
1665 : {
1666 0 : time_t timestamp = 0;
1667 0 : const struct smb_filename *smb_fname = NULL;
1668 :
1669 0 : smb_fname = fsp->fsp_name;
1670 0 : if (!shadow_copy2_strip_snapshot(talloc_tos(),
1671 : handle,
1672 : smb_fname,
1673 : ×tamp,
1674 : NULL)) {
1675 0 : return -1;
1676 : }
1677 0 : if (timestamp != 0) {
1678 0 : errno = EROFS;
1679 0 : return -1;
1680 : }
1681 0 : return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
1682 : }
1683 :
1684 0 : static void store_cwd_data(vfs_handle_struct *handle,
1685 : const char *connectpath)
1686 : {
1687 0 : struct shadow_copy2_private *priv = NULL;
1688 0 : struct smb_filename *cwd_fname = NULL;
1689 :
1690 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1691 : return);
1692 :
1693 0 : TALLOC_FREE(priv->shadow_cwd);
1694 0 : cwd_fname = SMB_VFS_NEXT_GETWD(handle, talloc_tos());
1695 0 : if (cwd_fname == NULL) {
1696 0 : smb_panic("getwd failed\n");
1697 : }
1698 0 : DBG_DEBUG("shadow cwd = %s\n", cwd_fname->base_name);
1699 0 : priv->shadow_cwd = talloc_strdup(priv, cwd_fname->base_name);
1700 0 : TALLOC_FREE(cwd_fname);
1701 0 : if (priv->shadow_cwd == NULL) {
1702 0 : smb_panic("talloc failed\n");
1703 : }
1704 0 : TALLOC_FREE(priv->shadow_connectpath);
1705 0 : if (connectpath) {
1706 0 : DBG_DEBUG("shadow connectpath = %s\n", connectpath);
1707 0 : priv->shadow_connectpath = talloc_strdup(priv, connectpath);
1708 0 : if (priv->shadow_connectpath == NULL) {
1709 0 : smb_panic("talloc failed\n");
1710 : }
1711 : }
1712 : }
1713 :
1714 0 : static int shadow_copy2_chdir(vfs_handle_struct *handle,
1715 : const struct smb_filename *smb_fname)
1716 : {
1717 0 : time_t timestamp = 0;
1718 0 : char *stripped = NULL;
1719 0 : char *snappath = NULL;
1720 0 : int ret = -1;
1721 0 : int saved_errno = 0;
1722 0 : char *conv = NULL;
1723 0 : size_t rootpath_len = 0;
1724 0 : struct smb_filename *conv_smb_fname = NULL;
1725 :
1726 0 : if (!shadow_copy2_strip_snapshot_internal(talloc_tos(),
1727 : handle,
1728 : smb_fname,
1729 : ×tamp,
1730 : &stripped,
1731 : &snappath,
1732 : NULL)) {
1733 0 : return -1;
1734 : }
1735 0 : if (stripped != NULL) {
1736 0 : conv = shadow_copy2_do_convert(talloc_tos(),
1737 : handle,
1738 : stripped,
1739 : timestamp,
1740 : &rootpath_len);
1741 0 : TALLOC_FREE(stripped);
1742 0 : if (conv == NULL) {
1743 0 : return -1;
1744 : }
1745 0 : conv_smb_fname = synthetic_smb_fname(talloc_tos(),
1746 : conv,
1747 : NULL,
1748 : NULL,
1749 : 0,
1750 : smb_fname->flags);
1751 : } else {
1752 0 : conv_smb_fname = cp_smb_filename(talloc_tos(), smb_fname);
1753 : }
1754 :
1755 0 : if (conv_smb_fname == NULL) {
1756 0 : TALLOC_FREE(conv);
1757 0 : errno = ENOMEM;
1758 0 : return -1;
1759 : }
1760 :
1761 0 : ret = SMB_VFS_NEXT_CHDIR(handle, conv_smb_fname);
1762 0 : if (ret == -1) {
1763 0 : saved_errno = errno;
1764 : }
1765 :
1766 0 : if (ret == 0) {
1767 0 : if (conv != NULL && rootpath_len != 0) {
1768 0 : conv[rootpath_len] = '\0';
1769 0 : } else if (snappath != 0) {
1770 0 : TALLOC_FREE(conv);
1771 0 : conv = snappath;
1772 : }
1773 0 : store_cwd_data(handle, conv);
1774 : }
1775 :
1776 0 : TALLOC_FREE(stripped);
1777 0 : TALLOC_FREE(conv);
1778 0 : TALLOC_FREE(conv_smb_fname);
1779 :
1780 0 : if (saved_errno != 0) {
1781 0 : errno = saved_errno;
1782 : }
1783 0 : return ret;
1784 : }
1785 :
1786 0 : static int shadow_copy2_fntimes(vfs_handle_struct *handle,
1787 : files_struct *fsp,
1788 : struct smb_file_time *ft)
1789 : {
1790 0 : time_t timestamp = 0;
1791 :
1792 0 : if (!shadow_copy2_strip_snapshot(talloc_tos(),
1793 : handle,
1794 : fsp->fsp_name,
1795 : ×tamp,
1796 : NULL)) {
1797 0 : return -1;
1798 : }
1799 0 : if (timestamp != 0) {
1800 0 : errno = EROFS;
1801 0 : return -1;
1802 : }
1803 0 : return SMB_VFS_NEXT_FNTIMES(handle, fsp, ft);
1804 : }
1805 :
1806 0 : static int shadow_copy2_readlinkat(vfs_handle_struct *handle,
1807 : const struct files_struct *dirfsp,
1808 : const struct smb_filename *smb_fname,
1809 : char *buf,
1810 : size_t bufsiz)
1811 : {
1812 0 : time_t timestamp = 0;
1813 0 : char *stripped = NULL;
1814 0 : int saved_errno = 0;
1815 : int ret;
1816 0 : struct smb_filename *full_fname = NULL;
1817 0 : struct smb_filename *conv = NULL;
1818 :
1819 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
1820 : dirfsp,
1821 : smb_fname);
1822 0 : if (full_fname == NULL) {
1823 0 : errno = ENOMEM;
1824 0 : return -1;
1825 : }
1826 :
1827 0 : if (!shadow_copy2_strip_snapshot(talloc_tos(),
1828 : handle,
1829 : full_fname,
1830 : ×tamp,
1831 : &stripped)) {
1832 0 : TALLOC_FREE(full_fname);
1833 0 : return -1;
1834 : }
1835 :
1836 0 : if (timestamp == 0) {
1837 0 : TALLOC_FREE(full_fname);
1838 0 : TALLOC_FREE(stripped);
1839 0 : return SMB_VFS_NEXT_READLINKAT(handle,
1840 : dirfsp,
1841 : smb_fname,
1842 : buf,
1843 : bufsiz);
1844 : }
1845 0 : conv = cp_smb_filename(talloc_tos(), full_fname);
1846 0 : if (conv == NULL) {
1847 0 : TALLOC_FREE(full_fname);
1848 0 : TALLOC_FREE(stripped);
1849 0 : errno = ENOMEM;
1850 0 : return -1;
1851 : }
1852 0 : TALLOC_FREE(full_fname);
1853 0 : conv->base_name = shadow_copy2_convert(
1854 : conv, handle, stripped, timestamp);
1855 0 : TALLOC_FREE(stripped);
1856 0 : if (conv->base_name == NULL) {
1857 0 : return -1;
1858 : }
1859 0 : ret = SMB_VFS_NEXT_READLINKAT(handle,
1860 : handle->conn->cwd_fsp,
1861 : conv,
1862 : buf,
1863 : bufsiz);
1864 0 : if (ret == -1) {
1865 0 : saved_errno = errno;
1866 : }
1867 0 : TALLOC_FREE(conv);
1868 0 : if (saved_errno != 0) {
1869 0 : errno = saved_errno;
1870 : }
1871 0 : return ret;
1872 : }
1873 :
1874 0 : static int shadow_copy2_mknodat(vfs_handle_struct *handle,
1875 : files_struct *dirfsp,
1876 : const struct smb_filename *smb_fname,
1877 : mode_t mode,
1878 : SMB_DEV_T dev)
1879 : {
1880 0 : time_t timestamp = 0;
1881 :
1882 0 : if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1883 : smb_fname,
1884 : ×tamp, NULL)) {
1885 0 : return -1;
1886 : }
1887 0 : if (timestamp != 0) {
1888 0 : errno = EROFS;
1889 0 : return -1;
1890 : }
1891 0 : return SMB_VFS_NEXT_MKNODAT(handle,
1892 : dirfsp,
1893 : smb_fname,
1894 : mode,
1895 : dev);
1896 : }
1897 :
1898 0 : static struct smb_filename *shadow_copy2_realpath(vfs_handle_struct *handle,
1899 : TALLOC_CTX *ctx,
1900 : const struct smb_filename *smb_fname)
1901 : {
1902 0 : time_t timestamp = 0;
1903 0 : char *stripped = NULL;
1904 0 : struct smb_filename *result_fname = NULL;
1905 0 : struct smb_filename *conv_fname = NULL;
1906 0 : int saved_errno = 0;
1907 :
1908 0 : if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1909 : smb_fname,
1910 : ×tamp, &stripped)) {
1911 0 : goto done;
1912 : }
1913 0 : if (timestamp == 0) {
1914 0 : return SMB_VFS_NEXT_REALPATH(handle, ctx, smb_fname);
1915 : }
1916 :
1917 0 : conv_fname = cp_smb_filename(talloc_tos(), smb_fname);
1918 0 : if (conv_fname == NULL) {
1919 0 : goto done;
1920 : }
1921 0 : conv_fname->base_name = shadow_copy2_convert(
1922 : conv_fname, handle, stripped, timestamp);
1923 0 : if (conv_fname->base_name == NULL) {
1924 0 : goto done;
1925 : }
1926 :
1927 0 : result_fname = SMB_VFS_NEXT_REALPATH(handle, ctx, conv_fname);
1928 :
1929 0 : done:
1930 0 : if (result_fname == NULL) {
1931 0 : saved_errno = errno;
1932 : }
1933 0 : TALLOC_FREE(conv_fname);
1934 0 : TALLOC_FREE(stripped);
1935 0 : if (saved_errno != 0) {
1936 0 : errno = saved_errno;
1937 : }
1938 0 : return result_fname;
1939 : }
1940 :
1941 : /**
1942 : * Check whether a given directory contains a
1943 : * snapshot directory as direct subdirectory.
1944 : * If yes, return the path of the snapshot-subdir,
1945 : * otherwise return NULL.
1946 : */
1947 0 : static char *have_snapdir(struct vfs_handle_struct *handle,
1948 : const char *path)
1949 : {
1950 : struct smb_filename smb_fname;
1951 : int ret;
1952 : struct shadow_copy2_private *priv;
1953 :
1954 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1955 : return NULL);
1956 :
1957 0 : ZERO_STRUCT(smb_fname);
1958 0 : smb_fname.base_name = talloc_asprintf(talloc_tos(), "%s/%s",
1959 0 : path, priv->config->snapdir);
1960 0 : if (smb_fname.base_name == NULL) {
1961 0 : return NULL;
1962 : }
1963 :
1964 0 : ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
1965 0 : if ((ret == 0) && (S_ISDIR(smb_fname.st.st_ex_mode))) {
1966 0 : return smb_fname.base_name;
1967 : }
1968 0 : TALLOC_FREE(smb_fname.base_name);
1969 0 : return NULL;
1970 : }
1971 :
1972 : /**
1973 : * Find the snapshot directory (if any) for the given
1974 : * filename (which is relative to the share).
1975 : */
1976 0 : static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx,
1977 : struct vfs_handle_struct *handle,
1978 : struct smb_filename *smb_fname)
1979 : {
1980 : char *path, *p;
1981 : const char *snapdir;
1982 : struct shadow_copy2_config *config;
1983 : struct shadow_copy2_private *priv;
1984 :
1985 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1986 : return NULL);
1987 :
1988 0 : config = priv->config;
1989 :
1990 : /*
1991 : * If the non-snapdisrseverywhere mode, we should not search!
1992 : */
1993 0 : if (!config->snapdirseverywhere) {
1994 0 : return config->snapshot_basepath;
1995 : }
1996 :
1997 0 : path = talloc_asprintf(mem_ctx, "%s/%s",
1998 0 : handle->conn->connectpath,
1999 : smb_fname->base_name);
2000 0 : if (path == NULL) {
2001 0 : return NULL;
2002 : }
2003 :
2004 0 : snapdir = have_snapdir(handle, path);
2005 0 : if (snapdir != NULL) {
2006 0 : TALLOC_FREE(path);
2007 0 : return snapdir;
2008 : }
2009 :
2010 0 : while ((p = strrchr(path, '/')) && (p > path)) {
2011 :
2012 0 : p[0] = '\0';
2013 :
2014 0 : snapdir = have_snapdir(handle, path);
2015 0 : if (snapdir != NULL) {
2016 0 : TALLOC_FREE(path);
2017 0 : return snapdir;
2018 : }
2019 : }
2020 0 : TALLOC_FREE(path);
2021 0 : return NULL;
2022 : }
2023 :
2024 0 : static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
2025 : const char *name,
2026 : char *gmt, size_t gmt_len)
2027 : {
2028 : struct tm timestamp;
2029 : time_t timestamp_t;
2030 : unsigned long int timestamp_long;
2031 : const char *fmt;
2032 : struct shadow_copy2_config *config;
2033 : struct shadow_copy2_private *priv;
2034 0 : char *tmpstr = NULL;
2035 0 : char *tmp = NULL;
2036 0 : bool converted = false;
2037 0 : int ret = -1;
2038 :
2039 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
2040 : return NULL);
2041 :
2042 0 : config = priv->config;
2043 :
2044 0 : fmt = config->gmt_format;
2045 :
2046 : /*
2047 : * If regex is provided, then we will have to parse the
2048 : * filename which will contain both the prefix and the time format.
2049 : * e.g. <prefix><delimiter><time_format>
2050 : */
2051 0 : if (priv->snaps->regex != NULL) {
2052 0 : tmpstr = talloc_strdup(talloc_tos(), name);
2053 : /* point "name" to the time format */
2054 0 : name = strstr(name, priv->config->delimiter);
2055 0 : if (name == NULL) {
2056 0 : goto done;
2057 : }
2058 : /* Extract the prefix */
2059 0 : tmp = strstr(tmpstr, priv->config->delimiter);
2060 0 : if (tmp == NULL) {
2061 0 : goto done;
2062 : }
2063 0 : *tmp = '\0';
2064 :
2065 : /* Parse regex */
2066 0 : ret = regexec(priv->snaps->regex, tmpstr, 0, NULL, 0);
2067 0 : if (ret) {
2068 0 : DBG_DEBUG("shadow_copy2_snapshot_to_gmt: "
2069 : "no regex match for %s\n", tmpstr);
2070 0 : goto done;
2071 : }
2072 : }
2073 :
2074 0 : ZERO_STRUCT(timestamp);
2075 0 : if (config->use_sscanf) {
2076 0 : if (sscanf(name, fmt, ×tamp_long) != 1) {
2077 0 : DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
2078 : "no sscanf match %s: %s\n",
2079 : fmt, name));
2080 0 : goto done;
2081 : }
2082 0 : timestamp_t = timestamp_long;
2083 0 : gmtime_r(×tamp_t, ×tamp);
2084 : } else {
2085 0 : if (strptime(name, fmt, ×tamp) == NULL) {
2086 0 : DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
2087 : "no match %s: %s\n",
2088 : fmt, name));
2089 0 : goto done;
2090 : }
2091 0 : DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n",
2092 : fmt, name));
2093 :
2094 0 : if (config->use_localtime) {
2095 0 : timestamp.tm_isdst = -1;
2096 0 : timestamp_t = mktime(×tamp);
2097 0 : gmtime_r(×tamp_t, ×tamp);
2098 : }
2099 : }
2100 :
2101 0 : strftime(gmt, gmt_len, GMT_FORMAT, ×tamp);
2102 0 : converted = true;
2103 :
2104 0 : done:
2105 0 : TALLOC_FREE(tmpstr);
2106 0 : return converted;
2107 : }
2108 :
2109 0 : static int shadow_copy2_label_cmp_asc(const void *x, const void *y)
2110 : {
2111 0 : return strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
2112 : }
2113 :
2114 0 : static int shadow_copy2_label_cmp_desc(const void *x, const void *y)
2115 : {
2116 0 : return -strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
2117 : }
2118 :
2119 : /*
2120 : sort the shadow copy data in ascending or descending order
2121 : */
2122 0 : static void shadow_copy2_sort_data(vfs_handle_struct *handle,
2123 : struct shadow_copy_data *shadow_copy2_data)
2124 : {
2125 : int (*cmpfunc)(const void *, const void *);
2126 : const char *sort;
2127 : struct shadow_copy2_private *priv;
2128 :
2129 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
2130 : return);
2131 :
2132 0 : sort = priv->config->sort_order;
2133 0 : if (sort == NULL) {
2134 0 : return;
2135 : }
2136 :
2137 0 : if (strcmp(sort, "asc") == 0) {
2138 0 : cmpfunc = shadow_copy2_label_cmp_asc;
2139 0 : } else if (strcmp(sort, "desc") == 0) {
2140 0 : cmpfunc = shadow_copy2_label_cmp_desc;
2141 : } else {
2142 0 : return;
2143 : }
2144 :
2145 0 : if (shadow_copy2_data && shadow_copy2_data->num_volumes > 0 &&
2146 0 : shadow_copy2_data->labels)
2147 : {
2148 0 : TYPESAFE_QSORT(shadow_copy2_data->labels,
2149 : shadow_copy2_data->num_volumes,
2150 : cmpfunc);
2151 : }
2152 : }
2153 :
2154 0 : static int shadow_copy2_get_shadow_copy_data(
2155 : vfs_handle_struct *handle, files_struct *fsp,
2156 : struct shadow_copy_data *shadow_copy2_data,
2157 : bool labels)
2158 : {
2159 0 : DIR *p = NULL;
2160 : const char *snapdir;
2161 0 : struct smb_filename *snapdir_smb_fname = NULL;
2162 0 : struct files_struct *dirfsp = NULL;
2163 0 : struct files_struct *fspcwd = NULL;
2164 : struct dirent *d;
2165 0 : TALLOC_CTX *tmp_ctx = talloc_stackframe();
2166 0 : struct shadow_copy2_private *priv = NULL;
2167 0 : struct shadow_copy2_snapentry *tmpentry = NULL;
2168 0 : bool get_snaplist = false;
2169 0 : struct vfs_open_how how = {
2170 : .flags = O_RDONLY, .mode = 0,
2171 : };
2172 : int fd;
2173 0 : int ret = -1;
2174 : NTSTATUS status;
2175 0 : int saved_errno = 0;
2176 :
2177 0 : snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle, fsp->fsp_name);
2178 0 : if (snapdir == NULL) {
2179 0 : DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
2180 : handle->conn->connectpath));
2181 0 : errno = EINVAL;
2182 0 : goto done;
2183 : }
2184 :
2185 0 : snapdir_smb_fname = synthetic_smb_fname(talloc_tos(),
2186 : snapdir,
2187 : NULL,
2188 : NULL,
2189 : 0,
2190 0 : fsp->fsp_name->flags);
2191 0 : if (snapdir_smb_fname == NULL) {
2192 0 : errno = ENOMEM;
2193 0 : goto done;
2194 : }
2195 :
2196 0 : status = create_internal_dirfsp(handle->conn,
2197 : snapdir_smb_fname,
2198 : &dirfsp);
2199 0 : if (!NT_STATUS_IS_OK(status)) {
2200 0 : DBG_WARNING("create_internal_dir_fsp() failed for '%s'"
2201 : " - %s\n", snapdir, nt_errstr(status));
2202 0 : errno = ENOSYS;
2203 0 : goto done;
2204 : }
2205 :
2206 0 : status = vfs_at_fspcwd(talloc_tos(), handle->conn, &fspcwd);
2207 0 : if (!NT_STATUS_IS_OK(status)) {
2208 0 : errno = ENOMEM;
2209 0 : goto done;
2210 : }
2211 :
2212 : #ifdef O_DIRECTORY
2213 0 : how.flags |= O_DIRECTORY;
2214 : #endif
2215 :
2216 0 : fd = SMB_VFS_NEXT_OPENAT(handle,
2217 : fspcwd,
2218 : snapdir_smb_fname,
2219 : dirfsp,
2220 : &how);
2221 0 : if (fd == -1) {
2222 0 : DBG_WARNING("SMB_VFS_NEXT_OPEN failed for '%s'"
2223 : " - %s\n", snapdir, strerror(errno));
2224 0 : errno = ENOSYS;
2225 0 : goto done;
2226 : }
2227 0 : fsp_set_fd(dirfsp, fd);
2228 :
2229 : /* Now we have the handle, check access here. */
2230 0 : status = smbd_check_access_rights_fsp(fspcwd,
2231 : dirfsp,
2232 : false,
2233 : SEC_DIR_LIST);
2234 0 : if (!NT_STATUS_IS_OK(status)) {
2235 0 : DBG_ERR("user does not have list permission "
2236 : "on snapdir %s\n",
2237 : fsp_str_dbg(dirfsp));
2238 0 : errno = EACCES;
2239 0 : goto done;
2240 : }
2241 :
2242 0 : p = SMB_VFS_NEXT_FDOPENDIR(handle, dirfsp, NULL, 0);
2243 0 : if (!p) {
2244 0 : DBG_NOTICE("shadow_copy2: SMB_VFS_NEXT_FDOPENDIR() failed for '%s'"
2245 : " - %s\n", snapdir, strerror(errno));
2246 0 : errno = ENOSYS;
2247 0 : goto done;
2248 : }
2249 :
2250 0 : if (shadow_copy2_data != NULL) {
2251 0 : shadow_copy2_data->num_volumes = 0;
2252 0 : shadow_copy2_data->labels = NULL;
2253 : }
2254 :
2255 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
2256 : goto done);
2257 :
2258 : /*
2259 : * Normally this function is called twice once with labels = false and
2260 : * then with labels = true. When labels is false it will return the
2261 : * number of volumes so that the caller can allocate memory for that
2262 : * many labels. Therefore to eliminate snaplist both the times it is
2263 : * good to check if labels is set or not.
2264 : *
2265 : * shadow_copy2_data is NULL when we only want to update the list and
2266 : * don't want any labels.
2267 : */
2268 0 : if ((priv->snaps->regex != NULL) && (labels || shadow_copy2_data == NULL)) {
2269 0 : get_snaplist = true;
2270 : /* Reset the global snaplist */
2271 0 : shadow_copy2_delete_snaplist(priv);
2272 :
2273 : /* Set the current time as snaplist update time */
2274 0 : time(&(priv->snaps->fetch_time));
2275 : }
2276 :
2277 0 : while ((d = SMB_VFS_NEXT_READDIR(handle, dirfsp, p, NULL))) {
2278 : char snapshot[GMT_NAME_LEN+1];
2279 : SHADOW_COPY_LABEL *tlabels;
2280 :
2281 : /*
2282 : * ignore names not of the right form in the snapshot
2283 : * directory
2284 : */
2285 0 : if (!shadow_copy2_snapshot_to_gmt(
2286 0 : handle, d->d_name,
2287 : snapshot, sizeof(snapshot))) {
2288 :
2289 0 : DEBUG(6, ("shadow_copy2_get_shadow_copy_data: "
2290 : "ignoring %s\n", d->d_name));
2291 0 : continue;
2292 : }
2293 0 : DEBUG(6,("shadow_copy2_get_shadow_copy_data: %s -> %s\n",
2294 : d->d_name, snapshot));
2295 :
2296 0 : if (get_snaplist) {
2297 : /*
2298 : * Create a snap entry for each successful
2299 : * pattern match.
2300 : */
2301 0 : tmpentry = shadow_copy2_create_snapentry(priv);
2302 0 : if (tmpentry == NULL) {
2303 0 : DBG_ERR("talloc_zero() failed\n");
2304 0 : goto done;
2305 : }
2306 0 : tmpentry->snapname = talloc_strdup(tmpentry, d->d_name);
2307 0 : tmpentry->time_fmt = talloc_strdup(tmpentry, snapshot);
2308 : }
2309 :
2310 0 : if (shadow_copy2_data == NULL) {
2311 0 : continue;
2312 : }
2313 :
2314 0 : if (!labels) {
2315 : /* the caller doesn't want the labels */
2316 0 : shadow_copy2_data->num_volumes++;
2317 0 : continue;
2318 : }
2319 :
2320 0 : tlabels = talloc_realloc(shadow_copy2_data,
2321 : shadow_copy2_data->labels,
2322 : SHADOW_COPY_LABEL,
2323 : shadow_copy2_data->num_volumes+1);
2324 0 : if (tlabels == NULL) {
2325 0 : DEBUG(0,("shadow_copy2: out of memory\n"));
2326 0 : goto done;
2327 : }
2328 :
2329 0 : strlcpy(tlabels[shadow_copy2_data->num_volumes], snapshot,
2330 : sizeof(*tlabels));
2331 :
2332 0 : shadow_copy2_data->num_volumes++;
2333 0 : shadow_copy2_data->labels = tlabels;
2334 : }
2335 :
2336 0 : shadow_copy2_sort_data(handle, shadow_copy2_data);
2337 0 : ret = 0;
2338 :
2339 0 : done:
2340 0 : if (ret != 0) {
2341 0 : saved_errno = errno;
2342 : }
2343 0 : TALLOC_FREE(fspcwd );
2344 0 : if (p != NULL) {
2345 0 : SMB_VFS_NEXT_CLOSEDIR(handle, p);
2346 0 : p = NULL;
2347 0 : if (dirfsp != NULL) {
2348 : /*
2349 : * VFS_CLOSEDIR implicitly
2350 : * closed the associated fd.
2351 : */
2352 0 : fsp_set_fd(dirfsp, -1);
2353 : }
2354 : }
2355 0 : if (dirfsp != NULL) {
2356 0 : fd_close(dirfsp);
2357 0 : file_free(NULL, dirfsp);
2358 : }
2359 0 : TALLOC_FREE(tmp_ctx);
2360 0 : if (saved_errno != 0) {
2361 0 : errno = saved_errno;
2362 : }
2363 0 : return ret;
2364 : }
2365 :
2366 0 : static int shadow_copy2_mkdirat(vfs_handle_struct *handle,
2367 : struct files_struct *dirfsp,
2368 : const struct smb_filename *smb_fname,
2369 : mode_t mode)
2370 : {
2371 0 : struct smb_filename *full_fname = NULL;
2372 0 : time_t timestamp = 0;
2373 :
2374 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
2375 : dirfsp,
2376 : smb_fname);
2377 0 : if (full_fname == NULL) {
2378 0 : errno = ENOMEM;
2379 0 : return -1;
2380 : }
2381 :
2382 0 : if (!shadow_copy2_strip_snapshot(talloc_tos(),
2383 : handle,
2384 : full_fname,
2385 : ×tamp,
2386 : NULL)) {
2387 0 : return -1;
2388 : }
2389 0 : TALLOC_FREE(full_fname);
2390 0 : if (timestamp != 0) {
2391 0 : errno = EROFS;
2392 0 : return -1;
2393 : }
2394 0 : return SMB_VFS_NEXT_MKDIRAT(handle,
2395 : dirfsp,
2396 : smb_fname,
2397 : mode);
2398 : }
2399 :
2400 0 : static int shadow_copy2_fchflags(vfs_handle_struct *handle,
2401 : struct files_struct *fsp,
2402 : unsigned int flags)
2403 : {
2404 0 : time_t timestamp = 0;
2405 :
2406 0 : if (!shadow_copy2_strip_snapshot(talloc_tos(),
2407 : handle,
2408 : fsp->fsp_name,
2409 : ×tamp,
2410 : NULL)) {
2411 0 : return -1;
2412 : }
2413 0 : if (timestamp != 0) {
2414 0 : errno = EROFS;
2415 0 : return -1;
2416 : }
2417 0 : return SMB_VFS_NEXT_FCHFLAGS(handle, fsp, flags);
2418 : }
2419 :
2420 0 : static int shadow_copy2_fsetxattr(struct vfs_handle_struct *handle,
2421 : struct files_struct *fsp,
2422 : const char *aname, const void *value,
2423 : size_t size, int flags)
2424 : {
2425 0 : time_t timestamp = 0;
2426 0 : const struct smb_filename *smb_fname = NULL;
2427 :
2428 0 : smb_fname = fsp->fsp_name;
2429 0 : if (!shadow_copy2_strip_snapshot(talloc_tos(),
2430 : handle,
2431 : smb_fname,
2432 : ×tamp,
2433 : NULL)) {
2434 0 : return -1;
2435 : }
2436 0 : if (timestamp != 0) {
2437 0 : errno = EROFS;
2438 0 : return -1;
2439 : }
2440 0 : return SMB_VFS_NEXT_FSETXATTR(handle, fsp,
2441 : aname, value, size, flags);
2442 : }
2443 :
2444 0 : static NTSTATUS shadow_copy2_create_dfs_pathat(struct vfs_handle_struct *handle,
2445 : struct files_struct *dirfsp,
2446 : const struct smb_filename *smb_fname,
2447 : const struct referral *reflist,
2448 : size_t referral_count)
2449 : {
2450 0 : time_t timestamp = 0;
2451 :
2452 0 : if (!shadow_copy2_strip_snapshot(talloc_tos(),
2453 : handle,
2454 : smb_fname,
2455 : ×tamp,
2456 : NULL)) {
2457 0 : return NT_STATUS_NO_MEMORY;
2458 : }
2459 0 : if (timestamp != 0) {
2460 0 : return NT_STATUS_MEDIA_WRITE_PROTECTED;
2461 : }
2462 0 : return SMB_VFS_NEXT_CREATE_DFS_PATHAT(handle,
2463 : dirfsp,
2464 : smb_fname,
2465 : reflist,
2466 : referral_count);
2467 : }
2468 :
2469 0 : static NTSTATUS shadow_copy2_read_dfs_pathat(struct vfs_handle_struct *handle,
2470 : TALLOC_CTX *mem_ctx,
2471 : struct files_struct *dirfsp,
2472 : struct smb_filename *smb_fname,
2473 : struct referral **ppreflist,
2474 : size_t *preferral_count)
2475 : {
2476 0 : time_t timestamp = 0;
2477 0 : char *stripped = NULL;
2478 0 : struct smb_filename *full_fname = NULL;
2479 0 : struct smb_filename *conv = NULL;
2480 : NTSTATUS status;
2481 :
2482 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
2483 : dirfsp,
2484 : smb_fname);
2485 0 : if (full_fname == NULL) {
2486 0 : return NT_STATUS_NO_MEMORY;
2487 : }
2488 :
2489 0 : if (!shadow_copy2_strip_snapshot(mem_ctx,
2490 : handle,
2491 : full_fname,
2492 : ×tamp,
2493 : &stripped)) {
2494 0 : TALLOC_FREE(full_fname);
2495 0 : return NT_STATUS_NO_MEMORY;
2496 : }
2497 0 : if (timestamp == 0) {
2498 0 : TALLOC_FREE(full_fname);
2499 0 : TALLOC_FREE(stripped);
2500 0 : return SMB_VFS_NEXT_READ_DFS_PATHAT(handle,
2501 : mem_ctx,
2502 : dirfsp,
2503 : smb_fname,
2504 : ppreflist,
2505 : preferral_count);
2506 : }
2507 :
2508 0 : conv = cp_smb_filename(mem_ctx, full_fname);
2509 0 : if (conv == NULL) {
2510 0 : TALLOC_FREE(full_fname);
2511 0 : TALLOC_FREE(stripped);
2512 0 : return NT_STATUS_NO_MEMORY;
2513 : }
2514 0 : TALLOC_FREE(full_fname);
2515 0 : conv->base_name = shadow_copy2_convert(conv,
2516 : handle,
2517 : stripped,
2518 : timestamp);
2519 0 : TALLOC_FREE(stripped);
2520 0 : if (conv->base_name == NULL) {
2521 0 : TALLOC_FREE(conv);
2522 0 : return NT_STATUS_NO_MEMORY;
2523 : }
2524 :
2525 0 : status = SMB_VFS_NEXT_READ_DFS_PATHAT(handle,
2526 : mem_ctx,
2527 : handle->conn->cwd_fsp,
2528 : conv,
2529 : ppreflist,
2530 : preferral_count);
2531 :
2532 0 : if (NT_STATUS_IS_OK(status)) {
2533 : /* Return any stat(2) info. */
2534 0 : smb_fname->st = conv->st;
2535 : }
2536 :
2537 0 : TALLOC_FREE(conv);
2538 0 : return status;
2539 : }
2540 :
2541 0 : static NTSTATUS shadow_copy2_get_real_filename_at(
2542 : struct vfs_handle_struct *handle,
2543 : struct files_struct *dirfsp,
2544 : const char *name,
2545 : TALLOC_CTX *mem_ctx,
2546 : char **found_name)
2547 : {
2548 0 : struct shadow_copy2_private *priv = NULL;
2549 0 : time_t timestamp = 0;
2550 0 : char *stripped = NULL;
2551 : char *conv;
2552 0 : struct smb_filename *conv_fname = NULL;
2553 : NTSTATUS status;
2554 : bool ok;
2555 :
2556 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
2557 : return NT_STATUS_INTERNAL_ERROR);
2558 :
2559 0 : DBG_DEBUG("Path=[%s] name=[%s]\n", fsp_str_dbg(dirfsp), name);
2560 :
2561 0 : ok = shadow_copy2_strip_snapshot(
2562 : talloc_tos(), handle, dirfsp->fsp_name, ×tamp, &stripped);
2563 0 : if (!ok) {
2564 0 : status = map_nt_error_from_unix(errno);
2565 0 : DEBUG(10, ("shadow_copy2_strip_snapshot failed\n"));
2566 0 : return status;
2567 : }
2568 0 : if (timestamp == 0) {
2569 0 : DEBUG(10, ("timestamp == 0\n"));
2570 0 : return SMB_VFS_NEXT_GET_REAL_FILENAME_AT(
2571 : handle, dirfsp, name, mem_ctx, found_name);
2572 : }
2573 :
2574 : /*
2575 : * Note that stripped may be an empty string "" if path was ".". As
2576 : * shadow_copy2_convert() combines "" with the shadow-copy tree connect
2577 : * root fullpath and get_real_filename_full_scan() has an explicit check
2578 : * for "" this works.
2579 : */
2580 0 : DBG_DEBUG("stripped [%s]\n", stripped);
2581 :
2582 0 : conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2583 0 : if (conv == NULL) {
2584 0 : status = map_nt_error_from_unix(errno);
2585 0 : DBG_DEBUG("shadow_copy2_convert [%s] failed: %s\n",
2586 : stripped,
2587 : strerror(errno));
2588 0 : return status;
2589 : }
2590 :
2591 0 : status = synthetic_pathref(
2592 : talloc_tos(),
2593 0 : dirfsp->conn->cwd_fsp,
2594 : conv,
2595 : NULL,
2596 : NULL,
2597 : 0,
2598 : 0,
2599 : &conv_fname);
2600 0 : if (!NT_STATUS_IS_OK(status)) {
2601 0 : return status;
2602 : }
2603 :
2604 0 : DEBUG(10, ("Calling NEXT_GET_REAL_FILE_NAME for conv=[%s], "
2605 : "name=[%s]\n", conv, name));
2606 0 : status = SMB_VFS_NEXT_GET_REAL_FILENAME_AT(
2607 : handle, conv_fname->fsp, name, mem_ctx, found_name);
2608 0 : DEBUG(10, ("NEXT_REAL_FILE_NAME returned %s\n", nt_errstr(status)));
2609 0 : if (NT_STATUS_IS_OK(status)) {
2610 0 : TALLOC_FREE(conv_fname);
2611 0 : return NT_STATUS_OK;
2612 : }
2613 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
2614 0 : TALLOC_FREE(conv_fname);
2615 0 : TALLOC_FREE(conv);
2616 0 : return NT_STATUS_NOT_SUPPORTED;
2617 : }
2618 :
2619 0 : status = get_real_filename_full_scan_at(
2620 0 : conv_fname->fsp, name, false, mem_ctx, found_name);
2621 0 : TALLOC_FREE(conv_fname);
2622 0 : if (!NT_STATUS_IS_OK(status)) {
2623 0 : DBG_DEBUG("Scan [%s] for [%s] failed\n",
2624 : conv, name);
2625 0 : return status;
2626 : }
2627 :
2628 0 : DBG_DEBUG("Scan [%s] for [%s] returned [%s]\n",
2629 : conv, name, *found_name);
2630 :
2631 0 : TALLOC_FREE(conv);
2632 0 : return NT_STATUS_OK;
2633 : }
2634 :
2635 0 : static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle,
2636 : const struct smb_filename *smb_fname_in)
2637 : {
2638 0 : time_t timestamp = 0;
2639 0 : char *stripped = NULL;
2640 0 : char *tmp = NULL;
2641 0 : const char *fname = smb_fname_in->base_name;
2642 0 : struct smb_filename smb_fname = {0};
2643 0 : struct smb_filename *result_fname = NULL;
2644 0 : char *result = NULL;
2645 0 : char *parent_dir = NULL;
2646 0 : int saved_errno = 0;
2647 0 : size_t rootpath_len = 0;
2648 0 : struct shadow_copy2_private *priv = NULL;
2649 :
2650 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
2651 : return NULL);
2652 :
2653 0 : DBG_DEBUG("Calc connect path for [%s]\n", fname);
2654 :
2655 0 : if (priv->shadow_connectpath != NULL) {
2656 0 : DBG_DEBUG("cached connect path is [%s]\n",
2657 : priv->shadow_connectpath);
2658 0 : return priv->shadow_connectpath;
2659 : }
2660 :
2661 0 : if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, smb_fname_in,
2662 : ×tamp, &stripped)) {
2663 0 : goto done;
2664 : }
2665 0 : if (timestamp == 0) {
2666 0 : return SMB_VFS_NEXT_CONNECTPATH(handle, smb_fname_in);
2667 : }
2668 :
2669 0 : tmp = shadow_copy2_do_convert(talloc_tos(), handle, stripped, timestamp,
2670 : &rootpath_len);
2671 0 : if (tmp == NULL) {
2672 0 : if (errno != ENOENT) {
2673 0 : goto done;
2674 : }
2675 :
2676 : /*
2677 : * If the converted path does not exist, and converting
2678 : * the parent yields something that does exist, then
2679 : * this path refers to something that has not been
2680 : * created yet, relative to the parent path.
2681 : * The snapshot finding is relative to the parent.
2682 : * (usually snapshots are read/only but this is not
2683 : * necessarily true).
2684 : * This code also covers getting a wildcard in the
2685 : * last component, because this function is called
2686 : * prior to sanitizing the path, and in SMB1 we may
2687 : * get wildcards in path names.
2688 : */
2689 0 : if (!parent_dirname(talloc_tos(), stripped, &parent_dir,
2690 : NULL)) {
2691 0 : errno = ENOMEM;
2692 0 : goto done;
2693 : }
2694 :
2695 0 : tmp = shadow_copy2_do_convert(talloc_tos(), handle, parent_dir,
2696 : timestamp, &rootpath_len);
2697 0 : if (tmp == NULL) {
2698 0 : goto done;
2699 : }
2700 : }
2701 :
2702 0 : DBG_DEBUG("converted path is [%s] root path is [%.*s]\n", tmp,
2703 : (int)rootpath_len, tmp);
2704 :
2705 0 : tmp[rootpath_len] = '\0';
2706 0 : smb_fname = (struct smb_filename) { .base_name = tmp };
2707 :
2708 0 : result_fname = SMB_VFS_NEXT_REALPATH(handle, priv, &smb_fname);
2709 0 : if (result_fname == NULL) {
2710 0 : goto done;
2711 : }
2712 :
2713 : /*
2714 : * SMB_VFS_NEXT_REALPATH returns a talloc'ed string.
2715 : * Don't leak memory.
2716 : */
2717 0 : TALLOC_FREE(priv->shadow_realpath);
2718 0 : priv->shadow_realpath = result_fname;
2719 0 : result = priv->shadow_realpath->base_name;
2720 :
2721 0 : DBG_DEBUG("connect path is [%s]\n", result);
2722 :
2723 0 : done:
2724 0 : if (result == NULL) {
2725 0 : saved_errno = errno;
2726 : }
2727 0 : TALLOC_FREE(tmp);
2728 0 : TALLOC_FREE(stripped);
2729 0 : TALLOC_FREE(parent_dir);
2730 0 : if (saved_errno != 0) {
2731 0 : errno = saved_errno;
2732 : }
2733 0 : return result;
2734 : }
2735 :
2736 0 : static NTSTATUS shadow_copy2_parent_pathname(vfs_handle_struct *handle,
2737 : TALLOC_CTX *ctx,
2738 : const struct smb_filename *smb_fname_in,
2739 : struct smb_filename **parent_dir_out,
2740 : struct smb_filename **atname_out)
2741 : {
2742 0 : time_t timestamp = 0;
2743 0 : char *stripped = NULL;
2744 0 : char *converted_name = NULL;
2745 0 : struct smb_filename *smb_fname = NULL;
2746 0 : struct smb_filename *parent = NULL;
2747 0 : struct smb_filename *atname = NULL;
2748 0 : struct shadow_copy2_private *priv = NULL;
2749 0 : bool ok = false;
2750 0 : bool is_converted = false;
2751 0 : NTSTATUS status = NT_STATUS_OK;
2752 0 : TALLOC_CTX *frame = NULL;
2753 :
2754 0 : SMB_VFS_HANDLE_GET_DATA(handle,
2755 : priv,
2756 : struct shadow_copy2_private,
2757 : return NT_STATUS_INTERNAL_ERROR);
2758 :
2759 0 : frame = talloc_stackframe();
2760 :
2761 0 : smb_fname = cp_smb_filename(frame, smb_fname_in);
2762 0 : if (smb_fname == NULL) {
2763 0 : status = NT_STATUS_NO_MEMORY;
2764 0 : goto fail;
2765 : }
2766 :
2767 : /* First, call the default PARENT_PATHNAME. */
2768 0 : status = SMB_VFS_NEXT_PARENT_PATHNAME(handle,
2769 : frame,
2770 : smb_fname,
2771 : &parent,
2772 : &atname);
2773 0 : if (!NT_STATUS_IS_OK(status)) {
2774 0 : goto fail;
2775 : }
2776 :
2777 0 : if (parent->twrp == 0) {
2778 : /*
2779 : * Parent is not a snapshot path, return
2780 : * the regular result.
2781 : */
2782 0 : status = NT_STATUS_OK;
2783 0 : goto out;
2784 : }
2785 :
2786 : /* See if we can find a snapshot for the parent. */
2787 0 : ok = shadow_copy2_strip_snapshot_converted(frame,
2788 : handle,
2789 : parent,
2790 : ×tamp,
2791 : &stripped,
2792 : &is_converted);
2793 0 : if (!ok) {
2794 0 : status = map_nt_error_from_unix(errno);
2795 0 : goto fail;
2796 : }
2797 :
2798 0 : if (is_converted) {
2799 : /*
2800 : * Already found snapshot for parent so wipe
2801 : * out the twrp.
2802 : */
2803 0 : parent->twrp = 0;
2804 0 : goto out;
2805 : }
2806 :
2807 0 : converted_name = shadow_copy2_convert(frame,
2808 : handle,
2809 : stripped,
2810 : timestamp);
2811 :
2812 0 : if (converted_name == NULL) {
2813 : /*
2814 : * Can't find snapshot for parent so wipe
2815 : * out the twrp.
2816 : */
2817 0 : parent->twrp = 0;
2818 : }
2819 :
2820 0 : out:
2821 :
2822 0 : *parent_dir_out = talloc_move(ctx, &parent);
2823 0 : if (atname_out != NULL) {
2824 0 : *atname_out = talloc_move(*parent_dir_out, &atname);
2825 : }
2826 :
2827 0 : fail:
2828 :
2829 0 : TALLOC_FREE(frame);
2830 0 : return status;
2831 : }
2832 :
2833 0 : static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle,
2834 : const struct smb_filename *smb_fname,
2835 : uint64_t *bsize,
2836 : uint64_t *dfree,
2837 : uint64_t *dsize)
2838 : {
2839 0 : time_t timestamp = 0;
2840 0 : char *stripped = NULL;
2841 0 : int saved_errno = 0;
2842 0 : char *conv = NULL;
2843 0 : struct smb_filename *conv_smb_fname = NULL;
2844 0 : uint64_t ret = (uint64_t)-1;
2845 :
2846 0 : if (!shadow_copy2_strip_snapshot(talloc_tos(),
2847 : handle,
2848 : smb_fname,
2849 : ×tamp,
2850 : &stripped)) {
2851 0 : return (uint64_t)-1;
2852 : }
2853 0 : if (timestamp == 0) {
2854 0 : return SMB_VFS_NEXT_DISK_FREE(handle, smb_fname,
2855 : bsize, dfree, dsize);
2856 : }
2857 0 : conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2858 0 : TALLOC_FREE(stripped);
2859 0 : if (conv == NULL) {
2860 0 : return (uint64_t)-1;
2861 : }
2862 0 : conv_smb_fname = synthetic_smb_fname(talloc_tos(),
2863 : conv,
2864 : NULL,
2865 : NULL,
2866 : 0,
2867 : smb_fname->flags);
2868 0 : if (conv_smb_fname == NULL) {
2869 0 : TALLOC_FREE(conv);
2870 0 : return (uint64_t)-1;
2871 : }
2872 0 : ret = SMB_VFS_NEXT_DISK_FREE(handle, conv_smb_fname,
2873 : bsize, dfree, dsize);
2874 0 : if (ret == (uint64_t)-1) {
2875 0 : saved_errno = errno;
2876 : }
2877 0 : TALLOC_FREE(conv);
2878 0 : TALLOC_FREE(conv_smb_fname);
2879 0 : if (saved_errno != 0) {
2880 0 : errno = saved_errno;
2881 : }
2882 0 : return ret;
2883 : }
2884 :
2885 0 : static int shadow_copy2_get_quota(vfs_handle_struct *handle,
2886 : const struct smb_filename *smb_fname,
2887 : enum SMB_QUOTA_TYPE qtype,
2888 : unid_t id,
2889 : SMB_DISK_QUOTA *dq)
2890 : {
2891 0 : time_t timestamp = 0;
2892 0 : char *stripped = NULL;
2893 : int ret;
2894 0 : int saved_errno = 0;
2895 : char *conv;
2896 0 : struct smb_filename *conv_smb_fname = NULL;
2897 :
2898 0 : if (!shadow_copy2_strip_snapshot(talloc_tos(),
2899 : handle,
2900 : smb_fname,
2901 : ×tamp,
2902 : &stripped)) {
2903 0 : return -1;
2904 : }
2905 0 : if (timestamp == 0) {
2906 0 : return SMB_VFS_NEXT_GET_QUOTA(handle, smb_fname, qtype, id, dq);
2907 : }
2908 :
2909 0 : conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2910 0 : TALLOC_FREE(stripped);
2911 0 : if (conv == NULL) {
2912 0 : return -1;
2913 : }
2914 0 : conv_smb_fname = synthetic_smb_fname(talloc_tos(),
2915 : conv,
2916 : NULL,
2917 : NULL,
2918 : 0,
2919 : smb_fname->flags);
2920 0 : if (conv_smb_fname == NULL) {
2921 0 : TALLOC_FREE(conv);
2922 0 : return -1;
2923 : }
2924 0 : ret = SMB_VFS_NEXT_GET_QUOTA(handle, conv_smb_fname, qtype, id, dq);
2925 :
2926 0 : if (ret == -1) {
2927 0 : saved_errno = errno;
2928 : }
2929 0 : TALLOC_FREE(conv);
2930 0 : TALLOC_FREE(conv_smb_fname);
2931 0 : if (saved_errno != 0) {
2932 0 : errno = saved_errno;
2933 : }
2934 :
2935 0 : return ret;
2936 : }
2937 :
2938 0 : static ssize_t shadow_copy2_pwrite(vfs_handle_struct *handle,
2939 : files_struct *fsp,
2940 : const void *data,
2941 : size_t n,
2942 : off_t offset)
2943 : {
2944 : ssize_t nwritten;
2945 :
2946 0 : nwritten = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
2947 0 : if (nwritten == -1) {
2948 0 : if (errno == EBADF && fsp->fsp_flags.can_write) {
2949 0 : errno = EROFS;
2950 : }
2951 : }
2952 :
2953 0 : return nwritten;
2954 : }
2955 :
2956 : struct shadow_copy2_pwrite_state {
2957 : vfs_handle_struct *handle;
2958 : files_struct *fsp;
2959 : ssize_t ret;
2960 : struct vfs_aio_state vfs_aio_state;
2961 : };
2962 :
2963 : static void shadow_copy2_pwrite_done(struct tevent_req *subreq);
2964 :
2965 0 : static struct tevent_req *shadow_copy2_pwrite_send(
2966 : struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx,
2967 : struct tevent_context *ev, struct files_struct *fsp,
2968 : const void *data, size_t n, off_t offset)
2969 : {
2970 0 : struct tevent_req *req = NULL, *subreq = NULL;
2971 0 : struct shadow_copy2_pwrite_state *state = NULL;
2972 :
2973 0 : req = tevent_req_create(mem_ctx, &state,
2974 : struct shadow_copy2_pwrite_state);
2975 0 : if (req == NULL) {
2976 0 : return NULL;
2977 : }
2978 0 : state->handle = handle;
2979 0 : state->fsp = fsp;
2980 :
2981 0 : subreq = SMB_VFS_NEXT_PWRITE_SEND(state,
2982 : ev,
2983 : handle,
2984 : fsp,
2985 : data,
2986 : n,
2987 : offset);
2988 0 : if (tevent_req_nomem(subreq, req)) {
2989 0 : return tevent_req_post(req, ev);
2990 : }
2991 0 : tevent_req_set_callback(subreq, shadow_copy2_pwrite_done, req);
2992 :
2993 0 : return req;
2994 : }
2995 :
2996 0 : static void shadow_copy2_pwrite_done(struct tevent_req *subreq)
2997 : {
2998 0 : struct tevent_req *req = tevent_req_callback_data(
2999 : subreq, struct tevent_req);
3000 0 : struct shadow_copy2_pwrite_state *state = tevent_req_data(
3001 : req, struct shadow_copy2_pwrite_state);
3002 :
3003 0 : state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
3004 0 : TALLOC_FREE(subreq);
3005 0 : if (state->ret == -1) {
3006 0 : tevent_req_error(req, state->vfs_aio_state.error);
3007 0 : return;
3008 : }
3009 :
3010 0 : tevent_req_done(req);
3011 : }
3012 :
3013 0 : static ssize_t shadow_copy2_pwrite_recv(struct tevent_req *req,
3014 : struct vfs_aio_state *vfs_aio_state)
3015 : {
3016 0 : struct shadow_copy2_pwrite_state *state = tevent_req_data(
3017 : req, struct shadow_copy2_pwrite_state);
3018 :
3019 0 : if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
3020 0 : if ((vfs_aio_state->error == EBADF) &&
3021 0 : state->fsp->fsp_flags.can_write)
3022 : {
3023 0 : vfs_aio_state->error = EROFS;
3024 0 : errno = EROFS;
3025 : }
3026 0 : return -1;
3027 : }
3028 :
3029 0 : *vfs_aio_state = state->vfs_aio_state;
3030 0 : return state->ret;
3031 : }
3032 :
3033 0 : static int shadow_copy2_connect(struct vfs_handle_struct *handle,
3034 : const char *service, const char *user)
3035 : {
3036 : struct shadow_copy2_config *config;
3037 : struct shadow_copy2_private *priv;
3038 : int ret;
3039 : const char *snapdir;
3040 0 : const char *snapprefix = NULL;
3041 : const char *delimiter;
3042 : const char *gmt_format;
3043 : const char *sort_order;
3044 0 : const char *basedir = NULL;
3045 0 : const char *snapsharepath = NULL;
3046 : const char *mount_point;
3047 :
3048 0 : DEBUG(10, (__location__ ": cnum[%u], connectpath[%s]\n",
3049 : (unsigned)handle->conn->cnum,
3050 : handle->conn->connectpath));
3051 :
3052 0 : ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
3053 0 : if (ret < 0) {
3054 0 : return ret;
3055 : }
3056 :
3057 0 : priv = talloc_zero(handle->conn, struct shadow_copy2_private);
3058 0 : if (priv == NULL) {
3059 0 : DBG_ERR("talloc_zero() failed\n");
3060 0 : errno = ENOMEM;
3061 0 : return -1;
3062 : }
3063 :
3064 0 : priv->snaps = talloc_zero(priv, struct shadow_copy2_snaplist_info);
3065 0 : if (priv->snaps == NULL) {
3066 0 : DBG_ERR("talloc_zero() failed\n");
3067 0 : errno = ENOMEM;
3068 0 : return -1;
3069 : }
3070 :
3071 0 : config = talloc_zero(priv, struct shadow_copy2_config);
3072 0 : if (config == NULL) {
3073 0 : DEBUG(0, ("talloc_zero() failed\n"));
3074 0 : errno = ENOMEM;
3075 0 : return -1;
3076 : }
3077 :
3078 0 : priv->config = config;
3079 :
3080 0 : gmt_format = lp_parm_const_string(SNUM(handle->conn),
3081 : "shadow", "format",
3082 : GMT_FORMAT);
3083 0 : config->gmt_format = talloc_strdup(config, gmt_format);
3084 0 : if (config->gmt_format == NULL) {
3085 0 : DEBUG(0, ("talloc_strdup() failed\n"));
3086 0 : errno = ENOMEM;
3087 0 : return -1;
3088 : }
3089 :
3090 : /* config->gmt_format must not contain a path separator. */
3091 0 : if (strchr(config->gmt_format, '/') != NULL) {
3092 0 : DEBUG(0, ("shadow:format %s must not contain a /"
3093 : "character. Unable to initialize module.\n",
3094 : config->gmt_format));
3095 0 : errno = EINVAL;
3096 0 : return -1;
3097 : }
3098 :
3099 0 : config->use_sscanf = lp_parm_bool(SNUM(handle->conn),
3100 : "shadow", "sscanf", false);
3101 :
3102 0 : config->use_localtime = lp_parm_bool(SNUM(handle->conn),
3103 : "shadow", "localtime",
3104 : false);
3105 :
3106 0 : snapdir = lp_parm_const_string(SNUM(handle->conn),
3107 : "shadow", "snapdir",
3108 : ".snapshots");
3109 0 : config->snapdir = talloc_strdup(config, snapdir);
3110 0 : if (config->snapdir == NULL) {
3111 0 : DEBUG(0, ("talloc_strdup() failed\n"));
3112 0 : errno = ENOMEM;
3113 0 : return -1;
3114 : }
3115 :
3116 0 : snapprefix = lp_parm_const_string(SNUM(handle->conn),
3117 : "shadow", "snapprefix",
3118 : NULL);
3119 0 : if (snapprefix != NULL) {
3120 0 : priv->snaps->regex = talloc_zero(priv->snaps, regex_t);
3121 0 : if (priv->snaps->regex == NULL) {
3122 0 : DBG_ERR("talloc_zero() failed\n");
3123 0 : errno = ENOMEM;
3124 0 : return -1;
3125 : }
3126 :
3127 : /* pre-compute regex rule for matching pattern later */
3128 0 : ret = regcomp(priv->snaps->regex, snapprefix, 0);
3129 0 : if (ret) {
3130 0 : DBG_ERR("Failed to create regex object\n");
3131 0 : return -1;
3132 : }
3133 : }
3134 :
3135 0 : delimiter = lp_parm_const_string(SNUM(handle->conn),
3136 : "shadow", "delimiter",
3137 : "_GMT");
3138 0 : if (delimiter != NULL) {
3139 0 : priv->config->delimiter = talloc_strdup(priv->config, delimiter);
3140 0 : if (priv->config->delimiter == NULL) {
3141 0 : DBG_ERR("talloc_strdup() failed\n");
3142 0 : errno = ENOMEM;
3143 0 : return -1;
3144 : }
3145 : }
3146 :
3147 0 : config->snapdirseverywhere = lp_parm_bool(SNUM(handle->conn),
3148 : "shadow",
3149 : "snapdirseverywhere",
3150 : false);
3151 :
3152 0 : config->crossmountpoints = lp_parm_bool(SNUM(handle->conn),
3153 : "shadow", "crossmountpoints",
3154 : false);
3155 :
3156 0 : if (config->crossmountpoints && !config->snapdirseverywhere) {
3157 0 : DBG_WARNING("Warning: 'crossmountpoints' depends on "
3158 : "'snapdirseverywhere'. Disabling crossmountpoints.\n");
3159 : }
3160 :
3161 0 : config->fixinodes = lp_parm_bool(SNUM(handle->conn),
3162 : "shadow", "fixinodes",
3163 : false);
3164 :
3165 0 : sort_order = lp_parm_const_string(SNUM(handle->conn),
3166 : "shadow", "sort", "desc");
3167 0 : config->sort_order = talloc_strdup(config, sort_order);
3168 0 : if (config->sort_order == NULL) {
3169 0 : DEBUG(0, ("talloc_strdup() failed\n"));
3170 0 : errno = ENOMEM;
3171 0 : return -1;
3172 : }
3173 :
3174 0 : mount_point = lp_parm_const_string(SNUM(handle->conn),
3175 : "shadow", "mountpoint", NULL);
3176 0 : if (mount_point != NULL) {
3177 0 : if (mount_point[0] != '/') {
3178 0 : DEBUG(1, (__location__ " Warning: 'mountpoint' is "
3179 : "relative ('%s'), but it has to be an "
3180 : "absolute path. Ignoring provided value.\n",
3181 : mount_point));
3182 0 : mount_point = NULL;
3183 : } else {
3184 : char *p;
3185 0 : p = strstr(handle->conn->connectpath, mount_point);
3186 0 : if (p != handle->conn->connectpath) {
3187 0 : DBG_WARNING("Warning: the share root (%s) is "
3188 : "not a subdirectory of the "
3189 : "specified mountpoint (%s). "
3190 : "Ignoring provided value.\n",
3191 : handle->conn->connectpath,
3192 : mount_point);
3193 0 : mount_point = NULL;
3194 : }
3195 : }
3196 : }
3197 :
3198 0 : if (mount_point != NULL) {
3199 0 : config->mount_point = talloc_strdup(config, mount_point);
3200 0 : if (config->mount_point == NULL) {
3201 0 : DEBUG(0, (__location__ " talloc_strdup() failed\n"));
3202 0 : return -1;
3203 : }
3204 : } else {
3205 0 : config->mount_point = shadow_copy2_find_mount_point(config,
3206 : handle);
3207 0 : if (config->mount_point == NULL) {
3208 0 : DBG_WARNING("shadow_copy2_find_mount_point "
3209 : "of the share root '%s' failed: %s\n",
3210 : handle->conn->connectpath, strerror(errno));
3211 0 : return -1;
3212 : }
3213 : }
3214 :
3215 0 : basedir = lp_parm_const_string(SNUM(handle->conn),
3216 : "shadow", "basedir", NULL);
3217 :
3218 0 : if (basedir != NULL) {
3219 0 : if (basedir[0] != '/') {
3220 0 : DEBUG(1, (__location__ " Warning: 'basedir' is "
3221 : "relative ('%s'), but it has to be an "
3222 : "absolute path. Disabling basedir.\n",
3223 : basedir));
3224 0 : basedir = NULL;
3225 : } else {
3226 : char *p;
3227 0 : p = strstr(basedir, config->mount_point);
3228 0 : if (p != basedir) {
3229 0 : DEBUG(1, ("Warning: basedir (%s) is not a "
3230 : "subdirectory of the share root's "
3231 : "mount point (%s). "
3232 : "Disabling basedir\n",
3233 : basedir, config->mount_point));
3234 0 : basedir = NULL;
3235 : }
3236 : }
3237 : }
3238 :
3239 0 : if (config->snapdirseverywhere && basedir != NULL) {
3240 0 : DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
3241 : "with 'snapdirseverywhere'. Disabling basedir.\n"));
3242 0 : basedir = NULL;
3243 : }
3244 :
3245 0 : snapsharepath = lp_parm_const_string(SNUM(handle->conn), "shadow",
3246 : "snapsharepath", NULL);
3247 0 : if (snapsharepath != NULL) {
3248 0 : if (snapsharepath[0] == '/') {
3249 0 : DBG_WARNING("Warning: 'snapsharepath' is "
3250 : "absolute ('%s'), but it has to be a "
3251 : "relative path. Disabling snapsharepath.\n",
3252 : snapsharepath);
3253 0 : snapsharepath = NULL;
3254 : }
3255 0 : if (config->snapdirseverywhere && snapsharepath != NULL) {
3256 0 : DBG_WARNING("Warning: 'snapsharepath' is incompatible "
3257 : "with 'snapdirseverywhere'. Disabling "
3258 : "snapsharepath.\n");
3259 0 : snapsharepath = NULL;
3260 : }
3261 : }
3262 :
3263 0 : if (basedir != NULL && snapsharepath != NULL) {
3264 0 : DBG_WARNING("Warning: 'snapsharepath' is incompatible with "
3265 : "'basedir'. Disabling snapsharepath\n");
3266 0 : snapsharepath = NULL;
3267 : }
3268 :
3269 0 : if (snapsharepath != NULL) {
3270 0 : config->rel_connectpath = talloc_strdup(config, snapsharepath);
3271 0 : if (config->rel_connectpath == NULL) {
3272 0 : DBG_ERR("talloc_strdup() failed\n");
3273 0 : errno = ENOMEM;
3274 0 : return -1;
3275 : }
3276 : }
3277 :
3278 0 : if (basedir == NULL) {
3279 0 : basedir = config->mount_point;
3280 : }
3281 :
3282 0 : if (config->rel_connectpath == NULL &&
3283 0 : strlen(basedir) < strlen(handle->conn->connectpath)) {
3284 0 : config->rel_connectpath = talloc_strdup(config,
3285 0 : handle->conn->connectpath + strlen(basedir));
3286 0 : if (config->rel_connectpath == NULL) {
3287 0 : DEBUG(0, ("talloc_strdup() failed\n"));
3288 0 : errno = ENOMEM;
3289 0 : return -1;
3290 : }
3291 : }
3292 :
3293 0 : if (config->snapdir[0] == '/') {
3294 0 : config->snapdir_absolute = true;
3295 :
3296 0 : if (config->snapdirseverywhere == true) {
3297 0 : DEBUG(1, (__location__ " Warning: An absolute snapdir "
3298 : "is incompatible with 'snapdirseverywhere', "
3299 : "setting 'snapdirseverywhere' to false.\n"));
3300 0 : config->snapdirseverywhere = false;
3301 : }
3302 :
3303 0 : if (config->crossmountpoints == true) {
3304 0 : DEBUG(1, (__location__ " Warning: 'crossmountpoints' "
3305 : "is not supported with an absolute snapdir. "
3306 : "Disabling it.\n"));
3307 0 : config->crossmountpoints = false;
3308 : }
3309 :
3310 0 : config->snapshot_basepath = config->snapdir;
3311 : } else {
3312 0 : config->snapshot_basepath = talloc_asprintf(config, "%s/%s",
3313 : config->mount_point, config->snapdir);
3314 0 : if (config->snapshot_basepath == NULL) {
3315 0 : DEBUG(0, ("talloc_asprintf() failed\n"));
3316 0 : errno = ENOMEM;
3317 0 : return -1;
3318 : }
3319 : }
3320 :
3321 0 : trim_string(config->mount_point, NULL, "/");
3322 0 : trim_string(config->rel_connectpath, "/", "/");
3323 0 : trim_string(config->snapdir, NULL, "/");
3324 0 : trim_string(config->snapshot_basepath, NULL, "/");
3325 :
3326 0 : DEBUG(10, ("shadow_copy2_connect: configuration:\n"
3327 : " share root: '%s'\n"
3328 : " mountpoint: '%s'\n"
3329 : " rel share root: '%s'\n"
3330 : " snapdir: '%s'\n"
3331 : " snapprefix: '%s'\n"
3332 : " delimiter: '%s'\n"
3333 : " snapshot base path: '%s'\n"
3334 : " format: '%s'\n"
3335 : " use sscanf: %s\n"
3336 : " snapdirs everywhere: %s\n"
3337 : " cross mountpoints: %s\n"
3338 : " fix inodes: %s\n"
3339 : " sort order: %s\n"
3340 : "",
3341 : handle->conn->connectpath,
3342 : config->mount_point,
3343 : config->rel_connectpath,
3344 : config->snapdir,
3345 : snapprefix,
3346 : config->delimiter,
3347 : config->snapshot_basepath,
3348 : config->gmt_format,
3349 : config->use_sscanf ? "yes" : "no",
3350 : config->snapdirseverywhere ? "yes" : "no",
3351 : config->crossmountpoints ? "yes" : "no",
3352 : config->fixinodes ? "yes" : "no",
3353 : config->sort_order
3354 : ));
3355 :
3356 :
3357 0 : SMB_VFS_HANDLE_SET_DATA(handle, priv,
3358 : NULL, struct shadow_copy2_private,
3359 : return -1);
3360 :
3361 0 : return 0;
3362 : }
3363 :
3364 0 : static struct dirent *shadow_copy2_readdir(vfs_handle_struct *handle,
3365 : struct files_struct *dirfsp,
3366 : DIR *dirp,
3367 : SMB_STRUCT_STAT *sbuf)
3368 : {
3369 0 : struct shadow_copy2_private *priv = NULL;
3370 0 : struct dirent *ent = NULL;
3371 : struct smb_filename atname;
3372 0 : struct smb_filename *full_fname = NULL;
3373 0 : time_t timestamp = 0;
3374 0 : char *stripped = NULL;
3375 0 : char *conv = NULL;
3376 0 : char *abspath = NULL;
3377 0 : bool converted = false;
3378 :
3379 0 : SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
3380 : return NULL);
3381 :
3382 0 : ent = SMB_VFS_NEXT_READDIR(handle, dirfsp, dirp, sbuf);
3383 0 : if (ent == NULL) {
3384 0 : return NULL;
3385 : }
3386 0 : if (sbuf == NULL) {
3387 0 : return ent;
3388 : }
3389 0 : if (ISDOT(dirfsp->fsp_name->base_name) && ISDOTDOT(ent->d_name)) {
3390 0 : return ent;
3391 : }
3392 :
3393 0 : atname = (struct smb_filename) {
3394 0 : .base_name = ent->d_name,
3395 0 : .twrp = dirfsp->fsp_name->twrp,
3396 0 : .flags = dirfsp->fsp_name->flags,
3397 : };
3398 :
3399 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
3400 : dirfsp,
3401 : &atname);
3402 0 : if (full_fname == NULL) {
3403 0 : return NULL;
3404 : }
3405 :
3406 0 : if (!shadow_copy2_strip_snapshot_converted(talloc_tos(),
3407 : handle,
3408 : full_fname,
3409 : ×tamp,
3410 : &stripped,
3411 : &converted)) {
3412 0 : TALLOC_FREE(full_fname);
3413 0 : return NULL;
3414 : }
3415 :
3416 0 : if (timestamp == 0 && !converted) {
3417 : /* Not a snapshot path, no need for convert_sbuf() */
3418 0 : TALLOC_FREE(stripped);
3419 0 : TALLOC_FREE(full_fname);
3420 0 : return ent;
3421 : }
3422 :
3423 0 : if (timestamp == 0) {
3424 0 : abspath = make_path_absolute(talloc_tos(),
3425 : priv,
3426 0 : full_fname->base_name);
3427 0 : TALLOC_FREE(full_fname);
3428 0 : if (abspath == NULL) {
3429 0 : return NULL;
3430 : }
3431 : } else {
3432 0 : conv = shadow_copy2_convert(talloc_tos(),
3433 : handle,
3434 : stripped,
3435 : timestamp);
3436 0 : TALLOC_FREE(stripped);
3437 0 : if (conv == NULL) {
3438 0 : return NULL;
3439 : }
3440 :
3441 0 : abspath = make_path_absolute(talloc_tos(), priv, conv);
3442 0 : TALLOC_FREE(conv);
3443 0 : if (abspath == NULL) {
3444 0 : return NULL;
3445 : }
3446 : }
3447 :
3448 0 : convert_sbuf(handle, abspath, sbuf);
3449 :
3450 0 : TALLOC_FREE(abspath);
3451 0 : return ent;
3452 : }
3453 :
3454 : static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
3455 : .connect_fn = shadow_copy2_connect,
3456 : .disk_free_fn = shadow_copy2_disk_free,
3457 : .get_quota_fn = shadow_copy2_get_quota,
3458 : .create_dfs_pathat_fn = shadow_copy2_create_dfs_pathat,
3459 : .read_dfs_pathat_fn = shadow_copy2_read_dfs_pathat,
3460 : .renameat_fn = shadow_copy2_renameat,
3461 : .linkat_fn = shadow_copy2_linkat,
3462 : .symlinkat_fn = shadow_copy2_symlinkat,
3463 : .stat_fn = shadow_copy2_stat,
3464 : .lstat_fn = shadow_copy2_lstat,
3465 : .fstat_fn = shadow_copy2_fstat,
3466 : .fstatat_fn = shadow_copy2_fstatat,
3467 : .openat_fn = shadow_copy2_openat,
3468 : .unlinkat_fn = shadow_copy2_unlinkat,
3469 : .fchmod_fn = shadow_copy2_fchmod,
3470 : .chdir_fn = shadow_copy2_chdir,
3471 : .fntimes_fn = shadow_copy2_fntimes,
3472 : .readlinkat_fn = shadow_copy2_readlinkat,
3473 : .mknodat_fn = shadow_copy2_mknodat,
3474 : .realpath_fn = shadow_copy2_realpath,
3475 : .get_shadow_copy_data_fn = shadow_copy2_get_shadow_copy_data,
3476 : .mkdirat_fn = shadow_copy2_mkdirat,
3477 : .fsetxattr_fn = shadow_copy2_fsetxattr,
3478 : .fchflags_fn = shadow_copy2_fchflags,
3479 : .get_real_filename_at_fn = shadow_copy2_get_real_filename_at,
3480 : .pwrite_fn = shadow_copy2_pwrite,
3481 : .pwrite_send_fn = shadow_copy2_pwrite_send,
3482 : .pwrite_recv_fn = shadow_copy2_pwrite_recv,
3483 : .connectpath_fn = shadow_copy2_connectpath,
3484 : .parent_pathname_fn = shadow_copy2_parent_pathname,
3485 : .readdir_fn = shadow_copy2_readdir,
3486 : };
3487 :
3488 : static_decl_vfs;
3489 26 : NTSTATUS vfs_shadow_copy2_init(TALLOC_CTX *ctx)
3490 : {
3491 26 : return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
3492 : "shadow_copy2", &vfs_shadow_copy2_fns);
3493 : }
|