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
;
57 static bool shadow_copy2_find_slashes(TALLOC_CTX
*mem_ctx
, const char *str
,
59 unsigned *pnum_offsets
)
68 while ((p
= strchr(p
, '/')) != NULL
) {
73 offsets
= talloc_array(mem_ctx
, size_t, num_offsets
);
74 if (offsets
== NULL
) {
80 while ((p
= strchr(p
, '/')) != NULL
) {
81 offsets
[num_offsets
] = p
-str
;
87 *pnum_offsets
= num_offsets
;
92 * Given a timestamp, build the posix level GMT-tag string
93 * based on the configurable format.
95 static size_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct
*handle
,
97 char *snaptime_string
,
102 struct shadow_copy2_config
*config
;
104 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
107 if (config
->use_sscanf
) {
108 snaptime_len
= snprintf(snaptime_string
,
111 (unsigned long)snapshot
);
112 if (snaptime_len
<= 0) {
113 DEBUG(10, ("snprintf failed\n"));
117 if (config
->use_localtime
) {
118 if (localtime_r(&snapshot
, &snap_tm
) == 0) {
119 DEBUG(10, ("gmtime_r failed\n"));
123 if (gmtime_r(&snapshot
, &snap_tm
) == 0) {
124 DEBUG(10, ("gmtime_r failed\n"));
128 snaptime_len
= strftime(snaptime_string
,
132 if (snaptime_len
== 0) {
133 DEBUG(10, ("strftime failed\n"));
142 * Given a timestamp, build the string to insert into a path
143 * as a path component for creating the local path to the
144 * snapshot at the given timestamp of the input path.
146 * In the case of a parallel snapdir (specified with an
147 * absolute path), this is the inital portion of the
148 * local path of any snapshot file. The complete path is
149 * obtained by appending the portion of the file's path
150 * below the share root's mountpoint.
152 static char *shadow_copy2_insert_string(TALLOC_CTX
*mem_ctx
,
153 struct vfs_handle_struct
*handle
,
156 fstring snaptime_string
;
157 size_t snaptime_len
= 0;
159 struct shadow_copy2_config
*config
;
161 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
164 snaptime_len
= shadow_copy2_posix_gmt_string(handle
,
167 sizeof(snaptime_string
));
168 if (snaptime_len
<= 0) {
172 if (config
->snapdir_absolute
) {
173 result
= talloc_asprintf(mem_ctx
, "%s/%s",
174 config
->snapdir
, snaptime_string
);
176 result
= talloc_asprintf(mem_ctx
, "/%s/%s",
177 config
->snapdir
, snaptime_string
);
179 if (result
== NULL
) {
180 DEBUG(1, (__location__
" talloc_asprintf failed\n"));
187 * Build the posix snapshot path for the connection
188 * at the given timestamp, i.e. the absolute posix path
189 * that contains the snapshot for this file system.
191 * This only applies to classical case, i.e. not
192 * to the "snapdirseverywhere" mode.
194 static char *shadow_copy2_snapshot_path(TALLOC_CTX
*mem_ctx
,
195 struct vfs_handle_struct
*handle
,
198 fstring snaptime_string
;
199 size_t snaptime_len
= 0;
201 struct shadow_copy2_config
*config
;
203 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
206 snaptime_len
= shadow_copy2_posix_gmt_string(handle
,
209 sizeof(snaptime_string
));
210 if (snaptime_len
<= 0) {
214 result
= talloc_asprintf(mem_ctx
, "%s/%s",
215 config
->snapshot_basepath
, snaptime_string
);
216 if (result
== NULL
) {
217 DEBUG(1, (__location__
" talloc_asprintf failed\n"));
223 static char *make_path_absolute(TALLOC_CTX
*mem_ctx
,
224 struct shadow_copy2_config
*config
,
227 char *newpath
= NULL
;
228 char *abs_path
= NULL
;
230 if (name
[0] != '/') {
231 newpath
= talloc_asprintf(mem_ctx
,
235 if (newpath
== NULL
) {
240 abs_path
= canonicalize_absolute_path(mem_ctx
, name
);
241 TALLOC_FREE(newpath
);
245 /* Return a $cwd-relative path. */
246 static bool make_relative_path(const char *cwd
, char *abs_path
)
248 size_t cwd_len
= strlen(cwd
);
249 size_t abs_len
= strlen(abs_path
);
251 if (abs_len
< cwd_len
) {
254 if (memcmp(abs_path
, cwd
, cwd_len
) != 0) {
257 if (abs_path
[cwd_len
] != '/' && abs_path
[cwd_len
] != '\0') {
260 if (abs_path
[cwd_len
] == '/') {
263 memmove(abs_path
, &abs_path
[cwd_len
], abs_len
+ 1 - cwd_len
);
268 * Strip a snapshot component from a filename as
269 * handed in via the smb layer.
270 * Returns the parsed timestamp and the stripped filename.
272 static bool shadow_copy2_strip_snapshot_internal(TALLOC_CTX
*mem_ctx
,
273 struct vfs_handle_struct
*handle
,
274 const char *orig_name
,
280 time_t timestamp
= 0;
283 char *stripped
= NULL
;
284 size_t rest_len
, dst_len
;
285 struct shadow_copy2_config
*config
;
288 ptrdiff_t len_before_gmt
;
289 const char *name
= orig_name
;
291 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
294 DEBUG(10, (__location__
": enter path '%s'\n", name
));
296 p
= strstr_m(name
, "@GMT-");
298 DEBUG(11, ("@GMT not found\n"));
301 if ((p
> name
) && (p
[-1] != '/')) {
302 /* the GMT-token does not start a path-component */
303 DEBUG(10, ("not at start, p=%p, name=%p, p[-1]=%d\n",
304 p
, name
, (int)p
[-1]));
309 * Figure out whether we got an already converted string. One
310 * case where this happens is in a smb2 create call with the
311 * mxac create blob set. We do the get_acl call on
312 * fsp->fsp_name, which is already converted. We are converted
313 * if we got a file name of the form ".snapshots/@GMT-",
314 * i.e. ".snapshots/" precedes "p".
317 snapdir
= lp_parm_const_string(SNUM(handle
->conn
), "shadow", "snapdir",
319 snapdirlen
= strlen(snapdir
);
320 len_before_gmt
= p
- name
;
322 if ((len_before_gmt
>= (snapdirlen
+ 1)) && (p
[-1] == '/')) {
323 const char *parent_snapdir
= p
- (snapdirlen
+1);
325 DEBUG(10, ("parent_snapdir = %s\n", parent_snapdir
));
327 if (strncmp(parent_snapdir
, snapdir
, snapdirlen
) == 0) {
328 DEBUG(10, ("name=%s is already converted\n", name
));
332 q
= strptime(p
, GMT_FORMAT
, &tm
);
334 DEBUG(10, ("strptime failed\n"));
338 timestamp
= timegm(&tm
);
339 if (timestamp
== (time_t)-1) {
340 DEBUG(10, ("timestamp==-1\n"));
345 * The name consists of only the GMT token or the GMT
346 * token is at the end of the path. XP seems to send
347 * @GMT- at the end under certain circumstances even
348 * with a path prefix.
350 if (pstripped
!= NULL
) {
351 stripped
= talloc_strndup(mem_ctx
, name
, p
- name
);
352 if (stripped
== NULL
) {
355 *pstripped
= stripped
;
357 *ptimestamp
= timestamp
;
362 * It is not a complete path component, i.e. the path
363 * component continues after the gmt-token.
365 DEBUG(10, ("q[0] = %d\n", (int)q
[0]));
370 rest_len
= strlen(q
);
371 dst_len
= (p
-name
) + rest_len
;
373 if (config
->snapdirseverywhere
) {
376 insert
= shadow_copy2_insert_string(talloc_tos(), handle
,
378 if (insert
== NULL
) {
383 DEBUG(10, (__location__
": snapdirseverywhere mode.\n"
385 "insert string '%s'\n", name
, insert
));
387 have_insert
= (strstr(name
, insert
+1) != NULL
);
388 DEBUG(10, ("have_insert=%d, name=%s, insert+1=%s\n",
389 (int)have_insert
, name
, insert
+1));
391 DEBUG(10, (__location__
": insert string '%s' found in "
392 "path '%s' found in snapdirseverywhere mode "
393 "==> already converted\n", insert
, name
));
402 snapshot_path
= shadow_copy2_snapshot_path(talloc_tos(),
405 if (snapshot_path
== NULL
) {
410 DEBUG(10, (__location__
" path: '%s'.\n"
411 "snapshot path: '%s'\n", name
, snapshot_path
));
413 s
= strstr(name
, snapshot_path
);
416 * this starts with "snapshot_basepath/GMT-Token"
417 * so it is already a converted absolute
418 * path. Don't process further.
420 DEBUG(10, (__location__
": path '%s' starts with "
421 "snapshot path '%s' (not in "
422 "snapdirseverywhere mode) ==> "
423 "already converted\n", name
, snapshot_path
));
424 talloc_free(snapshot_path
);
427 talloc_free(snapshot_path
);
430 if (pstripped
!= NULL
) {
431 stripped
= talloc_array(mem_ctx
, char, dst_len
+1);
432 if (stripped
== NULL
) {
437 memcpy(stripped
, name
, p
-name
);
440 memcpy(stripped
+ (p
-name
), q
, rest_len
);
442 stripped
[dst_len
] = '\0';
443 *pstripped
= stripped
;
445 *ptimestamp
= timestamp
;
452 static bool shadow_copy2_strip_snapshot(TALLOC_CTX
*mem_ctx
,
453 struct vfs_handle_struct
*handle
,
454 const char *orig_name
,
458 return shadow_copy2_strip_snapshot_internal(mem_ctx
,
466 static char *shadow_copy2_find_mount_point(TALLOC_CTX
*mem_ctx
,
467 vfs_handle_struct
*handle
)
469 char *path
= talloc_strdup(mem_ctx
, handle
->conn
->connectpath
);
474 if (stat(path
, &st
) != 0) {
481 while ((p
= strrchr(path
, '/')) && p
> path
) {
483 if (stat(path
, &st
) != 0) {
487 if (st
.st_dev
!= dev
) {
497 * Convert from a name as handed in via the SMB layer
498 * and a timestamp into the local path of the snapshot
499 * of the provided file at the provided time.
500 * Also return the path in the snapshot corresponding
501 * to the file's share root.
503 static char *shadow_copy2_do_convert(TALLOC_CTX
*mem_ctx
,
504 struct vfs_handle_struct
*handle
,
505 const char *name
, time_t timestamp
,
506 size_t *snaproot_len
)
508 struct smb_filename converted_fname
;
510 size_t *slashes
= NULL
;
511 unsigned num_slashes
;
515 char *converted
= NULL
;
516 size_t insertlen
, connectlen
= 0;
519 struct shadow_copy2_config
*config
;
520 size_t in_share_offset
= 0;
522 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
525 DEBUG(10, ("converting '%s'\n", name
));
527 if (!config
->snapdirseverywhere
) {
531 snapshot_path
= shadow_copy2_snapshot_path(talloc_tos(),
534 if (snapshot_path
== NULL
) {
538 if (config
->rel_connectpath
== NULL
) {
539 converted
= talloc_asprintf(mem_ctx
, "%s/%s",
540 snapshot_path
, name
);
542 converted
= talloc_asprintf(mem_ctx
, "%s/%s/%s",
544 config
->rel_connectpath
,
547 if (converted
== NULL
) {
551 ZERO_STRUCT(converted_fname
);
552 converted_fname
.base_name
= converted
;
554 ret
= SMB_VFS_NEXT_LSTAT(handle
, &converted_fname
);
555 DEBUG(10, ("Trying[not snapdirseverywhere] %s: %d (%s)\n",
557 ret
, ret
== 0 ? "ok" : strerror(errno
)));
559 DEBUG(10, ("Found %s\n", converted
));
562 if (snaproot_len
!= NULL
) {
563 *snaproot_len
= strlen(snapshot_path
);
564 if (config
->rel_connectpath
!= NULL
) {
566 strlen(config
->rel_connectpath
) + 1;
574 /* never reached ... */
577 connectlen
= strlen(handle
->conn
->connectpath
);
579 path
= talloc_strdup(mem_ctx
, handle
->conn
->connectpath
);
581 path
= talloc_asprintf(
582 mem_ctx
, "%s/%s", handle
->conn
->connectpath
, name
);
588 pathlen
= talloc_get_size(path
)-1;
590 if (!shadow_copy2_find_slashes(talloc_tos(), path
,
591 &slashes
, &num_slashes
)) {
595 insert
= shadow_copy2_insert_string(talloc_tos(), handle
, timestamp
);
596 if (insert
== NULL
) {
599 insertlen
= talloc_get_size(insert
)-1;
602 * Note: We deliberatly don't expensively initialize the
603 * array with talloc_zero here: Putting zero into
604 * converted[pathlen+insertlen] below is sufficient, because
605 * in the following for loop, the insert string is inserted
606 * at various slash places. So the memory up to position
607 * pathlen+insertlen will always be initialized when the
608 * converted string is used.
610 converted
= talloc_array(mem_ctx
, char, pathlen
+ insertlen
+ 1);
611 if (converted
== NULL
) {
615 if (path
[pathlen
-1] != '/') {
617 * Append a fake slash to find the snapshot root
620 tmp
= talloc_realloc(talloc_tos(), slashes
,
621 size_t, num_slashes
+1);
626 slashes
[num_slashes
] = pathlen
;
632 if (!config
->crossmountpoints
) {
633 min_offset
= strlen(config
->mount_point
);
636 memcpy(converted
, path
, pathlen
+1);
637 converted
[pathlen
+insertlen
] = '\0';
639 ZERO_STRUCT(converted_fname
);
640 converted_fname
.base_name
= converted
;
642 for (i
= num_slashes
-1; i
>=0; i
--) {
648 if (offset
< min_offset
) {
653 if (offset
>= connectlen
) {
654 in_share_offset
= offset
;
657 memcpy(converted
+offset
, insert
, insertlen
);
660 memcpy(converted
+offset
, path
+ slashes
[i
],
661 pathlen
- slashes
[i
]);
663 ret
= SMB_VFS_NEXT_LSTAT(handle
, &converted_fname
);
665 DEBUG(10, ("Trying[snapdirseverywhere] %s: %d (%s)\n",
667 ret
, ret
== 0 ? "ok" : strerror(errno
)));
670 if (snaproot_len
!= NULL
) {
671 *snaproot_len
= in_share_offset
+ insertlen
;
675 if (errno
== ENOTDIR
) {
677 * This is a valid condition: We appended the
678 * .snaphots/@GMT.. to a file name. Just try
679 * with the upper levels.
683 if (errno
!= ENOENT
) {
684 /* Other problem than "not found" */
693 DEBUG(10, ("Found %s\n", converted
));
701 TALLOC_FREE(converted
);
703 TALLOC_FREE(slashes
);
710 * Convert from a name as handed in via the SMB layer
711 * and a timestamp into the local path of the snapshot
712 * of the provided file at the provided time.
714 static char *shadow_copy2_convert(TALLOC_CTX
*mem_ctx
,
715 struct vfs_handle_struct
*handle
,
716 const char *name
, time_t timestamp
)
718 return shadow_copy2_do_convert(mem_ctx
, handle
, name
, timestamp
, NULL
);
722 modify a sbuf return to ensure that inodes in the shadow directory
723 are different from those in the main directory
725 static void convert_sbuf(vfs_handle_struct
*handle
, const char *fname
,
726 SMB_STRUCT_STAT
*sbuf
)
728 struct shadow_copy2_config
*config
;
730 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
733 if (config
->fixinodes
) {
734 /* some snapshot systems, like GPFS, return the name
735 device:inode for the snapshot files as the current
736 files. That breaks the 'restore' button in the shadow copy
737 GUI, as the client gets a sharing violation.
739 This is a crude way of allowing both files to be
740 open at once. It has a slight chance of inode
741 number collision, but I can't see a better approach
742 without significant VFS changes
744 TDB_DATA key
= { .dptr
= discard_const_p(uint8_t, fname
),
745 .dsize
= strlen(fname
) };
748 shash
= tdb_jenkins_hash(&key
) & 0xFF000000;
752 sbuf
->st_ex_ino
^= shash
;
756 static DIR *shadow_copy2_opendir(vfs_handle_struct
*handle
,
761 time_t timestamp
= 0;
762 char *stripped
= NULL
;
767 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
768 ×tamp
, &stripped
)) {
771 if (timestamp
== 0) {
772 return SMB_VFS_NEXT_OPENDIR(handle
, fname
, mask
, attr
);
774 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
775 TALLOC_FREE(stripped
);
779 ret
= SMB_VFS_NEXT_OPENDIR(handle
, conv
, mask
, attr
);
786 static int shadow_copy2_rename(vfs_handle_struct
*handle
,
787 const struct smb_filename
*smb_fname_src
,
788 const struct smb_filename
*smb_fname_dst
)
790 time_t timestamp_src
= 0;
791 time_t timestamp_dst
= 0;
793 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
,
794 smb_fname_src
->base_name
,
795 ×tamp_src
, NULL
)) {
798 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
,
799 smb_fname_dst
->base_name
,
800 ×tamp_dst
, NULL
)) {
803 if (timestamp_src
!= 0) {
807 if (timestamp_dst
!= 0) {
811 return SMB_VFS_NEXT_RENAME(handle
, smb_fname_src
, smb_fname_dst
);
814 static int shadow_copy2_symlink(vfs_handle_struct
*handle
,
815 const char *oldname
, const char *newname
)
817 time_t timestamp_old
= 0;
818 time_t timestamp_new
= 0;
820 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, oldname
,
821 ×tamp_old
, NULL
)) {
824 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, newname
,
825 ×tamp_new
, NULL
)) {
828 if ((timestamp_old
!= 0) || (timestamp_new
!= 0)) {
832 return SMB_VFS_NEXT_SYMLINK(handle
, oldname
, newname
);
835 static int shadow_copy2_link(vfs_handle_struct
*handle
,
836 const char *oldname
, const char *newname
)
838 time_t timestamp_old
= 0;
839 time_t timestamp_new
= 0;
841 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, oldname
,
842 ×tamp_old
, NULL
)) {
845 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, newname
,
846 ×tamp_new
, NULL
)) {
849 if ((timestamp_old
!= 0) || (timestamp_new
!= 0)) {
853 return SMB_VFS_NEXT_LINK(handle
, oldname
, newname
);
856 static int shadow_copy2_stat(vfs_handle_struct
*handle
,
857 struct smb_filename
*smb_fname
)
859 time_t timestamp
= 0;
860 char *stripped
= NULL
;
862 int ret
, saved_errno
;
864 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
,
865 smb_fname
->base_name
,
866 ×tamp
, &stripped
)) {
869 if (timestamp
== 0) {
870 return SMB_VFS_NEXT_STAT(handle
, smb_fname
);
873 tmp
= smb_fname
->base_name
;
874 smb_fname
->base_name
= shadow_copy2_convert(
875 talloc_tos(), handle
, stripped
, timestamp
);
876 TALLOC_FREE(stripped
);
878 if (smb_fname
->base_name
== NULL
) {
879 smb_fname
->base_name
= tmp
;
883 ret
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
886 TALLOC_FREE(smb_fname
->base_name
);
887 smb_fname
->base_name
= tmp
;
890 convert_sbuf(handle
, smb_fname
->base_name
, &smb_fname
->st
);
896 static int shadow_copy2_lstat(vfs_handle_struct
*handle
,
897 struct smb_filename
*smb_fname
)
899 time_t timestamp
= 0;
900 char *stripped
= NULL
;
902 int ret
, saved_errno
;
904 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
,
905 smb_fname
->base_name
,
906 ×tamp
, &stripped
)) {
909 if (timestamp
== 0) {
910 return SMB_VFS_NEXT_LSTAT(handle
, smb_fname
);
913 tmp
= smb_fname
->base_name
;
914 smb_fname
->base_name
= shadow_copy2_convert(
915 talloc_tos(), handle
, stripped
, timestamp
);
916 TALLOC_FREE(stripped
);
918 if (smb_fname
->base_name
== NULL
) {
919 smb_fname
->base_name
= tmp
;
923 ret
= SMB_VFS_NEXT_LSTAT(handle
, smb_fname
);
926 TALLOC_FREE(smb_fname
->base_name
);
927 smb_fname
->base_name
= tmp
;
930 convert_sbuf(handle
, smb_fname
->base_name
, &smb_fname
->st
);
936 static int shadow_copy2_fstat(vfs_handle_struct
*handle
, files_struct
*fsp
,
937 SMB_STRUCT_STAT
*sbuf
)
939 time_t timestamp
= 0;
942 ret
= SMB_VFS_NEXT_FSTAT(handle
, fsp
, sbuf
);
946 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
,
947 fsp
->fsp_name
->base_name
,
951 if (timestamp
!= 0) {
952 convert_sbuf(handle
, fsp
->fsp_name
->base_name
, sbuf
);
957 static int shadow_copy2_open(vfs_handle_struct
*handle
,
958 struct smb_filename
*smb_fname
, files_struct
*fsp
,
959 int flags
, mode_t mode
)
961 time_t timestamp
= 0;
962 char *stripped
= NULL
;
964 int ret
, saved_errno
;
966 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
,
967 smb_fname
->base_name
,
968 ×tamp
, &stripped
)) {
971 if (timestamp
== 0) {
972 return SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
975 tmp
= smb_fname
->base_name
;
976 smb_fname
->base_name
= shadow_copy2_convert(
977 talloc_tos(), handle
, stripped
, timestamp
);
978 TALLOC_FREE(stripped
);
980 if (smb_fname
->base_name
== NULL
) {
981 smb_fname
->base_name
= tmp
;
985 ret
= SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
988 TALLOC_FREE(smb_fname
->base_name
);
989 smb_fname
->base_name
= tmp
;
995 static int shadow_copy2_unlink(vfs_handle_struct
*handle
,
996 const struct smb_filename
*smb_fname
)
998 time_t timestamp
= 0;
999 char *stripped
= NULL
;
1000 int ret
, saved_errno
;
1001 struct smb_filename
*conv
;
1003 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
,
1004 smb_fname
->base_name
,
1005 ×tamp
, &stripped
)) {
1008 if (timestamp
== 0) {
1009 return SMB_VFS_NEXT_UNLINK(handle
, smb_fname
);
1011 conv
= cp_smb_filename(talloc_tos(), smb_fname
);
1016 conv
->base_name
= shadow_copy2_convert(
1017 conv
, handle
, stripped
, timestamp
);
1018 TALLOC_FREE(stripped
);
1019 if (conv
->base_name
== NULL
) {
1022 ret
= SMB_VFS_NEXT_UNLINK(handle
, conv
);
1023 saved_errno
= errno
;
1025 errno
= saved_errno
;
1029 static int shadow_copy2_chmod(vfs_handle_struct
*handle
, const char *fname
,
1032 time_t timestamp
= 0;
1033 char *stripped
= NULL
;
1034 int ret
, saved_errno
;
1037 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1038 ×tamp
, &stripped
)) {
1041 if (timestamp
== 0) {
1042 return SMB_VFS_NEXT_CHMOD(handle
, fname
, mode
);
1044 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1045 TALLOC_FREE(stripped
);
1049 ret
= SMB_VFS_NEXT_CHMOD(handle
, conv
, mode
);
1050 saved_errno
= errno
;
1052 errno
= saved_errno
;
1056 static int shadow_copy2_chown(vfs_handle_struct
*handle
, const char *fname
,
1057 uid_t uid
, gid_t gid
)
1059 time_t timestamp
= 0;
1060 char *stripped
= NULL
;
1061 int ret
, saved_errno
;
1064 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1065 ×tamp
, &stripped
)) {
1068 if (timestamp
== 0) {
1069 return SMB_VFS_NEXT_CHOWN(handle
, fname
, uid
, gid
);
1071 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1072 TALLOC_FREE(stripped
);
1076 ret
= SMB_VFS_NEXT_CHOWN(handle
, conv
, uid
, gid
);
1077 saved_errno
= errno
;
1079 errno
= saved_errno
;
1083 static void store_cwd_data(vfs_handle_struct
*handle
,
1084 const char *connectpath
)
1086 struct shadow_copy2_config
*config
= NULL
;
1089 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
1092 TALLOC_FREE(config
->shadow_cwd
);
1093 cwd
= SMB_VFS_NEXT_GETWD(handle
);
1095 smb_panic("getwd failed\n");
1097 DBG_DEBUG("shadow cwd = %s\n", cwd
);
1098 config
->shadow_cwd
= talloc_strdup(config
, cwd
);
1100 if (config
->shadow_cwd
== NULL
) {
1101 smb_panic("talloc failed\n");
1103 TALLOC_FREE(config
->shadow_connectpath
);
1105 DBG_DEBUG("shadow conectpath = %s\n", connectpath
);
1106 config
->shadow_connectpath
= talloc_strdup(config
, connectpath
);
1107 if (config
->shadow_connectpath
== NULL
) {
1108 smb_panic("talloc failed\n");
1113 static int shadow_copy2_chdir(vfs_handle_struct
*handle
,
1116 time_t timestamp
= 0;
1117 char *stripped
= NULL
;
1118 char *snappath
= NULL
;
1120 int saved_errno
= 0;
1122 size_t rootpath_len
= 0;
1124 if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle
, fname
,
1125 ×tamp
, &stripped
, &snappath
)) {
1128 if (stripped
!= NULL
) {
1129 conv
= shadow_copy2_do_convert(talloc_tos(),
1134 TALLOC_FREE(stripped
);
1141 ret
= SMB_VFS_NEXT_CHDIR(handle
, fname
);
1143 saved_errno
= errno
;
1147 if (conv
!= NULL
&& rootpath_len
!= 0) {
1148 conv
[rootpath_len
] = '\0';
1149 } else if (snappath
!= 0) {
1153 store_cwd_data(handle
, conv
);
1156 TALLOC_FREE(stripped
);
1159 if (saved_errno
!= 0) {
1160 errno
= saved_errno
;
1165 static int shadow_copy2_ntimes(vfs_handle_struct
*handle
,
1166 const struct smb_filename
*smb_fname
,
1167 struct smb_file_time
*ft
)
1169 time_t timestamp
= 0;
1170 char *stripped
= NULL
;
1171 int ret
, saved_errno
;
1172 struct smb_filename
*conv
;
1174 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
,
1175 smb_fname
->base_name
,
1176 ×tamp
, &stripped
)) {
1179 if (timestamp
== 0) {
1180 return SMB_VFS_NEXT_NTIMES(handle
, smb_fname
, ft
);
1182 conv
= cp_smb_filename(talloc_tos(), smb_fname
);
1187 conv
->base_name
= shadow_copy2_convert(
1188 conv
, handle
, stripped
, timestamp
);
1189 TALLOC_FREE(stripped
);
1190 if (conv
->base_name
== NULL
) {
1193 ret
= SMB_VFS_NEXT_NTIMES(handle
, conv
, ft
);
1194 saved_errno
= errno
;
1196 errno
= saved_errno
;
1200 static int shadow_copy2_readlink(vfs_handle_struct
*handle
,
1201 const char *fname
, char *buf
, size_t bufsiz
)
1203 time_t timestamp
= 0;
1204 char *stripped
= NULL
;
1205 int ret
, saved_errno
;
1208 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1209 ×tamp
, &stripped
)) {
1212 if (timestamp
== 0) {
1213 return SMB_VFS_NEXT_READLINK(handle
, fname
, buf
, bufsiz
);
1215 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1216 TALLOC_FREE(stripped
);
1220 ret
= SMB_VFS_NEXT_READLINK(handle
, conv
, buf
, bufsiz
);
1221 saved_errno
= errno
;
1223 errno
= saved_errno
;
1227 static int shadow_copy2_mknod(vfs_handle_struct
*handle
,
1228 const char *fname
, mode_t mode
, SMB_DEV_T dev
)
1230 time_t timestamp
= 0;
1231 char *stripped
= NULL
;
1232 int ret
, saved_errno
;
1235 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1236 ×tamp
, &stripped
)) {
1239 if (timestamp
== 0) {
1240 return SMB_VFS_NEXT_MKNOD(handle
, fname
, mode
, dev
);
1242 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1243 TALLOC_FREE(stripped
);
1247 ret
= SMB_VFS_NEXT_MKNOD(handle
, conv
, mode
, dev
);
1248 saved_errno
= errno
;
1250 errno
= saved_errno
;
1254 static char *shadow_copy2_realpath(vfs_handle_struct
*handle
,
1257 time_t timestamp
= 0;
1258 char *stripped
= NULL
;
1260 char *result
= NULL
;
1263 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1264 ×tamp
, &stripped
)) {
1267 if (timestamp
== 0) {
1268 return SMB_VFS_NEXT_REALPATH(handle
, fname
);
1271 tmp
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1276 result
= SMB_VFS_NEXT_REALPATH(handle
, tmp
);
1279 saved_errno
= errno
;
1281 TALLOC_FREE(stripped
);
1282 errno
= saved_errno
;
1287 * Check whether a given directory contains a
1288 * snapshot directory as direct subdirectory.
1289 * If yes, return the path of the snapshot-subdir,
1290 * otherwise return NULL.
1292 static char *have_snapdir(struct vfs_handle_struct
*handle
,
1295 struct smb_filename smb_fname
;
1297 struct shadow_copy2_config
*config
;
1299 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
1302 ZERO_STRUCT(smb_fname
);
1303 smb_fname
.base_name
= talloc_asprintf(talloc_tos(), "%s/%s",
1304 path
, config
->snapdir
);
1305 if (smb_fname
.base_name
== NULL
) {
1309 ret
= SMB_VFS_NEXT_STAT(handle
, &smb_fname
);
1310 if ((ret
== 0) && (S_ISDIR(smb_fname
.st
.st_ex_mode
))) {
1311 return smb_fname
.base_name
;
1313 TALLOC_FREE(smb_fname
.base_name
);
1317 static bool check_access_snapdir(struct vfs_handle_struct
*handle
,
1320 struct smb_filename smb_fname
;
1324 ZERO_STRUCT(smb_fname
);
1325 smb_fname
.base_name
= talloc_asprintf(talloc_tos(),
1328 if (smb_fname
.base_name
== NULL
) {
1332 ret
= SMB_VFS_NEXT_STAT(handle
, &smb_fname
);
1333 if (ret
!= 0 || !S_ISDIR(smb_fname
.st
.st_ex_mode
)) {
1334 TALLOC_FREE(smb_fname
.base_name
);
1338 status
= smbd_check_access_rights(handle
->conn
,
1342 if (!NT_STATUS_IS_OK(status
)) {
1343 DEBUG(0,("user does not have list permission "
1345 smb_fname
.base_name
));
1346 TALLOC_FREE(smb_fname
.base_name
);
1349 TALLOC_FREE(smb_fname
.base_name
);
1354 * Find the snapshot directory (if any) for the given
1355 * filename (which is relative to the share).
1357 static const char *shadow_copy2_find_snapdir(TALLOC_CTX
*mem_ctx
,
1358 struct vfs_handle_struct
*handle
,
1359 struct smb_filename
*smb_fname
)
1362 const char *snapdir
;
1363 struct shadow_copy2_config
*config
;
1365 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
1369 * If the non-snapdisrseverywhere mode, we should not search!
1371 if (!config
->snapdirseverywhere
) {
1372 return config
->snapshot_basepath
;
1375 path
= talloc_asprintf(mem_ctx
, "%s/%s",
1376 handle
->conn
->connectpath
,
1377 smb_fname
->base_name
);
1382 snapdir
= have_snapdir(handle
, path
);
1383 if (snapdir
!= NULL
) {
1388 while ((p
= strrchr(path
, '/')) && (p
> path
)) {
1392 snapdir
= have_snapdir(handle
, path
);
1393 if (snapdir
!= NULL
) {
1402 static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct
*handle
,
1404 char *gmt
, size_t gmt_len
)
1406 struct tm timestamp
;
1408 unsigned long int timestamp_long
;
1410 struct shadow_copy2_config
*config
;
1412 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
1415 fmt
= config
->gmt_format
;
1417 ZERO_STRUCT(timestamp
);
1418 if (config
->use_sscanf
) {
1419 if (sscanf(name
, fmt
, ×tamp_long
) != 1) {
1420 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1421 "no sscanf match %s: %s\n",
1425 timestamp_t
= timestamp_long
;
1426 gmtime_r(×tamp_t
, ×tamp
);
1428 if (strptime(name
, fmt
, ×tamp
) == NULL
) {
1429 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1430 "no match %s: %s\n",
1434 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n",
1437 if (config
->use_localtime
) {
1438 timestamp
.tm_isdst
= -1;
1439 timestamp_t
= mktime(×tamp
);
1440 gmtime_r(×tamp_t
, ×tamp
);
1444 strftime(gmt
, gmt_len
, GMT_FORMAT
, ×tamp
);
1448 static int shadow_copy2_label_cmp_asc(const void *x
, const void *y
)
1450 return strncmp((const char *)x
, (const char *)y
, sizeof(SHADOW_COPY_LABEL
));
1453 static int shadow_copy2_label_cmp_desc(const void *x
, const void *y
)
1455 return -strncmp((const char *)x
, (const char *)y
, sizeof(SHADOW_COPY_LABEL
));
1459 sort the shadow copy data in ascending or descending order
1461 static void shadow_copy2_sort_data(vfs_handle_struct
*handle
,
1462 struct shadow_copy_data
*shadow_copy2_data
)
1464 int (*cmpfunc
)(const void *, const void *);
1466 struct shadow_copy2_config
*config
;
1468 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
1471 sort
= config
->sort_order
;
1476 if (strcmp(sort
, "asc") == 0) {
1477 cmpfunc
= shadow_copy2_label_cmp_asc
;
1478 } else if (strcmp(sort
, "desc") == 0) {
1479 cmpfunc
= shadow_copy2_label_cmp_desc
;
1484 if (shadow_copy2_data
&& shadow_copy2_data
->num_volumes
> 0 &&
1485 shadow_copy2_data
->labels
)
1487 TYPESAFE_QSORT(shadow_copy2_data
->labels
,
1488 shadow_copy2_data
->num_volumes
,
1493 static int shadow_copy2_get_shadow_copy_data(
1494 vfs_handle_struct
*handle
, files_struct
*fsp
,
1495 struct shadow_copy_data
*shadow_copy2_data
,
1499 const char *snapdir
;
1501 TALLOC_CTX
*tmp_ctx
= talloc_stackframe();
1504 snapdir
= shadow_copy2_find_snapdir(tmp_ctx
, handle
, fsp
->fsp_name
);
1505 if (snapdir
== NULL
) {
1506 DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
1507 handle
->conn
->connectpath
));
1509 talloc_free(tmp_ctx
);
1512 ret
= check_access_snapdir(handle
, snapdir
);
1514 DEBUG(0,("access denied on listing snapdir %s\n", snapdir
));
1516 talloc_free(tmp_ctx
);
1520 p
= SMB_VFS_NEXT_OPENDIR(handle
, snapdir
, NULL
, 0);
1523 DEBUG(2,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s'"
1524 " - %s\n", snapdir
, strerror(errno
)));
1525 talloc_free(tmp_ctx
);
1530 shadow_copy2_data
->num_volumes
= 0;
1531 shadow_copy2_data
->labels
= NULL
;
1533 while ((d
= SMB_VFS_NEXT_READDIR(handle
, p
, NULL
))) {
1534 char snapshot
[GMT_NAME_LEN
+1];
1535 SHADOW_COPY_LABEL
*tlabels
;
1538 * ignore names not of the right form in the snapshot
1541 if (!shadow_copy2_snapshot_to_gmt(
1543 snapshot
, sizeof(snapshot
))) {
1545 DEBUG(6, ("shadow_copy2_get_shadow_copy_data: "
1546 "ignoring %s\n", d
->d_name
));
1549 DEBUG(6,("shadow_copy2_get_shadow_copy_data: %s -> %s\n",
1550 d
->d_name
, snapshot
));
1553 /* the caller doesn't want the labels */
1554 shadow_copy2_data
->num_volumes
++;
1558 tlabels
= talloc_realloc(shadow_copy2_data
,
1559 shadow_copy2_data
->labels
,
1561 shadow_copy2_data
->num_volumes
+1);
1562 if (tlabels
== NULL
) {
1563 DEBUG(0,("shadow_copy2: out of memory\n"));
1564 SMB_VFS_NEXT_CLOSEDIR(handle
, p
);
1565 talloc_free(tmp_ctx
);
1569 strlcpy(tlabels
[shadow_copy2_data
->num_volumes
], snapshot
,
1572 shadow_copy2_data
->num_volumes
++;
1573 shadow_copy2_data
->labels
= tlabels
;
1576 SMB_VFS_NEXT_CLOSEDIR(handle
,p
);
1578 shadow_copy2_sort_data(handle
, shadow_copy2_data
);
1580 talloc_free(tmp_ctx
);
1584 static NTSTATUS
shadow_copy2_fget_nt_acl(vfs_handle_struct
*handle
,
1585 struct files_struct
*fsp
,
1586 uint32_t security_info
,
1587 TALLOC_CTX
*mem_ctx
,
1588 struct security_descriptor
**ppdesc
)
1590 time_t timestamp
= 0;
1591 char *stripped
= NULL
;
1595 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
,
1596 fsp
->fsp_name
->base_name
,
1597 ×tamp
, &stripped
)) {
1598 return map_nt_error_from_unix(errno
);
1600 if (timestamp
== 0) {
1601 return SMB_VFS_NEXT_FGET_NT_ACL(handle
, fsp
, security_info
,
1605 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1606 TALLOC_FREE(stripped
);
1608 return map_nt_error_from_unix(errno
);
1610 status
= SMB_VFS_NEXT_GET_NT_ACL(handle
, conv
, security_info
,
1616 static NTSTATUS
shadow_copy2_get_nt_acl(vfs_handle_struct
*handle
,
1618 uint32_t security_info
,
1619 TALLOC_CTX
*mem_ctx
,
1620 struct security_descriptor
**ppdesc
)
1622 time_t timestamp
= 0;
1623 char *stripped
= NULL
;
1627 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1628 ×tamp
, &stripped
)) {
1629 return map_nt_error_from_unix(errno
);
1631 if (timestamp
== 0) {
1632 return SMB_VFS_NEXT_GET_NT_ACL(handle
, fname
, security_info
,
1635 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1636 TALLOC_FREE(stripped
);
1638 return map_nt_error_from_unix(errno
);
1640 status
= SMB_VFS_NEXT_GET_NT_ACL(handle
, conv
, security_info
,
1646 static int shadow_copy2_mkdir(vfs_handle_struct
*handle
,
1647 const char *fname
, mode_t mode
)
1649 time_t timestamp
= 0;
1650 char *stripped
= NULL
;
1651 int ret
, saved_errno
;
1654 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1655 ×tamp
, &stripped
)) {
1658 if (timestamp
== 0) {
1659 return SMB_VFS_NEXT_MKDIR(handle
, fname
, mode
);
1661 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1662 TALLOC_FREE(stripped
);
1666 ret
= SMB_VFS_NEXT_MKDIR(handle
, conv
, mode
);
1667 saved_errno
= errno
;
1669 errno
= saved_errno
;
1673 static int shadow_copy2_rmdir(vfs_handle_struct
*handle
, const char *fname
)
1675 time_t timestamp
= 0;
1676 char *stripped
= NULL
;
1677 int ret
, saved_errno
;
1680 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1681 ×tamp
, &stripped
)) {
1684 if (timestamp
== 0) {
1685 return SMB_VFS_NEXT_RMDIR(handle
, fname
);
1687 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1688 TALLOC_FREE(stripped
);
1692 ret
= SMB_VFS_NEXT_RMDIR(handle
, conv
);
1693 saved_errno
= errno
;
1695 errno
= saved_errno
;
1699 static int shadow_copy2_chflags(vfs_handle_struct
*handle
, const char *fname
,
1702 time_t timestamp
= 0;
1703 char *stripped
= NULL
;
1704 int ret
, saved_errno
;
1707 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1708 ×tamp
, &stripped
)) {
1711 if (timestamp
== 0) {
1712 return SMB_VFS_NEXT_CHFLAGS(handle
, fname
, flags
);
1714 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1715 TALLOC_FREE(stripped
);
1719 ret
= SMB_VFS_NEXT_CHFLAGS(handle
, conv
, flags
);
1720 saved_errno
= errno
;
1722 errno
= saved_errno
;
1726 static ssize_t
shadow_copy2_getxattr(vfs_handle_struct
*handle
,
1727 const char *fname
, const char *aname
,
1728 void *value
, size_t size
)
1730 time_t timestamp
= 0;
1731 char *stripped
= NULL
;
1736 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1737 ×tamp
, &stripped
)) {
1740 if (timestamp
== 0) {
1741 return SMB_VFS_NEXT_GETXATTR(handle
, fname
, aname
, value
,
1744 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1745 TALLOC_FREE(stripped
);
1749 ret
= SMB_VFS_NEXT_GETXATTR(handle
, conv
, aname
, value
, size
);
1750 saved_errno
= errno
;
1752 errno
= saved_errno
;
1756 static ssize_t
shadow_copy2_listxattr(struct vfs_handle_struct
*handle
,
1758 char *list
, size_t size
)
1760 time_t timestamp
= 0;
1761 char *stripped
= NULL
;
1766 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1767 ×tamp
, &stripped
)) {
1770 if (timestamp
== 0) {
1771 return SMB_VFS_NEXT_LISTXATTR(handle
, fname
, list
, size
);
1773 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1774 TALLOC_FREE(stripped
);
1778 ret
= SMB_VFS_NEXT_LISTXATTR(handle
, conv
, list
, size
);
1779 saved_errno
= errno
;
1781 errno
= saved_errno
;
1785 static int shadow_copy2_removexattr(vfs_handle_struct
*handle
,
1786 const char *fname
, const char *aname
)
1788 time_t timestamp
= 0;
1789 char *stripped
= NULL
;
1790 int ret
, saved_errno
;
1793 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1794 ×tamp
, &stripped
)) {
1797 if (timestamp
== 0) {
1798 return SMB_VFS_NEXT_REMOVEXATTR(handle
, fname
, aname
);
1800 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1801 TALLOC_FREE(stripped
);
1805 ret
= SMB_VFS_NEXT_REMOVEXATTR(handle
, conv
, aname
);
1806 saved_errno
= errno
;
1808 errno
= saved_errno
;
1812 static int shadow_copy2_setxattr(struct vfs_handle_struct
*handle
,
1814 const char *aname
, const void *value
,
1815 size_t size
, int flags
)
1817 time_t timestamp
= 0;
1818 char *stripped
= NULL
;
1823 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1824 ×tamp
, &stripped
)) {
1827 if (timestamp
== 0) {
1828 return SMB_VFS_NEXT_SETXATTR(handle
, fname
, aname
, value
, size
,
1831 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1832 TALLOC_FREE(stripped
);
1836 ret
= SMB_VFS_NEXT_SETXATTR(handle
, conv
, aname
, value
, size
, flags
);
1837 saved_errno
= errno
;
1839 errno
= saved_errno
;
1843 static int shadow_copy2_chmod_acl(vfs_handle_struct
*handle
,
1844 const char *fname
, mode_t mode
)
1846 time_t timestamp
= 0;
1847 char *stripped
= NULL
;
1852 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1853 ×tamp
, &stripped
)) {
1856 if (timestamp
== 0) {
1857 return SMB_VFS_NEXT_CHMOD_ACL(handle
, fname
, mode
);
1859 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1860 TALLOC_FREE(stripped
);
1864 ret
= SMB_VFS_NEXT_CHMOD_ACL(handle
, conv
, mode
);
1865 saved_errno
= errno
;
1867 errno
= saved_errno
;
1871 static int shadow_copy2_get_real_filename(struct vfs_handle_struct
*handle
,
1874 TALLOC_CTX
*mem_ctx
,
1877 time_t timestamp
= 0;
1878 char *stripped
= NULL
;
1883 DEBUG(10, ("shadow_copy2_get_real_filename called for path=[%s], "
1884 "name=[%s]\n", path
, name
));
1886 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, path
,
1887 ×tamp
, &stripped
)) {
1888 DEBUG(10, ("shadow_copy2_strip_snapshot failed\n"));
1891 if (timestamp
== 0) {
1892 DEBUG(10, ("timestamp == 0\n"));
1893 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle
, path
, name
,
1894 mem_ctx
, found_name
);
1896 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
1897 TALLOC_FREE(stripped
);
1899 DEBUG(10, ("shadow_copy2_convert failed\n"));
1902 DEBUG(10, ("Calling NEXT_GET_REAL_FILE_NAME for conv=[%s], "
1903 "name=[%s]\n", conv
, name
));
1904 ret
= SMB_VFS_NEXT_GET_REAL_FILENAME(handle
, conv
, name
,
1905 mem_ctx
, found_name
);
1906 DEBUG(10, ("NEXT_REAL_FILE_NAME returned %d\n", (int)ret
));
1907 saved_errno
= errno
;
1909 errno
= saved_errno
;
1913 static const char *shadow_copy2_connectpath(struct vfs_handle_struct
*handle
,
1916 time_t timestamp
= 0;
1917 char *stripped
= NULL
;
1919 char *result
= NULL
;
1920 char *parent_dir
= NULL
;
1922 size_t rootpath_len
= 0;
1923 struct shadow_copy2_config
*config
= NULL
;
1925 SMB_VFS_HANDLE_GET_DATA(handle
, config
, struct shadow_copy2_config
,
1928 DBG_DEBUG("Calc connect path for [%s]\n", fname
);
1930 if (config
->shadow_connectpath
!= NULL
) {
1931 DBG_DEBUG("cached connect path is [%s]\n",
1932 config
->shadow_connectpath
);
1933 return config
->shadow_connectpath
;
1936 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, fname
,
1937 ×tamp
, &stripped
)) {
1940 if (timestamp
== 0) {
1941 return SMB_VFS_NEXT_CONNECTPATH(handle
, fname
);
1944 tmp
= shadow_copy2_do_convert(talloc_tos(), handle
, stripped
, timestamp
,
1947 if (errno
!= ENOENT
) {
1952 * If the converted path does not exist, and converting
1953 * the parent yields something that does exist, then
1954 * this path refers to something that has not been
1955 * created yet, relative to the parent path.
1956 * The snapshot finding is relative to the parent.
1957 * (usually snapshots are read/only but this is not
1958 * necessarily true).
1959 * This code also covers getting a wildcard in the
1960 * last component, because this function is called
1961 * prior to sanitizing the path, and in SMB1 we may
1962 * get wildcards in path names.
1964 if (!parent_dirname(talloc_tos(), stripped
, &parent_dir
,
1970 tmp
= shadow_copy2_do_convert(talloc_tos(), handle
, parent_dir
,
1971 timestamp
, &rootpath_len
);
1977 DBG_DEBUG("converted path is [%s] root path is [%.*s]\n", tmp
,
1978 (int)rootpath_len
, tmp
);
1980 tmp
[rootpath_len
] = '\0';
1981 result
= SMB_VFS_NEXT_REALPATH(handle
, tmp
);
1982 if (result
== NULL
) {
1986 DBG_DEBUG("connect path is [%s]\n", result
);
1989 saved_errno
= errno
;
1991 TALLOC_FREE(stripped
);
1992 TALLOC_FREE(parent_dir
);
1993 errno
= saved_errno
;
1997 static uint64_t shadow_copy2_disk_free(vfs_handle_struct
*handle
,
1998 const char *path
, uint64_t *bsize
,
1999 uint64_t *dfree
, uint64_t *dsize
)
2001 time_t timestamp
= 0;
2002 char *stripped
= NULL
;
2007 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, path
,
2008 ×tamp
, &stripped
)) {
2011 if (timestamp
== 0) {
2012 return SMB_VFS_NEXT_DISK_FREE(handle
, path
,
2013 bsize
, dfree
, dsize
);
2016 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
2017 TALLOC_FREE(stripped
);
2022 ret
= SMB_VFS_NEXT_DISK_FREE(handle
, conv
, bsize
, dfree
, dsize
);
2024 saved_errno
= errno
;
2026 errno
= saved_errno
;
2031 static int shadow_copy2_get_quota(vfs_handle_struct
*handle
, const char *path
,
2032 enum SMB_QUOTA_TYPE qtype
, unid_t id
,
2035 time_t timestamp
= 0;
2036 char *stripped
= NULL
;
2041 if (!shadow_copy2_strip_snapshot(talloc_tos(), handle
, path
, ×tamp
,
2045 if (timestamp
== 0) {
2046 return SMB_VFS_NEXT_GET_QUOTA(handle
, path
, qtype
, id
, dq
);
2049 conv
= shadow_copy2_convert(talloc_tos(), handle
, stripped
, timestamp
);
2050 TALLOC_FREE(stripped
);
2055 ret
= SMB_VFS_NEXT_GET_QUOTA(handle
, conv
, qtype
, id
, dq
);
2057 saved_errno
= errno
;
2059 errno
= saved_errno
;
2064 static int shadow_copy2_connect(struct vfs_handle_struct
*handle
,
2065 const char *service
, const char *user
)
2067 struct shadow_copy2_config
*config
;
2069 const char *snapdir
;
2070 const char *gmt_format
;
2071 const char *sort_order
;
2072 const char *basedir
= NULL
;
2073 const char *snapsharepath
= NULL
;
2074 const char *mount_point
;
2076 DEBUG(10, (__location__
": cnum[%u], connectpath[%s]\n",
2077 (unsigned)handle
->conn
->cnum
,
2078 handle
->conn
->connectpath
));
2080 ret
= SMB_VFS_NEXT_CONNECT(handle
, service
, user
);
2085 config
= talloc_zero(handle
->conn
, struct shadow_copy2_config
);
2086 if (config
== NULL
) {
2087 DEBUG(0, ("talloc_zero() failed\n"));
2092 gmt_format
= lp_parm_const_string(SNUM(handle
->conn
),
2095 config
->gmt_format
= talloc_strdup(config
, gmt_format
);
2096 if (config
->gmt_format
== NULL
) {
2097 DEBUG(0, ("talloc_strdup() failed\n"));
2102 /* config->gmt_format must not contain a path separator. */
2103 if (strchr(config
->gmt_format
, '/') != NULL
) {
2104 DEBUG(0, ("shadow:format %s must not contain a /"
2105 "character. Unable to initialize module.\n",
2106 config
->gmt_format
));
2111 config
->use_sscanf
= lp_parm_bool(SNUM(handle
->conn
),
2112 "shadow", "sscanf", false);
2114 config
->use_localtime
= lp_parm_bool(SNUM(handle
->conn
),
2115 "shadow", "localtime",
2118 snapdir
= lp_parm_const_string(SNUM(handle
->conn
),
2119 "shadow", "snapdir",
2121 config
->snapdir
= talloc_strdup(config
, snapdir
);
2122 if (config
->snapdir
== NULL
) {
2123 DEBUG(0, ("talloc_strdup() failed\n"));
2128 config
->snapdirseverywhere
= lp_parm_bool(SNUM(handle
->conn
),
2130 "snapdirseverywhere",
2133 config
->crossmountpoints
= lp_parm_bool(SNUM(handle
->conn
),
2134 "shadow", "crossmountpoints",
2137 if (config
->crossmountpoints
&& !config
->snapdirseverywhere
) {
2138 DBG_WARNING("Warning: 'crossmountpoints' depends on "
2139 "'snapdirseverywhere'. Disabling crossmountpoints.\n");
2142 config
->fixinodes
= lp_parm_bool(SNUM(handle
->conn
),
2143 "shadow", "fixinodes",
2146 sort_order
= lp_parm_const_string(SNUM(handle
->conn
),
2147 "shadow", "sort", "desc");
2148 config
->sort_order
= talloc_strdup(config
, sort_order
);
2149 if (config
->sort_order
== NULL
) {
2150 DEBUG(0, ("talloc_strdup() failed\n"));
2155 mount_point
= lp_parm_const_string(SNUM(handle
->conn
),
2156 "shadow", "mountpoint", NULL
);
2157 if (mount_point
!= NULL
) {
2158 if (mount_point
[0] != '/') {
2159 DEBUG(1, (__location__
" Warning: 'mountpoint' is "
2160 "relative ('%s'), but it has to be an "
2161 "absolute path. Ignoring provided value.\n",
2166 p
= strstr(handle
->conn
->connectpath
, mount_point
);
2167 if (p
!= handle
->conn
->connectpath
) {
2168 DBG_WARNING("Warning: the share root (%s) is "
2169 "not a subdirectory of the "
2170 "specified mountpoint (%s). "
2171 "Ignoring provided value.\n",
2172 handle
->conn
->connectpath
,
2179 if (mount_point
!= NULL
) {
2180 config
->mount_point
= talloc_strdup(config
, mount_point
);
2181 if (config
->mount_point
== NULL
) {
2182 DEBUG(0, (__location__
" talloc_strdup() failed\n"));
2186 config
->mount_point
= shadow_copy2_find_mount_point(config
,
2188 if (config
->mount_point
== NULL
) {
2189 DBG_WARNING("shadow_copy2_find_mount_point "
2190 "of the share root '%s' failed: %s\n",
2191 handle
->conn
->connectpath
, strerror(errno
));
2196 basedir
= lp_parm_const_string(SNUM(handle
->conn
),
2197 "shadow", "basedir", NULL
);
2199 if (basedir
!= NULL
) {
2200 if (basedir
[0] != '/') {
2201 DEBUG(1, (__location__
" Warning: 'basedir' is "
2202 "relative ('%s'), but it has to be an "
2203 "absolute path. Disabling basedir.\n",
2208 p
= strstr(basedir
, config
->mount_point
);
2210 DEBUG(1, ("Warning: basedir (%s) is not a "
2211 "subdirectory of the share root's "
2212 "mount point (%s). "
2213 "Disabling basedir\n",
2214 basedir
, config
->mount_point
));
2220 if (config
->snapdirseverywhere
&& basedir
!= NULL
) {
2221 DEBUG(1, (__location__
" Warning: 'basedir' is incompatible "
2222 "with 'snapdirseverywhere'. Disabling basedir.\n"));
2226 snapsharepath
= lp_parm_const_string(SNUM(handle
->conn
), "shadow",
2227 "snapsharepath", NULL
);
2228 if (snapsharepath
!= NULL
) {
2229 if (snapsharepath
[0] == '/') {
2230 DBG_WARNING("Warning: 'snapsharepath' is "
2231 "absolute ('%s'), but it has to be a "
2232 "relative path. Disabling snapsharepath.\n",
2234 snapsharepath
= NULL
;
2236 if (config
->snapdirseverywhere
&& snapsharepath
!= NULL
) {
2237 DBG_WARNING("Warning: 'snapsharepath' is incompatible "
2238 "with 'snapdirseverywhere'. Disabling "
2239 "snapsharepath.\n");
2240 snapsharepath
= NULL
;
2244 if (basedir
!= NULL
&& snapsharepath
!= NULL
) {
2245 DBG_WARNING("Warning: 'snapsharepath' is incompatible with "
2246 "'basedir'. Disabling snapsharepath\n");
2247 snapsharepath
= NULL
;
2250 if (snapsharepath
!= NULL
) {
2251 config
->rel_connectpath
= talloc_strdup(config
, snapsharepath
);
2252 if (config
->rel_connectpath
== NULL
) {
2253 DBG_ERR("talloc_strdup() failed\n");
2259 if (basedir
== NULL
) {
2260 basedir
= config
->mount_point
;
2263 if (config
->rel_connectpath
== NULL
&&
2264 strlen(basedir
) < strlen(handle
->conn
->connectpath
)) {
2265 config
->rel_connectpath
= talloc_strdup(config
,
2266 handle
->conn
->connectpath
+ strlen(basedir
));
2267 if (config
->rel_connectpath
== NULL
) {
2268 DEBUG(0, ("talloc_strdup() failed\n"));
2274 if (config
->snapdir
[0] == '/') {
2275 config
->snapdir_absolute
= true;
2277 if (config
->snapdirseverywhere
== true) {
2278 DEBUG(1, (__location__
" Warning: An absolute snapdir "
2279 "is incompatible with 'snapdirseverywhere', "
2280 "setting 'snapdirseverywhere' to false.\n"));
2281 config
->snapdirseverywhere
= false;
2284 if (config
->crossmountpoints
== true) {
2285 DEBUG(1, (__location__
" Warning: 'crossmountpoints' "
2286 "is not supported with an absolute snapdir. "
2287 "Disabling it.\n"));
2288 config
->crossmountpoints
= false;
2291 config
->snapshot_basepath
= config
->snapdir
;
2293 config
->snapshot_basepath
= talloc_asprintf(config
, "%s/%s",
2294 config
->mount_point
, config
->snapdir
);
2295 if (config
->snapshot_basepath
== NULL
) {
2296 DEBUG(0, ("talloc_asprintf() failed\n"));
2302 trim_string(config
->mount_point
, NULL
, "/");
2303 trim_string(config
->rel_connectpath
, "/", "/");
2304 trim_string(config
->snapdir
, NULL
, "/");
2305 trim_string(config
->snapshot_basepath
, NULL
, "/");
2307 DEBUG(10, ("shadow_copy2_connect: configuration:\n"
2308 " share root: '%s'\n"
2309 " mountpoint: '%s'\n"
2310 " rel share root: '%s'\n"
2312 " snapshot base path: '%s'\n"
2315 " snapdirs everywhere: %s\n"
2316 " cross mountpoints: %s\n"
2320 handle
->conn
->connectpath
,
2321 config
->mount_point
,
2322 config
->rel_connectpath
,
2324 config
->snapshot_basepath
,
2326 config
->use_sscanf
? "yes" : "no",
2327 config
->snapdirseverywhere
? "yes" : "no",
2328 config
->crossmountpoints
? "yes" : "no",
2329 config
->fixinodes
? "yes" : "no",
2334 SMB_VFS_HANDLE_SET_DATA(handle
, config
,
2335 NULL
, struct shadow_copy2_config
,
2341 static struct vfs_fn_pointers vfs_shadow_copy2_fns
= {
2342 .connect_fn
= shadow_copy2_connect
,
2343 .opendir_fn
= shadow_copy2_opendir
,
2344 .disk_free_fn
= shadow_copy2_disk_free
,
2345 .get_quota_fn
= shadow_copy2_get_quota
,
2346 .rename_fn
= shadow_copy2_rename
,
2347 .link_fn
= shadow_copy2_link
,
2348 .symlink_fn
= shadow_copy2_symlink
,
2349 .stat_fn
= shadow_copy2_stat
,
2350 .lstat_fn
= shadow_copy2_lstat
,
2351 .fstat_fn
= shadow_copy2_fstat
,
2352 .open_fn
= shadow_copy2_open
,
2353 .unlink_fn
= shadow_copy2_unlink
,
2354 .chmod_fn
= shadow_copy2_chmod
,
2355 .chown_fn
= shadow_copy2_chown
,
2356 .chdir_fn
= shadow_copy2_chdir
,
2357 .ntimes_fn
= shadow_copy2_ntimes
,
2358 .readlink_fn
= shadow_copy2_readlink
,
2359 .mknod_fn
= shadow_copy2_mknod
,
2360 .realpath_fn
= shadow_copy2_realpath
,
2361 .get_nt_acl_fn
= shadow_copy2_get_nt_acl
,
2362 .fget_nt_acl_fn
= shadow_copy2_fget_nt_acl
,
2363 .get_shadow_copy_data_fn
= shadow_copy2_get_shadow_copy_data
,
2364 .mkdir_fn
= shadow_copy2_mkdir
,
2365 .rmdir_fn
= shadow_copy2_rmdir
,
2366 .getxattr_fn
= shadow_copy2_getxattr
,
2367 .listxattr_fn
= shadow_copy2_listxattr
,
2368 .removexattr_fn
= shadow_copy2_removexattr
,
2369 .setxattr_fn
= shadow_copy2_setxattr
,
2370 .chmod_acl_fn
= shadow_copy2_chmod_acl
,
2371 .chflags_fn
= shadow_copy2_chflags
,
2372 .get_real_filename_fn
= shadow_copy2_get_real_filename
,
2373 .connectpath_fn
= shadow_copy2_connectpath
,
2376 NTSTATUS
vfs_shadow_copy2_init(void);
2377 NTSTATUS
vfs_shadow_copy2_init(void)
2379 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
,
2380 "shadow_copy2", &vfs_shadow_copy2_fns
);