2 * Module for snapshot IO using snapper
4 * Copyright (C) David Disseldorp 2012-2014
6 * Portions taken from vfs_shadow_copy2.c:
7 * Copyright (C) Andrew Tridgell 2007
8 * Copyright (C) Ed Plese 2009
9 * Copyright (C) Volker Lendecke 2011
10 * Copyright (C) Christian Ambach 2011
11 * Copyright (C) Michael Adam 2013
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, see <http://www.gnu.org/licenses/>.
27 #include <dbus/dbus.h>
28 #ifdef HAVE_LINUX_IOCTL_H
29 #include <linux/ioctl.h>
31 #include <sys/ioctl.h>
35 #include "include/ntioctl.h"
36 #include "include/smb.h"
37 #include "system/filesys.h"
38 #include "smbd/smbd.h"
39 #include "lib/util/tevent_ntstatus.h"
41 #define SNAPPER_SIG_LIST_SNAPS_RSP "a(uquxussa{ss})"
42 #define SNAPPER_SIG_LIST_CONFS_RSP "a(ssa{ss})"
43 #define SNAPPER_SIG_STRING_DICT "{ss}"
58 uint32_t num_user_data
;
59 struct snapper_dict
*user_data
;
66 struct snapper_dict
*attrs
;
70 const char *snapper_err_str
;
72 } snapper_err_map
[] = {
73 { "error.no_permissions", NT_STATUS_ACCESS_DENIED
},
76 static NTSTATUS
snapper_err_ntstatus_map(const char *snapper_err_str
)
80 if (snapper_err_str
== NULL
) {
81 return NT_STATUS_UNSUCCESSFUL
;
83 for (i
= 0; i
< ARRAY_SIZE(snapper_err_map
); i
++) {
84 if (!strcmp(snapper_err_map
[i
].snapper_err_str
,
86 return snapper_err_map
[i
].status
;
89 DEBUG(2, ("no explicit mapping for dbus error: %s\n", snapper_err_str
));
91 return NT_STATUS_UNSUCCESSFUL
;
94 static DBusConnection
*snapper_dbus_conn_create(void)
97 DBusConnection
*dconn
;
99 dbus_error_init(&err
);
102 * Always create a new DBus connection, to ensure snapperd detects the
103 * correct client [E]UID. With dbus_bus_get() it does not!
105 dconn
= dbus_bus_get_private(DBUS_BUS_SYSTEM
, &err
);
106 if (dbus_error_is_set(&err
)) {
107 DEBUG(0, ("dbus connection error: %s\n", err
.message
));
108 dbus_error_free(&err
);
114 /* dbus_bus_get_private() sets exit-on-disconnect by default, undo it */
115 dbus_connection_set_exit_on_disconnect(dconn
, false);
120 static void snapper_dbus_conn_destroy(DBusConnection
*dconn
)
123 DEBUG(2, ("attempt to destroy NULL dbus connection\n"));
127 dbus_connection_close(dconn
);
128 dbus_connection_unref(dconn
);
132 * send the message @send_msg over the dbus and wait for a response, return the
133 * responsee via @recv_msg_out.
134 * @send_msg is not freed, dbus_message_unref() must be handled by the caller.
136 static NTSTATUS
snapper_dbus_msg_xchng(DBusConnection
*dconn
,
137 DBusMessage
*send_msg
,
138 DBusMessage
**recv_msg_out
)
140 DBusPendingCall
*pending
;
141 DBusMessage
*recv_msg
;
143 /* send message and get a handle for a reply */
144 if (!dbus_connection_send_with_reply(dconn
, send_msg
, &pending
, -1)) {
145 return NT_STATUS_NO_MEMORY
;
147 if (NULL
== pending
) {
148 DEBUG(0, ("dbus msg send failed\n"));
149 return NT_STATUS_UNSUCCESSFUL
;
152 dbus_connection_flush(dconn
);
154 /* block until we receive a reply */
155 dbus_pending_call_block(pending
);
157 /* get the reply message */
158 recv_msg
= dbus_pending_call_steal_reply(pending
);
159 if (recv_msg
== NULL
) {
160 DEBUG(0, ("Reply Null\n"));
161 return NT_STATUS_UNSUCCESSFUL
;
163 /* free the pending message handle */
164 dbus_pending_call_unref(pending
);
165 *recv_msg_out
= recv_msg
;
170 static NTSTATUS
snapper_type_check(DBusMessageIter
*iter
,
173 int type
= dbus_message_iter_get_arg_type(iter
);
174 if (type
!= expected_type
) {
175 DEBUG(0, ("got type %d, expecting %d\n",
176 type
, expected_type
));
177 return NT_STATUS_INVALID_PARAMETER
;
183 static NTSTATUS
snapper_type_check_get(DBusMessageIter
*iter
,
188 status
= snapper_type_check(iter
, expected_type
);
189 if (!NT_STATUS_IS_OK(status
)) {
193 dbus_message_iter_get_basic(iter
, val
);
198 static NTSTATUS
snapper_dict_unpack(DBusMessageIter
*iter
,
199 struct snapper_dict
*dict_out
)
203 DBusMessageIter dct_iter
;
205 status
= snapper_type_check(iter
, DBUS_TYPE_DICT_ENTRY
);
206 if (!NT_STATUS_IS_OK(status
)) {
209 dbus_message_iter_recurse(iter
, &dct_iter
);
211 status
= snapper_type_check_get(&dct_iter
, DBUS_TYPE_STRING
,
213 if (!NT_STATUS_IS_OK(status
)) {
217 dbus_message_iter_next(&dct_iter
);
218 status
= snapper_type_check_get(&dct_iter
, DBUS_TYPE_STRING
,
220 if (!NT_STATUS_IS_OK(status
)) {
227 static void snapper_dict_array_print(uint32_t num_dicts
,
228 struct snapper_dict
*dicts
)
232 for (i
= 0; i
< num_dicts
; i
++) {
233 DEBUG(10, ("dict (key: %s, val: %s)\n",
234 dicts
[i
].key
, dicts
[i
].val
));
238 static NTSTATUS
snapper_dict_array_unpack(TALLOC_CTX
*mem_ctx
,
239 DBusMessageIter
*iter
,
240 uint32_t *num_dicts_out
,
241 struct snapper_dict
**dicts_out
)
244 DBusMessageIter array_iter
;
246 struct snapper_dict
*dicts
= NULL
;
248 status
= snapper_type_check(iter
, DBUS_TYPE_ARRAY
);
249 if (!NT_STATUS_IS_OK(status
)) {
252 dbus_message_iter_recurse(iter
, &array_iter
);
255 while (dbus_message_iter_get_arg_type(&array_iter
)
256 != DBUS_TYPE_INVALID
) {
258 dicts
= talloc_realloc(mem_ctx
, dicts
, struct snapper_dict
,
263 status
= snapper_dict_unpack(&array_iter
,
264 &dicts
[num_dicts
- 1]);
265 if (!NT_STATUS_IS_OK(status
)) {
269 dbus_message_iter_next(&array_iter
);
272 *num_dicts_out
= num_dicts
;
278 static NTSTATUS
snapper_list_confs_pack(DBusMessage
**req_msg_out
)
282 msg
= dbus_message_new_method_call("org.opensuse.Snapper",
283 "/org/opensuse/Snapper",
284 "org.opensuse.Snapper",
287 DEBUG(0, ("null msg\n"));
288 return NT_STATUS_NO_MEMORY
;
291 /* no arguments to append */
297 static NTSTATUS
snapper_conf_unpack(TALLOC_CTX
*mem_ctx
,
298 DBusMessageIter
*iter
,
299 struct snapper_conf
*conf_out
)
302 DBusMessageIter st_iter
;
304 status
= snapper_type_check(iter
, DBUS_TYPE_STRUCT
);
305 if (!NT_STATUS_IS_OK(status
)) {
308 dbus_message_iter_recurse(iter
, &st_iter
);
310 status
= snapper_type_check_get(&st_iter
, DBUS_TYPE_STRING
,
312 if (!NT_STATUS_IS_OK(status
)) {
316 dbus_message_iter_next(&st_iter
);
317 status
= snapper_type_check_get(&st_iter
, DBUS_TYPE_STRING
,
319 if (!NT_STATUS_IS_OK(status
)) {
323 dbus_message_iter_next(&st_iter
);
324 status
= snapper_dict_array_unpack(mem_ctx
, &st_iter
,
325 &conf_out
->num_attrs
,
331 static struct snapper_conf
*snapper_conf_array_base_find(int32_t num_confs
,
332 struct snapper_conf
*confs
,
337 for (i
= 0; i
< num_confs
; i
++) {
338 if (strcmp(confs
[i
].mnt
, base
) == 0) {
339 DEBUG(5, ("found snapper conf %s for path %s\n",
340 confs
[i
].name
, base
));
344 DEBUG(5, ("config for base %s not found\n", base
));
349 static void snapper_conf_array_print(int32_t num_confs
,
350 struct snapper_conf
*confs
)
354 for (i
= 0; i
< num_confs
; i
++) {
355 DEBUG(10, ("name: %s, mnt: %s\n",
356 confs
[i
].name
, confs
[i
].mnt
));
357 snapper_dict_array_print(confs
[i
].num_attrs
, confs
[i
].attrs
);
361 static NTSTATUS
snapper_conf_array_unpack(TALLOC_CTX
*mem_ctx
,
362 DBusMessageIter
*iter
,
363 uint32_t *num_confs_out
,
364 struct snapper_conf
**confs_out
)
368 struct snapper_conf
*confs
= NULL
;
369 DBusMessageIter array_iter
;
372 status
= snapper_type_check(iter
, DBUS_TYPE_ARRAY
);
373 if (!NT_STATUS_IS_OK(status
)) {
376 dbus_message_iter_recurse(iter
, &array_iter
);
379 while (dbus_message_iter_get_arg_type(&array_iter
)
380 != DBUS_TYPE_INVALID
) {
382 confs
= talloc_realloc(mem_ctx
, confs
, struct snapper_conf
,
387 status
= snapper_conf_unpack(confs
, &array_iter
,
388 &confs
[num_confs
- 1]);
389 if (!NT_STATUS_IS_OK(status
)) {
393 dbus_message_iter_next(&array_iter
);
396 *num_confs_out
= num_confs
;
402 static NTSTATUS
snapper_list_confs_unpack(TALLOC_CTX
*mem_ctx
,
403 DBusConnection
*dconn
,
404 DBusMessage
*rsp_msg
,
405 uint32_t *num_confs_out
,
406 struct snapper_conf
**confs_out
)
409 DBusMessageIter iter
;
412 struct snapper_conf
*confs
;
415 msg_type
= dbus_message_get_type(rsp_msg
);
416 if (msg_type
== DBUS_MESSAGE_TYPE_ERROR
) {
417 const char *err_str
= dbus_message_get_error_name(rsp_msg
);
418 DEBUG(0, ("list_confs error response: %s\n", err_str
));
419 return snapper_err_ntstatus_map(err_str
);
422 if (msg_type
!= DBUS_MESSAGE_TYPE_METHOD_RETURN
) {
423 DEBUG(0, ("unexpected list_confs ret type: %d\n",
425 return NT_STATUS_INVALID_PARAMETER
;
428 sig
= dbus_message_get_signature(rsp_msg
);
430 || (strcmp(sig
, SNAPPER_SIG_LIST_CONFS_RSP
) != 0)) {
431 DEBUG(0, ("bad list confs response sig: %s, expected: %s\n",
432 (sig
? sig
: "NULL"), SNAPPER_SIG_LIST_CONFS_RSP
));
433 return NT_STATUS_INVALID_PARAMETER
;
436 if (!dbus_message_iter_init(rsp_msg
, &iter
)) {
437 /* FIXME return empty? */
438 DEBUG(0, ("Message has no arguments!\n"));
439 return NT_STATUS_INVALID_PARAMETER
;
442 status
= snapper_conf_array_unpack(mem_ctx
, &iter
, &num_confs
, &confs
);
443 if (!NT_STATUS_IS_OK(status
)) {
444 DEBUG(0, ("failed to unpack conf array\n"));
448 snapper_conf_array_print(num_confs
, confs
);
450 *num_confs_out
= num_confs
;
456 static NTSTATUS
snapper_list_snaps_pack(char *snapper_conf
,
457 DBusMessage
**req_msg_out
)
460 DBusMessageIter args
;
462 msg
= dbus_message_new_method_call("org.opensuse.Snapper", /* target for the method call */
463 "/org/opensuse/Snapper", /* object to call on */
464 "org.opensuse.Snapper", /* interface to call on */
465 "ListSnapshots"); /* method name */
467 DEBUG(0, ("failed to create list snaps message\n"));
468 return NT_STATUS_NO_MEMORY
;
471 /* append arguments */
472 dbus_message_iter_init_append(msg
, &args
);
473 if (!dbus_message_iter_append_basic(&args
, DBUS_TYPE_STRING
,
475 return NT_STATUS_NO_MEMORY
;
483 static NTSTATUS
snapper_snap_struct_unpack(TALLOC_CTX
*mem_ctx
,
484 DBusMessageIter
*iter
,
485 struct snapper_snap
*snap_out
)
488 DBusMessageIter st_iter
;
490 status
= snapper_type_check(iter
, DBUS_TYPE_STRUCT
);
491 if (!NT_STATUS_IS_OK(status
)) {
494 dbus_message_iter_recurse(iter
, &st_iter
);
496 status
= snapper_type_check_get(&st_iter
, DBUS_TYPE_UINT32
,
498 if (!NT_STATUS_IS_OK(status
)) {
502 dbus_message_iter_next(&st_iter
);
503 status
= snapper_type_check_get(&st_iter
, DBUS_TYPE_UINT16
,
505 if (!NT_STATUS_IS_OK(status
)) {
509 dbus_message_iter_next(&st_iter
);
510 status
= snapper_type_check_get(&st_iter
, DBUS_TYPE_UINT32
,
512 if (!NT_STATUS_IS_OK(status
)) {
516 dbus_message_iter_next(&st_iter
);
517 status
= snapper_type_check_get(&st_iter
, DBUS_TYPE_INT64
,
519 if (!NT_STATUS_IS_OK(status
)) {
523 dbus_message_iter_next(&st_iter
);
524 status
= snapper_type_check_get(&st_iter
, DBUS_TYPE_UINT32
,
525 &snap_out
->creator_uid
);
526 if (!NT_STATUS_IS_OK(status
)) {
530 dbus_message_iter_next(&st_iter
);
531 status
= snapper_type_check_get(&st_iter
, DBUS_TYPE_STRING
,
533 if (!NT_STATUS_IS_OK(status
)) {
537 dbus_message_iter_next(&st_iter
);
538 status
= snapper_type_check_get(&st_iter
, DBUS_TYPE_STRING
,
540 if (!NT_STATUS_IS_OK(status
)) {
544 dbus_message_iter_next(&st_iter
);
545 status
= snapper_dict_array_unpack(mem_ctx
, &st_iter
,
546 &snap_out
->num_user_data
,
547 &snap_out
->user_data
);
552 static void snapper_snap_array_print(int32_t num_snaps
,
553 struct snapper_snap
*snaps
)
557 for (i
= 0; i
< num_snaps
; i
++) {
558 DEBUG(10, ("id: %u, "
565 (unsigned int)snaps
[i
].id
,
566 (unsigned int)snaps
[i
].type
,
567 (unsigned int)snaps
[i
].pre_id
,
568 (long int)snaps
[i
].time
,
569 (unsigned int)snaps
[i
].creator_uid
,
572 snapper_dict_array_print(snaps
[i
].num_user_data
,
577 static NTSTATUS
snapper_snap_array_unpack(TALLOC_CTX
*mem_ctx
,
578 DBusMessageIter
*iter
,
579 uint32_t *num_snaps_out
,
580 struct snapper_snap
**snaps_out
)
584 struct snapper_snap
*snaps
= NULL
;
585 DBusMessageIter array_iter
;
588 status
= snapper_type_check(iter
, DBUS_TYPE_ARRAY
);
589 if (!NT_STATUS_IS_OK(status
)) {
592 dbus_message_iter_recurse(iter
, &array_iter
);
595 while (dbus_message_iter_get_arg_type(&array_iter
)
596 != DBUS_TYPE_INVALID
) {
598 snaps
= talloc_realloc(mem_ctx
, snaps
, struct snapper_snap
,
603 status
= snapper_snap_struct_unpack(snaps
, &array_iter
,
604 &snaps
[num_snaps
- 1]);
605 if (!NT_STATUS_IS_OK(status
)) {
609 dbus_message_iter_next(&array_iter
);
612 *num_snaps_out
= num_snaps
;
618 static NTSTATUS
snapper_list_snaps_unpack(TALLOC_CTX
*mem_ctx
,
619 DBusMessage
*rsp_msg
,
620 uint32_t *num_snaps_out
,
621 struct snapper_snap
**snaps_out
)
624 DBusMessageIter iter
;
627 struct snapper_snap
*snaps
;
630 msg_type
= dbus_message_get_type(rsp_msg
);
631 if (msg_type
== DBUS_MESSAGE_TYPE_ERROR
) {
632 const char *err_str
= dbus_message_get_error_name(rsp_msg
);
633 DEBUG(0, ("list_snaps error response: %s\n", err_str
));
634 return snapper_err_ntstatus_map(err_str
);
637 if (msg_type
!= DBUS_MESSAGE_TYPE_METHOD_RETURN
) {
638 DEBUG(0,("unexpected list_snaps ret type: %d\n",
640 return NT_STATUS_INVALID_PARAMETER
;
643 sig
= dbus_message_get_signature(rsp_msg
);
645 || (strcmp(sig
, SNAPPER_SIG_LIST_SNAPS_RSP
) != 0)) {
646 DEBUG(0, ("bad list snaps response sig: %s, "
648 (sig
? sig
: "NULL"),
649 SNAPPER_SIG_LIST_SNAPS_RSP
));
650 return NT_STATUS_INVALID_PARAMETER
;
653 /* read the parameters */
654 if (!dbus_message_iter_init(rsp_msg
, &iter
)) {
655 DEBUG(0, ("response has no arguments!\n"));
656 return NT_STATUS_INVALID_PARAMETER
;
659 status
= snapper_snap_array_unpack(mem_ctx
, &iter
, &num_snaps
, &snaps
);
660 if (!NT_STATUS_IS_OK(status
)) {
661 DEBUG(0, ("failed to unpack snap array\n"));
662 return NT_STATUS_INVALID_PARAMETER
;
665 snapper_snap_array_print(num_snaps
, snaps
);
667 *num_snaps_out
= num_snaps
;
673 static NTSTATUS
snapper_list_snaps_at_time_pack(const char *snapper_conf
,
676 DBusMessage
**req_msg_out
)
679 DBusMessageIter args
;
681 msg
= dbus_message_new_method_call("org.opensuse.Snapper",
682 "/org/opensuse/Snapper",
683 "org.opensuse.Snapper",
684 "ListSnapshotsAtTime");
686 DEBUG(0, ("failed to create list snaps message\n"));
687 return NT_STATUS_NO_MEMORY
;
690 dbus_message_iter_init_append(msg
, &args
);
691 if (!dbus_message_iter_append_basic(&args
, DBUS_TYPE_STRING
,
693 return NT_STATUS_NO_MEMORY
;
696 if (!dbus_message_iter_append_basic(&args
, DBUS_TYPE_INT64
,
698 return NT_STATUS_NO_MEMORY
;
701 if (!dbus_message_iter_append_basic(&args
, DBUS_TYPE_INT64
,
703 return NT_STATUS_NO_MEMORY
;
710 /* no snapper_list_snaps_at_time_unpack, use snapper_list_snaps_unpack */
713 * Determine the snapper snapshot path given an id and base.
714 * Ideally this should be determined via a lookup.
716 static NTSTATUS
snapper_snap_id_to_path(TALLOC_CTX
*mem_ctx
,
717 const char *base_path
,
719 char **snap_path_out
)
723 snap_path
= talloc_asprintf(mem_ctx
, "%s/.snapshots/%u/snapshot",
725 if (snap_path
== NULL
) {
726 return NT_STATUS_NO_MEMORY
;
729 *snap_path_out
= snap_path
;
733 static NTSTATUS
snapper_get_conf_call(TALLOC_CTX
*mem_ctx
,
734 DBusConnection
*dconn
,
736 char **conf_name_out
,
737 char **base_path_out
)
740 DBusMessage
*req_msg
;
741 DBusMessage
*rsp_msg
;
742 uint32_t num_confs
= 0;
743 struct snapper_conf
*confs
= NULL
;
744 struct snapper_conf
*conf
;
748 status
= snapper_list_confs_pack(&req_msg
);
749 if (!NT_STATUS_IS_OK(status
)) {
753 status
= snapper_dbus_msg_xchng(dconn
, req_msg
, &rsp_msg
);
754 if (!NT_STATUS_IS_OK(status
)) {
758 status
= snapper_list_confs_unpack(mem_ctx
, dconn
, rsp_msg
,
760 if (!NT_STATUS_IS_OK(status
)) {
765 * for now we only support shares where the path directly corresponds
766 * to a snapper configuration.
768 conf
= snapper_conf_array_base_find(num_confs
, confs
,
771 status
= NT_STATUS_NOT_SUPPORTED
;
775 conf_name
= talloc_strdup(mem_ctx
, conf
->name
);
776 if (conf_name
== NULL
) {
777 status
= NT_STATUS_NO_MEMORY
;
780 base_path
= talloc_strdup(mem_ctx
, conf
->mnt
);
781 if (base_path
== NULL
) {
782 status
= NT_STATUS_NO_MEMORY
;
783 goto err_conf_name_free
;
787 dbus_message_unref(rsp_msg
);
788 dbus_message_unref(req_msg
);
790 *conf_name_out
= conf_name
;
791 *base_path_out
= base_path
;
796 talloc_free(conf_name
);
800 dbus_message_unref(rsp_msg
);
802 dbus_message_unref(req_msg
);
807 /* sc_data used as parent talloc context for all labels */
808 static int snapper_get_shadow_copy_data(struct vfs_handle_struct
*handle
,
809 struct files_struct
*fsp
,
810 struct shadow_copy_data
*sc_data
,
813 DBusConnection
*dconn
;
818 DBusMessage
*req_msg
;
819 DBusMessage
*rsp_msg
;
821 struct snapper_snap
*snaps
;
825 tmp_ctx
= talloc_new(sc_data
);
826 if (tmp_ctx
== NULL
) {
827 status
= NT_STATUS_NO_MEMORY
;
831 dconn
= snapper_dbus_conn_create();
833 status
= NT_STATUS_UNSUCCESSFUL
;
834 goto err_mem_ctx_free
;
837 if (fsp
->conn
->connectpath
== NULL
) {
838 status
= NT_STATUS_INVALID_PARAMETER
;
842 status
= snapper_get_conf_call(tmp_ctx
, dconn
,
843 fsp
->conn
->connectpath
,
846 if (!NT_STATUS_IS_OK(status
)) {
850 status
= snapper_list_snaps_pack(conf_name
, &req_msg
);
851 if (!NT_STATUS_IS_OK(status
)) {
855 status
= snapper_dbus_msg_xchng(dconn
, req_msg
, &rsp_msg
);
856 if (!NT_STATUS_IS_OK(status
)) {
860 status
= snapper_list_snaps_unpack(tmp_ctx
, rsp_msg
,
862 if (!NT_STATUS_IS_OK(status
)) {
865 /* we should always get at least one snapshot (current) */
866 if (num_snaps
== 0) {
867 DEBUG(1, ("zero snapshots in snap list response\n"));
868 status
= NT_STATUS_UNSUCCESSFUL
;
872 /* subtract 1, (current) snapshot is not returned */
873 sc_data
->num_volumes
= num_snaps
- 1;
874 sc_data
->labels
= NULL
;
876 if ((labels
== false) || (sc_data
->num_volumes
== 0)) {
877 /* tokens need not be added to the labels array */
881 sc_data
->labels
= talloc_array(sc_data
, SHADOW_COPY_LABEL
,
882 sc_data
->num_volumes
);
883 if (sc_data
->labels
== NULL
) {
884 status
= NT_STATUS_NO_MEMORY
;
888 /* start at end for decending order, do not include 0 (current) */
890 for (i
= num_snaps
- 1; i
> 0; i
--) {
891 char *lbl
= sc_data
->labels
[lbl_off
++];
892 struct tm gmt_snap_time
;
896 tm_ret
= gmtime_r((time_t *)&snaps
[i
].time
, &gmt_snap_time
);
897 if (tm_ret
== NULL
) {
898 status
= NT_STATUS_UNSUCCESSFUL
;
899 goto err_labels_free
;
901 str_sz
= strftime(lbl
, sizeof(SHADOW_COPY_LABEL
),
902 "@GMT-%Y.%m.%d-%H.%M.%S", &gmt_snap_time
);
904 status
= NT_STATUS_UNSUCCESSFUL
;
905 goto err_labels_free
;
910 talloc_free(tmp_ctx
);
911 dbus_message_unref(rsp_msg
);
912 dbus_message_unref(req_msg
);
913 snapper_dbus_conn_destroy(dconn
);
918 TALLOC_FREE(sc_data
->labels
);
920 dbus_message_unref(rsp_msg
);
922 dbus_message_unref(req_msg
);
924 snapper_dbus_conn_destroy(dconn
);
926 talloc_free(tmp_ctx
);
928 errno
= map_errno_from_nt_status(status
);
932 static bool snapper_gmt_strip_snapshot(TALLOC_CTX
*mem_ctx
,
933 struct vfs_handle_struct
*handle
,
943 size_t rest_len
, dst_len
;
945 p
= strstr_m(name
, "@GMT-");
949 if ((p
> name
) && (p
[-1] != '/')) {
952 q
= strptime(p
, GMT_FORMAT
, &tm
);
957 timestamp
= timegm(&tm
);
958 if (timestamp
== (time_t)-1) {
961 if ((p
== name
) && (q
[0] == '\0')) {
962 if (pstripped
!= NULL
) {
963 stripped
= talloc_strdup(mem_ctx
, "");
964 if (stripped
== NULL
) {
967 *pstripped
= stripped
;
969 *ptimestamp
= timestamp
;
977 rest_len
= strlen(q
);
978 dst_len
= (p
-name
) + rest_len
;
980 if (pstripped
!= NULL
) {
981 stripped
= talloc_array(mem_ctx
, char, dst_len
+1);
982 if (stripped
== NULL
) {
987 memcpy(stripped
, name
, p
-name
);
990 memcpy(stripped
+ (p
-name
), q
, rest_len
);
992 stripped
[dst_len
] = '\0';
993 *pstripped
= stripped
;
995 *ptimestamp
= timestamp
;
1002 static NTSTATUS
snapper_get_snap_at_time_call(TALLOC_CTX
*mem_ctx
,
1003 DBusConnection
*dconn
,
1004 const char *conf_name
,
1005 const char *base_path
,
1007 char **snap_path_out
)
1010 DBusMessage
*req_msg
;
1011 DBusMessage
*rsp_msg
;
1013 struct snapper_snap
*snaps
;
1016 status
= snapper_list_snaps_at_time_pack(conf_name
,
1020 if (!NT_STATUS_IS_OK(status
)) {
1024 status
= snapper_dbus_msg_xchng(dconn
, req_msg
, &rsp_msg
);
1025 if (!NT_STATUS_IS_OK(status
)) {
1029 status
= snapper_list_snaps_unpack(mem_ctx
, rsp_msg
,
1030 &num_snaps
, &snaps
);
1031 if (!NT_STATUS_IS_OK(status
)) {
1035 if (num_snaps
== 0) {
1036 DEBUG(4, ("no snapshots found with time: %lu\n", snaptime
));
1037 status
= NT_STATUS_INVALID_PARAMETER
;
1038 goto err_snap_array_free
;
1039 } else if (num_snaps
> 0) {
1040 DEBUG(4, ("got %u snapshots for single time %lu, using top\n",
1041 num_snaps
, snaptime
));
1044 status
= snapper_snap_id_to_path(mem_ctx
, base_path
, snaps
[0].id
,
1046 if (!NT_STATUS_IS_OK(status
)) {
1047 goto err_snap_array_free
;
1050 *snap_path_out
= snap_path
;
1051 err_snap_array_free
:
1054 dbus_message_unref(rsp_msg
);
1056 dbus_message_unref(req_msg
);
1061 static NTSTATUS
snapper_snap_path_expand(struct connection_struct
*conn
,
1062 TALLOC_CTX
*mem_ctx
,
1064 char **snap_dir_out
)
1066 DBusConnection
*dconn
;
1072 dconn
= snapper_dbus_conn_create();
1073 if (dconn
== NULL
) {
1074 status
= NT_STATUS_UNSUCCESSFUL
;
1078 if (conn
->connectpath
== NULL
) {
1079 status
= NT_STATUS_INVALID_PARAMETER
;
1083 status
= snapper_get_conf_call(mem_ctx
, dconn
,
1087 if (!NT_STATUS_IS_OK(status
)) {
1091 status
= snapper_get_snap_at_time_call(mem_ctx
, dconn
,
1092 conf_name
, base_path
, snap_time
,
1094 if (!NT_STATUS_IS_OK(status
)) {
1095 goto err_conf_name_free
;
1098 /* confirm snapshot path is nested under base path */
1099 if (strncmp(snap_path
, base_path
, strlen(base_path
)) != 0) {
1100 status
= NT_STATUS_INVALID_PARAMETER
;
1101 goto err_snap_path_free
;
1104 talloc_free(conf_name
);
1105 talloc_free(base_path
);
1106 snapper_dbus_conn_destroy(dconn
);
1107 *snap_dir_out
= snap_path
;
1109 return NT_STATUS_OK
;
1112 talloc_free(snap_path
);
1114 talloc_free(conf_name
);
1115 talloc_free(base_path
);
1117 snapper_dbus_conn_destroy(dconn
);
1122 static char *snapper_gmt_convert(TALLOC_CTX
*mem_ctx
,
1123 struct vfs_handle_struct
*handle
,
1124 const char *name
, time_t timestamp
)
1126 char *snap_path
= NULL
;
1131 status
= snapper_snap_path_expand(handle
->conn
, mem_ctx
, timestamp
,
1133 if (!NT_STATUS_IS_OK(status
)) {
1134 errno
= map_errno_from_nt_status(status
);
1138 path
= talloc_asprintf(mem_ctx
, "%s/%s", snap_path
, name
);
1141 goto err_snap_path_free
;
1144 DEBUG(10, ("converted %s/%s @ time to %s\n",
1145 handle
->conn
->connectpath
, name
, path
));
1149 saved_errno
= errno
;
1150 talloc_free(snap_path
);
1151 errno
= saved_errno
;
1156 static DIR *snapper_gmt_opendir(vfs_handle_struct
*handle
,
1167 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, fname
,
1168 ×tamp
, &stripped
)) {
1171 if (timestamp
== 0) {
1172 return SMB_VFS_NEXT_OPENDIR(handle
, fname
, mask
, attr
);
1174 conv
= snapper_gmt_convert(talloc_tos(), handle
, stripped
, timestamp
);
1175 TALLOC_FREE(stripped
);
1179 ret
= SMB_VFS_NEXT_OPENDIR(handle
, conv
, mask
, attr
);
1180 saved_errno
= errno
;
1182 errno
= saved_errno
;
1186 static int snapper_gmt_rename(vfs_handle_struct
*handle
,
1187 const struct smb_filename
*smb_fname_src
,
1188 const struct smb_filename
*smb_fname_dst
)
1190 time_t timestamp_src
, timestamp_dst
;
1192 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
,
1193 smb_fname_src
->base_name
,
1194 ×tamp_src
, NULL
)) {
1197 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
,
1198 smb_fname_dst
->base_name
,
1199 ×tamp_dst
, NULL
)) {
1202 if (timestamp_src
!= 0) {
1206 if (timestamp_dst
!= 0) {
1210 return SMB_VFS_NEXT_RENAME(handle
, smb_fname_src
, smb_fname_dst
);
1213 static int snapper_gmt_symlink(vfs_handle_struct
*handle
,
1214 const char *oldname
, const char *newname
)
1216 time_t timestamp_old
, timestamp_new
;
1218 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, oldname
,
1219 ×tamp_old
, NULL
)) {
1222 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, newname
,
1223 ×tamp_new
, NULL
)) {
1226 if ((timestamp_old
!= 0) || (timestamp_new
!= 0)) {
1230 return SMB_VFS_NEXT_SYMLINK(handle
, oldname
, newname
);
1233 static int snapper_gmt_link(vfs_handle_struct
*handle
,
1234 const char *oldname
, const char *newname
)
1236 time_t timestamp_old
, timestamp_new
;
1238 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, oldname
,
1239 ×tamp_old
, NULL
)) {
1242 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, newname
,
1243 ×tamp_new
, NULL
)) {
1246 if ((timestamp_old
!= 0) || (timestamp_new
!= 0)) {
1250 return SMB_VFS_NEXT_LINK(handle
, oldname
, newname
);
1253 static int snapper_gmt_stat(vfs_handle_struct
*handle
,
1254 struct smb_filename
*smb_fname
)
1257 char *stripped
, *tmp
;
1258 int ret
, saved_errno
;
1260 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
,
1261 smb_fname
->base_name
,
1262 ×tamp
, &stripped
)) {
1265 if (timestamp
== 0) {
1266 return SMB_VFS_NEXT_STAT(handle
, smb_fname
);
1269 tmp
= smb_fname
->base_name
;
1270 smb_fname
->base_name
= snapper_gmt_convert(talloc_tos(), handle
,
1271 stripped
, timestamp
);
1272 TALLOC_FREE(stripped
);
1274 if (smb_fname
->base_name
== NULL
) {
1275 smb_fname
->base_name
= tmp
;
1279 ret
= SMB_VFS_NEXT_STAT(handle
, smb_fname
);
1280 saved_errno
= errno
;
1282 TALLOC_FREE(smb_fname
->base_name
);
1283 smb_fname
->base_name
= tmp
;
1285 errno
= saved_errno
;
1289 static int snapper_gmt_lstat(vfs_handle_struct
*handle
,
1290 struct smb_filename
*smb_fname
)
1293 char *stripped
, *tmp
;
1294 int ret
, saved_errno
;
1296 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
,
1297 smb_fname
->base_name
,
1298 ×tamp
, &stripped
)) {
1301 if (timestamp
== 0) {
1302 return SMB_VFS_NEXT_LSTAT(handle
, smb_fname
);
1305 tmp
= smb_fname
->base_name
;
1306 smb_fname
->base_name
= snapper_gmt_convert(talloc_tos(), handle
,
1307 stripped
, timestamp
);
1308 TALLOC_FREE(stripped
);
1310 if (smb_fname
->base_name
== NULL
) {
1311 smb_fname
->base_name
= tmp
;
1315 ret
= SMB_VFS_NEXT_LSTAT(handle
, smb_fname
);
1316 saved_errno
= errno
;
1318 TALLOC_FREE(smb_fname
->base_name
);
1319 smb_fname
->base_name
= tmp
;
1321 errno
= saved_errno
;
1325 static int snapper_gmt_fstat(vfs_handle_struct
*handle
, files_struct
*fsp
,
1326 SMB_STRUCT_STAT
*sbuf
)
1331 ret
= SMB_VFS_NEXT_FSTAT(handle
, fsp
, sbuf
);
1335 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
,
1336 fsp
->fsp_name
->base_name
,
1337 ×tamp
, NULL
)) {
1343 static int snapper_gmt_open(vfs_handle_struct
*handle
,
1344 struct smb_filename
*smb_fname
, files_struct
*fsp
,
1345 int flags
, mode_t mode
)
1348 char *stripped
, *tmp
;
1349 int ret
, saved_errno
;
1351 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
,
1352 smb_fname
->base_name
,
1353 ×tamp
, &stripped
)) {
1356 if (timestamp
== 0) {
1357 return SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
1360 tmp
= smb_fname
->base_name
;
1361 smb_fname
->base_name
= snapper_gmt_convert(talloc_tos(), handle
,
1362 stripped
, timestamp
);
1363 TALLOC_FREE(stripped
);
1365 if (smb_fname
->base_name
== NULL
) {
1366 smb_fname
->base_name
= tmp
;
1370 ret
= SMB_VFS_NEXT_OPEN(handle
, smb_fname
, fsp
, flags
, mode
);
1371 saved_errno
= errno
;
1373 TALLOC_FREE(smb_fname
->base_name
);
1374 smb_fname
->base_name
= tmp
;
1376 errno
= saved_errno
;
1380 static int snapper_gmt_unlink(vfs_handle_struct
*handle
,
1381 const struct smb_filename
*smb_fname
)
1385 int ret
, saved_errno
;
1386 struct smb_filename
*conv
;
1388 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
,
1389 smb_fname
->base_name
,
1390 ×tamp
, &stripped
)) {
1393 if (timestamp
== 0) {
1394 return SMB_VFS_NEXT_UNLINK(handle
, smb_fname
);
1396 conv
= cp_smb_filename(talloc_tos(), smb_fname
);
1401 conv
->base_name
= snapper_gmt_convert(conv
, handle
,
1402 stripped
, timestamp
);
1403 TALLOC_FREE(stripped
);
1404 if (conv
->base_name
== NULL
) {
1407 ret
= SMB_VFS_NEXT_UNLINK(handle
, conv
);
1408 saved_errno
= errno
;
1410 errno
= saved_errno
;
1414 static int snapper_gmt_chmod(vfs_handle_struct
*handle
, const char *fname
,
1419 int ret
, saved_errno
;
1422 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, fname
,
1423 ×tamp
, &stripped
)) {
1426 if (timestamp
== 0) {
1427 return SMB_VFS_NEXT_CHMOD(handle
, fname
, mode
);
1429 conv
= snapper_gmt_convert(talloc_tos(), handle
, stripped
, timestamp
);
1430 TALLOC_FREE(stripped
);
1434 ret
= SMB_VFS_NEXT_CHMOD(handle
, conv
, mode
);
1435 saved_errno
= errno
;
1437 errno
= saved_errno
;
1441 static int snapper_gmt_chown(vfs_handle_struct
*handle
, const char *fname
,
1442 uid_t uid
, gid_t gid
)
1446 int ret
, saved_errno
;
1449 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, fname
,
1450 ×tamp
, &stripped
)) {
1453 if (timestamp
== 0) {
1454 return SMB_VFS_NEXT_CHOWN(handle
, fname
, uid
, gid
);
1456 conv
= snapper_gmt_convert(talloc_tos(), handle
, stripped
, timestamp
);
1457 TALLOC_FREE(stripped
);
1461 ret
= SMB_VFS_NEXT_CHOWN(handle
, conv
, uid
, gid
);
1462 saved_errno
= errno
;
1464 errno
= saved_errno
;
1468 static int snapper_gmt_chdir(vfs_handle_struct
*handle
,
1473 int ret
, saved_errno
;
1476 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, fname
,
1477 ×tamp
, &stripped
)) {
1480 if (timestamp
== 0) {
1481 return SMB_VFS_NEXT_CHDIR(handle
, fname
);
1483 conv
= snapper_gmt_convert(talloc_tos(), handle
, stripped
, timestamp
);
1484 TALLOC_FREE(stripped
);
1488 ret
= SMB_VFS_NEXT_CHDIR(handle
, conv
);
1489 saved_errno
= errno
;
1491 errno
= saved_errno
;
1495 static int snapper_gmt_ntimes(vfs_handle_struct
*handle
,
1496 const struct smb_filename
*smb_fname
,
1497 struct smb_file_time
*ft
)
1501 int ret
, saved_errno
;
1502 struct smb_filename
*conv
;
1504 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
,
1505 smb_fname
->base_name
,
1506 ×tamp
, &stripped
)) {
1509 if (timestamp
== 0) {
1510 return SMB_VFS_NEXT_NTIMES(handle
, smb_fname
, ft
);
1512 conv
= cp_smb_filename(talloc_tos(), smb_fname
);
1517 conv
->base_name
= snapper_gmt_convert(conv
, handle
,
1518 stripped
, timestamp
);
1519 TALLOC_FREE(stripped
);
1520 if (conv
->base_name
== NULL
) {
1523 ret
= SMB_VFS_NEXT_NTIMES(handle
, conv
, ft
);
1524 saved_errno
= errno
;
1526 errno
= saved_errno
;
1530 static int snapper_gmt_readlink(vfs_handle_struct
*handle
,
1531 const char *fname
, char *buf
, size_t bufsiz
)
1535 int ret
, saved_errno
;
1538 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, fname
,
1539 ×tamp
, &stripped
)) {
1542 if (timestamp
== 0) {
1543 return SMB_VFS_NEXT_READLINK(handle
, fname
, buf
, bufsiz
);
1545 conv
= snapper_gmt_convert(talloc_tos(), handle
, stripped
, timestamp
);
1546 TALLOC_FREE(stripped
);
1550 ret
= SMB_VFS_NEXT_READLINK(handle
, conv
, buf
, bufsiz
);
1551 saved_errno
= errno
;
1553 errno
= saved_errno
;
1557 static int snapper_gmt_mknod(vfs_handle_struct
*handle
,
1558 const char *fname
, mode_t mode
, SMB_DEV_T dev
)
1562 int ret
, saved_errno
;
1565 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, fname
,
1566 ×tamp
, &stripped
)) {
1569 if (timestamp
== 0) {
1570 return SMB_VFS_NEXT_MKNOD(handle
, fname
, mode
, dev
);
1572 conv
= snapper_gmt_convert(talloc_tos(), handle
, stripped
, timestamp
);
1573 TALLOC_FREE(stripped
);
1577 ret
= SMB_VFS_NEXT_MKNOD(handle
, conv
, mode
, dev
);
1578 saved_errno
= errno
;
1580 errno
= saved_errno
;
1584 static char *snapper_gmt_realpath(vfs_handle_struct
*handle
,
1588 char *stripped
= NULL
;
1590 char *result
= NULL
;
1593 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, fname
,
1594 ×tamp
, &stripped
)) {
1597 if (timestamp
== 0) {
1598 return SMB_VFS_NEXT_REALPATH(handle
, fname
);
1601 tmp
= snapper_gmt_convert(talloc_tos(), handle
, stripped
, timestamp
);
1606 result
= SMB_VFS_NEXT_REALPATH(handle
, tmp
);
1607 if (result
== NULL
) {
1612 saved_errno
= errno
;
1614 TALLOC_FREE(stripped
);
1615 errno
= saved_errno
;
1619 static NTSTATUS
snapper_gmt_fget_nt_acl(vfs_handle_struct
*handle
,
1620 struct files_struct
*fsp
,
1621 uint32 security_info
,
1622 TALLOC_CTX
*mem_ctx
,
1623 struct security_descriptor
**ppdesc
)
1630 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
,
1631 fsp
->fsp_name
->base_name
,
1632 ×tamp
, &stripped
)) {
1633 return map_nt_error_from_unix(errno
);
1635 if (timestamp
== 0) {
1636 return SMB_VFS_NEXT_FGET_NT_ACL(handle
, fsp
, security_info
,
1640 conv
= snapper_gmt_convert(talloc_tos(), handle
, stripped
, timestamp
);
1641 TALLOC_FREE(stripped
);
1643 return map_nt_error_from_unix(errno
);
1645 status
= SMB_VFS_NEXT_GET_NT_ACL(handle
, conv
, security_info
,
1651 static NTSTATUS
snapper_gmt_get_nt_acl(vfs_handle_struct
*handle
,
1653 uint32 security_info
,
1654 TALLOC_CTX
*mem_ctx
,
1655 struct security_descriptor
**ppdesc
)
1662 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, fname
,
1663 ×tamp
, &stripped
)) {
1664 return map_nt_error_from_unix(errno
);
1666 if (timestamp
== 0) {
1667 return SMB_VFS_NEXT_GET_NT_ACL(handle
, fname
, security_info
,
1670 conv
= snapper_gmt_convert(talloc_tos(), handle
, stripped
, timestamp
);
1671 TALLOC_FREE(stripped
);
1673 return map_nt_error_from_unix(errno
);
1675 status
= SMB_VFS_NEXT_GET_NT_ACL(handle
, conv
, security_info
,
1681 static int snapper_gmt_mkdir(vfs_handle_struct
*handle
,
1682 const char *fname
, mode_t mode
)
1686 int ret
, saved_errno
;
1689 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, fname
,
1690 ×tamp
, &stripped
)) {
1693 if (timestamp
== 0) {
1694 return SMB_VFS_NEXT_MKDIR(handle
, fname
, mode
);
1696 conv
= snapper_gmt_convert(talloc_tos(), handle
, stripped
, timestamp
);
1697 TALLOC_FREE(stripped
);
1701 ret
= SMB_VFS_NEXT_MKDIR(handle
, conv
, mode
);
1702 saved_errno
= errno
;
1704 errno
= saved_errno
;
1708 static int snapper_gmt_rmdir(vfs_handle_struct
*handle
, const char *fname
)
1712 int ret
, saved_errno
;
1715 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, fname
,
1716 ×tamp
, &stripped
)) {
1719 if (timestamp
== 0) {
1720 return SMB_VFS_NEXT_RMDIR(handle
, fname
);
1722 conv
= snapper_gmt_convert(talloc_tos(), handle
, stripped
, timestamp
);
1723 TALLOC_FREE(stripped
);
1727 ret
= SMB_VFS_NEXT_RMDIR(handle
, conv
);
1728 saved_errno
= errno
;
1730 errno
= saved_errno
;
1734 static int snapper_gmt_chflags(vfs_handle_struct
*handle
, const char *fname
,
1739 int ret
, saved_errno
;
1742 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, fname
,
1743 ×tamp
, &stripped
)) {
1746 if (timestamp
== 0) {
1747 return SMB_VFS_NEXT_CHFLAGS(handle
, fname
, flags
);
1749 conv
= snapper_gmt_convert(talloc_tos(), handle
, stripped
, timestamp
);
1750 TALLOC_FREE(stripped
);
1754 ret
= SMB_VFS_NEXT_CHFLAGS(handle
, conv
, flags
);
1755 saved_errno
= errno
;
1757 errno
= saved_errno
;
1761 static ssize_t
snapper_gmt_getxattr(vfs_handle_struct
*handle
,
1762 const char *fname
, const char *aname
,
1763 void *value
, size_t size
)
1771 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, fname
,
1772 ×tamp
, &stripped
)) {
1775 if (timestamp
== 0) {
1776 return SMB_VFS_NEXT_GETXATTR(handle
, fname
, aname
, value
,
1779 conv
= snapper_gmt_convert(talloc_tos(), handle
, stripped
, timestamp
);
1780 TALLOC_FREE(stripped
);
1784 ret
= SMB_VFS_NEXT_GETXATTR(handle
, conv
, aname
, value
, size
);
1785 saved_errno
= errno
;
1787 errno
= saved_errno
;
1791 static ssize_t
snapper_gmt_listxattr(struct vfs_handle_struct
*handle
,
1793 char *list
, size_t size
)
1801 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, fname
,
1802 ×tamp
, &stripped
)) {
1805 if (timestamp
== 0) {
1806 return SMB_VFS_NEXT_LISTXATTR(handle
, fname
, list
, size
);
1808 conv
= snapper_gmt_convert(talloc_tos(), handle
, stripped
, timestamp
);
1809 TALLOC_FREE(stripped
);
1813 ret
= SMB_VFS_NEXT_LISTXATTR(handle
, conv
, list
, size
);
1814 saved_errno
= errno
;
1816 errno
= saved_errno
;
1820 static int snapper_gmt_removexattr(vfs_handle_struct
*handle
,
1821 const char *fname
, const char *aname
)
1825 int ret
, saved_errno
;
1828 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, fname
,
1829 ×tamp
, &stripped
)) {
1832 if (timestamp
== 0) {
1833 return SMB_VFS_NEXT_REMOVEXATTR(handle
, fname
, aname
);
1835 conv
= snapper_gmt_convert(talloc_tos(), handle
, stripped
, timestamp
);
1836 TALLOC_FREE(stripped
);
1840 ret
= SMB_VFS_NEXT_REMOVEXATTR(handle
, conv
, aname
);
1841 saved_errno
= errno
;
1843 errno
= saved_errno
;
1847 static int snapper_gmt_setxattr(struct vfs_handle_struct
*handle
,
1849 const char *aname
, const void *value
,
1850 size_t size
, int flags
)
1858 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, fname
,
1859 ×tamp
, &stripped
)) {
1862 if (timestamp
== 0) {
1863 return SMB_VFS_NEXT_SETXATTR(handle
, fname
, aname
, value
, size
,
1866 conv
= snapper_gmt_convert(talloc_tos(), handle
, stripped
, timestamp
);
1867 TALLOC_FREE(stripped
);
1871 ret
= SMB_VFS_NEXT_SETXATTR(handle
, conv
, aname
, value
, size
, flags
);
1872 saved_errno
= errno
;
1874 errno
= saved_errno
;
1878 static int snapper_gmt_chmod_acl(vfs_handle_struct
*handle
,
1879 const char *fname
, mode_t mode
)
1887 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, fname
,
1888 ×tamp
, &stripped
)) {
1891 if (timestamp
== 0) {
1892 return SMB_VFS_NEXT_CHMOD_ACL(handle
, fname
, mode
);
1894 conv
= snapper_gmt_convert(talloc_tos(), handle
, stripped
, timestamp
);
1895 TALLOC_FREE(stripped
);
1899 ret
= SMB_VFS_NEXT_CHMOD_ACL(handle
, conv
, mode
);
1900 saved_errno
= errno
;
1902 errno
= saved_errno
;
1906 static int snapper_gmt_get_real_filename(struct vfs_handle_struct
*handle
,
1909 TALLOC_CTX
*mem_ctx
,
1918 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, path
,
1919 ×tamp
, &stripped
)) {
1922 if (timestamp
== 0) {
1923 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle
, path
, name
,
1924 mem_ctx
, found_name
);
1926 if (stripped
[0] == '\0') {
1927 *found_name
= talloc_strdup(mem_ctx
, name
);
1928 if (*found_name
== NULL
) {
1934 conv
= snapper_gmt_convert(talloc_tos(), handle
, stripped
, timestamp
);
1935 TALLOC_FREE(stripped
);
1939 ret
= SMB_VFS_NEXT_GET_REAL_FILENAME(handle
, conv
, name
,
1940 mem_ctx
, found_name
);
1941 saved_errno
= errno
;
1943 errno
= saved_errno
;
1947 static uint64_t snapper_gmt_disk_free(vfs_handle_struct
*handle
,
1948 const char *path
, bool small_query
,
1949 uint64_t *bsize
, uint64_t *dfree
,
1958 if (!snapper_gmt_strip_snapshot(talloc_tos(), handle
, path
,
1959 ×tamp
, &stripped
)) {
1962 if (timestamp
== 0) {
1963 return SMB_VFS_NEXT_DISK_FREE(handle
, path
, small_query
,
1964 bsize
, dfree
, dsize
);
1967 conv
= snapper_gmt_convert(talloc_tos(), handle
, stripped
, timestamp
);
1968 TALLOC_FREE(stripped
);
1973 ret
= SMB_VFS_NEXT_DISK_FREE(handle
, conv
, small_query
, bsize
, dfree
,
1976 saved_errno
= errno
;
1978 errno
= saved_errno
;
1984 static struct vfs_fn_pointers snapper_fns
= {
1985 .get_shadow_copy_data_fn
= snapper_get_shadow_copy_data
,
1986 .opendir_fn
= snapper_gmt_opendir
,
1987 .disk_free_fn
= snapper_gmt_disk_free
,
1988 .rename_fn
= snapper_gmt_rename
,
1989 .link_fn
= snapper_gmt_link
,
1990 .symlink_fn
= snapper_gmt_symlink
,
1991 .stat_fn
= snapper_gmt_stat
,
1992 .lstat_fn
= snapper_gmt_lstat
,
1993 .fstat_fn
= snapper_gmt_fstat
,
1994 .open_fn
= snapper_gmt_open
,
1995 .unlink_fn
= snapper_gmt_unlink
,
1996 .chmod_fn
= snapper_gmt_chmod
,
1997 .chown_fn
= snapper_gmt_chown
,
1998 .chdir_fn
= snapper_gmt_chdir
,
1999 .ntimes_fn
= snapper_gmt_ntimes
,
2000 .readlink_fn
= snapper_gmt_readlink
,
2001 .mknod_fn
= snapper_gmt_mknod
,
2002 .realpath_fn
= snapper_gmt_realpath
,
2003 .get_nt_acl_fn
= snapper_gmt_get_nt_acl
,
2004 .fget_nt_acl_fn
= snapper_gmt_fget_nt_acl
,
2005 .mkdir_fn
= snapper_gmt_mkdir
,
2006 .rmdir_fn
= snapper_gmt_rmdir
,
2007 .getxattr_fn
= snapper_gmt_getxattr
,
2008 .listxattr_fn
= snapper_gmt_listxattr
,
2009 .removexattr_fn
= snapper_gmt_removexattr
,
2010 .setxattr_fn
= snapper_gmt_setxattr
,
2011 .chmod_acl_fn
= snapper_gmt_chmod_acl
,
2012 .chflags_fn
= snapper_gmt_chflags
,
2013 .get_real_filename_fn
= snapper_gmt_get_real_filename
,
2016 NTSTATUS
vfs_snapper_init(void);
2017 NTSTATUS
vfs_snapper_init(void)
2019 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
,
2020 "snapper", &snapper_fns
);