SQ snapper: working snapshot delete support
authorDavid Disseldorp <ddiss@samba.org>
Sun, 14 Oct 2012 23:01:09 +0000 (01:01 +0200)
committerDavid Disseldorp <ddiss@samba.org>
Mon, 15 Apr 2013 16:15:21 +0000 (18:15 +0200)
source3/modules/vfs_snapper.c

index fc14025f47b9b1799113fa2b88e23933d49b889d..bc53464ad4a48433d1ef431e9888d8c074be90fa 100644 (file)
@@ -33,6 +33,7 @@
 #define SNAPPER_SIG_LIST_SNAPS_RSP "a(uqutussa{ss})"
 #define SNAPPER_SIG_LIST_CONFS_RSP "a(ssa{ss})"
 #define SNAPPER_SIG_CREATE_SNAP_RSP "u"
+#define SNAPPER_SIG_DEL_SNAPS_RSP ""
 #define SNAPPER_SIG_STRING_DICT "{ss}"
 
 struct snapper_dict {
@@ -780,6 +781,84 @@ static NTSTATUS snapper_create_snap_unpack(DBusConnection *conn,
        return NT_STATUS_OK;
 }
 
+static NTSTATUS snapper_del_snap_pack(const char *snapper_conf,
+                                     uint32_t snap_id,
+                                     DBusMessage **req_msg_out)
+{
+       DBusMessage *msg;
+       DBusMessageIter args;
+       DBusMessageIter array_iter;
+       bool ok;
+
+       msg = dbus_message_new_method_call("org.opensuse.Snapper",
+                                          "/org/opensuse/Snapper",
+                                          "org.opensuse.Snapper",
+                                          "DeleteSnapshots");
+       if (msg == NULL) {
+               DEBUG(0, ("failed to create req msg\n"));
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       /* append arguments */
+       dbus_message_iter_init_append(msg, &args);
+       ok = dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING,
+                                           &snapper_conf);
+       if (!ok) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ok = dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY,
+                                              DBUS_TYPE_UINT32_AS_STRING,
+                                              &array_iter);
+       if (!ok) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ok = dbus_message_iter_append_basic(&array_iter,
+                                           DBUS_TYPE_UINT32,
+                                           &snap_id);
+       if (!ok) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       dbus_message_iter_close_container(&args, &array_iter);
+       *req_msg_out = msg;
+
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS snapper_del_snap_unpack(DBusConnection *conn,
+                                       DBusMessage *rsp_msg)
+{
+       int msg_type;
+       const char *sig;
+
+       msg_type = dbus_message_get_type(rsp_msg);
+       if (msg_type == DBUS_MESSAGE_TYPE_ERROR) {
+               DEBUG(0, ("del snap error response: %s\n",
+                         dbus_message_get_error_name(rsp_msg)));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (msg_type != DBUS_MESSAGE_TYPE_METHOD_RETURN) {
+               DEBUG(0, ("unexpected del snap ret type: %d\n",
+                         msg_type));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       sig = dbus_message_get_signature(rsp_msg);
+       if ((sig == NULL)
+        || (strcmp(sig, SNAPPER_SIG_DEL_SNAPS_RSP) != 0)) {
+               DEBUG(0, ("bad create snap response sig: %s, expected: %s\n",
+                         (sig ? sig : "NULL"), SNAPPER_SIG_DEL_SNAPS_RSP));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       /* no parameters in response */
+
+       return NT_STATUS_OK;
+}
+
 static NTSTATUS snapper_get_conf_call(TALLOC_CTX *mem_ctx,
                                      DBusConnection *dconn,
                                      const char *path,
@@ -933,7 +1012,7 @@ static NTSTATUS snapper_create_snap_call(TALLOC_CTX *mem_ctx,
         * Assume snapshot exists in the .snapshots subdir of the base.
         * TODO lookup via GetSnapshot
         */
-       snap_path = talloc_asprintf(mem_ctx, "%s/%u", base_path, snap_id);
+       snap_path = talloc_asprintf(mem_ctx, "%s/.snapshots/%u", base_path, snap_id);
        if (snap_path == NULL) {
                status = NT_STATUS_NO_MEMORY;
                goto err_rsp_free;
@@ -1035,25 +1114,110 @@ static NTSTATUS snapper_snap_create_recv(struct vfs_handle_struct *handle,
        return NT_STATUS_OK;
 }
 
+static NTSTATUS snapper_delete_snap_call(TALLOC_CTX *mem_ctx,
+                                        DBusConnection *dconn,
+                                        const char *conf_name,
+                                        uint32_t snap_id)
+{
+       NTSTATUS status;
+       DBusMessage *req_msg;
+       DBusMessage *rsp_msg;
+
+       status = snapper_del_snap_pack(conf_name, snap_id, &req_msg);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto err_out;
+       }
+
+       status = snapper_dbus_msg_xchng(dconn, req_msg, &rsp_msg);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto err_req_free;
+       }
+
+       status = snapper_del_snap_unpack(dconn, rsp_msg);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto err_rsp_free;
+       }
+
+       dbus_message_unref(rsp_msg);
+       dbus_message_unref(req_msg);
+
+       DEBUG(6, ("deleted snapshot %u\n", snap_id));
+
+       return NT_STATUS_OK;
+
+err_rsp_free:
+       dbus_message_unref(rsp_msg);
+err_req_free:
+       dbus_message_unref(req_msg);
+err_out:
+       return status;
+}
+
+struct snapper_snap_delete_state {
+       char *conf_name;
+       char *base_path;
+       char *snap_path;
+       uint32_t snap_id;
+};
+
 static struct tevent_req *snapper_snap_delete_send(struct vfs_handle_struct *handle,
                                                   TALLOC_CTX *mem_ctx,
                                                   struct tevent_context *ev,
+                                                  char *base_path,
                                                   char *snap_path)
 {
        struct tevent_req *req;
+       DBusConnection *dconn;
+       struct snapper_snap_delete_state *delete_state;
+       NTSTATUS status;
+       char *snap_id_str;
+       char *str_end;
 
-       /* no state retained over delete, only the ntstatus in req */
-       req = tevent_req_create(mem_ctx, NULL, NULL);
+       req = tevent_req_create(mem_ctx, &delete_state,
+                               struct snapper_snap_delete_state);
        if (req == NULL) {
                return NULL;
        }
 
-       /* always fail for now */
-       if (req) {
+       dconn = snapper_dbus_conn();
+       if (dconn == NULL) {
                tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
                return tevent_req_post(req, ev);
        }
 
+       status = snapper_get_conf_call(delete_state, dconn, base_path,
+                                      &delete_state->conf_name,
+                                      &delete_state->base_path);
+       if (tevent_req_nterror(req, status)) {
+               dbus_connection_unref(dconn);
+               return tevent_req_post(req, ev);
+       }
+
+       /* TODO we should look this up by doing a list_snapshots */
+       snap_id_str = strrchr(snap_path, '/');
+       if (snap_id_str == NULL) {
+               tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               dbus_connection_unref(dconn);
+               return tevent_req_post(req, ev);
+       }
+       snap_id_str++;
+       delete_state->snap_id = strtoul(snap_id_str, &str_end, 10);
+       if (snap_id_str == str_end) {
+               tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               dbus_connection_unref(dconn);
+               return tevent_req_post(req, ev);
+       }
+
+       status = snapper_delete_snap_call(delete_state, dconn,
+                                         delete_state->conf_name,
+                                         delete_state->snap_id);
+       if (tevent_req_nterror(req, status)) {
+               dbus_connection_unref(dconn);
+               return tevent_req_post(req, ev);
+       }
+
+       dbus_connection_unref(dconn);
+
        tevent_req_done(req);
        return tevent_req_post(req, ev);
 }