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
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 * This is a second implemetation of a shadow copy module for exposing
27 * file system snapshots to windows clients as shadow copies.
29 * See the manual page for documentation.
33 #include "smbd/smbd.h"
34 #include "system/filesys.h"
35 #include "include/ntioctl.h"
37 #include "lib/util_path.h"
39 struct shadow_copy2_config
{
44 bool snapdirseverywhere
;
45 bool crossmountpoints
;
48 bool snapdir_absolute
;
50 char *rel_connectpath
; /* share root, relative to a snapshot root */
51 char *snapshot_basepath
; /* the absolute version of snapdir */
52 char *shadow_cwd
; /* Absolute $cwd path. */
53 /* Absolute connectpath - can vary depending on $cwd. */
54 char *shadow_connectpath
;
55 /* malloc'ed realpath return. */
56 char *shadow_realpath
;
59 static bool shadow_copy2_find_slashes(TALLOC_CTX
*mem_ctx
, const char *str
,
61 unsigned *pnum_offsets
)
70 while ((p
= strchr(p
, '/')) != NULL
) {
75 offsets
= talloc_array(mem_ctx
, size_t, num_offsets
);
76 if (offsets
== NULL
) {
82 while ((p
= strchr(p
, '/')) != NULL
) {
83 offsets
[num_offsets
] = p
-str
;
89 *pnum_offsets
= num_offsets
;
94 * Given a timestamp, build the posix level GMT-tag string
95 * based on the configurable format.
97 static size_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct
*handle
,
99 char *snaptime_string
,
104 struct shadow_copy2_config
*config
;
106 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
109 if (config
->use_sscanf
) {
110 snaptime_len
= snprintf(snaptime_string
,
113 (unsigned long)snapshot
);
114 if (snaptime_len
<= 0) {
115 DEBUG(10, ("snprintf failed\n"));
119 if (config
->use_localtime
) {
120 if (localtime_r(&snapshot
, &snap_tm
) == 0) {
121 DEBUG(10, ("gmtime_r failed\n"));
125 if (gmtime_r(&snapshot
, &snap_tm
) == 0) {
126 DEBUG(10, ("gmtime_r failed\n"));
130 snaptime_len
= strftime(snaptime_string
,
134 if (snaptime_len
== 0) {
135 DEBUG(10, ("strftime failed\n"));
144 * Given a timestamp, build the string to insert into a path
145 * as a path component for creating the local path to the
146 * snapshot at the given timestamp of the input path.
148 * In the case of a parallel snapdir (specified with an
149 * absolute path), this is the inital portion of the
150 * local path of any snapshot file. The complete path is
151 * obtained by appending the portion of the file's path
152 * below the share root's mountpoint.
154 static char *shadow_copy2_insert_string(TALLOC_CTX
*mem_ctx
,
155 struct vfs_handle_struct
*handle
,
158 fstring snaptime_string
;
159 size_t snaptime_len
= 0;
161 struct shadow_copy2_config
*config
;
163 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
166 snaptime_len
= shadow_copy2_posix_gmt_string(handle
,
169 sizeof(snaptime_string
));
170 if (snaptime_len
<= 0) {
174 if (config
->snapdir_absolute
) {
175 result
= talloc_asprintf(mem_ctx
, "%s/%s",
176 config
->snapdir
, snaptime_string
);
178 result
= talloc_asprintf(mem_ctx
, "/%s/%s",
179 config
->snapdir
, snaptime_string
);
181 if (result
== NULL
) {
182 DEBUG(1, (__location__
" talloc_asprintf failed\n"));
189 * Build the posix snapshot path for the connection
190 * at the given timestamp, i.e. the absolute posix path
191 * that contains the snapshot for this file system.
193 * This only applies to classical case, i.e. not
194 * to the "snapdirseverywhere" mode.
196 static char *shadow_copy2_snapshot_path(TALLOC_CTX
*mem_ctx
,
197 struct vfs_handle_struct
*handle
,
200 fstring snaptime_string
;
201 size_t snaptime_len
= 0;
203 struct shadow_copy2_config
*config
;
205 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
208 snaptime_len
= shadow_copy2_posix_gmt_string(handle
,
211 sizeof(snaptime_string
));
212 if (snaptime_len
<= 0) {
216 result
= talloc_asprintf(mem_ctx
, "%s/%s",
217 config
->snapshot_basepath
, snaptime_string
);
218 if (result
== NULL
) {
219 DEBUG(1, (__location__
" talloc_asprintf failed\n"));
225 static char *make_path_absolute(TALLOC_CTX
*mem_ctx
,
226 struct shadow_copy2_config
*config
,
229 char *newpath
= NULL
;
230 char *abs_path
= NULL
;
232 if (name
[0] != '/') {
233 newpath
= talloc_asprintf(mem_ctx
,
237 if (newpath
== NULL
) {
242 abs_path
= canonicalize_absolute_path(mem_ctx
, name
);
243 TALLOC_FREE(newpath
);
247 /* Return a $cwd-relative path. */
248 static bool make_relative_path(const char *cwd
, char *abs_path
)
250 size_t cwd_len
= strlen(cwd
);
251 size_t abs_len
= strlen(abs_path
);
253 if (abs_len
< cwd_len
) {
256 if (memcmp(abs_path
, cwd
, cwd_len
) != 0) {
259 if (abs_path
[cwd_len
] != '/' && abs_path
[cwd_len
] != '\0') {
262 if (abs_path
[cwd_len
] == '/') {
265 memmove(abs_path
, &abs_path
[cwd_len
], abs_len
+ 1 - cwd_len
);
269 static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct
*handle
,
271 char *gmt
, size_t gmt_len
);
274 * Check if an incoming filename is already a snapshot converted pathname.
276 * If so, it returns the pathname truncated at the snapshot point which
277 * will be used as the connectpath.
280 static int check_for_converted_path(TALLOC_CTX
*mem_ctx
,
281 struct vfs_handle_struct
*handle
,
282 struct shadow_copy2_config
*config
,
284 bool *ppath_already_converted
,
287 size_t snapdirlen
= 0;
288 char *p
= strstr_m(abs_path
, config
->snapdir
);
290 char *connect_path
= NULL
;
291 char snapshot
[GMT_NAME_LEN
+1];
293 *ppath_already_converted
= false;
296 /* Must at least contain shadow:snapdir. */
300 if (config
->snapdir
[0] == '/' &&
302 /* Absolute shadow:snapdir must be at the start. */
306 snapdirlen
= strlen(config
->snapdir
);
307 if (p
[snapdirlen
] != '/') {
308 /* shadow:snapdir must end as a separate component. */
312 if (p
> abs_path
&& p
[-1] != '/') {
313 /* shadow:snapdir must start as a separate component. */
318 p
++; /* Move past the / */
321 * Need to return up to the next path
322 * component after the time.
323 * This will be used as the connectpath.
328 * No next path component.
331 connect_path
= talloc_strdup(mem_ctx
,
334 connect_path
= talloc_strndup(mem_ctx
,
338 if (connect_path
== NULL
) {
343 * Point p at the same offset in connect_path as
347 p
= &connect_path
[p
- abs_path
];
350 * Now ensure there is a time string at p.
351 * The SMB-format @GMT-token string is returned
355 if (!shadow_copy2_snapshot_to_gmt(handle
,
359 TALLOC_FREE(connect_path
);
363 if (pconnectpath
!= NULL
) {
364 *pconnectpath
= connect_path
;
367 *ppath_already_converted
= true;
369 DBG_DEBUG("path |%s| is already converted. "
370 "connect path = |%s|\n",
378 * This function does two things.
380 * 1). Checks if an incoming filename is already a
381 * snapshot converted pathname.
382 * If so, it returns the pathname truncated
383 * at the snapshot point which will be used
384 * as the connectpath, and then does an early return.
386 * 2). Checks if an incoming filename contains an
387 * SMB-layer @GMT- style timestamp.
388 * If so, it strips the timestamp, and returns
389 * both the timestamp and the stripped path
390 * (making it cwd-relative).
393 static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX
*mem_ctx
,
394 struct vfs_handle_struct
*handle
,
395 const char *orig_name
,
401 time_t timestamp
= 0;
404 char *stripped
= NULL
;
405 size_t rest_len
, dst_len
;
406 struct shadow_copy2_config
*config
;
407 ptrdiff_t len_before_gmt
;
408 const char *name
= orig_name
;
409 char *abs_path
= NULL
;
411 bool already_converted
= false;
414 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
417 DEBUG(10, (__location__
": enter path '%s'\n", name
));
419 abs_path
= make_path_absolute(mem_ctx
, config
, name
);
420 if (abs_path
== NULL
) {
426 DEBUG(10, (__location__
": abs path '%s'\n", name
));
428 err
= check_for_converted_path(mem_ctx
,
435 /* error in conversion. */
440 if (already_converted
) {
445 * From here we're only looking to strip an
446 * SMB-layer @GMT- token.
449 p
= strstr_m(name
, "@GMT-");
451 DEBUG(11, ("@GMT not found\n"));
454 if ((p
> name
) && (p
[-1] != '/')) {
455 /* the GMT-token does not start a path-component */
456 DEBUG(10, ("not at start, p=%p, name=%p, p[-1]=%d\n",
457 p
, name
, (int)p
[-1]));
461 len_before_gmt
= p
- name
;
463 q
= strptime(p
, GMT_FORMAT
, &tm
);
465 DEBUG(10, ("strptime failed\n"));
469 timestamp
= timegm(&tm
);
470 if (timestamp
== (time_t)-1) {
471 DEBUG(10, ("timestamp==-1\n"));
476 * The name consists of only the GMT token or the GMT
477 * token is at the end of the path. XP seems to send
478 * @GMT- at the end under certain circumstances even
479 * with a path prefix.
481 if (pstripped
!= NULL
) {
482 if (len_before_gmt
> 0) {
484 * There is a slash before
485 * the @GMT-. Remove it.
489 stripped
= talloc_strndup(mem_ctx
, name
, p
- name
);
490 if (stripped
== NULL
) {
494 if (orig_name
[0] != '/') {
495 if (make_relative_path(config
->shadow_cwd
,
496 stripped
) == false) {
497 DEBUG(10, (__location__
": path '%s' "
498 "doesn't start with cwd '%s\n",
499 stripped
, config
->shadow_cwd
));
505 *pstripped
= stripped
;
507 *ptimestamp
= timestamp
;
512 * It is not a complete path component, i.e. the path
513 * component continues after the gmt-token.
515 DEBUG(10, ("q[0] = %d\n", (int)q
[0]));
520 rest_len
= strlen(q
);
521 dst_len
= (p
-name
) + rest_len
;
523 if (pstripped
!= NULL
) {
524 stripped
= talloc_array(mem_ctx
, char, dst_len
+1);
525 if (stripped
== NULL
) {
530 memcpy(stripped
, name
, p
-name
);
533 memcpy(stripped
+ (p
-name
), q
, rest_len
);
535 stripped
[dst_len
] = '\0';
536 if (orig_name
[0] != '/') {
537 if (make_relative_path(config
->shadow_cwd
,
538 stripped
) == false) {
539 DEBUG(10, (__location__
": path '%s' "
540 "doesn't start with cwd '%s\n",
541 stripped
, config
->shadow_cwd
));
547 *pstripped
= stripped
;
549 *ptimestamp
= timestamp
;
553 TALLOC_FREE(abs_path
);
557 static bool shadow_copy2_strip_snapshot(TALLOC_CTX
*mem_ctx
,
558 struct vfs_handle_struct
*handle
,
559 const char *orig_name
,
563 return shadow_copy2_strip_snapshot_internal(mem_ctx
,
571 static char *shadow_copy2_find_mount_point(TALLOC_CTX
*mem_ctx
,
572 vfs_handle_struct
*handle
)
574 char *path
= talloc_strdup(mem_ctx
, handle
->conn
->connectpath
);
579 if (stat(path
, &st
) != 0) {
586 while ((p
= strrchr(path
, '/')) && p
> path
) {
588 if (stat(path
, &st
) != 0) {
592 if (st
.st_dev
!= dev
) {
602 * Convert from a name as handed in via the SMB layer
603 * and a timestamp into the local path of the snapshot
604 * of the provided file at the provided time.
605 * Also return the path in the snapshot corresponding
606 * to the file's share root.
608 static char *shadow_copy2_do_convert(TALLOC_CTX
*mem_ctx
,
609 struct vfs_handle_struct
*handle
,
610 const char *name
, time_t timestamp
,
611 size_t *snaproot_len
)
613 struct smb_filename converted_fname
;
615 size_t *slashes
= NULL
;
616 unsigned num_slashes
;
620 char *converted
= NULL
;
621 size_t insertlen
, connectlen
= 0;
625 struct shadow_copy2_config
*config
;
626 size_t in_share_offset
= 0;
628 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
631 DEBUG(10, ("converting '%s'\n", name
));
633 if (!config
->snapdirseverywhere
) {
637 snapshot_path
= shadow_copy2_snapshot_path(talloc_tos(),
640 if (snapshot_path
== NULL
) {
644 if (config
->rel_connectpath
== NULL
) {
645 converted
= talloc_asprintf(mem_ctx
, "%s/%s",
646 snapshot_path
, name
);
648 converted
= talloc_asprintf(mem_ctx
, "%s/%s/%s",
650 config
->rel_connectpath
,
653 if (converted
== NULL
) {
657 ZERO_STRUCT(converted_fname
);
658 converted_fname
.base_name
= converted
;
660 ret
= SMB_VFS_NEXT_LSTAT(handle
, &converted_fname
);
661 DEBUG(10, ("Trying[not snapdirseverywhere] %s: %d (%s)\n",
663 ret
, ret
== 0 ? "ok" : strerror(errno
)));
665 DEBUG(10, ("Found %s\n", converted
));
668 if (snaproot_len
!= NULL
) {
669 *snaproot_len
= strlen(snapshot_path
);
670 if (config
->rel_connectpath
!= NULL
) {
672 strlen(config
->rel_connectpath
) + 1;
680 /* never reached ... */
683 connectlen
= strlen(handle
->conn
->connectpath
);
685 path
= talloc_strdup(mem_ctx
, handle
->conn
->connectpath
);
687 path
= talloc_asprintf(
688 mem_ctx
, "%s/%s", handle
->conn
->connectpath
, name
);
694 pathlen
= talloc_get_size(path
)-1;
696 if (!shadow_copy2_find_slashes(talloc_tos(), path
,
697 &slashes
, &num_slashes
)) {
701 insert
= shadow_copy2_insert_string(talloc_tos(), handle
, timestamp
);
702 if (insert
== NULL
) {
705 insertlen
= talloc_get_size(insert
)-1;
708 * Note: We deliberatly don't expensively initialize the
709 * array with talloc_zero here: Putting zero into
710 * converted[pathlen+insertlen] below is sufficient, because
711 * in the following for loop, the insert string is inserted
712 * at various slash places. So the memory up to position
713 * pathlen+insertlen will always be initialized when the
714 * converted string is used.
716 converted
= talloc_array(mem_ctx
, char, pathlen
+ insertlen
+ 1);
717 if (converted
== NULL
) {
721 if (path
[pathlen
-1] != '/') {
723 * Append a fake slash to find the snapshot root
726 tmp
= talloc_realloc(talloc_tos(), slashes
,
727 size_t, num_slashes
+1);
732 slashes
[num_slashes
] = pathlen
;
738 if (!config
->crossmountpoints
) {
739 min_offset
= strlen(config
->mount_point
);
742 memcpy(converted
, path
, pathlen
+1);
743 converted
[pathlen
+insertlen
] = '\0';
745 ZERO_STRUCT(converted_fname
);
746 converted_fname
.base_name
= converted
;
748 for (i
= num_slashes
-1; i
>=0; i
--) {
754 if (offset
< min_offset
) {
759 if (offset
>= connectlen
) {
760 in_share_offset
= offset
;
763 memcpy(converted
+offset
, insert
, insertlen
);
766 memcpy(converted
+offset
, path
+ slashes
[i
],
767 pathlen
- slashes
[i
]);
769 ret
= SMB_VFS_NEXT_LSTAT(handle
, &converted_fname
);
771 DEBUG(10, ("Trying[snapdirseverywhere] %s: %d (%s)\n",
773 ret
, ret
== 0 ? "ok" : strerror(errno
)));
776 if (snaproot_len
!= NULL
) {
777 *snaproot_len
= in_share_offset
+ insertlen
;
781 if (errno
== ENOTDIR
) {
783 * This is a valid condition: We appended the
784 * .snaphots/@GMT.. to a file name. Just try
785 * with the upper levels.
789 if (errno
!= ENOENT
) {
790 /* Other problem than "not found" */
799 DEBUG(10, ("Found %s\n", converted
));
806 if (result
== NULL
) {
809 TALLOC_FREE(converted
);
811 TALLOC_FREE(slashes
);
813 if (saved_errno
!= 0) {
820 * Convert from a name as handed in via the SMB layer
821 * and a timestamp into the local path of the snapshot
822 * of the provided file at the provided time.
824 static char *shadow_copy2_convert(TALLOC_CTX
*mem_ctx
,
825 struct vfs_handle_struct
*handle
,
826 const char *name
, time_t timestamp
)
828 return shadow_copy2_do_convert(mem_ctx
, handle
, name
, timestamp
, NULL
);
832 modify a sbuf return to ensure that inodes in the shadow directory
833 are different from those in the main directory
835 static void convert_sbuf(vfs_handle_struct
*handle
, const char *fname
,
836 SMB_STRUCT_STAT
*sbuf
)
838 struct shadow_copy2_config
*config
;
840 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
843 if (config
->fixinodes
) {
844 /* some snapshot systems, like GPFS, return the name
845 device:inode for the snapshot files as the current
846 files. That breaks the 'restore' button in the shadow copy
847 GUI, as the client gets a sharing violation.
849 This is a crude way of allowing both files to be
850 open at once. It has a slight chance of inode
851 number collision, but I can't see a better approach
852 without significant VFS changes
854 TDB_DATA key
= { .dptr
= discard_const_p(uint8_t, fname
),
855 .dsize
= strlen(fname
) };
858 shash
= tdb_jenkins_hash(&key
) & 0xFF000000;
862 sbuf
->st_ex_ino
^= shash
;
866 static DIR *shadow_copy2_opendir(vfs_handle_struct
*handle
,
871 time_t timestamp
= 0;
872 char *stripped
= NULL
;
877 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
878 ×tamp
, &stripped
)) {
881 if (timestamp
== 0) {
882 return SMB_VFS_NEXT_OPENDIR(handle
, fname
, mask
, attr
);
884 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
885 TALLOC_FREE(stripped
);
889 ret
= SMB_VFS_NEXT_OPENDIR(handle
, conv
, mask
, attr
);
894 if (saved_errno
!= 0) {
900 static int shadow_copy2_rename(vfs_handle_struct
*handle
,
901 const struct smb_filename
*smb_fname_src
,
902 const struct smb_filename
*smb_fname_dst
)
904 time_t timestamp_src
= 0;
905 time_t timestamp_dst
= 0;
906 char *snappath_src
= NULL
;
907 char *snappath_dst
= NULL
;
909 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle
,
910 smb_fname_src
->base_name
,
911 ×tamp_src
, NULL
, &snappath_src
)) {
914 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle
,
915 smb_fname_dst
->base_name
,
916 ×tamp_dst
, NULL
, &snappath_dst
)) {
919 if (timestamp_src
!= 0) {
923 if (timestamp_dst
!= 0) {
928 * Don't allow rename on already converted paths.
930 if (snappath_src
!= NULL
) {
934 if (snappath_dst
!= NULL
) {
938 return SMB_VFS_NEXT_RENAME(handle
, smb_fname_src
, smb_fname_dst
);
941 static int shadow_copy2_symlink(vfs_handle_struct
*handle
,
942 const char *oldname
, const char *newname
)
944 time_t timestamp_old
= 0;
945 time_t timestamp_new
= 0;
946 char *snappath_old
= NULL
;
947 char *snappath_new
= NULL
;
949 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle
, oldname
,
950 ×tamp_old
, NULL
, &snappath_old
)) {
953 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle
, newname
,
954 ×tamp_new
, NULL
, &snappath_new
)) {
957 if ((timestamp_old
!= 0) || (timestamp_new
!= 0)) {
962 * Don't allow symlinks on already converted paths.
964 if ((snappath_old
!= NULL
) || (snappath_new
!= NULL
)) {
968 return SMB_VFS_NEXT_SYMLINK(handle
, oldname
, newname
);
971 static int shadow_copy2_link(vfs_handle_struct
*handle
,
972 const char *oldname
, const char *newname
)
974 time_t timestamp_old
= 0;
975 time_t timestamp_new
= 0;
976 char *snappath_old
= NULL
;
977 char *snappath_new
= NULL
;
979 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle
, oldname
,
980 ×tamp_old
, NULL
, &snappath_old
)) {
983 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle
, newname
,
984 ×tamp_new
, NULL
, &snappath_new
)) {
987 if ((timestamp_old
!= 0) || (timestamp_new
!= 0)) {
992 * Don't allow links on already converted paths.
994 if ((snappath_old
!= NULL
) || (snappath_new
!= NULL
)) {
998 return SMB_VFS_NEXT_LINK(handle
, oldname
, newname
);
1001 static int shadow_copy2_stat(vfs_handle_struct
*handle
,
1002 struct smb_filename
*smb_fname
)
1004 time_t timestamp
= 0;
1005 char *stripped
= NULL
;
1007 int saved_errno
= 0;
1010 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
,
1011 smb_fname
->base_name
,
1012 ×tamp
, &stripped
)) {
1015 if (timestamp
== 0) {
1016 return SMB_VFS_NEXT_STAT(handle
, smb_fname
);
1019 tmp
= smb_fname
->base_name
;
1020 smb_fname
->base_name
= shadow_copy2_convert(
1021 talloc_tos(), handle
, stripped
, timestamp
);
1022 TALLOC_FREE(stripped
);
1024 if (smb_fname
->base_name
== NULL
) {
1025 smb_fname
->base_name
= tmp
;
1029 ret
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
1031 saved_errno
= errno
;
1034 TALLOC_FREE(smb_fname
->base_name
);
1035 smb_fname
->base_name
= tmp
;
1038 convert_sbuf(handle
, smb_fname
->base_name
, &smb_fname
->st
);
1040 if (saved_errno
!= 0) {
1041 errno
= saved_errno
;
1046 static int shadow_copy2_lstat(vfs_handle_struct
*handle
,
1047 struct smb_filename
*smb_fname
)
1049 time_t timestamp
= 0;
1050 char *stripped
= NULL
;
1052 int saved_errno
= 0;
1055 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
,
1056 smb_fname
->base_name
,
1057 ×tamp
, &stripped
)) {
1060 if (timestamp
== 0) {
1061 return SMB_VFS_NEXT_LSTAT(handle
, smb_fname
);
1064 tmp
= smb_fname
->base_name
;
1065 smb_fname
->base_name
= shadow_copy2_convert(
1066 talloc_tos(), handle
, stripped
, timestamp
);
1067 TALLOC_FREE(stripped
);
1069 if (smb_fname
->base_name
== NULL
) {
1070 smb_fname
->base_name
= tmp
;
1074 ret
= SMB_VFS_NEXT_LSTAT(handle
, smb_fname
);
1076 saved_errno
= errno
;
1079 TALLOC_FREE(smb_fname
->base_name
);
1080 smb_fname
->base_name
= tmp
;
1083 convert_sbuf(handle
, smb_fname
->base_name
, &smb_fname
->st
);
1085 if (saved_errno
!= 0) {
1086 errno
= saved_errno
;
1091 static int shadow_copy2_fstat(vfs_handle_struct
*handle
, files_struct
*fsp
,
1092 SMB_STRUCT_STAT
*sbuf
)
1094 time_t timestamp
= 0;
1097 ret
= SMB_VFS_NEXT_FSTAT(handle
, fsp
, sbuf
);
1101 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
,
1102 fsp
->fsp_name
->base_name
,
1103 ×tamp
, NULL
)) {
1106 if (timestamp
!= 0) {
1107 convert_sbuf(handle
, fsp
->fsp_name
->base_name
, sbuf
);
1112 static int shadow_copy2_open(vfs_handle_struct
*handle
,
1113 struct smb_filename
*smb_fname
, files_struct
*fsp
,
1114 int flags
, mode_t mode
)
1116 time_t timestamp
= 0;
1117 char *stripped
= NULL
;
1119 int saved_errno
= 0;
1122 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
,
1123 smb_fname
->base_name
,
1124 ×tamp
, &stripped
)) {
1127 if (timestamp
== 0) {
1128 return SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
1131 tmp
= smb_fname
->base_name
;
1132 smb_fname
->base_name
= shadow_copy2_convert(
1133 talloc_tos(), handle
, stripped
, timestamp
);
1134 TALLOC_FREE(stripped
);
1136 if (smb_fname
->base_name
== NULL
) {
1137 smb_fname
->base_name
= tmp
;
1141 ret
= SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
1143 saved_errno
= errno
;
1146 TALLOC_FREE(smb_fname
->base_name
);
1147 smb_fname
->base_name
= tmp
;
1149 if (saved_errno
!= 0) {
1150 errno
= saved_errno
;
1155 static int shadow_copy2_unlink(vfs_handle_struct
*handle
,
1156 const struct smb_filename
*smb_fname
)
1158 time_t timestamp
= 0;
1159 char *stripped
= NULL
;
1160 int saved_errno
= 0;
1162 struct smb_filename
*conv
;
1164 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
,
1165 smb_fname
->base_name
,
1166 ×tamp
, &stripped
)) {
1169 if (timestamp
== 0) {
1170 return SMB_VFS_NEXT_UNLINK(handle
, smb_fname
);
1172 conv
= cp_smb_filename(talloc_tos(), smb_fname
);
1177 conv
->base_name
= shadow_copy2_convert(
1178 conv
, handle
, stripped
, timestamp
);
1179 TALLOC_FREE(stripped
);
1180 if (conv
->base_name
== NULL
) {
1183 ret
= SMB_VFS_NEXT_UNLINK(handle
, conv
);
1185 saved_errno
= errno
;
1188 if (saved_errno
!= 0) {
1189 errno
= saved_errno
;
1194 static int shadow_copy2_chmod(vfs_handle_struct
*handle
, const char *fname
,
1197 time_t timestamp
= 0;
1198 char *stripped
= NULL
;
1199 int saved_errno
= 0;
1203 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1204 ×tamp
, &stripped
)) {
1207 if (timestamp
== 0) {
1208 return SMB_VFS_NEXT_CHMOD(handle
, fname
, mode
);
1210 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1211 TALLOC_FREE(stripped
);
1215 ret
= SMB_VFS_NEXT_CHMOD(handle
, conv
, mode
);
1217 saved_errno
= errno
;
1220 if (saved_errno
!= 0) {
1221 errno
= saved_errno
;
1226 static int shadow_copy2_chown(vfs_handle_struct
*handle
, const char *fname
,
1227 uid_t uid
, gid_t gid
)
1229 time_t timestamp
= 0;
1230 char *stripped
= NULL
;
1231 int saved_errno
= 0;
1235 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1236 ×tamp
, &stripped
)) {
1239 if (timestamp
== 0) {
1240 return SMB_VFS_NEXT_CHOWN(handle
, fname
, uid
, gid
);
1242 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1243 TALLOC_FREE(stripped
);
1247 ret
= SMB_VFS_NEXT_CHOWN(handle
, conv
, uid
, gid
);
1249 saved_errno
= errno
;
1252 if (saved_errno
!= 0) {
1253 errno
= saved_errno
;
1258 static void store_cwd_data(vfs_handle_struct
*handle
,
1259 const char *connectpath
)
1261 struct shadow_copy2_config
*config
= NULL
;
1264 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
1267 TALLOC_FREE(config
->shadow_cwd
);
1268 cwd
= SMB_VFS_NEXT_GETWD(handle
);
1270 smb_panic("getwd failed\n");
1272 DBG_DEBUG("shadow cwd = %s\n", cwd
);
1273 config
->shadow_cwd
= talloc_strdup(config
, cwd
);
1275 if (config
->shadow_cwd
== NULL
) {
1276 smb_panic("talloc failed\n");
1278 TALLOC_FREE(config
->shadow_connectpath
);
1280 DBG_DEBUG("shadow conectpath = %s\n", connectpath
);
1281 config
->shadow_connectpath
= talloc_strdup(config
, connectpath
);
1282 if (config
->shadow_connectpath
== NULL
) {
1283 smb_panic("talloc failed\n");
1288 static int shadow_copy2_chdir(vfs_handle_struct
*handle
,
1291 time_t timestamp
= 0;
1292 char *stripped
= NULL
;
1293 char *snappath
= NULL
;
1295 int saved_errno
= 0;
1297 size_t rootpath_len
= 0;
1299 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle
, fname
,
1300 ×tamp
, &stripped
, &snappath
)) {
1303 if (stripped
!= NULL
) {
1304 conv
= shadow_copy2_do_convert(talloc_tos(),
1309 TALLOC_FREE(stripped
);
1316 ret
= SMB_VFS_NEXT_CHDIR(handle
, fname
);
1318 saved_errno
= errno
;
1322 if (conv
!= NULL
&& rootpath_len
!= 0) {
1323 conv
[rootpath_len
] = '\0';
1324 } else if (snappath
!= 0) {
1328 store_cwd_data(handle
, conv
);
1331 TALLOC_FREE(stripped
);
1334 if (saved_errno
!= 0) {
1335 errno
= saved_errno
;
1340 static int shadow_copy2_ntimes(vfs_handle_struct
*handle
,
1341 const struct smb_filename
*smb_fname
,
1342 struct smb_file_time
*ft
)
1344 time_t timestamp
= 0;
1345 char *stripped
= NULL
;
1346 int saved_errno
= 0;
1348 struct smb_filename
*conv
;
1350 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
,
1351 smb_fname
->base_name
,
1352 ×tamp
, &stripped
)) {
1355 if (timestamp
== 0) {
1356 return SMB_VFS_NEXT_NTIMES(handle
, smb_fname
, ft
);
1358 conv
= cp_smb_filename(talloc_tos(), smb_fname
);
1363 conv
->base_name
= shadow_copy2_convert(
1364 conv
, handle
, stripped
, timestamp
);
1365 TALLOC_FREE(stripped
);
1366 if (conv
->base_name
== NULL
) {
1369 ret
= SMB_VFS_NEXT_NTIMES(handle
, conv
, ft
);
1371 saved_errno
= errno
;
1374 if (saved_errno
!= 0) {
1375 errno
= saved_errno
;
1380 static int shadow_copy2_readlink(vfs_handle_struct
*handle
,
1381 const char *fname
, char *buf
, size_t bufsiz
)
1383 time_t timestamp
= 0;
1384 char *stripped
= NULL
;
1385 int saved_errno
= 0;
1389 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1390 ×tamp
, &stripped
)) {
1393 if (timestamp
== 0) {
1394 return SMB_VFS_NEXT_READLINK(handle
, fname
, buf
, bufsiz
);
1396 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1397 TALLOC_FREE(stripped
);
1401 ret
= SMB_VFS_NEXT_READLINK(handle
, conv
, buf
, bufsiz
);
1403 saved_errno
= errno
;
1406 if (saved_errno
!= 0) {
1407 errno
= saved_errno
;
1412 static int shadow_copy2_mknod(vfs_handle_struct
*handle
,
1413 const char *fname
, mode_t mode
, SMB_DEV_T dev
)
1415 time_t timestamp
= 0;
1416 char *stripped
= NULL
;
1417 int saved_errno
= 0;
1421 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1422 ×tamp
, &stripped
)) {
1425 if (timestamp
== 0) {
1426 return SMB_VFS_NEXT_MKNOD(handle
, fname
, mode
, dev
);
1428 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1429 TALLOC_FREE(stripped
);
1433 ret
= SMB_VFS_NEXT_MKNOD(handle
, conv
, mode
, dev
);
1435 saved_errno
= errno
;
1438 if (saved_errno
!= 0) {
1439 errno
= saved_errno
;
1444 static char *shadow_copy2_realpath(vfs_handle_struct
*handle
,
1447 time_t timestamp
= 0;
1448 char *stripped
= NULL
;
1450 char *result
= NULL
;
1451 int saved_errno
= 0;
1453 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1454 ×tamp
, &stripped
)) {
1457 if (timestamp
== 0) {
1458 return SMB_VFS_NEXT_REALPATH(handle
, fname
);
1461 tmp
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1466 result
= SMB_VFS_NEXT_REALPATH(handle
, tmp
);
1469 if (result
== NULL
) {
1470 saved_errno
= errno
;
1473 TALLOC_FREE(stripped
);
1474 if (saved_errno
!= 0) {
1475 errno
= saved_errno
;
1481 * Check whether a given directory contains a
1482 * snapshot directory as direct subdirectory.
1483 * If yes, return the path of the snapshot-subdir,
1484 * otherwise return NULL.
1486 static char *have_snapdir(struct vfs_handle_struct
*handle
,
1489 struct smb_filename smb_fname
;
1491 struct shadow_copy2_config
*config
;
1493 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
1496 ZERO_STRUCT(smb_fname
);
1497 smb_fname
.base_name
= talloc_asprintf(talloc_tos(), "%s/%s",
1498 path
, config
->snapdir
);
1499 if (smb_fname
.base_name
== NULL
) {
1503 ret
= SMB_VFS_NEXT_STAT(handle
, &smb_fname
);
1504 if ((ret
== 0) && (S_ISDIR(smb_fname
.st
.st_ex_mode
))) {
1505 return smb_fname
.base_name
;
1507 TALLOC_FREE(smb_fname
.base_name
);
1511 static bool check_access_snapdir(struct vfs_handle_struct
*handle
,
1514 struct smb_filename smb_fname
;
1518 ZERO_STRUCT(smb_fname
);
1519 smb_fname
.base_name
= talloc_asprintf(talloc_tos(),
1522 if (smb_fname
.base_name
== NULL
) {
1526 ret
= SMB_VFS_NEXT_STAT(handle
, &smb_fname
);
1527 if (ret
!= 0 || !S_ISDIR(smb_fname
.st
.st_ex_mode
)) {
1528 TALLOC_FREE(smb_fname
.base_name
);
1532 status
= smbd_check_access_rights(handle
->conn
,
1536 if (!NT_STATUS_IS_OK(status
)) {
1537 DEBUG(0,("user does not have list permission "
1539 smb_fname
.base_name
));
1540 TALLOC_FREE(smb_fname
.base_name
);
1543 TALLOC_FREE(smb_fname
.base_name
);
1548 * Find the snapshot directory (if any) for the given
1549 * filename (which is relative to the share).
1551 static const char *shadow_copy2_find_snapdir(TALLOC_CTX
*mem_ctx
,
1552 struct vfs_handle_struct
*handle
,
1553 struct smb_filename
*smb_fname
)
1556 const char *snapdir
;
1557 struct shadow_copy2_config
*config
;
1559 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
1563 * If the non-snapdisrseverywhere mode, we should not search!
1565 if (!config
->snapdirseverywhere
) {
1566 return config
->snapshot_basepath
;
1569 path
= talloc_asprintf(mem_ctx
, "%s/%s",
1570 handle
->conn
->connectpath
,
1571 smb_fname
->base_name
);
1576 snapdir
= have_snapdir(handle
, path
);
1577 if (snapdir
!= NULL
) {
1582 while ((p
= strrchr(path
, '/')) && (p
> path
)) {
1586 snapdir
= have_snapdir(handle
, path
);
1587 if (snapdir
!= NULL
) {
1596 static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct
*handle
,
1598 char *gmt
, size_t gmt_len
)
1600 struct tm timestamp
;
1602 unsigned long int timestamp_long
;
1604 struct shadow_copy2_config
*config
;
1606 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
1609 fmt
= config
->gmt_format
;
1611 ZERO_STRUCT(timestamp
);
1612 if (config
->use_sscanf
) {
1613 if (sscanf(name
, fmt
, ×tamp_long
) != 1) {
1614 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1615 "no sscanf match %s: %s\n",
1619 timestamp_t
= timestamp_long
;
1620 gmtime_r(×tamp_t
, ×tamp
);
1622 if (strptime(name
, fmt
, ×tamp
) == NULL
) {
1623 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1624 "no match %s: %s\n",
1628 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n",
1631 if (config
->use_localtime
) {
1632 timestamp
.tm_isdst
= -1;
1633 timestamp_t
= mktime(×tamp
);
1634 gmtime_r(×tamp_t
, ×tamp
);
1638 strftime(gmt
, gmt_len
, GMT_FORMAT
, ×tamp
);
1642 static int shadow_copy2_label_cmp_asc(const void *x
, const void *y
)
1644 return strncmp((const char *)x
, (const char *)y
, sizeof(SHADOW_COPY_LABEL
));
1647 static int shadow_copy2_label_cmp_desc(const void *x
, const void *y
)
1649 return -strncmp((const char *)x
, (const char *)y
, sizeof(SHADOW_COPY_LABEL
));
1653 sort the shadow copy data in ascending or descending order
1655 static void shadow_copy2_sort_data(vfs_handle_struct
*handle
,
1656 struct shadow_copy_data
*shadow_copy2_data
)
1658 int (*cmpfunc
)(const void *, const void *);
1660 struct shadow_copy2_config
*config
;
1662 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
1665 sort
= config
->sort_order
;
1670 if (strcmp(sort
, "asc") == 0) {
1671 cmpfunc
= shadow_copy2_label_cmp_asc
;
1672 } else if (strcmp(sort
, "desc") == 0) {
1673 cmpfunc
= shadow_copy2_label_cmp_desc
;
1678 if (shadow_copy2_data
&& shadow_copy2_data
->num_volumes
> 0 &&
1679 shadow_copy2_data
->labels
)
1681 TYPESAFE_QSORT(shadow_copy2_data
->labels
,
1682 shadow_copy2_data
->num_volumes
,
1687 static int shadow_copy2_get_shadow_copy_data(
1688 vfs_handle_struct
*handle
, files_struct
*fsp
,
1689 struct shadow_copy_data
*shadow_copy2_data
,
1693 const char *snapdir
;
1695 TALLOC_CTX
*tmp_ctx
= talloc_stackframe();
1698 snapdir
= shadow_copy2_find_snapdir(tmp_ctx
, handle
, fsp
->fsp_name
);
1699 if (snapdir
== NULL
) {
1700 DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
1701 handle
->conn
->connectpath
));
1703 talloc_free(tmp_ctx
);
1706 ret
= check_access_snapdir(handle
, snapdir
);
1708 DEBUG(0,("access denied on listing snapdir %s\n", snapdir
));
1710 talloc_free(tmp_ctx
);
1714 p
= SMB_VFS_NEXT_OPENDIR(handle
, snapdir
, NULL
, 0);
1717 DEBUG(2,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s'"
1718 " - %s\n", snapdir
, strerror(errno
)));
1719 talloc_free(tmp_ctx
);
1724 shadow_copy2_data
->num_volumes
= 0;
1725 shadow_copy2_data
->labels
= NULL
;
1727 while ((d
= SMB_VFS_NEXT_READDIR(handle
, p
, NULL
))) {
1728 char snapshot
[GMT_NAME_LEN
+1];
1729 SHADOW_COPY_LABEL
*tlabels
;
1732 * ignore names not of the right form in the snapshot
1735 if (!shadow_copy2_snapshot_to_gmt(
1737 snapshot
, sizeof(snapshot
))) {
1739 DEBUG(6, ("shadow_copy2_get_shadow_copy_data: "
1740 "ignoring %s\n", d
->d_name
));
1743 DEBUG(6,("shadow_copy2_get_shadow_copy_data: %s -> %s\n",
1744 d
->d_name
, snapshot
));
1747 /* the caller doesn't want the labels */
1748 shadow_copy2_data
->num_volumes
++;
1752 tlabels
= talloc_realloc(shadow_copy2_data
,
1753 shadow_copy2_data
->labels
,
1755 shadow_copy2_data
->num_volumes
+1);
1756 if (tlabels
== NULL
) {
1757 DEBUG(0,("shadow_copy2: out of memory\n"));
1758 SMB_VFS_NEXT_CLOSEDIR(handle
, p
);
1759 talloc_free(tmp_ctx
);
1763 strlcpy(tlabels
[shadow_copy2_data
->num_volumes
], snapshot
,
1766 shadow_copy2_data
->num_volumes
++;
1767 shadow_copy2_data
->labels
= tlabels
;
1770 SMB_VFS_NEXT_CLOSEDIR(handle
,p
);
1772 shadow_copy2_sort_data(handle
, shadow_copy2_data
);
1774 talloc_free(tmp_ctx
);
1778 static NTSTATUS
shadow_copy2_fget_nt_acl(vfs_handle_struct
*handle
,
1779 struct files_struct
*fsp
,
1780 uint32_t security_info
,
1781 TALLOC_CTX
*mem_ctx
,
1782 struct security_descriptor
**ppdesc
)
1784 time_t timestamp
= 0;
1785 char *stripped
= NULL
;
1789 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
,
1790 fsp
->fsp_name
->base_name
,
1791 ×tamp
, &stripped
)) {
1792 return map_nt_error_from_unix(errno
);
1794 if (timestamp
== 0) {
1795 return SMB_VFS_NEXT_FGET_NT_ACL(handle
, fsp
, security_info
,
1799 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1800 TALLOC_FREE(stripped
);
1802 return map_nt_error_from_unix(errno
);
1804 status
= SMB_VFS_NEXT_GET_NT_ACL(handle
, conv
, security_info
,
1810 static NTSTATUS
shadow_copy2_get_nt_acl(vfs_handle_struct
*handle
,
1812 uint32_t security_info
,
1813 TALLOC_CTX
*mem_ctx
,
1814 struct security_descriptor
**ppdesc
)
1816 time_t timestamp
= 0;
1817 char *stripped
= NULL
;
1821 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1822 ×tamp
, &stripped
)) {
1823 return map_nt_error_from_unix(errno
);
1825 if (timestamp
== 0) {
1826 return SMB_VFS_NEXT_GET_NT_ACL(handle
, fname
, security_info
,
1829 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1830 TALLOC_FREE(stripped
);
1832 return map_nt_error_from_unix(errno
);
1834 status
= SMB_VFS_NEXT_GET_NT_ACL(handle
, conv
, security_info
,
1840 static int shadow_copy2_mkdir(vfs_handle_struct
*handle
,
1841 const char *fname
, mode_t mode
)
1843 time_t timestamp
= 0;
1844 char *stripped
= NULL
;
1845 int saved_errno
= 0;
1849 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1850 ×tamp
, &stripped
)) {
1853 if (timestamp
== 0) {
1854 return SMB_VFS_NEXT_MKDIR(handle
, fname
, mode
);
1856 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1857 TALLOC_FREE(stripped
);
1861 ret
= SMB_VFS_NEXT_MKDIR(handle
, conv
, mode
);
1863 saved_errno
= errno
;
1866 if (saved_errno
!= 0) {
1867 errno
= saved_errno
;
1872 static int shadow_copy2_rmdir(vfs_handle_struct
*handle
, const char *fname
)
1874 time_t timestamp
= 0;
1875 char *stripped
= NULL
;
1876 int saved_errno
= 0;
1880 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1881 ×tamp
, &stripped
)) {
1884 if (timestamp
== 0) {
1885 return SMB_VFS_NEXT_RMDIR(handle
, fname
);
1887 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1888 TALLOC_FREE(stripped
);
1892 ret
= SMB_VFS_NEXT_RMDIR(handle
, conv
);
1894 saved_errno
= errno
;
1897 if (saved_errno
!= 0) {
1898 errno
= saved_errno
;
1903 static int shadow_copy2_chflags(vfs_handle_struct
*handle
, const char *fname
,
1906 time_t timestamp
= 0;
1907 char *stripped
= NULL
;
1908 int saved_errno
= 0;
1912 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1913 ×tamp
, &stripped
)) {
1916 if (timestamp
== 0) {
1917 return SMB_VFS_NEXT_CHFLAGS(handle
, fname
, flags
);
1919 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1920 TALLOC_FREE(stripped
);
1924 ret
= SMB_VFS_NEXT_CHFLAGS(handle
, conv
, flags
);
1926 saved_errno
= errno
;
1929 if (saved_errno
!= 0) {
1930 errno
= saved_errno
;
1935 static ssize_t
shadow_copy2_getxattr(vfs_handle_struct
*handle
,
1936 const char *fname
, const char *aname
,
1937 void *value
, size_t size
)
1939 time_t timestamp
= 0;
1940 char *stripped
= NULL
;
1942 int saved_errno
= 0;
1945 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1946 ×tamp
, &stripped
)) {
1949 if (timestamp
== 0) {
1950 return SMB_VFS_NEXT_GETXATTR(handle
, fname
, aname
, value
,
1953 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1954 TALLOC_FREE(stripped
);
1958 ret
= SMB_VFS_NEXT_GETXATTR(handle
, conv
, aname
, value
, size
);
1960 saved_errno
= errno
;
1963 if (saved_errno
!= 0) {
1964 errno
= saved_errno
;
1969 static ssize_t
shadow_copy2_listxattr(struct vfs_handle_struct
*handle
,
1971 char *list
, size_t size
)
1973 time_t timestamp
= 0;
1974 char *stripped
= NULL
;
1976 int saved_errno
= 0;
1979 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1980 ×tamp
, &stripped
)) {
1983 if (timestamp
== 0) {
1984 return SMB_VFS_NEXT_LISTXATTR(handle
, fname
, list
, size
);
1986 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1987 TALLOC_FREE(stripped
);
1991 ret
= SMB_VFS_NEXT_LISTXATTR(handle
, conv
, list
, size
);
1993 saved_errno
= errno
;
1996 if (saved_errno
!= 0) {
1997 errno
= saved_errno
;
2002 static int shadow_copy2_removexattr(vfs_handle_struct
*handle
,
2003 const char *fname
, const char *aname
)
2005 time_t timestamp
= 0;
2006 char *stripped
= NULL
;
2007 int saved_errno
= 0;
2011 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
2012 ×tamp
, &stripped
)) {
2015 if (timestamp
== 0) {
2016 return SMB_VFS_NEXT_REMOVEXATTR(handle
, fname
, aname
);
2018 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
2019 TALLOC_FREE(stripped
);
2023 ret
= SMB_VFS_NEXT_REMOVEXATTR(handle
, conv
, aname
);
2025 saved_errno
= errno
;
2028 if (saved_errno
!= 0) {
2029 errno
= saved_errno
;
2034 static int shadow_copy2_setxattr(struct vfs_handle_struct
*handle
,
2036 const char *aname
, const void *value
,
2037 size_t size
, int flags
)
2039 time_t timestamp
= 0;
2040 char *stripped
= NULL
;
2042 int saved_errno
= 0;
2045 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
2046 ×tamp
, &stripped
)) {
2049 if (timestamp
== 0) {
2050 return SMB_VFS_NEXT_SETXATTR(handle
, fname
, aname
, value
, size
,
2053 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
2054 TALLOC_FREE(stripped
);
2058 ret
= SMB_VFS_NEXT_SETXATTR(handle
, conv
, aname
, value
, size
, flags
);
2060 saved_errno
= errno
;
2063 if (saved_errno
!= 0) {
2064 errno
= saved_errno
;
2069 static int shadow_copy2_chmod_acl(vfs_handle_struct
*handle
,
2070 const char *fname
, mode_t mode
)
2072 time_t timestamp
= 0;
2073 char *stripped
= NULL
;
2075 int saved_errno
= 0;
2078 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
2079 ×tamp
, &stripped
)) {
2082 if (timestamp
== 0) {
2083 return SMB_VFS_NEXT_CHMOD_ACL(handle
, fname
, mode
);
2085 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
2086 TALLOC_FREE(stripped
);
2090 ret
= SMB_VFS_NEXT_CHMOD_ACL(handle
, conv
, mode
);
2092 saved_errno
= errno
;
2095 if (saved_errno
!= 0) {
2096 errno
= saved_errno
;
2101 static int shadow_copy2_get_real_filename(struct vfs_handle_struct
*handle
,
2104 TALLOC_CTX
*mem_ctx
,
2107 time_t timestamp
= 0;
2108 char *stripped
= NULL
;
2110 int saved_errno
= 0;
2113 DEBUG(10, ("shadow_copy2_get_real_filename called for path=[%s], "
2114 "name=[%s]\n", path
, name
));
2116 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, path
,
2117 ×tamp
, &stripped
)) {
2118 DEBUG(10, ("shadow_copy2_strip_snapshot failed\n"));
2121 if (timestamp
== 0) {
2122 DEBUG(10, ("timestamp == 0\n"));
2123 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle
, path
, name
,
2124 mem_ctx
, found_name
);
2126 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
2127 TALLOC_FREE(stripped
);
2129 DEBUG(10, ("shadow_copy2_convert failed\n"));
2132 DEBUG(10, ("Calling NEXT_GET_REAL_FILE_NAME for conv=[%s], "
2133 "name=[%s]\n", conv
, name
));
2134 ret
= SMB_VFS_NEXT_GET_REAL_FILENAME(handle
, conv
, name
,
2135 mem_ctx
, found_name
);
2136 DEBUG(10, ("NEXT_REAL_FILE_NAME returned %d\n", (int)ret
));
2138 saved_errno
= errno
;
2141 if (saved_errno
!= 0) {
2142 errno
= saved_errno
;
2147 static const char *shadow_copy2_connectpath(struct vfs_handle_struct
*handle
,
2150 time_t timestamp
= 0;
2151 char *stripped
= NULL
;
2153 char *result
= NULL
;
2154 char *parent_dir
= NULL
;
2155 int saved_errno
= 0;
2156 size_t rootpath_len
= 0;
2157 struct shadow_copy2_config
*config
= NULL
;
2159 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
2162 DBG_DEBUG("Calc connect path for [%s]\n", fname
);
2164 if (config
->shadow_connectpath
!= NULL
) {
2165 DBG_DEBUG("cached connect path is [%s]\n",
2166 config
->shadow_connectpath
);
2167 return config
->shadow_connectpath
;
2170 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
2171 ×tamp
, &stripped
)) {
2174 if (timestamp
== 0) {
2175 return SMB_VFS_NEXT_CONNECTPATH(handle
, fname
);
2178 tmp
= shadow_copy2_do_convert(talloc_tos(), handle
, stripped
, timestamp
,
2181 if (errno
!= ENOENT
) {
2186 * If the converted path does not exist, and converting
2187 * the parent yields something that does exist, then
2188 * this path refers to something that has not been
2189 * created yet, relative to the parent path.
2190 * The snapshot finding is relative to the parent.
2191 * (usually snapshots are read/only but this is not
2192 * necessarily true).
2193 * This code also covers getting a wildcard in the
2194 * last component, because this function is called
2195 * prior to sanitizing the path, and in SMB1 we may
2196 * get wildcards in path names.
2198 if (!parent_dirname(talloc_tos(), stripped
, &parent_dir
,
2204 tmp
= shadow_copy2_do_convert(talloc_tos(), handle
, parent_dir
,
2205 timestamp
, &rootpath_len
);
2211 DBG_DEBUG("converted path is [%s] root path is [%.*s]\n", tmp
,
2212 (int)rootpath_len
, tmp
);
2214 tmp
[rootpath_len
] = '\0';
2215 result
= SMB_VFS_NEXT_REALPATH(handle
, tmp
);
2216 if (result
== NULL
) {
2221 * SMB_VFS_NEXT_REALPATH returns a malloc'ed string.
2222 * Don't leak memory.
2224 SAFE_FREE(config
->shadow_realpath
);
2225 config
->shadow_realpath
= result
;
2227 DBG_DEBUG("connect path is [%s]\n", result
);
2230 if (result
== NULL
) {
2231 saved_errno
= errno
;
2234 TALLOC_FREE(stripped
);
2235 TALLOC_FREE(parent_dir
);
2236 if (saved_errno
!= 0) {
2237 errno
= saved_errno
;
2242 static uint64_t shadow_copy2_disk_free(vfs_handle_struct
*handle
,
2243 const char *path
, uint64_t *bsize
,
2244 uint64_t *dfree
, uint64_t *dsize
)
2246 time_t timestamp
= 0;
2247 char *stripped
= NULL
;
2249 int saved_errno
= 0;
2252 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, path
,
2253 ×tamp
, &stripped
)) {
2256 if (timestamp
== 0) {
2257 return SMB_VFS_NEXT_DISK_FREE(handle
, path
,
2258 bsize
, dfree
, dsize
);
2261 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
2262 TALLOC_FREE(stripped
);
2267 ret
= SMB_VFS_NEXT_DISK_FREE(handle
, conv
, bsize
, dfree
, dsize
);
2270 saved_errno
= errno
;
2273 if (saved_errno
!= 0) {
2274 errno
= saved_errno
;
2280 static int shadow_copy2_get_quota(vfs_handle_struct
*handle
, const char *path
,
2281 enum SMB_QUOTA_TYPE qtype
, unid_t id
,
2284 time_t timestamp
= 0;
2285 char *stripped
= NULL
;
2287 int saved_errno
= 0;
2290 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, path
, ×tamp
,
2294 if (timestamp
== 0) {
2295 return SMB_VFS_NEXT_GET_QUOTA(handle
, path
, qtype
, id
, dq
);
2298 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
2299 TALLOC_FREE(stripped
);
2304 ret
= SMB_VFS_NEXT_GET_QUOTA(handle
, conv
, qtype
, id
, dq
);
2307 saved_errno
= errno
;
2310 if (saved_errno
!= 0) {
2311 errno
= saved_errno
;
2317 static int shadow_copy2_config_destructor(struct shadow_copy2_config
*config
)
2319 SAFE_FREE(config
->shadow_realpath
);
2323 static int shadow_copy2_connect(struct vfs_handle_struct
*handle
,
2324 const char *service
, const char *user
)
2326 struct shadow_copy2_config
*config
;
2328 const char *snapdir
;
2329 const char *gmt_format
;
2330 const char *sort_order
;
2331 const char *basedir
= NULL
;
2332 const char *snapsharepath
= NULL
;
2333 const char *mount_point
;
2335 DEBUG(10, (__location__
": cnum[%u], connectpath[%s]\n",
2336 (unsigned)handle
->conn
->cnum
,
2337 handle
->conn
->connectpath
));
2339 ret
= SMB_VFS_NEXT_CONNECT(handle
, service
, user
);
2344 config
= talloc_zero(handle
->conn
, struct shadow_copy2_config
);
2345 if (config
== NULL
) {
2346 DEBUG(0, ("talloc_zero() failed\n"));
2351 talloc_set_destructor(config
, shadow_copy2_config_destructor
);
2353 gmt_format
= lp_parm_const_string(SNUM(handle
->conn
),
2356 config
->gmt_format
= talloc_strdup(config
, gmt_format
);
2357 if (config
->gmt_format
== NULL
) {
2358 DEBUG(0, ("talloc_strdup() failed\n"));
2363 /* config->gmt_format must not contain a path separator. */
2364 if (strchr(config
->gmt_format
, '/') != NULL
) {
2365 DEBUG(0, ("shadow:format %s must not contain a /"
2366 "character. Unable to initialize module.\n",
2367 config
->gmt_format
));
2372 config
->use_sscanf
= lp_parm_bool(SNUM(handle
->conn
),
2373 "shadow", "sscanf", false);
2375 config
->use_localtime
= lp_parm_bool(SNUM(handle
->conn
),
2376 "shadow", "localtime",
2379 snapdir
= lp_parm_const_string(SNUM(handle
->conn
),
2380 "shadow", "snapdir",
2382 config
->snapdir
= talloc_strdup(config
, snapdir
);
2383 if (config
->snapdir
== NULL
) {
2384 DEBUG(0, ("talloc_strdup() failed\n"));
2389 config
->snapdirseverywhere
= lp_parm_bool(SNUM(handle
->conn
),
2391 "snapdirseverywhere",
2394 config
->crossmountpoints
= lp_parm_bool(SNUM(handle
->conn
),
2395 "shadow", "crossmountpoints",
2398 if (config
->crossmountpoints
&& !config
->snapdirseverywhere
) {
2399 DBG_WARNING("Warning: 'crossmountpoints' depends on "
2400 "'snapdirseverywhere'. Disabling crossmountpoints.\n");
2403 config
->fixinodes
= lp_parm_bool(SNUM(handle
->conn
),
2404 "shadow", "fixinodes",
2407 sort_order
= lp_parm_const_string(SNUM(handle
->conn
),
2408 "shadow", "sort", "desc");
2409 config
->sort_order
= talloc_strdup(config
, sort_order
);
2410 if (config
->sort_order
== NULL
) {
2411 DEBUG(0, ("talloc_strdup() failed\n"));
2416 mount_point
= lp_parm_const_string(SNUM(handle
->conn
),
2417 "shadow", "mountpoint", NULL
);
2418 if (mount_point
!= NULL
) {
2419 if (mount_point
[0] != '/') {
2420 DEBUG(1, (__location__
" Warning: 'mountpoint' is "
2421 "relative ('%s'), but it has to be an "
2422 "absolute path. Ignoring provided value.\n",
2427 p
= strstr(handle
->conn
->connectpath
, mount_point
);
2428 if (p
!= handle
->conn
->connectpath
) {
2429 DBG_WARNING("Warning: the share root (%s) is "
2430 "not a subdirectory of the "
2431 "specified mountpoint (%s). "
2432 "Ignoring provided value.\n",
2433 handle
->conn
->connectpath
,
2440 if (mount_point
!= NULL
) {
2441 config
->mount_point
= talloc_strdup(config
, mount_point
);
2442 if (config
->mount_point
== NULL
) {
2443 DEBUG(0, (__location__
" talloc_strdup() failed\n"));
2447 config
->mount_point
= shadow_copy2_find_mount_point(config
,
2449 if (config
->mount_point
== NULL
) {
2450 DBG_WARNING("shadow_copy2_find_mount_point "
2451 "of the share root '%s' failed: %s\n",
2452 handle
->conn
->connectpath
, strerror(errno
));
2457 basedir
= lp_parm_const_string(SNUM(handle
->conn
),
2458 "shadow", "basedir", NULL
);
2460 if (basedir
!= NULL
) {
2461 if (basedir
[0] != '/') {
2462 DEBUG(1, (__location__
" Warning: 'basedir' is "
2463 "relative ('%s'), but it has to be an "
2464 "absolute path. Disabling basedir.\n",
2469 p
= strstr(basedir
, config
->mount_point
);
2471 DEBUG(1, ("Warning: basedir (%s) is not a "
2472 "subdirectory of the share root's "
2473 "mount point (%s). "
2474 "Disabling basedir\n",
2475 basedir
, config
->mount_point
));
2481 if (config
->snapdirseverywhere
&& basedir
!= NULL
) {
2482 DEBUG(1, (__location__
" Warning: 'basedir' is incompatible "
2483 "with 'snapdirseverywhere'. Disabling basedir.\n"));
2487 snapsharepath
= lp_parm_const_string(SNUM(handle
->conn
), "shadow",
2488 "snapsharepath", NULL
);
2489 if (snapsharepath
!= NULL
) {
2490 if (snapsharepath
[0] == '/') {
2491 DBG_WARNING("Warning: 'snapsharepath' is "
2492 "absolute ('%s'), but it has to be a "
2493 "relative path. Disabling snapsharepath.\n",
2495 snapsharepath
= NULL
;
2497 if (config
->snapdirseverywhere
&& snapsharepath
!= NULL
) {
2498 DBG_WARNING("Warning: 'snapsharepath' is incompatible "
2499 "with 'snapdirseverywhere'. Disabling "
2500 "snapsharepath.\n");
2501 snapsharepath
= NULL
;
2505 if (basedir
!= NULL
&& snapsharepath
!= NULL
) {
2506 DBG_WARNING("Warning: 'snapsharepath' is incompatible with "
2507 "'basedir'. Disabling snapsharepath\n");
2508 snapsharepath
= NULL
;
2511 if (snapsharepath
!= NULL
) {
2512 config
->rel_connectpath
= talloc_strdup(config
, snapsharepath
);
2513 if (config
->rel_connectpath
== NULL
) {
2514 DBG_ERR("talloc_strdup() failed\n");
2520 if (basedir
== NULL
) {
2521 basedir
= config
->mount_point
;
2524 if (config
->rel_connectpath
== NULL
&&
2525 strlen(basedir
) < strlen(handle
->conn
->connectpath
)) {
2526 config
->rel_connectpath
= talloc_strdup(config
,
2527 handle
->conn
->connectpath
+ strlen(basedir
));
2528 if (config
->rel_connectpath
== NULL
) {
2529 DEBUG(0, ("talloc_strdup() failed\n"));
2535 if (config
->snapdir
[0] == '/') {
2536 config
->snapdir_absolute
= true;
2538 if (config
->snapdirseverywhere
== true) {
2539 DEBUG(1, (__location__
" Warning: An absolute snapdir "
2540 "is incompatible with 'snapdirseverywhere', "
2541 "setting 'snapdirseverywhere' to false.\n"));
2542 config
->snapdirseverywhere
= false;
2545 if (config
->crossmountpoints
== true) {
2546 DEBUG(1, (__location__
" Warning: 'crossmountpoints' "
2547 "is not supported with an absolute snapdir. "
2548 "Disabling it.\n"));
2549 config
->crossmountpoints
= false;
2552 config
->snapshot_basepath
= config
->snapdir
;
2554 config
->snapshot_basepath
= talloc_asprintf(config
, "%s/%s",
2555 config
->mount_point
, config
->snapdir
);
2556 if (config
->snapshot_basepath
== NULL
) {
2557 DEBUG(0, ("talloc_asprintf() failed\n"));
2563 trim_string(config
->mount_point
, NULL
, "/");
2564 trim_string(config
->rel_connectpath
, "/", "/");
2565 trim_string(config
->snapdir
, NULL
, "/");
2566 trim_string(config
->snapshot_basepath
, NULL
, "/");
2568 DEBUG(10, ("shadow_copy2_connect: configuration:\n"
2569 " share root: '%s'\n"
2570 " mountpoint: '%s'\n"
2571 " rel share root: '%s'\n"
2573 " snapshot base path: '%s'\n"
2576 " snapdirs everywhere: %s\n"
2577 " cross mountpoints: %s\n"
2581 handle
->conn
->connectpath
,
2582 config
->mount_point
,
2583 config
->rel_connectpath
,
2585 config
->snapshot_basepath
,
2587 config
->use_sscanf
? "yes" : "no",
2588 config
->snapdirseverywhere
? "yes" : "no",
2589 config
->crossmountpoints
? "yes" : "no",
2590 config
->fixinodes
? "yes" : "no",
2595 SMB_VFS_HANDLE_SET_DATA(handle
, config
,
2596 NULL
, struct shadow_copy2_config
,
2602 static struct vfs_fn_pointers vfs_shadow_copy2_fns
= {
2603 .connect_fn
= shadow_copy2_connect
,
2604 .opendir_fn
= shadow_copy2_opendir
,
2605 .disk_free_fn
= shadow_copy2_disk_free
,
2606 .get_quota_fn
= shadow_copy2_get_quota
,
2607 .rename_fn
= shadow_copy2_rename
,
2608 .link_fn
= shadow_copy2_link
,
2609 .symlink_fn
= shadow_copy2_symlink
,
2610 .stat_fn
= shadow_copy2_stat
,
2611 .lstat_fn
= shadow_copy2_lstat
,
2612 .fstat_fn
= shadow_copy2_fstat
,
2613 .open_fn
= shadow_copy2_open
,
2614 .unlink_fn
= shadow_copy2_unlink
,
2615 .chmod_fn
= shadow_copy2_chmod
,
2616 .chown_fn
= shadow_copy2_chown
,
2617 .chdir_fn
= shadow_copy2_chdir
,
2618 .ntimes_fn
= shadow_copy2_ntimes
,
2619 .readlink_fn
= shadow_copy2_readlink
,
2620 .mknod_fn
= shadow_copy2_mknod
,
2621 .realpath_fn
= shadow_copy2_realpath
,
2622 .get_nt_acl_fn
= shadow_copy2_get_nt_acl
,
2623 .fget_nt_acl_fn
= shadow_copy2_fget_nt_acl
,
2624 .get_shadow_copy_data_fn
= shadow_copy2_get_shadow_copy_data
,
2625 .mkdir_fn
= shadow_copy2_mkdir
,
2626 .rmdir_fn
= shadow_copy2_rmdir
,
2627 .getxattr_fn
= shadow_copy2_getxattr
,
2628 .listxattr_fn
= shadow_copy2_listxattr
,
2629 .removexattr_fn
= shadow_copy2_removexattr
,
2630 .setxattr_fn
= shadow_copy2_setxattr
,
2631 .chmod_acl_fn
= shadow_copy2_chmod_acl
,
2632 .chflags_fn
= shadow_copy2_chflags
,
2633 .get_real_filename_fn
= shadow_copy2_get_real_filename
,
2634 .connectpath_fn
= shadow_copy2_connectpath
,
2637 NTSTATUS
vfs_shadow_copy2_init(void);
2638 NTSTATUS
vfs_shadow_copy2_init(void)
2640 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
,
2641 "shadow_copy2", &vfs_shadow_copy2_fns
);