2 * shadow_copy2: a shadow copy module (second implementation)
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
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.
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.
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.
27 * This is a second implementation of a shadow copy module for exposing
28 * file system snapshots to windows clients as shadow copies.
30 * See the manual page for documentation.
34 #include "smbd/smbd.h"
35 #include "system/filesys.h"
36 #include "include/ntioctl.h"
38 #include "lib/util_path.h"
39 #include "libcli/security/security.h"
40 #include "lib/util/tevent_unix.h"
42 struct shadow_copy2_config
{
48 bool snapdirseverywhere
;
49 bool crossmountpoints
;
52 bool snapdir_absolute
;
54 char *rel_connectpath
; /* share root, relative to a snapshot root */
55 char *snapshot_basepath
; /* the absolute version of snapdir */
58 /* Data-structure to hold the list of snap entries */
59 struct shadow_copy2_snapentry
{
62 struct shadow_copy2_snapentry
*next
;
63 struct shadow_copy2_snapentry
*prev
;
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 */
73 * shadow_copy2 private structure. This structure will be
74 * used to keep module specific information
76 struct shadow_copy2_private
{
77 struct shadow_copy2_config
*config
;
78 struct shadow_copy2_snaplist_info
*snaps
;
79 char *shadow_cwd
; /* Absolute $cwd path. */
80 /* Absolute connectpath - can vary depending on $cwd. */
81 char *shadow_connectpath
;
82 /* talloc'ed realpath return. */
83 struct smb_filename
*shadow_realpath
;
86 static int shadow_copy2_get_shadow_copy_data(
87 vfs_handle_struct
*handle
, files_struct
*fsp
,
88 struct shadow_copy_data
*shadow_copy2_data
,
92 * This function will create a new snapshot list entry and
93 * return to the caller. This entry will also be added to
94 * the global snapshot list.
96 * @param[in] priv shadow_copy2 specific data structure
97 * @return Newly created snapshot entry or NULL on failure
99 static struct shadow_copy2_snapentry
*shadow_copy2_create_snapentry(
100 struct shadow_copy2_private
*priv
)
102 struct shadow_copy2_snapentry
*tmpentry
= NULL
;
104 tmpentry
= talloc_zero(priv
->snaps
, struct shadow_copy2_snapentry
);
105 if (tmpentry
== NULL
) {
106 DBG_ERR("talloc_zero() failed\n");
111 DLIST_ADD(priv
->snaps
->snaplist
, tmpentry
);
117 * This function will delete the entire snaplist and reset
118 * priv->snaps->snaplist to NULL.
120 * @param[in] priv shadow_copye specific data structure
122 static void shadow_copy2_delete_snaplist(struct shadow_copy2_private
*priv
)
124 struct shadow_copy2_snapentry
*tmp
= NULL
;
126 while ((tmp
= priv
->snaps
->snaplist
) != NULL
) {
127 DLIST_REMOVE(priv
->snaps
->snaplist
, tmp
);
133 * Given a timestamp this function searches the global snapshot list
134 * and returns the complete snapshot directory name saved in the entry.
136 * @param[in] priv shadow_copy2 specific structure
137 * @param[in] timestamp timestamp corresponding to one of the snapshot
138 * @param[out] snap_str buffer to copy the actual snapshot name
139 * @param[in] len length of snap_str buffer
141 * @return Length of actual snapshot name, and -1 on failure
143 static ssize_t
shadow_copy2_saved_snapname(struct shadow_copy2_private
*priv
,
144 struct tm
*timestamp
,
145 char *snap_str
, size_t len
)
147 ssize_t snaptime_len
= -1;
148 struct shadow_copy2_snapentry
*entry
= NULL
;
150 snaptime_len
= strftime(snap_str
, len
, GMT_FORMAT
, timestamp
);
151 if (snaptime_len
== 0) {
152 DBG_ERR("strftime failed\n");
158 for (entry
= priv
->snaps
->snaplist
; entry
; entry
= entry
->next
) {
159 if (strcmp(entry
->time_fmt
, snap_str
) == 0) {
160 snaptime_len
= snprintf(snap_str
, len
, "%s",
172 * This function will check if snaplist is updated or not. If snaplist
173 * is empty then it will create a new list. Each time snaplist is updated
174 * the time is recorded. If the snapshot time is greater than the snaplist
175 * update time then chances are we are working on an older list. Then discard
176 * the old list and fetch a new snaplist.
178 * @param[in] handle VFS handle struct
179 * @param[in] snap_time time of snapshot
181 * @return true if the list is updated else false
183 static bool shadow_copy2_update_snaplist(struct vfs_handle_struct
*handle
,
187 bool snaplist_updated
= false;
188 struct files_struct fsp
= {0};
189 struct smb_filename smb_fname
= {0};
190 double seconds
= 0.0;
191 struct shadow_copy2_private
*priv
= NULL
;
193 SMB_VFS_HANDLE_GET_DATA(handle
, priv
, struct shadow_copy2_private
,
196 seconds
= difftime(snap_time
, priv
->snaps
->fetch_time
);
199 * Fetch the snapshot list if either the snaplist is empty or the
200 * required snapshot time is greater than the last fetched snaplist
203 if (seconds
> 0 || (priv
->snaps
->snaplist
== NULL
)) {
204 smb_fname
.base_name
= discard_const_p(char, ".");
205 fsp
.fsp_name
= &smb_fname
;
207 ret
= shadow_copy2_get_shadow_copy_data(handle
, &fsp
,
210 snaplist_updated
= true;
212 DBG_ERR("Failed to get shadow copy data\n");
217 return snaplist_updated
;
220 static bool shadow_copy2_find_slashes(TALLOC_CTX
*mem_ctx
, const char *str
,
222 unsigned *pnum_offsets
)
224 unsigned num_offsets
;
231 while ((p
= strchr(p
, '/')) != NULL
) {
236 offsets
= talloc_array(mem_ctx
, size_t, num_offsets
);
237 if (offsets
== NULL
) {
243 while ((p
= strchr(p
, '/')) != NULL
) {
244 offsets
[num_offsets
] = p
-str
;
250 *pnum_offsets
= num_offsets
;
255 * Given a timestamp, build the posix level GMT-tag string
256 * based on the configurable format.
258 static ssize_t
shadow_copy2_posix_gmt_string(struct vfs_handle_struct
*handle
,
260 char *snaptime_string
,
264 ssize_t snaptime_len
;
265 struct shadow_copy2_config
*config
;
266 struct shadow_copy2_private
*priv
;
268 SMB_VFS_HANDLE_GET_DATA(handle
, priv
, struct shadow_copy2_private
,
271 config
= priv
->config
;
273 if (config
->use_sscanf
) {
274 snaptime_len
= snprintf(snaptime_string
,
277 (unsigned long)snapshot
);
278 if (snaptime_len
<= 0) {
279 DEBUG(10, ("snprintf failed\n"));
283 if (config
->use_localtime
) {
284 if (localtime_r(&snapshot
, &snap_tm
) == 0) {
285 DEBUG(10, ("gmtime_r failed\n"));
289 if (gmtime_r(&snapshot
, &snap_tm
) == 0) {
290 DEBUG(10, ("gmtime_r failed\n"));
295 if (priv
->snaps
->regex
!= NULL
) {
296 snaptime_len
= shadow_copy2_saved_snapname(priv
,
297 &snap_tm
, snaptime_string
, len
);
298 if (snaptime_len
>= 0)
302 * If we fail to find the snapshot name, chances are
303 * that we have not updated our snaplist. Make sure the
304 * snaplist is updated.
306 if (!shadow_copy2_update_snaplist(handle
, snapshot
)) {
307 DBG_DEBUG("shadow_copy2_update_snaplist "
312 return shadow_copy2_saved_snapname(priv
,
313 &snap_tm
, snaptime_string
, len
);
316 snaptime_len
= strftime(snaptime_string
,
320 if (snaptime_len
== 0) {
321 DEBUG(10, ("strftime failed\n"));
330 * Given a timestamp, build the string to insert into a path
331 * as a path component for creating the local path to the
332 * snapshot at the given timestamp of the input path.
334 * In the case of a parallel snapdir (specified with an
335 * absolute path), this is the initial portion of the
336 * local path of any snapshot file. The complete path is
337 * obtained by appending the portion of the file's path
338 * below the share root's mountpoint.
340 static char *shadow_copy2_insert_string(TALLOC_CTX
*mem_ctx
,
341 struct vfs_handle_struct
*handle
,
344 fstring snaptime_string
;
345 ssize_t snaptime_len
= 0;
347 struct shadow_copy2_config
*config
;
348 struct shadow_copy2_private
*priv
;
350 SMB_VFS_HANDLE_GET_DATA(handle
, priv
, struct shadow_copy2_private
,
353 config
= priv
->config
;
355 snaptime_len
= shadow_copy2_posix_gmt_string(handle
,
358 sizeof(snaptime_string
));
359 if (snaptime_len
<= 0) {
363 if (config
->snapdir_absolute
) {
364 result
= talloc_asprintf(mem_ctx
, "%s/%s",
365 config
->snapdir
, snaptime_string
);
367 result
= talloc_asprintf(mem_ctx
, "/%s/%s",
368 config
->snapdir
, snaptime_string
);
370 if (result
== NULL
) {
371 DBG_WARNING("talloc_asprintf failed\n");
378 * Build the posix snapshot path for the connection
379 * at the given timestamp, i.e. the absolute posix path
380 * that contains the snapshot for this file system.
382 * This only applies to classical case, i.e. not
383 * to the "snapdirseverywhere" mode.
385 static char *shadow_copy2_snapshot_path(TALLOC_CTX
*mem_ctx
,
386 struct vfs_handle_struct
*handle
,
389 fstring snaptime_string
;
390 ssize_t snaptime_len
= 0;
392 struct shadow_copy2_private
*priv
;
394 SMB_VFS_HANDLE_GET_DATA(handle
, priv
, struct shadow_copy2_private
,
397 snaptime_len
= shadow_copy2_posix_gmt_string(handle
,
400 sizeof(snaptime_string
));
401 if (snaptime_len
<= 0) {
405 result
= talloc_asprintf(mem_ctx
, "%s/%s",
406 priv
->config
->snapshot_basepath
, snaptime_string
);
407 if (result
== NULL
) {
408 DBG_WARNING("talloc_asprintf failed\n");
414 static char *make_path_absolute(TALLOC_CTX
*mem_ctx
,
415 struct shadow_copy2_private
*priv
,
418 char *newpath
= NULL
;
419 char *abs_path
= NULL
;
421 if (name
[0] != '/') {
422 newpath
= talloc_asprintf(mem_ctx
,
426 if (newpath
== NULL
) {
431 abs_path
= canonicalize_absolute_path(mem_ctx
, name
);
432 TALLOC_FREE(newpath
);
436 /* Return a $cwd-relative path. */
437 static bool make_relative_path(const char *cwd
, char *abs_path
)
439 size_t cwd_len
= strlen(cwd
);
440 size_t abs_len
= strlen(abs_path
);
442 if (abs_len
< cwd_len
) {
445 if (memcmp(abs_path
, cwd
, cwd_len
) != 0) {
448 /* The cwd_len != 1 case is for $cwd == '/' */
450 abs_path
[cwd_len
] != '/' &&
451 abs_path
[cwd_len
] != '\0')
455 if (abs_path
[cwd_len
] == '/') {
458 memmove(abs_path
, &abs_path
[cwd_len
], abs_len
+ 1 - cwd_len
);
462 static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct
*handle
,
464 char *gmt
, size_t gmt_len
);
467 * Check if an incoming filename is already a snapshot converted pathname.
469 * If so, it returns the pathname truncated at the snapshot point which
470 * will be used as the connectpath.
473 static int check_for_converted_path(TALLOC_CTX
*mem_ctx
,
474 struct vfs_handle_struct
*handle
,
475 struct shadow_copy2_private
*priv
,
477 bool *ppath_already_converted
,
480 size_t snapdirlen
= 0;
481 char *p
= strstr_m(abs_path
, priv
->config
->snapdir
);
483 char *connect_path
= NULL
;
484 char snapshot
[GMT_NAME_LEN
+1];
486 *ppath_already_converted
= false;
489 /* Must at least contain shadow:snapdir. */
493 if (priv
->config
->snapdir
[0] == '/' &&
495 /* Absolute shadow:snapdir must be at the start. */
499 snapdirlen
= strlen(priv
->config
->snapdir
);
500 if (p
[snapdirlen
] != '/') {
501 /* shadow:snapdir must end as a separate component. */
505 if (p
> abs_path
&& p
[-1] != '/') {
506 /* shadow:snapdir must start as a separate component. */
511 p
++; /* Move past the / */
514 * Need to return up to the next path
515 * component after the time.
516 * This will be used as the connectpath.
521 * No next path component.
524 connect_path
= talloc_strdup(mem_ctx
,
527 connect_path
= talloc_strndup(mem_ctx
,
531 if (connect_path
== NULL
) {
536 * Point p at the same offset in connect_path as
540 p
= &connect_path
[p
- abs_path
];
543 * Now ensure there is a time string at p.
544 * The SMB-format @GMT-token string is returned
548 if (!shadow_copy2_snapshot_to_gmt(handle
,
552 TALLOC_FREE(connect_path
);
556 if (pconnectpath
!= NULL
) {
557 *pconnectpath
= connect_path
;
560 *ppath_already_converted
= true;
562 DBG_DEBUG("path |%s| is already converted. "
563 "connect path = |%s|\n",
571 * This function does two things.
573 * 1). Checks if an incoming filename is already a
574 * snapshot converted pathname.
575 * If so, it returns the pathname truncated
576 * at the snapshot point which will be used
577 * as the connectpath, and then does an early return.
579 * 2). Checks if an incoming filename contains an
580 * SMB-layer @GMT- style timestamp.
581 * If so, it strips the timestamp, and returns
582 * both the timestamp and the stripped path
583 * (making it cwd-relative).
586 static bool _shadow_copy2_strip_snapshot_internal(TALLOC_CTX
*mem_ctx
,
587 struct vfs_handle_struct
*handle
,
588 const struct smb_filename
*smb_fname
,
592 bool *_already_converted
,
593 const char *function
)
595 char *stripped
= NULL
;
596 struct shadow_copy2_private
*priv
;
597 char *abs_path
= NULL
;
599 bool already_converted
= false;
602 SMB_VFS_HANDLE_GET_DATA(handle
, priv
, struct shadow_copy2_private
,
605 DBG_DEBUG("[from %s()] Path '%s'\n",
606 function
, smb_fname_str_dbg(smb_fname
));
608 if (_already_converted
!= NULL
) {
609 *_already_converted
= false;
612 abs_path
= make_path_absolute(mem_ctx
, priv
, smb_fname
->base_name
);
613 if (abs_path
== NULL
) {
618 DBG_DEBUG("abs path '%s'\n", abs_path
);
620 err
= check_for_converted_path(mem_ctx
,
627 /* error in conversion. */
632 if (already_converted
) {
633 if (_already_converted
!= NULL
) {
634 *_already_converted
= true;
639 if (smb_fname
->twrp
== 0) {
643 if (ptimestamp
!= NULL
) {
644 *ptimestamp
= nt_time_to_unix(smb_fname
->twrp
);
647 if (pstripped
!= NULL
) {
648 stripped
= talloc_strdup(mem_ctx
, abs_path
);
649 if (stripped
== NULL
) {
654 if (smb_fname
->base_name
[0] != '/') {
655 ret
= make_relative_path(priv
->shadow_cwd
, stripped
);
657 DBG_DEBUG("Path '%s' "
658 "doesn't start with cwd '%s'\n",
659 stripped
, priv
->shadow_cwd
);
665 *pstripped
= stripped
;
671 TALLOC_FREE(abs_path
);
675 #define shadow_copy2_strip_snapshot_internal(mem_ctx, handle, orig_name, \
676 ptimestamp, pstripped, psnappath, _already_converted) \
677 _shadow_copy2_strip_snapshot_internal((mem_ctx), (handle), (orig_name), \
678 (ptimestamp), (pstripped), (psnappath), (_already_converted), \
681 static bool _shadow_copy2_strip_snapshot(TALLOC_CTX
*mem_ctx
,
682 struct vfs_handle_struct
*handle
,
683 const struct smb_filename
*orig_name
,
686 const char *function
)
688 return _shadow_copy2_strip_snapshot_internal(mem_ctx
,
698 #define shadow_copy2_strip_snapshot(mem_ctx, handle, orig_name, \
699 ptimestamp, pstripped) \
700 _shadow_copy2_strip_snapshot((mem_ctx), (handle), (orig_name), \
701 (ptimestamp), (pstripped), __FUNCTION__)
703 static bool _shadow_copy2_strip_snapshot_converted(TALLOC_CTX
*mem_ctx
,
704 struct vfs_handle_struct
*handle
,
705 const struct smb_filename
*orig_name
,
709 const char *function
)
711 return _shadow_copy2_strip_snapshot_internal(mem_ctx
,
721 #define shadow_copy2_strip_snapshot_converted(mem_ctx, handle, orig_name, \
722 ptimestamp, pstripped, is_converted) \
723 _shadow_copy2_strip_snapshot_converted((mem_ctx), (handle), (orig_name), \
724 (ptimestamp), (pstripped), (is_converted), __FUNCTION__)
726 static char *shadow_copy2_find_mount_point(TALLOC_CTX
*mem_ctx
,
727 vfs_handle_struct
*handle
)
729 char *path
= talloc_strdup(mem_ctx
, handle
->conn
->connectpath
);
734 if (stat(path
, &st
) != 0) {
741 while ((p
= strrchr(path
, '/')) && p
> path
) {
743 if (stat(path
, &st
) != 0) {
747 if (st
.st_dev
!= dev
) {
757 * Convert from a name as handed in via the SMB layer
758 * and a timestamp into the local path of the snapshot
759 * of the provided file at the provided time.
760 * Also return the path in the snapshot corresponding
761 * to the file's share root.
763 static char *shadow_copy2_do_convert(TALLOC_CTX
*mem_ctx
,
764 struct vfs_handle_struct
*handle
,
765 const char *name
, time_t timestamp
,
766 size_t *snaproot_len
)
768 struct smb_filename converted_fname
;
770 size_t *slashes
= NULL
;
771 unsigned num_slashes
;
775 char *converted
= NULL
;
776 size_t insertlen
, connectlen
= 0;
780 struct shadow_copy2_config
*config
;
781 struct shadow_copy2_private
*priv
;
782 size_t in_share_offset
= 0;
784 SMB_VFS_HANDLE_GET_DATA(handle
, priv
, struct shadow_copy2_private
,
787 config
= priv
->config
;
789 DEBUG(10, ("converting '%s'\n", name
));
791 if (!config
->snapdirseverywhere
) {
795 snapshot_path
= shadow_copy2_snapshot_path(talloc_tos(),
798 if (snapshot_path
== NULL
) {
802 if (config
->rel_connectpath
== NULL
) {
803 converted
= talloc_asprintf(mem_ctx
, "%s/%s",
804 snapshot_path
, name
);
806 converted
= talloc_asprintf(mem_ctx
, "%s/%s/%s",
808 config
->rel_connectpath
,
811 if (converted
== NULL
) {
815 converted_fname
= (struct smb_filename
) {
816 .base_name
= converted
,
819 ret
= SMB_VFS_NEXT_LSTAT(handle
, &converted_fname
);
820 DEBUG(10, ("Trying[not snapdirseverywhere] %s: %d (%s)\n",
822 ret
, ret
== 0 ? "ok" : strerror(errno
)));
824 DEBUG(10, ("Found %s\n", converted
));
827 if (snaproot_len
!= NULL
) {
828 *snaproot_len
= strlen(snapshot_path
);
829 if (config
->rel_connectpath
!= NULL
) {
831 strlen(config
->rel_connectpath
) + 1;
839 /* never reached ... */
842 connectlen
= strlen(handle
->conn
->connectpath
);
844 path
= talloc_strdup(mem_ctx
, handle
->conn
->connectpath
);
846 path
= talloc_asprintf(
847 mem_ctx
, "%s/%s", handle
->conn
->connectpath
, name
);
853 pathlen
= talloc_get_size(path
)-1;
855 if (!shadow_copy2_find_slashes(talloc_tos(), path
,
856 &slashes
, &num_slashes
)) {
860 insert
= shadow_copy2_insert_string(talloc_tos(), handle
, timestamp
);
861 if (insert
== NULL
) {
864 insertlen
= talloc_get_size(insert
)-1;
867 * Note: We deliberately 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.
875 converted
= talloc_array(mem_ctx
, char, pathlen
+ insertlen
+ 1);
876 if (converted
== NULL
) {
880 if (path
[pathlen
-1] != '/') {
882 * Append a fake slash to find the snapshot root
885 tmp
= talloc_realloc(talloc_tos(), slashes
,
886 size_t, num_slashes
+1);
891 slashes
[num_slashes
] = pathlen
;
897 if (!config
->crossmountpoints
) {
898 min_offset
= strlen(config
->mount_point
);
901 memcpy(converted
, path
, pathlen
+1);
902 converted
[pathlen
+insertlen
] = '\0';
904 converted_fname
= (struct smb_filename
) {
905 .base_name
= converted
,
908 for (i
= num_slashes
-1; i
>=0; i
--) {
914 if (offset
< min_offset
) {
919 if (offset
>= connectlen
) {
920 in_share_offset
= offset
;
923 memcpy(converted
+offset
, insert
, insertlen
);
926 memcpy(converted
+offset
, path
+ slashes
[i
],
927 pathlen
- slashes
[i
]);
929 ret
= SMB_VFS_NEXT_LSTAT(handle
, &converted_fname
);
931 DEBUG(10, ("Trying[snapdirseverywhere] %s: %d (%s)\n",
933 ret
, ret
== 0 ? "ok" : strerror(errno
)));
936 if (snaproot_len
!= NULL
) {
937 *snaproot_len
= in_share_offset
+ insertlen
;
941 if (errno
== ENOTDIR
) {
943 * This is a valid condition: We appended the
944 * .snapshots/@GMT.. to a file name. Just try
945 * with the upper levels.
949 if (errno
!= ENOENT
) {
950 /* Other problem than "not found" */
959 DEBUG(10, ("Found %s\n", converted
));
966 if (result
== NULL
) {
969 TALLOC_FREE(converted
);
971 TALLOC_FREE(slashes
);
973 if (saved_errno
!= 0) {
980 * Convert from a name as handed in via the SMB layer
981 * and a timestamp into the local path of the snapshot
982 * of the provided file at the provided time.
984 static char *shadow_copy2_convert(TALLOC_CTX
*mem_ctx
,
985 struct vfs_handle_struct
*handle
,
986 const char *name
, time_t timestamp
)
988 return shadow_copy2_do_convert(mem_ctx
, handle
, name
, timestamp
, NULL
);
992 modify a sbuf return to ensure that inodes in the shadow directory
993 are different from those in the main directory
995 static void convert_sbuf(vfs_handle_struct
*handle
, const char *fname
,
996 SMB_STRUCT_STAT
*sbuf
)
998 struct shadow_copy2_private
*priv
;
1000 SMB_VFS_HANDLE_GET_DATA(handle
, priv
, struct shadow_copy2_private
,
1003 if (priv
->config
->fixinodes
) {
1004 /* some snapshot systems, like GPFS, return the same
1005 device:inode for the snapshot files as the current
1006 files. That breaks the 'restore' button in the shadow copy
1007 GUI, as the client gets a sharing violation.
1009 This is a crude way of allowing both files to be
1010 open at once. It has a slight chance of inode
1011 number collision, but I can't see a better approach
1012 without significant VFS changes
1014 TDB_DATA key
= { .dptr
= discard_const_p(uint8_t, fname
),
1015 .dsize
= strlen(fname
) };
1018 shash
= tdb_jenkins_hash(&key
) & 0xFF000000;
1022 sbuf
->st_ex_ino
^= shash
;
1026 static int shadow_copy2_renameat(vfs_handle_struct
*handle
,
1027 files_struct
*srcfsp
,
1028 const struct smb_filename
*smb_fname_src
,
1029 files_struct
*dstfsp
,
1030 const struct smb_filename
*smb_fname_dst
)
1032 time_t timestamp_src
= 0;
1033 time_t timestamp_dst
= 0;
1034 char *snappath_src
= NULL
;
1035 char *snappath_dst
= NULL
;
1037 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle
,
1039 ×tamp_src
, NULL
, &snappath_src
,
1043 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle
,
1045 ×tamp_dst
, NULL
, &snappath_dst
,
1049 if (timestamp_src
!= 0) {
1053 if (timestamp_dst
!= 0) {
1058 * Don't allow rename on already converted paths.
1060 if (snappath_src
!= NULL
) {
1064 if (snappath_dst
!= NULL
) {
1068 return SMB_VFS_NEXT_RENAMEAT(handle
,
1075 static int shadow_copy2_symlinkat(vfs_handle_struct
*handle
,
1076 const struct smb_filename
*link_contents
,
1077 struct files_struct
*dirfsp
,
1078 const struct smb_filename
*new_smb_fname
)
1080 time_t timestamp_old
= 0;
1081 time_t timestamp_new
= 0;
1082 char *snappath_old
= NULL
;
1083 char *snappath_new
= NULL
;
1085 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(),
1094 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(),
1103 if ((timestamp_old
!= 0) || (timestamp_new
!= 0)) {
1108 * Don't allow symlinks on already converted paths.
1110 if ((snappath_old
!= NULL
) || (snappath_new
!= NULL
)) {
1114 return SMB_VFS_NEXT_SYMLINKAT(handle
,
1120 static int shadow_copy2_linkat(vfs_handle_struct
*handle
,
1121 files_struct
*srcfsp
,
1122 const struct smb_filename
*old_smb_fname
,
1123 files_struct
*dstfsp
,
1124 const struct smb_filename
*new_smb_fname
,
1127 time_t timestamp_old
= 0;
1128 time_t timestamp_new
= 0;
1129 char *snappath_old
= NULL
;
1130 char *snappath_new
= NULL
;
1132 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(),
1141 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(),
1150 if ((timestamp_old
!= 0) || (timestamp_new
!= 0)) {
1155 * Don't allow links on already converted paths.
1157 if ((snappath_old
!= NULL
) || (snappath_new
!= NULL
)) {
1161 return SMB_VFS_NEXT_LINKAT(handle
,
1169 static int shadow_copy2_stat(vfs_handle_struct
*handle
,
1170 struct smb_filename
*smb_fname
)
1172 struct shadow_copy2_private
*priv
= NULL
;
1173 time_t timestamp
= 0;
1174 char *stripped
= NULL
;
1175 bool converted
= false;
1176 char *abspath
= NULL
;
1180 SMB_VFS_HANDLE_GET_DATA(handle
, priv
, struct shadow_copy2_private
,
1183 if (!shadow_copy2_strip_snapshot_converted(talloc_tos(),
1191 if (timestamp
== 0) {
1192 TALLOC_FREE(stripped
);
1193 ret
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
1201 abspath
= make_path_absolute(talloc_tos(),
1203 smb_fname
->base_name
);
1204 if (abspath
== NULL
) {
1208 convert_sbuf(handle
, abspath
, &smb_fname
->st
);
1209 TALLOC_FREE(abspath
);
1213 tmp
= smb_fname
->base_name
;
1214 smb_fname
->base_name
= shadow_copy2_convert(
1215 talloc_tos(), handle
, stripped
, timestamp
);
1216 TALLOC_FREE(stripped
);
1218 if (smb_fname
->base_name
== NULL
) {
1219 smb_fname
->base_name
= tmp
;
1223 ret
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
1228 abspath
= make_path_absolute(talloc_tos(),
1230 smb_fname
->base_name
);
1231 if (abspath
== NULL
) {
1236 convert_sbuf(handle
, abspath
, &smb_fname
->st
);
1237 TALLOC_FREE(abspath
);
1240 TALLOC_FREE(smb_fname
->base_name
);
1241 smb_fname
->base_name
= tmp
;
1246 static int shadow_copy2_lstat(vfs_handle_struct
*handle
,
1247 struct smb_filename
*smb_fname
)
1249 struct shadow_copy2_private
*priv
= NULL
;
1250 time_t timestamp
= 0;
1251 char *stripped
= NULL
;
1252 bool converted
= false;
1253 char *abspath
= NULL
;
1257 SMB_VFS_HANDLE_GET_DATA(handle
, priv
, struct shadow_copy2_private
,
1260 if (!shadow_copy2_strip_snapshot_converted(talloc_tos(),
1268 if (timestamp
== 0) {
1269 TALLOC_FREE(stripped
);
1270 ret
= SMB_VFS_NEXT_LSTAT(handle
, smb_fname
);
1278 abspath
= make_path_absolute(talloc_tos(),
1280 smb_fname
->base_name
);
1281 if (abspath
== NULL
) {
1285 convert_sbuf(handle
, abspath
, &smb_fname
->st
);
1286 TALLOC_FREE(abspath
);
1290 tmp
= smb_fname
->base_name
;
1291 smb_fname
->base_name
= shadow_copy2_convert(
1292 talloc_tos(), handle
, stripped
, timestamp
);
1293 TALLOC_FREE(stripped
);
1295 if (smb_fname
->base_name
== NULL
) {
1296 smb_fname
->base_name
= tmp
;
1300 ret
= SMB_VFS_NEXT_LSTAT(handle
, smb_fname
);
1305 abspath
= make_path_absolute(talloc_tos(),
1307 smb_fname
->base_name
);
1308 if (abspath
== NULL
) {
1313 convert_sbuf(handle
, abspath
, &smb_fname
->st
);
1314 TALLOC_FREE(abspath
);
1317 TALLOC_FREE(smb_fname
->base_name
);
1318 smb_fname
->base_name
= tmp
;
1323 static int shadow_copy2_fstat(vfs_handle_struct
*handle
, files_struct
*fsp
,
1324 SMB_STRUCT_STAT
*sbuf
)
1326 struct shadow_copy2_private
*priv
= NULL
;
1327 time_t timestamp
= 0;
1328 struct smb_filename
*orig_smb_fname
= NULL
;
1329 struct smb_filename vss_smb_fname
;
1330 struct smb_filename
*orig_base_smb_fname
= NULL
;
1331 struct smb_filename vss_base_smb_fname
;
1332 char *stripped
= NULL
;
1333 char *abspath
= NULL
;
1334 bool converted
= false;
1338 SMB_VFS_HANDLE_GET_DATA(handle
, priv
, struct shadow_copy2_private
,
1341 ok
= shadow_copy2_strip_snapshot_converted(talloc_tos(),
1351 if (timestamp
== 0) {
1352 TALLOC_FREE(stripped
);
1353 ret
= SMB_VFS_NEXT_FSTAT(handle
, fsp
, sbuf
);
1361 abspath
= make_path_absolute(talloc_tos(),
1363 fsp
->fsp_name
->base_name
);
1364 if (abspath
== NULL
) {
1368 convert_sbuf(handle
, abspath
, sbuf
);
1369 TALLOC_FREE(abspath
);
1373 vss_smb_fname
= *fsp
->fsp_name
;
1374 vss_smb_fname
.base_name
= shadow_copy2_convert(talloc_tos(),
1378 TALLOC_FREE(stripped
);
1379 if (vss_smb_fname
.base_name
== NULL
) {
1383 orig_smb_fname
= fsp
->fsp_name
;
1384 fsp
->fsp_name
= &vss_smb_fname
;
1386 if (fsp_is_alternate_stream(fsp
)) {
1387 vss_base_smb_fname
= *fsp
->base_fsp
->fsp_name
;
1388 vss_base_smb_fname
.base_name
= vss_smb_fname
.base_name
;
1389 orig_base_smb_fname
= fsp
->base_fsp
->fsp_name
;
1390 fsp
->base_fsp
->fsp_name
= &vss_base_smb_fname
;
1393 ret
= SMB_VFS_NEXT_FSTAT(handle
, fsp
, sbuf
);
1398 abspath
= make_path_absolute(talloc_tos(),
1400 fsp
->fsp_name
->base_name
);
1401 if (abspath
== NULL
) {
1406 convert_sbuf(handle
, abspath
, sbuf
);
1407 TALLOC_FREE(abspath
);
1410 fsp
->fsp_name
= orig_smb_fname
;
1411 if (fsp_is_alternate_stream(fsp
)) {
1412 fsp
->base_fsp
->fsp_name
= orig_base_smb_fname
;
1418 static int shadow_copy2_fstatat(
1419 struct vfs_handle_struct
*handle
,
1420 const struct files_struct
*dirfsp
,
1421 const struct smb_filename
*smb_fname_in
,
1422 SMB_STRUCT_STAT
*sbuf
,
1425 struct shadow_copy2_private
*priv
= NULL
;
1426 struct smb_filename
*smb_fname
= NULL
;
1427 time_t timestamp
= 0;
1428 char *stripped
= NULL
;
1429 char *abspath
= NULL
;
1430 bool converted
= false;
1434 SMB_VFS_HANDLE_GET_DATA(handle
, priv
, struct shadow_copy2_private
,
1437 smb_fname
= full_path_from_dirfsp_atname(talloc_tos(),
1440 if (smb_fname
== NULL
) {
1445 ok
= shadow_copy2_strip_snapshot_converted(talloc_tos(),
1454 if (timestamp
== 0) {
1455 TALLOC_FREE(stripped
);
1456 ret
= SMB_VFS_NEXT_FSTATAT(
1457 handle
, dirfsp
, smb_fname_in
, sbuf
, flags
);
1465 abspath
= make_path_absolute(
1466 talloc_tos(), priv
, smb_fname
->base_name
);
1467 if (abspath
== NULL
) {
1472 convert_sbuf(handle
, abspath
, sbuf
);
1473 TALLOC_FREE(abspath
);
1477 smb_fname
->base_name
= shadow_copy2_convert(
1478 smb_fname
, handle
, stripped
, timestamp
);
1479 TALLOC_FREE(stripped
);
1480 if (smb_fname
->base_name
== NULL
) {
1481 TALLOC_FREE(smb_fname
);
1486 ret
= SMB_VFS_NEXT_FSTATAT(handle
,
1492 int saved_errno
= errno
;
1493 TALLOC_FREE(smb_fname
);
1494 errno
= saved_errno
;
1498 abspath
= make_path_absolute(
1499 talloc_tos(), priv
, smb_fname
->base_name
);
1500 if (abspath
== NULL
) {
1501 TALLOC_FREE(smb_fname
);
1506 convert_sbuf(handle
, abspath
, sbuf
);
1507 TALLOC_FREE(abspath
);
1509 TALLOC_FREE(smb_fname
);
1514 static struct smb_filename
*shadow_copy2_openat_name(
1515 TALLOC_CTX
*mem_ctx
,
1516 const struct files_struct
*dirfsp
,
1517 const struct files_struct
*fsp
,
1518 const struct smb_filename
*smb_fname_in
)
1520 struct smb_filename
*result
= NULL
;
1522 if (fsp
->base_fsp
!= NULL
) {
1523 struct smb_filename
*base_fname
= fsp
->base_fsp
->fsp_name
;
1525 if (smb_fname_in
->base_name
[0] == '/') {
1527 * Special-case stream names from streams_depot
1529 result
= cp_smb_filename(mem_ctx
, smb_fname_in
);
1532 SMB_ASSERT(is_named_stream(smb_fname_in
));
1534 result
= synthetic_smb_fname(mem_ctx
,
1535 base_fname
->base_name
,
1536 smb_fname_in
->stream_name
,
1539 smb_fname_in
->flags
);
1542 result
= full_path_from_dirfsp_atname(
1543 mem_ctx
, dirfsp
, smb_fname_in
);
1549 static int shadow_copy2_openat(vfs_handle_struct
*handle
,
1550 const struct files_struct
*dirfsp
,
1551 const struct smb_filename
*smb_fname_in
,
1552 struct files_struct
*fsp
,
1553 const struct vfs_open_how
*_how
)
1555 struct vfs_open_how how
= *_how
;
1556 struct smb_filename
*smb_fname
= NULL
;
1557 time_t timestamp
= 0;
1558 char *stripped
= NULL
;
1559 int saved_errno
= 0;
1563 if (how
.resolve
!= 0) {
1568 smb_fname
= shadow_copy2_openat_name(
1569 talloc_tos(), dirfsp
, fsp
, smb_fname_in
);
1570 if (smb_fname
== NULL
) {
1575 ok
= shadow_copy2_strip_snapshot(talloc_tos(),
1581 TALLOC_FREE(smb_fname
);
1584 if (timestamp
== 0) {
1585 TALLOC_FREE(stripped
);
1586 TALLOC_FREE(smb_fname
);
1587 return SMB_VFS_NEXT_OPENAT(handle
,
1594 smb_fname
->base_name
= shadow_copy2_convert(smb_fname
,
1598 if (smb_fname
->base_name
== NULL
) {
1600 TALLOC_FREE(stripped
);
1601 TALLOC_FREE(smb_fname
);
1605 TALLOC_FREE(stripped
);
1607 ret
= SMB_VFS_NEXT_OPENAT(handle
,
1613 saved_errno
= errno
;
1616 TALLOC_FREE(smb_fname
);
1618 if (saved_errno
!= 0) {
1619 errno
= saved_errno
;
1624 static int shadow_copy2_unlinkat(vfs_handle_struct
*handle
,
1625 struct files_struct
*dirfsp
,
1626 const struct smb_filename
*smb_fname
,
1629 time_t timestamp
= 0;
1631 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
,
1633 ×tamp
, NULL
)) {
1636 if (timestamp
!= 0) {
1640 return SMB_VFS_NEXT_UNLINKAT(handle
,
1646 static int shadow_copy2_fchmod(vfs_handle_struct
*handle
,
1647 struct files_struct
*fsp
,
1650 time_t timestamp
= 0;
1651 const struct smb_filename
*smb_fname
= NULL
;
1653 smb_fname
= fsp
->fsp_name
;
1654 if (!shadow_copy2_strip_snapshot(talloc_tos(),
1661 if (timestamp
!= 0) {
1665 return SMB_VFS_NEXT_FCHMOD(handle
, fsp
, mode
);
1668 static void store_cwd_data(vfs_handle_struct
*handle
,
1669 const char *connectpath
)
1671 struct shadow_copy2_private
*priv
= NULL
;
1672 struct smb_filename
*cwd_fname
= NULL
;
1674 SMB_VFS_HANDLE_GET_DATA(handle
, priv
, struct shadow_copy2_private
,
1677 TALLOC_FREE(priv
->shadow_cwd
);
1678 cwd_fname
= SMB_VFS_NEXT_GETWD(handle
, talloc_tos());
1679 if (cwd_fname
== NULL
) {
1680 smb_panic("getwd failed\n");
1682 DBG_DEBUG("shadow cwd = %s\n", cwd_fname
->base_name
);
1683 priv
->shadow_cwd
= talloc_strdup(priv
, cwd_fname
->base_name
);
1684 TALLOC_FREE(cwd_fname
);
1685 if (priv
->shadow_cwd
== NULL
) {
1686 smb_panic("talloc failed\n");
1688 TALLOC_FREE(priv
->shadow_connectpath
);
1690 DBG_DEBUG("shadow connectpath = %s\n", connectpath
);
1691 priv
->shadow_connectpath
= talloc_strdup(priv
, connectpath
);
1692 if (priv
->shadow_connectpath
== NULL
) {
1693 smb_panic("talloc failed\n");
1698 static int shadow_copy2_chdir(vfs_handle_struct
*handle
,
1699 const struct smb_filename
*smb_fname
)
1701 time_t timestamp
= 0;
1702 char *stripped
= NULL
;
1703 char *snappath
= NULL
;
1705 int saved_errno
= 0;
1707 size_t rootpath_len
= 0;
1708 struct smb_filename
*conv_smb_fname
= NULL
;
1710 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(),
1719 if (stripped
!= NULL
) {
1720 conv
= shadow_copy2_do_convert(talloc_tos(),
1725 TALLOC_FREE(stripped
);
1729 conv_smb_fname
= synthetic_smb_fname(talloc_tos(),
1736 conv_smb_fname
= cp_smb_filename(talloc_tos(), smb_fname
);
1739 if (conv_smb_fname
== NULL
) {
1745 ret
= SMB_VFS_NEXT_CHDIR(handle
, conv_smb_fname
);
1747 saved_errno
= errno
;
1751 if (conv
!= NULL
&& rootpath_len
!= 0) {
1752 conv
[rootpath_len
] = '\0';
1753 } else if (snappath
!= 0) {
1757 store_cwd_data(handle
, conv
);
1760 TALLOC_FREE(stripped
);
1762 TALLOC_FREE(conv_smb_fname
);
1764 if (saved_errno
!= 0) {
1765 errno
= saved_errno
;
1770 static int shadow_copy2_fntimes(vfs_handle_struct
*handle
,
1772 struct smb_file_time
*ft
)
1774 time_t timestamp
= 0;
1776 if (!shadow_copy2_strip_snapshot(talloc_tos(),
1783 if (timestamp
!= 0) {
1787 return SMB_VFS_NEXT_FNTIMES(handle
, fsp
, ft
);
1790 static int shadow_copy2_readlinkat(vfs_handle_struct
*handle
,
1791 const struct files_struct
*dirfsp
,
1792 const struct smb_filename
*smb_fname
,
1796 time_t timestamp
= 0;
1797 char *stripped
= NULL
;
1798 int saved_errno
= 0;
1800 struct smb_filename
*full_fname
= NULL
;
1801 struct smb_filename
*conv
= NULL
;
1803 full_fname
= full_path_from_dirfsp_atname(talloc_tos(),
1806 if (full_fname
== NULL
) {
1811 if (!shadow_copy2_strip_snapshot(talloc_tos(),
1816 TALLOC_FREE(full_fname
);
1820 if (timestamp
== 0) {
1821 TALLOC_FREE(full_fname
);
1822 TALLOC_FREE(stripped
);
1823 return SMB_VFS_NEXT_READLINKAT(handle
,
1829 conv
= cp_smb_filename(talloc_tos(), full_fname
);
1831 TALLOC_FREE(full_fname
);
1832 TALLOC_FREE(stripped
);
1836 TALLOC_FREE(full_fname
);
1837 conv
->base_name
= shadow_copy2_convert(
1838 conv
, handle
, stripped
, timestamp
);
1839 TALLOC_FREE(stripped
);
1840 if (conv
->base_name
== NULL
) {
1843 ret
= SMB_VFS_NEXT_READLINKAT(handle
,
1844 handle
->conn
->cwd_fsp
,
1849 saved_errno
= errno
;
1852 if (saved_errno
!= 0) {
1853 errno
= saved_errno
;
1858 static int shadow_copy2_mknodat(vfs_handle_struct
*handle
,
1859 files_struct
*dirfsp
,
1860 const struct smb_filename
*smb_fname
,
1864 time_t timestamp
= 0;
1866 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
,
1868 ×tamp
, NULL
)) {
1871 if (timestamp
!= 0) {
1875 return SMB_VFS_NEXT_MKNODAT(handle
,
1882 static struct smb_filename
*shadow_copy2_realpath(vfs_handle_struct
*handle
,
1884 const struct smb_filename
*smb_fname
)
1886 time_t timestamp
= 0;
1887 char *stripped
= NULL
;
1888 struct smb_filename
*result_fname
= NULL
;
1889 struct smb_filename
*conv_fname
= NULL
;
1890 int saved_errno
= 0;
1892 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
,
1894 ×tamp
, &stripped
)) {
1897 if (timestamp
== 0) {
1898 return SMB_VFS_NEXT_REALPATH(handle
, ctx
, smb_fname
);
1901 conv_fname
= cp_smb_filename(talloc_tos(), smb_fname
);
1902 if (conv_fname
== NULL
) {
1905 conv_fname
->base_name
= shadow_copy2_convert(
1906 conv_fname
, handle
, stripped
, timestamp
);
1907 if (conv_fname
->base_name
== NULL
) {
1911 result_fname
= SMB_VFS_NEXT_REALPATH(handle
, ctx
, conv_fname
);
1914 if (result_fname
== NULL
) {
1915 saved_errno
= errno
;
1917 TALLOC_FREE(conv_fname
);
1918 TALLOC_FREE(stripped
);
1919 if (saved_errno
!= 0) {
1920 errno
= saved_errno
;
1922 return result_fname
;
1926 * Check whether a given directory contains a
1927 * snapshot directory as direct subdirectory.
1928 * If yes, return the path of the snapshot-subdir,
1929 * otherwise return NULL.
1931 static char *have_snapdir(struct vfs_handle_struct
*handle
,
1932 TALLOC_CTX
*mem_ctx
,
1935 struct smb_filename smb_fname
;
1937 struct shadow_copy2_private
*priv
;
1939 SMB_VFS_HANDLE_GET_DATA(handle
, priv
, struct shadow_copy2_private
,
1942 smb_fname
= (struct smb_filename
) {
1943 .base_name
= talloc_asprintf(
1944 mem_ctx
, "%s/%s", path
, priv
->config
->snapdir
),
1946 if (smb_fname
.base_name
== NULL
) {
1950 ret
= SMB_VFS_NEXT_STAT(handle
, &smb_fname
);
1951 if ((ret
== 0) && (S_ISDIR(smb_fname
.st
.st_ex_mode
))) {
1952 return smb_fname
.base_name
;
1954 TALLOC_FREE(smb_fname
.base_name
);
1959 * Find the snapshot directory (if any) for the given
1960 * filename (which is relative to the share).
1962 static const char *shadow_copy2_find_snapdir(TALLOC_CTX
*mem_ctx
,
1963 struct vfs_handle_struct
*handle
,
1964 struct smb_filename
*smb_fname
)
1967 const char *snapdir
;
1968 struct shadow_copy2_config
*config
;
1969 struct shadow_copy2_private
*priv
;
1971 SMB_VFS_HANDLE_GET_DATA(handle
, priv
, struct shadow_copy2_private
,
1974 config
= priv
->config
;
1977 * If the non-snapdirseverywhere mode, we should not search!
1979 if (!config
->snapdirseverywhere
) {
1980 return config
->snapshot_basepath
;
1983 path
= talloc_asprintf(mem_ctx
, "%s/%s",
1984 handle
->conn
->connectpath
,
1985 smb_fname
->base_name
);
1990 snapdir
= have_snapdir(handle
, talloc_tos(), path
);
1991 if (snapdir
!= NULL
) {
1996 while ((p
= strrchr(path
, '/')) && (p
> path
)) {
2000 snapdir
= have_snapdir(handle
, talloc_tos(), path
);
2001 if (snapdir
!= NULL
) {
2010 static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct
*handle
,
2012 char *gmt
, size_t gmt_len
)
2014 struct tm timestamp
= { .tm_sec
= 0, };
2016 unsigned long int timestamp_long
;
2018 struct shadow_copy2_config
*config
;
2019 struct shadow_copy2_private
*priv
;
2020 char *tmpstr
= NULL
;
2022 bool converted
= false;
2025 SMB_VFS_HANDLE_GET_DATA(handle
, priv
, struct shadow_copy2_private
,
2028 config
= priv
->config
;
2030 fmt
= config
->gmt_format
;
2033 * If regex is provided, then we will have to parse the
2034 * filename which will contain both the prefix and the time format.
2035 * e.g. <prefix><delimiter><time_format>
2037 if (priv
->snaps
->regex
!= NULL
) {
2038 tmpstr
= talloc_strdup(talloc_tos(), name
);
2039 /* point "name" to the time format */
2040 name
= strstr(name
, priv
->config
->delimiter
);
2044 /* Extract the prefix */
2045 tmp
= strstr(tmpstr
, priv
->config
->delimiter
);
2052 ret
= regexec(priv
->snaps
->regex
, tmpstr
, 0, NULL
, 0);
2054 DBG_DEBUG("shadow_copy2_snapshot_to_gmt: "
2055 "no regex match for %s\n", tmpstr
);
2060 if (config
->use_sscanf
) {
2061 if (sscanf(name
, fmt
, ×tamp_long
) != 1) {
2062 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
2063 "no sscanf match %s: %s\n",
2067 timestamp_t
= timestamp_long
;
2068 gmtime_r(×tamp_t
, ×tamp
);
2070 if (strptime(name
, fmt
, ×tamp
) == NULL
) {
2071 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
2072 "no match %s: %s\n",
2076 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n",
2079 if (config
->use_localtime
) {
2080 timestamp
.tm_isdst
= -1;
2081 timestamp_t
= mktime(×tamp
);
2082 gmtime_r(×tamp_t
, ×tamp
);
2086 strftime(gmt
, gmt_len
, GMT_FORMAT
, ×tamp
);
2090 TALLOC_FREE(tmpstr
);
2094 static int shadow_copy2_label_cmp_asc(const void *x
, const void *y
)
2096 return strncmp((const char *)x
, (const char *)y
, sizeof(SHADOW_COPY_LABEL
));
2099 static int shadow_copy2_label_cmp_desc(const void *x
, const void *y
)
2101 return -strncmp((const char *)x
, (const char *)y
, sizeof(SHADOW_COPY_LABEL
));
2105 sort the shadow copy data in ascending or descending order
2107 static void shadow_copy2_sort_data(vfs_handle_struct
*handle
,
2108 struct shadow_copy_data
*shadow_copy2_data
)
2110 int (*cmpfunc
)(const void *, const void *);
2112 struct shadow_copy2_private
*priv
;
2114 SMB_VFS_HANDLE_GET_DATA(handle
, priv
, struct shadow_copy2_private
,
2117 sort
= priv
->config
->sort_order
;
2122 if (strcmp(sort
, "asc") == 0) {
2123 cmpfunc
= shadow_copy2_label_cmp_asc
;
2124 } else if (strcmp(sort
, "desc") == 0) {
2125 cmpfunc
= shadow_copy2_label_cmp_desc
;
2130 if (shadow_copy2_data
&& shadow_copy2_data
->num_volumes
> 0 &&
2131 shadow_copy2_data
->labels
)
2133 TYPESAFE_QSORT(shadow_copy2_data
->labels
,
2134 shadow_copy2_data
->num_volumes
,
2139 static int shadow_copy2_get_shadow_copy_data(
2140 vfs_handle_struct
*handle
, files_struct
*fsp
,
2141 struct shadow_copy_data
*shadow_copy2_data
,
2145 const char *snapdir
;
2146 struct smb_filename
*snapdir_smb_fname
= NULL
;
2147 struct files_struct
*dirfsp
= NULL
;
2148 struct files_struct
*fspcwd
= NULL
;
2150 TALLOC_CTX
*tmp_ctx
= talloc_stackframe();
2151 struct shadow_copy2_private
*priv
= NULL
;
2152 struct shadow_copy2_snapentry
*tmpentry
= NULL
;
2153 bool get_snaplist
= false;
2154 struct vfs_open_how how
= {
2155 .flags
= O_RDONLY
, .mode
= 0,
2160 int saved_errno
= 0;
2162 snapdir
= shadow_copy2_find_snapdir(tmp_ctx
, handle
, fsp
->fsp_name
);
2163 if (snapdir
== NULL
) {
2164 DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
2165 handle
->conn
->connectpath
));
2170 snapdir_smb_fname
= synthetic_smb_fname(talloc_tos(),
2175 fsp
->fsp_name
->flags
);
2176 if (snapdir_smb_fname
== NULL
) {
2181 status
= create_internal_dirfsp(handle
->conn
,
2184 if (!NT_STATUS_IS_OK(status
)) {
2185 DBG_WARNING("create_internal_dir_fsp() failed for '%s'"
2186 " - %s\n", snapdir
, nt_errstr(status
));
2191 status
= vfs_at_fspcwd(talloc_tos(), handle
->conn
, &fspcwd
);
2192 if (!NT_STATUS_IS_OK(status
)) {
2198 how
.flags
|= O_DIRECTORY
;
2201 fd
= SMB_VFS_NEXT_OPENAT(handle
,
2207 DBG_WARNING("SMB_VFS_NEXT_OPEN failed for '%s'"
2208 " - %s\n", snapdir
, strerror(errno
));
2212 fsp_set_fd(dirfsp
, fd
);
2214 /* Now we have the handle, check access here. */
2215 status
= smbd_check_access_rights_fsp(fspcwd
,
2219 if (!NT_STATUS_IS_OK(status
)) {
2220 DBG_ERR("user does not have list permission "
2222 fsp_str_dbg(dirfsp
));
2227 p
= SMB_VFS_NEXT_FDOPENDIR(handle
, dirfsp
, NULL
, 0);
2229 DBG_NOTICE("shadow_copy2: SMB_VFS_NEXT_FDOPENDIR() failed for '%s'"
2230 " - %s\n", snapdir
, strerror(errno
));
2235 if (shadow_copy2_data
!= NULL
) {
2236 shadow_copy2_data
->num_volumes
= 0;
2237 shadow_copy2_data
->labels
= NULL
;
2240 SMB_VFS_HANDLE_GET_DATA(handle
, priv
, struct shadow_copy2_private
,
2244 * Normally this function is called twice once with labels = false and
2245 * then with labels = true. When labels is false it will return the
2246 * number of volumes so that the caller can allocate memory for that
2247 * many labels. Therefore to eliminate snaplist both the times it is
2248 * good to check if labels is set or not.
2250 * shadow_copy2_data is NULL when we only want to update the list and
2251 * don't want any labels.
2253 if ((priv
->snaps
->regex
!= NULL
) && (labels
|| shadow_copy2_data
== NULL
)) {
2254 get_snaplist
= true;
2255 /* Reset the global snaplist */
2256 shadow_copy2_delete_snaplist(priv
);
2258 /* Set the current time as snaplist update time */
2259 time(&(priv
->snaps
->fetch_time
));
2262 while ((d
= SMB_VFS_NEXT_READDIR(handle
, dirfsp
, p
))) {
2263 char snapshot
[GMT_NAME_LEN
+1];
2264 SHADOW_COPY_LABEL
*tlabels
;
2267 * ignore names not of the right form in the snapshot
2270 if (!shadow_copy2_snapshot_to_gmt(
2272 snapshot
, sizeof(snapshot
))) {
2274 DEBUG(6, ("shadow_copy2_get_shadow_copy_data: "
2275 "ignoring %s\n", d
->d_name
));
2278 DEBUG(6,("shadow_copy2_get_shadow_copy_data: %s -> %s\n",
2279 d
->d_name
, snapshot
));
2283 * Create a snap entry for each successful
2286 tmpentry
= shadow_copy2_create_snapentry(priv
);
2287 if (tmpentry
== NULL
) {
2288 DBG_ERR("talloc_zero() failed\n");
2291 tmpentry
->snapname
= talloc_strdup(tmpentry
, d
->d_name
);
2292 tmpentry
->time_fmt
= talloc_strdup(tmpentry
, snapshot
);
2295 if (shadow_copy2_data
== NULL
) {
2300 /* the caller doesn't want the labels */
2301 shadow_copy2_data
->num_volumes
++;
2305 tlabels
= talloc_realloc(shadow_copy2_data
,
2306 shadow_copy2_data
->labels
,
2308 shadow_copy2_data
->num_volumes
+1);
2309 if (tlabels
== NULL
) {
2310 DEBUG(0,("shadow_copy2: out of memory\n"));
2314 strlcpy(tlabels
[shadow_copy2_data
->num_volumes
], snapshot
,
2317 shadow_copy2_data
->num_volumes
++;
2318 shadow_copy2_data
->labels
= tlabels
;
2321 shadow_copy2_sort_data(handle
, shadow_copy2_data
);
2326 saved_errno
= errno
;
2328 TALLOC_FREE(fspcwd
);
2330 SMB_VFS_NEXT_CLOSEDIR(handle
, p
);
2332 if (dirfsp
!= NULL
) {
2334 * VFS_CLOSEDIR implicitly
2335 * closed the associated fd.
2337 fsp_set_fd(dirfsp
, -1);
2340 if (dirfsp
!= NULL
) {
2342 file_free(NULL
, dirfsp
);
2344 TALLOC_FREE(tmp_ctx
);
2345 if (saved_errno
!= 0) {
2346 errno
= saved_errno
;
2351 static int shadow_copy2_mkdirat(vfs_handle_struct
*handle
,
2352 struct files_struct
*dirfsp
,
2353 const struct smb_filename
*smb_fname
,
2356 struct smb_filename
*full_fname
= NULL
;
2357 time_t timestamp
= 0;
2359 full_fname
= full_path_from_dirfsp_atname(talloc_tos(),
2362 if (full_fname
== NULL
) {
2367 if (!shadow_copy2_strip_snapshot(talloc_tos(),
2372 TALLOC_FREE(full_fname
);
2375 TALLOC_FREE(full_fname
);
2376 if (timestamp
!= 0) {
2380 return SMB_VFS_NEXT_MKDIRAT(handle
,
2386 static int shadow_copy2_fchflags(vfs_handle_struct
*handle
,
2387 struct files_struct
*fsp
,
2390 time_t timestamp
= 0;
2392 if (!shadow_copy2_strip_snapshot(talloc_tos(),
2399 if (timestamp
!= 0) {
2403 return SMB_VFS_NEXT_FCHFLAGS(handle
, fsp
, flags
);
2406 static int shadow_copy2_fsetxattr(struct vfs_handle_struct
*handle
,
2407 struct files_struct
*fsp
,
2408 const char *aname
, const void *value
,
2409 size_t size
, int flags
)
2411 time_t timestamp
= 0;
2412 const struct smb_filename
*smb_fname
= NULL
;
2414 smb_fname
= fsp
->fsp_name
;
2415 if (!shadow_copy2_strip_snapshot(talloc_tos(),
2422 if (timestamp
!= 0) {
2426 return SMB_VFS_NEXT_FSETXATTR(handle
, fsp
,
2427 aname
, value
, size
, flags
);
2430 static NTSTATUS
shadow_copy2_create_dfs_pathat(struct vfs_handle_struct
*handle
,
2431 struct files_struct
*dirfsp
,
2432 const struct smb_filename
*smb_fname
,
2433 const struct referral
*reflist
,
2434 size_t referral_count
)
2436 time_t timestamp
= 0;
2438 if (!shadow_copy2_strip_snapshot(talloc_tos(),
2443 return NT_STATUS_NO_MEMORY
;
2445 if (timestamp
!= 0) {
2446 return NT_STATUS_MEDIA_WRITE_PROTECTED
;
2448 return SMB_VFS_NEXT_CREATE_DFS_PATHAT(handle
,
2455 static NTSTATUS
shadow_copy2_read_dfs_pathat(struct vfs_handle_struct
*handle
,
2456 TALLOC_CTX
*mem_ctx
,
2457 struct files_struct
*dirfsp
,
2458 struct smb_filename
*smb_fname
,
2459 struct referral
**ppreflist
,
2460 size_t *preferral_count
)
2462 time_t timestamp
= 0;
2463 char *stripped
= NULL
;
2464 struct smb_filename
*full_fname
= NULL
;
2465 struct smb_filename
*conv
= NULL
;
2468 full_fname
= full_path_from_dirfsp_atname(talloc_tos(),
2471 if (full_fname
== NULL
) {
2472 return NT_STATUS_NO_MEMORY
;
2475 if (!shadow_copy2_strip_snapshot(mem_ctx
,
2480 TALLOC_FREE(full_fname
);
2481 return NT_STATUS_NO_MEMORY
;
2483 if (timestamp
== 0) {
2484 TALLOC_FREE(full_fname
);
2485 TALLOC_FREE(stripped
);
2486 return SMB_VFS_NEXT_READ_DFS_PATHAT(handle
,
2494 conv
= cp_smb_filename(mem_ctx
, full_fname
);
2496 TALLOC_FREE(full_fname
);
2497 TALLOC_FREE(stripped
);
2498 return NT_STATUS_NO_MEMORY
;
2500 TALLOC_FREE(full_fname
);
2501 conv
->base_name
= shadow_copy2_convert(conv
,
2505 TALLOC_FREE(stripped
);
2506 if (conv
->base_name
== NULL
) {
2508 return NT_STATUS_NO_MEMORY
;
2511 status
= SMB_VFS_NEXT_READ_DFS_PATHAT(handle
,
2513 handle
->conn
->cwd_fsp
,
2518 if (NT_STATUS_IS_OK(status
)) {
2519 /* Return any stat(2) info. */
2520 smb_fname
->st
= conv
->st
;
2527 static const char *shadow_copy2_connectpath(
2528 struct vfs_handle_struct
*handle
,
2529 const struct files_struct
*dirfsp
,
2530 const struct smb_filename
*smb_fname_in
)
2532 time_t timestamp
= 0;
2533 char *stripped
= NULL
;
2535 const char *fname
= smb_fname_in
->base_name
;
2536 const struct smb_filename
*full
= NULL
;
2537 struct smb_filename smb_fname
= {0};
2538 struct smb_filename
*result_fname
= NULL
;
2539 char *result
= NULL
;
2540 char *parent_dir
= NULL
;
2541 int saved_errno
= 0;
2542 size_t rootpath_len
= 0;
2543 struct shadow_copy2_private
*priv
= NULL
;
2545 SMB_VFS_HANDLE_GET_DATA(handle
, priv
, struct shadow_copy2_private
,
2548 DBG_DEBUG("Calc connect path for [%s]\n", fname
);
2550 if (priv
->shadow_connectpath
!= NULL
) {
2551 DBG_DEBUG("cached connect path is [%s]\n",
2552 priv
->shadow_connectpath
);
2553 return priv
->shadow_connectpath
;
2556 full
= full_path_from_dirfsp_atname(
2557 talloc_tos(), dirfsp
, smb_fname_in
);
2562 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, full
,
2563 ×tamp
, &stripped
)) {
2566 if (timestamp
== 0) {
2567 return SMB_VFS_NEXT_CONNECTPATH(handle
, dirfsp
, smb_fname_in
);
2570 tmp
= shadow_copy2_do_convert(talloc_tos(), handle
, stripped
, timestamp
,
2573 if (errno
!= ENOENT
) {
2578 * If the converted path does not exist, and converting
2579 * the parent yields something that does exist, then
2580 * this path refers to something that has not been
2581 * created yet, relative to the parent path.
2582 * The snapshot finding is relative to the parent.
2583 * (usually snapshots are read/only but this is not
2584 * necessarily true).
2585 * This code also covers getting a wildcard in the
2586 * last component, because this function is called
2587 * prior to sanitizing the path, and in SMB1 we may
2588 * get wildcards in path names.
2590 if (!parent_dirname(talloc_tos(), stripped
, &parent_dir
,
2596 tmp
= shadow_copy2_do_convert(talloc_tos(), handle
, parent_dir
,
2597 timestamp
, &rootpath_len
);
2603 DBG_DEBUG("converted path is [%s] root path is [%.*s]\n", tmp
,
2604 (int)rootpath_len
, tmp
);
2606 tmp
[rootpath_len
] = '\0';
2607 smb_fname
= (struct smb_filename
) { .base_name
= tmp
};
2609 result_fname
= SMB_VFS_NEXT_REALPATH(handle
, priv
, &smb_fname
);
2610 if (result_fname
== NULL
) {
2615 * SMB_VFS_NEXT_REALPATH returns a talloc'ed string.
2616 * Don't leak memory.
2618 TALLOC_FREE(priv
->shadow_realpath
);
2619 priv
->shadow_realpath
= result_fname
;
2620 result
= priv
->shadow_realpath
->base_name
;
2622 DBG_DEBUG("connect path is [%s]\n", result
);
2625 if (result
== NULL
) {
2626 saved_errno
= errno
;
2629 TALLOC_FREE(stripped
);
2630 TALLOC_FREE(parent_dir
);
2631 if (saved_errno
!= 0) {
2632 errno
= saved_errno
;
2637 static NTSTATUS
shadow_copy2_parent_pathname(vfs_handle_struct
*handle
,
2639 const struct smb_filename
*smb_fname_in
,
2640 struct smb_filename
**parent_dir_out
,
2641 struct smb_filename
**atname_out
)
2643 time_t timestamp
= 0;
2644 char *stripped
= NULL
;
2645 char *converted_name
= NULL
;
2646 struct smb_filename
*smb_fname
= NULL
;
2647 struct smb_filename
*parent
= NULL
;
2648 struct smb_filename
*atname
= NULL
;
2649 struct shadow_copy2_private
*priv
= NULL
;
2651 bool is_converted
= false;
2652 NTSTATUS status
= NT_STATUS_OK
;
2653 TALLOC_CTX
*frame
= NULL
;
2655 SMB_VFS_HANDLE_GET_DATA(handle
,
2657 struct shadow_copy2_private
,
2658 return NT_STATUS_INTERNAL_ERROR
);
2660 frame
= talloc_stackframe();
2662 smb_fname
= cp_smb_filename(frame
, smb_fname_in
);
2663 if (smb_fname
== NULL
) {
2664 status
= NT_STATUS_NO_MEMORY
;
2668 /* First, call the default PARENT_PATHNAME. */
2669 status
= SMB_VFS_NEXT_PARENT_PATHNAME(handle
,
2674 if (!NT_STATUS_IS_OK(status
)) {
2678 if (parent
->twrp
== 0) {
2680 * Parent is not a snapshot path, return
2681 * the regular result.
2683 status
= NT_STATUS_OK
;
2687 /* See if we can find a snapshot for the parent. */
2688 ok
= shadow_copy2_strip_snapshot_converted(frame
,
2695 status
= map_nt_error_from_unix(errno
);
2701 * Already found snapshot for parent so wipe
2708 converted_name
= shadow_copy2_convert(frame
,
2713 if (converted_name
== NULL
) {
2715 * Can't find snapshot for parent so wipe
2723 *parent_dir_out
= talloc_move(ctx
, &parent
);
2724 if (atname_out
!= NULL
) {
2725 *atname_out
= talloc_move(*parent_dir_out
, &atname
);
2734 static uint64_t shadow_copy2_disk_free(vfs_handle_struct
*handle
,
2735 const struct smb_filename
*smb_fname
,
2740 time_t timestamp
= 0;
2741 char *stripped
= NULL
;
2742 int saved_errno
= 0;
2744 struct smb_filename
*conv_smb_fname
= NULL
;
2745 uint64_t ret
= (uint64_t)-1;
2747 if (!shadow_copy2_strip_snapshot(talloc_tos(),
2752 return (uint64_t)-1;
2754 if (timestamp
== 0) {
2755 return SMB_VFS_NEXT_DISK_FREE(handle
, smb_fname
,
2756 bsize
, dfree
, dsize
);
2758 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
2759 TALLOC_FREE(stripped
);
2761 return (uint64_t)-1;
2763 conv_smb_fname
= synthetic_smb_fname(talloc_tos(),
2769 if (conv_smb_fname
== NULL
) {
2771 return (uint64_t)-1;
2773 ret
= SMB_VFS_NEXT_DISK_FREE(handle
, conv_smb_fname
,
2774 bsize
, dfree
, dsize
);
2775 if (ret
== (uint64_t)-1) {
2776 saved_errno
= errno
;
2779 TALLOC_FREE(conv_smb_fname
);
2780 if (saved_errno
!= 0) {
2781 errno
= saved_errno
;
2786 static int shadow_copy2_get_quota(vfs_handle_struct
*handle
,
2787 const struct smb_filename
*smb_fname
,
2788 enum SMB_QUOTA_TYPE qtype
,
2792 time_t timestamp
= 0;
2793 char *stripped
= NULL
;
2795 int saved_errno
= 0;
2797 struct smb_filename
*conv_smb_fname
= NULL
;
2799 if (!shadow_copy2_strip_snapshot(talloc_tos(),
2806 if (timestamp
== 0) {
2807 return SMB_VFS_NEXT_GET_QUOTA(handle
, smb_fname
, qtype
, id
, dq
);
2810 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
2811 TALLOC_FREE(stripped
);
2815 conv_smb_fname
= synthetic_smb_fname(talloc_tos(),
2821 if (conv_smb_fname
== NULL
) {
2825 ret
= SMB_VFS_NEXT_GET_QUOTA(handle
, conv_smb_fname
, qtype
, id
, dq
);
2828 saved_errno
= errno
;
2831 TALLOC_FREE(conv_smb_fname
);
2832 if (saved_errno
!= 0) {
2833 errno
= saved_errno
;
2839 static ssize_t
shadow_copy2_pwrite(vfs_handle_struct
*handle
,
2847 nwritten
= SMB_VFS_NEXT_PWRITE(handle
, fsp
, data
, n
, offset
);
2848 if (nwritten
== -1) {
2849 if (errno
== EBADF
&& fsp
->fsp_flags
.can_write
) {
2857 struct shadow_copy2_pwrite_state
{
2858 vfs_handle_struct
*handle
;
2861 struct vfs_aio_state vfs_aio_state
;
2864 static void shadow_copy2_pwrite_done(struct tevent_req
*subreq
);
2866 static struct tevent_req
*shadow_copy2_pwrite_send(
2867 struct vfs_handle_struct
*handle
, TALLOC_CTX
*mem_ctx
,
2868 struct tevent_context
*ev
, struct files_struct
*fsp
,
2869 const void *data
, size_t n
, off_t offset
)
2871 struct tevent_req
*req
= NULL
, *subreq
= NULL
;
2872 struct shadow_copy2_pwrite_state
*state
= NULL
;
2874 req
= tevent_req_create(mem_ctx
, &state
,
2875 struct shadow_copy2_pwrite_state
);
2879 state
->handle
= handle
;
2882 subreq
= SMB_VFS_NEXT_PWRITE_SEND(state
,
2889 if (tevent_req_nomem(subreq
, req
)) {
2890 return tevent_req_post(req
, ev
);
2892 tevent_req_set_callback(subreq
, shadow_copy2_pwrite_done
, req
);
2897 static void shadow_copy2_pwrite_done(struct tevent_req
*subreq
)
2899 struct tevent_req
*req
= tevent_req_callback_data(
2900 subreq
, struct tevent_req
);
2901 struct shadow_copy2_pwrite_state
*state
= tevent_req_data(
2902 req
, struct shadow_copy2_pwrite_state
);
2904 state
->ret
= SMB_VFS_PWRITE_RECV(subreq
, &state
->vfs_aio_state
);
2905 TALLOC_FREE(subreq
);
2906 if (state
->ret
== -1) {
2907 tevent_req_error(req
, state
->vfs_aio_state
.error
);
2911 tevent_req_done(req
);
2914 static ssize_t
shadow_copy2_pwrite_recv(struct tevent_req
*req
,
2915 struct vfs_aio_state
*vfs_aio_state
)
2917 struct shadow_copy2_pwrite_state
*state
= tevent_req_data(
2918 req
, struct shadow_copy2_pwrite_state
);
2920 if (tevent_req_is_unix_error(req
, &vfs_aio_state
->error
)) {
2921 if ((vfs_aio_state
->error
== EBADF
) &&
2922 state
->fsp
->fsp_flags
.can_write
)
2924 vfs_aio_state
->error
= EROFS
;
2930 *vfs_aio_state
= state
->vfs_aio_state
;
2934 static int shadow_copy2_connect(struct vfs_handle_struct
*handle
,
2935 const char *service
, const char *user
)
2937 struct shadow_copy2_config
*config
;
2938 struct shadow_copy2_private
*priv
;
2940 const char *snapdir
;
2941 const char *snapprefix
= NULL
;
2942 const char *delimiter
;
2943 const char *gmt_format
;
2944 const char *sort_order
;
2945 const char *basedir
= NULL
;
2946 const char *snapsharepath
= NULL
;
2947 const char *mount_point
;
2949 DBG_DEBUG("cnum[%" PRIu32
"], connectpath[%s]\n",
2951 handle
->conn
->connectpath
);
2953 ret
= SMB_VFS_NEXT_CONNECT(handle
, service
, user
);
2958 priv
= talloc_zero(handle
->conn
, struct shadow_copy2_private
);
2960 DBG_ERR("talloc_zero() failed\n");
2965 priv
->snaps
= talloc_zero(priv
, struct shadow_copy2_snaplist_info
);
2966 if (priv
->snaps
== NULL
) {
2967 DBG_ERR("talloc_zero() failed\n");
2972 config
= talloc_zero(priv
, struct shadow_copy2_config
);
2973 if (config
== NULL
) {
2974 DEBUG(0, ("talloc_zero() failed\n"));
2979 priv
->config
= config
;
2981 gmt_format
= lp_parm_const_string(SNUM(handle
->conn
),
2984 config
->gmt_format
= talloc_strdup(config
, gmt_format
);
2985 if (config
->gmt_format
== NULL
) {
2986 DEBUG(0, ("talloc_strdup() failed\n"));
2991 /* config->gmt_format must not contain a path separator. */
2992 if (strchr(config
->gmt_format
, '/') != NULL
) {
2993 DEBUG(0, ("shadow:format %s must not contain a /"
2994 "character. Unable to initialize module.\n",
2995 config
->gmt_format
));
3000 config
->use_sscanf
= lp_parm_bool(SNUM(handle
->conn
),
3001 "shadow", "sscanf", false);
3003 config
->use_localtime
= lp_parm_bool(SNUM(handle
->conn
),
3004 "shadow", "localtime",
3007 snapdir
= lp_parm_const_string(SNUM(handle
->conn
),
3008 "shadow", "snapdir",
3010 config
->snapdir
= talloc_strdup(config
, snapdir
);
3011 if (config
->snapdir
== NULL
) {
3012 DEBUG(0, ("talloc_strdup() failed\n"));
3017 snapprefix
= lp_parm_const_string(SNUM(handle
->conn
),
3018 "shadow", "snapprefix",
3020 if (snapprefix
!= NULL
) {
3021 priv
->snaps
->regex
= talloc_zero(priv
->snaps
, regex_t
);
3022 if (priv
->snaps
->regex
== NULL
) {
3023 DBG_ERR("talloc_zero() failed\n");
3028 /* pre-compute regex rule for matching pattern later */
3029 ret
= regcomp(priv
->snaps
->regex
, snapprefix
, 0);
3031 DBG_ERR("Failed to create regex object\n");
3036 delimiter
= lp_parm_const_string(SNUM(handle
->conn
),
3037 "shadow", "delimiter",
3039 if (delimiter
!= NULL
) {
3040 priv
->config
->delimiter
= talloc_strdup(priv
->config
, delimiter
);
3041 if (priv
->config
->delimiter
== NULL
) {
3042 DBG_ERR("talloc_strdup() failed\n");
3048 config
->snapdirseverywhere
= lp_parm_bool(SNUM(handle
->conn
),
3050 "snapdirseverywhere",
3053 config
->crossmountpoints
= lp_parm_bool(SNUM(handle
->conn
),
3054 "shadow", "crossmountpoints",
3057 if (config
->crossmountpoints
&& !config
->snapdirseverywhere
) {
3058 DBG_WARNING("Warning: 'crossmountpoints' depends on "
3059 "'snapdirseverywhere'. Disabling crossmountpoints.\n");
3062 config
->fixinodes
= lp_parm_bool(SNUM(handle
->conn
),
3063 "shadow", "fixinodes",
3066 sort_order
= lp_parm_const_string(SNUM(handle
->conn
),
3067 "shadow", "sort", "desc");
3068 config
->sort_order
= talloc_strdup(config
, sort_order
);
3069 if (config
->sort_order
== NULL
) {
3070 DEBUG(0, ("talloc_strdup() failed\n"));
3075 mount_point
= lp_parm_const_string(SNUM(handle
->conn
),
3076 "shadow", "mountpoint", NULL
);
3077 if (mount_point
!= NULL
) {
3078 if (mount_point
[0] != '/') {
3079 DBG_WARNING("Warning: 'mountpoint' is relative "
3080 "('%s'), but it has to be an absolute "
3081 "path. Ignoring provided value.\n",
3086 p
= strstr(handle
->conn
->connectpath
, mount_point
);
3087 if (p
!= handle
->conn
->connectpath
) {
3088 DBG_WARNING("Warning: the share root (%s) is "
3089 "not a subdirectory of the "
3090 "specified mountpoint (%s). "
3091 "Ignoring provided value.\n",
3092 handle
->conn
->connectpath
,
3099 if (mount_point
!= NULL
) {
3100 config
->mount_point
= talloc_strdup(config
, mount_point
);
3101 if (config
->mount_point
== NULL
) {
3102 DBG_ERR("talloc_strdup() failed\n");
3106 config
->mount_point
= shadow_copy2_find_mount_point(config
,
3108 if (config
->mount_point
== NULL
) {
3109 DBG_WARNING("shadow_copy2_find_mount_point "
3110 "of the share root '%s' failed: %s\n",
3111 handle
->conn
->connectpath
, strerror(errno
));
3116 basedir
= lp_parm_const_string(SNUM(handle
->conn
),
3117 "shadow", "basedir", NULL
);
3119 if (basedir
!= NULL
) {
3120 if (basedir
[0] != '/') {
3121 DBG_WARNING("Warning: 'basedir' is "
3122 "relative ('%s'), but it has to be an "
3123 "absolute path. Disabling basedir.\n",
3128 p
= strstr(basedir
, config
->mount_point
);
3130 DEBUG(1, ("Warning: basedir (%s) is not a "
3131 "subdirectory of the share root's "
3132 "mount point (%s). "
3133 "Disabling basedir\n",
3134 basedir
, config
->mount_point
));
3140 if (config
->snapdirseverywhere
&& basedir
!= NULL
) {
3141 DBG_WARNING("Warning: 'basedir' is incompatible "
3142 "with 'snapdirseverywhere'. Disabling basedir.\n");
3146 snapsharepath
= lp_parm_const_string(SNUM(handle
->conn
), "shadow",
3147 "snapsharepath", NULL
);
3148 if (snapsharepath
!= NULL
) {
3149 if (snapsharepath
[0] == '/') {
3150 DBG_WARNING("Warning: 'snapsharepath' is "
3151 "absolute ('%s'), but it has to be a "
3152 "relative path. Disabling snapsharepath.\n",
3154 snapsharepath
= NULL
;
3156 if (config
->snapdirseverywhere
&& snapsharepath
!= NULL
) {
3157 DBG_WARNING("Warning: 'snapsharepath' is incompatible "
3158 "with 'snapdirseverywhere'. Disabling "
3159 "snapsharepath.\n");
3160 snapsharepath
= NULL
;
3164 if (basedir
!= NULL
&& snapsharepath
!= NULL
) {
3165 DBG_WARNING("Warning: 'snapsharepath' is incompatible with "
3166 "'basedir'. Disabling snapsharepath\n");
3167 snapsharepath
= NULL
;
3170 if (snapsharepath
!= NULL
) {
3171 config
->rel_connectpath
= talloc_strdup(config
, snapsharepath
);
3172 if (config
->rel_connectpath
== NULL
) {
3173 DBG_ERR("talloc_strdup() failed\n");
3179 if (basedir
== NULL
) {
3180 basedir
= config
->mount_point
;
3183 if (config
->rel_connectpath
== NULL
&&
3184 strlen(basedir
) < strlen(handle
->conn
->connectpath
)) {
3185 config
->rel_connectpath
= talloc_strdup(config
,
3186 handle
->conn
->connectpath
+ strlen(basedir
));
3187 if (config
->rel_connectpath
== NULL
) {
3188 DEBUG(0, ("talloc_strdup() failed\n"));
3194 if (config
->snapdir
[0] == '/') {
3195 config
->snapdir_absolute
= true;
3197 if (config
->snapdirseverywhere
) {
3198 DBG_WARNING("Warning: An absolute snapdir is "
3199 "incompatible with 'snapdirseverywhere', "
3200 "setting 'snapdirseverywhere' to "
3202 config
->snapdirseverywhere
= false;
3205 if (config
->crossmountpoints
) {
3206 DBG_WARNING("Warning: 'crossmountpoints' is not "
3207 "supported with an absolute snapdir. "
3209 config
->crossmountpoints
= false;
3212 config
->snapshot_basepath
= config
->snapdir
;
3214 config
->snapshot_basepath
= talloc_asprintf(config
, "%s/%s",
3215 config
->mount_point
, config
->snapdir
);
3216 if (config
->snapshot_basepath
== NULL
) {
3217 DEBUG(0, ("talloc_asprintf() failed\n"));
3223 trim_string(config
->mount_point
, NULL
, "/");
3224 trim_string(config
->rel_connectpath
, "/", "/");
3225 trim_string(config
->snapdir
, NULL
, "/");
3226 trim_string(config
->snapshot_basepath
, NULL
, "/");
3228 DEBUG(10, ("shadow_copy2_connect: configuration:\n"
3229 " share root: '%s'\n"
3230 " mountpoint: '%s'\n"
3231 " rel share root: '%s'\n"
3233 " snapprefix: '%s'\n"
3234 " delimiter: '%s'\n"
3235 " snapshot base path: '%s'\n"
3238 " snapdirs everywhere: %s\n"
3239 " cross mountpoints: %s\n"
3243 handle
->conn
->connectpath
,
3244 config
->mount_point
,
3245 config
->rel_connectpath
,
3249 config
->snapshot_basepath
,
3251 config
->use_sscanf
? "yes" : "no",
3252 config
->snapdirseverywhere
? "yes" : "no",
3253 config
->crossmountpoints
? "yes" : "no",
3254 config
->fixinodes
? "yes" : "no",
3259 SMB_VFS_HANDLE_SET_DATA(handle
, priv
,
3260 NULL
, struct shadow_copy2_private
,
3266 static struct vfs_fn_pointers vfs_shadow_copy2_fns
= {
3267 .connect_fn
= shadow_copy2_connect
,
3268 .disk_free_fn
= shadow_copy2_disk_free
,
3269 .get_quota_fn
= shadow_copy2_get_quota
,
3270 .create_dfs_pathat_fn
= shadow_copy2_create_dfs_pathat
,
3271 .read_dfs_pathat_fn
= shadow_copy2_read_dfs_pathat
,
3272 .renameat_fn
= shadow_copy2_renameat
,
3273 .linkat_fn
= shadow_copy2_linkat
,
3274 .symlinkat_fn
= shadow_copy2_symlinkat
,
3275 .stat_fn
= shadow_copy2_stat
,
3276 .lstat_fn
= shadow_copy2_lstat
,
3277 .fstat_fn
= shadow_copy2_fstat
,
3278 .fstatat_fn
= shadow_copy2_fstatat
,
3279 .openat_fn
= shadow_copy2_openat
,
3280 .unlinkat_fn
= shadow_copy2_unlinkat
,
3281 .fchmod_fn
= shadow_copy2_fchmod
,
3282 .chdir_fn
= shadow_copy2_chdir
,
3283 .fntimes_fn
= shadow_copy2_fntimes
,
3284 .readlinkat_fn
= shadow_copy2_readlinkat
,
3285 .mknodat_fn
= shadow_copy2_mknodat
,
3286 .realpath_fn
= shadow_copy2_realpath
,
3287 .get_shadow_copy_data_fn
= shadow_copy2_get_shadow_copy_data
,
3288 .mkdirat_fn
= shadow_copy2_mkdirat
,
3289 .fsetxattr_fn
= shadow_copy2_fsetxattr
,
3290 .fchflags_fn
= shadow_copy2_fchflags
,
3291 .pwrite_fn
= shadow_copy2_pwrite
,
3292 .pwrite_send_fn
= shadow_copy2_pwrite_send
,
3293 .pwrite_recv_fn
= shadow_copy2_pwrite_recv
,
3294 .connectpath_fn
= shadow_copy2_connectpath
,
3295 .parent_pathname_fn
= shadow_copy2_parent_pathname
,
3299 NTSTATUS
vfs_shadow_copy2_init(TALLOC_CTX
*ctx
)
3301 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
,
3302 "shadow_copy2", &vfs_shadow_copy2_fns
);