SQ snapper: implement get_shadow_copy_data
authorDavid Disseldorp <ddiss@samba.org>
Sun, 14 Oct 2012 21:25:37 +0000 (23:25 +0200)
committerDavid Disseldorp <ddiss@samba.org>
Mon, 15 Apr 2013 16:15:21 +0000 (18:15 +0200)
source3/modules/vfs_snapper.c

index 11d989d47c08a280c2462d40d74454bc78536075..fc14025f47b9b1799113fa2b88e23933d49b889d 100644 (file)
@@ -23,6 +23,7 @@
 #include <dirent.h>
 #include <libgen.h>
 #include "includes.h"
+#include "include/ntioctl.h"
 #include "system/filesys.h"
 #include "smbd/smbd.h"
 #include "lib/util/tevent_ntstatus.h"
@@ -589,7 +590,6 @@ static NTSTATUS snapper_snap_array_unpack(TALLOC_CTX *mem_ctx,
 }
 
 static NTSTATUS snapper_list_snaps_unpack(TALLOC_CTX *mem_ctx,
-                                         DBusConnection *dconn,
                                          DBusMessage *rsp_msg,
                                          uint32_t *num_snaps_out,
                                          struct snapper_snap **snaps_out)
@@ -975,11 +975,8 @@ static struct tevent_req *snapper_snap_create_send(struct vfs_handle_struct *han
                return NULL;
        }
 
-       /* become root for snapper dbus exchange */
-       become_root();
        dconn = snapper_dbus_conn();
        if (dconn == NULL) {
-               unbecome_root();
                tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
                return tevent_req_post(req, ev);
        }
@@ -989,7 +986,6 @@ static struct tevent_req *snapper_snap_create_send(struct vfs_handle_struct *han
                                       &create_state->base_path);
        if (tevent_req_nterror(req, status)) {
                dbus_connection_unref(dconn);
-               unbecome_root();
                return tevent_req_post(req, ev);
        }
 
@@ -1001,12 +997,10 @@ static struct tevent_req *snapper_snap_create_send(struct vfs_handle_struct *han
                                          &create_state->snap_path);
        if (tevent_req_nterror(req, status)) {
                dbus_connection_unref(dconn);
-               unbecome_root();
                return tevent_req_post(req, ev);
        }
 
        dbus_connection_unref(dconn);
-       unbecome_root();
 
        tevent_req_done(req);
        return tevent_req_post(req, ev);
@@ -1077,12 +1071,136 @@ static NTSTATUS snapper_snap_delete_recv(struct vfs_handle_struct *handle,
        return NT_STATUS_OK;
 }
 
+/* sc_data used as parent talloc context for all labels */
+static int snapper_get_shadow_copy_data(struct vfs_handle_struct *handle,
+                                       struct files_struct *fsp,
+                                       struct shadow_copy_data *sc_data,
+                                       bool labels)
+{
+       DBusConnection *dconn;
+       TALLOC_CTX *tmp_ctx;
+       NTSTATUS status;
+       char *conf_name;
+       char *base_path;
+       DBusMessage *req_msg;
+       DBusMessage *rsp_msg;
+       uint32_t num_snaps;
+       struct snapper_snap *snaps;
+       uint32_t i;
+
+       tmp_ctx = talloc_new(sc_data);
+       if (tmp_ctx == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto err_out;
+       }
+
+       dconn = snapper_dbus_conn();
+       if (dconn == NULL) {
+               status = NT_STATUS_UNSUCCESSFUL;
+               goto err_mem_ctx_free;
+       }
+
+       if (fsp->conn->connectpath == NULL) {
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto err_conn_free;
+       }
+
+       status = snapper_get_conf_call(tmp_ctx, dconn,
+                                      fsp->conn->connectpath,
+                                      &conf_name,
+                                      &base_path);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto err_conn_free;
+       }
+
+       status = snapper_list_snaps_pack(conf_name, &req_msg);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto err_req_free;
+       }
+
+       status = snapper_dbus_msg_xchng(dconn, req_msg, &rsp_msg);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto err_req_free;
+       }
+
+       status = snapper_list_snaps_unpack(tmp_ctx, rsp_msg,
+                                          &num_snaps, &snaps);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto err_rsp_free;
+       }
+       /* we should always get at least one snapshot (current) */
+       if (num_snaps == 0) {
+               DEBUG(0, ("zero snapshots in snap list response\n"));
+               goto err_rsp_free;
+       }
+
+       snapper_snap_array_print(num_snaps, snaps);
+
+       /* subtract 1, (current) snapshot is not returned */
+       sc_data->num_volumes = num_snaps - 1;
+       sc_data->labels = NULL;
+
+       if ((labels == false) || (sc_data->num_volumes == 0)) {
+               /* tokens need not be added to the labels array */
+               goto done;
+       }
+
+       sc_data->labels = talloc_array(sc_data, SHADOW_COPY_LABEL, num_snaps - 1);
+       if (sc_data->labels == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto err_rsp_free;
+       }
+
+       /* start at offset 1, skipping (current) */
+       for (i = 1; i < num_snaps; i++) {
+               char *lbl = sc_data->labels[i - 1];
+               struct tm gmt_snap_time;
+               struct tm *tm_ret;
+               size_t str_sz;
+
+               tm_ret = gmtime_r((time_t *)&snaps[i].time, &gmt_snap_time);
+               if (tm_ret == NULL) {
+                       status = NT_STATUS_UNSUCCESSFUL;
+                       goto err_labels_free;
+               }
+               str_sz = strftime(lbl, sizeof(SHADOW_COPY_LABEL),
+                                 "@GMT-%Y.%m.%d-%H.%M.%S", &gmt_snap_time);
+               if (str_sz == 0) {
+                       status = NT_STATUS_UNSUCCESSFUL;
+                       goto err_labels_free;
+               }
+       }
+
+done:
+       talloc_free(tmp_ctx);
+       dbus_message_unref(rsp_msg);
+       dbus_message_unref(req_msg);
+       dbus_connection_unref(dconn);
+
+       return 0;
+
+err_labels_free:
+       TALLOC_FREE(sc_data->labels);
+err_rsp_free:
+       dbus_message_unref(rsp_msg);
+err_req_free:
+       dbus_message_unref(req_msg);
+err_conn_free:
+       dbus_connection_unref(dconn);
+err_mem_ctx_free:
+       talloc_free(tmp_ctx);
+err_out:
+       /* all errors are collapsed to a -1 return code */
+       return -1;
+}
+
 static struct vfs_fn_pointers snapper_fns = {
        .snap_check_path_fn = snapper_snap_check_path,
        .snap_create_send_fn = snapper_snap_create_send,
        .snap_create_recv_fn = snapper_snap_create_recv,
        .snap_delete_send_fn = snapper_snap_delete_send,
        .snap_delete_recv_fn = snapper_snap_delete_recv,
+       .get_shadow_copy_data_fn = snapper_get_shadow_copy_data,
 };
 
 NTSTATUS vfs_snapper_init(void);