LCOV - code coverage report
Current view: top level - source3/modules - vfs_snapper.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 2 1195 0.2 %
Date: 2021-09-23 10:06:22 Functions: 1 61 1.6 %

          Line data    Source code
       1             : /*
       2             :  * Module for snapshot IO using snapper
       3             :  *
       4             :  * Copyright (C) David Disseldorp 2012-2014
       5             :  *
       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
      12             :  *
      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.
      17             :  *
      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.
      22             :  *
      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/>.
      25             :  */
      26             : 
      27             : #include <dbus/dbus.h>
      28             : #ifdef HAVE_LINUX_IOCTL_H
      29             : #include <linux/ioctl.h>
      30             : #endif
      31             : #include <sys/ioctl.h>
      32             : #include <dirent.h>
      33             : #include <libgen.h>
      34             : #include "includes.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"
      40             : #include "lib/util/smb_strtox.h"
      41             : 
      42             : #define SNAPPER_SIG_LIST_SNAPS_RSP "a(uquxussa{ss})"
      43             : #define SNAPPER_SIG_LIST_CONFS_RSP "a(ssa{ss})"
      44             : #define SNAPPER_SIG_CREATE_SNAP_RSP "u"
      45             : #define SNAPPER_SIG_DEL_SNAPS_RSP ""
      46             : #define SNAPPER_SIG_STRING_DICT "{ss}"
      47             : 
      48             : struct snapper_dict {
      49             :         char *key;
      50             :         char *val;
      51             : };
      52             : 
      53             : struct snapper_snap {
      54             :         uint32_t id;
      55             :         uint16_t type;
      56             :         uint32_t pre_id;
      57             :         int64_t time;
      58             :         uint32_t creator_uid;
      59             :         char *desc;
      60             :         char *cleanup;
      61             :         uint32_t num_user_data;
      62             :         struct snapper_dict *user_data;
      63             : };
      64             : 
      65             : struct snapper_conf {
      66             :         char *name;
      67             :         char *mnt;
      68             :         uint32_t num_attrs;
      69             :         struct snapper_dict *attrs;
      70             : };
      71             : 
      72             : static const struct {
      73             :         const char *snapper_err_str;
      74             :         NTSTATUS status;
      75             : } snapper_err_map[] = {
      76             :         { "error.no_permissions", NT_STATUS_ACCESS_DENIED },
      77             : };
      78             : 
      79           0 : static NTSTATUS snapper_err_ntstatus_map(const char *snapper_err_str)
      80             : {
      81             :         int i;
      82             : 
      83           0 :         if (snapper_err_str == NULL) {
      84           0 :                 return NT_STATUS_UNSUCCESSFUL;
      85             :         }
      86           0 :         for (i = 0; i < ARRAY_SIZE(snapper_err_map); i++) {
      87           0 :                 if (!strcmp(snapper_err_map[i].snapper_err_str,
      88             :                             snapper_err_str)) {
      89           0 :                         return snapper_err_map[i].status;
      90             :                 }
      91             :         }
      92           0 :         DEBUG(2, ("no explicit mapping for dbus error: %s\n", snapper_err_str));
      93             : 
      94           0 :         return NT_STATUS_UNSUCCESSFUL;
      95             : }
      96             : 
      97             : /*
      98             :  * Strings are UTF-8. Other characters must be encoded hexadecimal as "\x??".
      99             :  * As a consequence "\" must be encoded as "\\".
     100             :  */
     101           0 : static NTSTATUS snapper_dbus_str_encode(TALLOC_CTX *mem_ctx, const char *in_str,
     102             :                                         char **_out_str)
     103             : {
     104             :         size_t in_len;
     105             :         char *out_str;
     106             :         int i;
     107             :         int out_off;
     108             :         int out_len;
     109             : 
     110           0 :         if (in_str == NULL) {
     111           0 :                 return NT_STATUS_INVALID_PARAMETER;
     112             :         }
     113             : 
     114           0 :         in_len = strlen(in_str);
     115             : 
     116             :         /* output can be max 4 times the length of @in_str, +1 for terminator */
     117           0 :         out_len = (in_len * 4) + 1;
     118             : 
     119           0 :         out_str = talloc_array(mem_ctx, char, out_len);
     120           0 :         if (out_str == NULL) {
     121           0 :                 return NT_STATUS_NO_MEMORY;
     122             :         }
     123             : 
     124           0 :         out_off = 0;
     125           0 :         for (i = 0; i < in_len; i++) {
     126             :                 size_t pushed;
     127             : 
     128           0 :                 if (in_str[i] == '\\') {
     129           0 :                         pushed = snprintf(out_str + out_off, out_len - out_off,
     130             :                                           "\\\\");
     131           0 :                 } else if ((unsigned char)in_str[i] > 127) {
     132           0 :                         pushed = snprintf(out_str + out_off, out_len - out_off,
     133           0 :                                           "\\x%02x", (unsigned char)in_str[i]);
     134             :                 } else {
     135             :                         /* regular character */
     136           0 :                         *(out_str + out_off) = in_str[i];
     137           0 :                         pushed = sizeof(char);
     138             :                 }
     139           0 :                 if (pushed >= out_len - out_off) {
     140             :                         /* truncated, should never happen */
     141           0 :                         talloc_free(out_str);
     142           0 :                         return NT_STATUS_INTERNAL_ERROR;
     143             :                 }
     144           0 :                 out_off += pushed;
     145             :         }
     146             : 
     147           0 :         *(out_str + out_off) = '\0';
     148           0 :         *_out_str = out_str;
     149             : 
     150           0 :         return NT_STATUS_OK;
     151             : }
     152             : 
     153           0 : static NTSTATUS snapper_dbus_str_decode(TALLOC_CTX *mem_ctx, const char *in_str,
     154             :                                         char **_out_str)
     155             : {
     156             :         size_t in_len;
     157             :         char *out_str;
     158             :         int i;
     159             :         int out_off;
     160             :         int out_len;
     161             : 
     162           0 :         if (in_str == NULL) {
     163           0 :                 return NT_STATUS_INVALID_PARAMETER;
     164             :         }
     165             : 
     166           0 :         in_len = strlen(in_str);
     167             : 
     168             :         /* output cannot be larger than input, +1 for terminator */
     169           0 :         out_len = in_len + 1;
     170             : 
     171           0 :         out_str = talloc_array(mem_ctx, char, out_len);
     172           0 :         if (out_str == NULL) {
     173           0 :                 return NT_STATUS_NO_MEMORY;
     174             :         }
     175             : 
     176           0 :         out_off = 0;
     177           0 :         for (i = 0; i < in_len; i++) {
     178             :                 int j;
     179             :                 char hex_buf[3];
     180             :                 unsigned int non_ascii_byte;
     181             : 
     182           0 :                 if (in_str[i] != '\\') {
     183           0 :                         out_str[out_off] = in_str[i];
     184           0 :                         out_off++;
     185           0 :                         continue;
     186             :                 }
     187             : 
     188           0 :                 i++;
     189           0 :                 if (in_str[i] == '\\') {
     190           0 :                         out_str[out_off] = '\\';
     191           0 :                         out_off++;
     192           0 :                         continue;
     193           0 :                 } else if (in_str[i] != 'x') {
     194           0 :                         goto err_invalid_src_encoding;
     195             :                 }
     196             : 
     197             :                 /* non-ASCII, encoded as two hex chars */
     198           0 :                 for (j = 0; j < 2; j++) {
     199           0 :                         i++;
     200           0 :                         if ((in_str[i] == '\0') || !isxdigit(in_str[i])) {
     201             :                                 goto err_invalid_src_encoding;
     202             :                         }
     203           0 :                         hex_buf[j] = in_str[i];
     204             :                 }
     205           0 :                 hex_buf[2] = '\0';
     206             : 
     207           0 :                 sscanf(hex_buf, "%x", &non_ascii_byte);
     208           0 :                 out_str[out_off] = (unsigned char)non_ascii_byte;
     209           0 :                 out_off++;
     210             :         }
     211             : 
     212           0 :         out_str[out_off] = '\0';
     213           0 :         *_out_str = out_str;
     214             : 
     215           0 :         return NT_STATUS_OK;
     216           0 : err_invalid_src_encoding:
     217           0 :         DEBUG(0, ("invalid encoding %s\n", in_str));
     218           0 :         return NT_STATUS_INVALID_PARAMETER;
     219             : }
     220             : 
     221           0 : static DBusConnection *snapper_dbus_conn_create(void)
     222             : {
     223             :         DBusError err;
     224             :         DBusConnection *dconn;
     225             : 
     226           0 :         dbus_error_init(&err);
     227             : 
     228             :         /*
     229             :          * Always create a new DBus connection, to ensure snapperd detects the
     230             :          * correct client [E]UID. With dbus_bus_get() it does not!
     231             :          */
     232           0 :         dconn = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
     233           0 :         if (dbus_error_is_set(&err)) {
     234           0 :                 DEBUG(0, ("dbus connection error: %s\n", err.message));
     235           0 :                 dbus_error_free(&err);
     236             :         }
     237           0 :         if (dconn == NULL) {
     238           0 :                 return NULL;
     239             :         }
     240             : 
     241             :         /* dbus_bus_get_private() sets exit-on-disconnect by default, undo it */
     242           0 :         dbus_connection_set_exit_on_disconnect(dconn, false);
     243             : 
     244           0 :         return dconn;
     245             : }
     246             : 
     247           0 : static void snapper_dbus_conn_destroy(DBusConnection *dconn)
     248             : {
     249           0 :         if (dconn == NULL) {
     250           0 :                 DEBUG(2, ("attempt to destroy NULL dbus connection\n"));
     251           0 :                 return;
     252             :         }
     253             : 
     254           0 :         dbus_connection_close(dconn);
     255           0 :         dbus_connection_unref(dconn);
     256             : }
     257             : 
     258             : /*
     259             :  * send the message @send_msg over the dbus and wait for a response, return the
     260             :  * responsee via @recv_msg_out.
     261             :  * @send_msg is not freed, dbus_message_unref() must be handled by the caller.
     262             :  */
     263           0 : static NTSTATUS snapper_dbus_msg_xchng(DBusConnection *dconn,
     264             :                                        DBusMessage *send_msg,
     265             :                                        DBusMessage **recv_msg_out)
     266             : {
     267             :         DBusPendingCall *pending;
     268             :         DBusMessage *recv_msg;
     269             : 
     270             :         /* send message and get a handle for a reply */
     271           0 :         if (!dbus_connection_send_with_reply(dconn, send_msg, &pending, -1)) {
     272           0 :                 return NT_STATUS_NO_MEMORY;
     273             :         }
     274           0 :         if (NULL == pending) {
     275           0 :                 DEBUG(0, ("dbus msg send failed\n"));
     276           0 :                 return NT_STATUS_UNSUCCESSFUL;
     277             :         }
     278             : 
     279           0 :         dbus_connection_flush(dconn);
     280             : 
     281             :         /* block until we receive a reply */
     282           0 :         dbus_pending_call_block(pending);
     283             : 
     284             :         /* get the reply message */
     285           0 :         recv_msg = dbus_pending_call_steal_reply(pending);
     286           0 :         if (recv_msg == NULL) {
     287           0 :                 DEBUG(0, ("Reply Null\n"));
     288           0 :                 return NT_STATUS_UNSUCCESSFUL;
     289             :         }
     290             :         /* free the pending message handle */
     291           0 :         dbus_pending_call_unref(pending);
     292           0 :         *recv_msg_out = recv_msg;
     293             : 
     294           0 :         return NT_STATUS_OK;
     295             : }
     296             : 
     297           0 : static NTSTATUS snapper_type_check(DBusMessageIter *iter,
     298             :                                    int expected_type)
     299             : {
     300           0 :         int type = dbus_message_iter_get_arg_type(iter);
     301           0 :         if (type != expected_type) {
     302           0 :                 DEBUG(0, ("got type %d, expecting %d\n",
     303             :                         type, expected_type));
     304           0 :                 return NT_STATUS_INVALID_PARAMETER;
     305             :         }
     306             : 
     307           0 :         return NT_STATUS_OK;
     308             : }
     309             : 
     310           0 : static NTSTATUS snapper_type_check_get(DBusMessageIter *iter,
     311             :                                        int expected_type,
     312             :                                        void *val)
     313             : {
     314             :         NTSTATUS status;
     315           0 :         status = snapper_type_check(iter, expected_type);
     316           0 :         if (!NT_STATUS_IS_OK(status)) {
     317           0 :                 return status;
     318             :         }
     319             : 
     320           0 :         dbus_message_iter_get_basic(iter, val);
     321             : 
     322           0 :         return NT_STATUS_OK;
     323             : }
     324             : 
     325           0 : static NTSTATUS snapper_dict_unpack(TALLOC_CTX *mem_ctx,
     326             :                                     DBusMessageIter *iter,
     327             :                                     struct snapper_dict *dict_out)
     328             : 
     329             : {
     330             :         NTSTATUS status;
     331             :         DBusMessageIter dct_iter;
     332             :         char *key_encoded;
     333             :         char *val_encoded;
     334             : 
     335           0 :         status = snapper_type_check(iter, DBUS_TYPE_DICT_ENTRY);
     336           0 :         if (!NT_STATUS_IS_OK(status)) {
     337           0 :                 return status;
     338             :         }
     339           0 :         dbus_message_iter_recurse(iter, &dct_iter);
     340             : 
     341           0 :         status = snapper_type_check_get(&dct_iter, DBUS_TYPE_STRING,
     342             :                                         &key_encoded);
     343           0 :         if (!NT_STATUS_IS_OK(status)) {
     344           0 :                 return status;
     345             :         }
     346           0 :         status = snapper_dbus_str_decode(mem_ctx, key_encoded, &dict_out->key);
     347           0 :         if (!NT_STATUS_IS_OK(status)) {
     348           0 :                 return status;
     349             :         }
     350             : 
     351           0 :         dbus_message_iter_next(&dct_iter);
     352           0 :         status = snapper_type_check_get(&dct_iter, DBUS_TYPE_STRING,
     353             :                                         &val_encoded);
     354           0 :         if (!NT_STATUS_IS_OK(status)) {
     355           0 :                 talloc_free(dict_out->key);
     356           0 :                 return status;
     357             :         }
     358           0 :         status = snapper_dbus_str_decode(mem_ctx, val_encoded, &dict_out->val);
     359           0 :         if (!NT_STATUS_IS_OK(status)) {
     360           0 :                 talloc_free(dict_out->key);
     361           0 :                 return status;
     362             :         }
     363             : 
     364           0 :         return NT_STATUS_OK;
     365             : }
     366             : 
     367           0 : static void snapper_dict_array_print(uint32_t num_dicts,
     368             :                                      struct snapper_dict *dicts)
     369             : {
     370             :         int i;
     371             : 
     372           0 :         for (i = 0; i < num_dicts; i++) {
     373           0 :                 DEBUG(10, ("dict (key: %s, val: %s)\n",
     374             :                            dicts[i].key, dicts[i].val));
     375             :         }
     376           0 : }
     377             : 
     378           0 : static NTSTATUS snapper_dict_array_unpack(TALLOC_CTX *mem_ctx,
     379             :                                           DBusMessageIter *iter,
     380             :                                           uint32_t *num_dicts_out,
     381             :                                           struct snapper_dict **dicts_out)
     382             : {
     383             :         NTSTATUS status;
     384             :         DBusMessageIter array_iter;
     385             :         uint32_t num_dicts;
     386           0 :         struct snapper_dict *dicts = NULL;
     387             : 
     388           0 :         status = snapper_type_check(iter, DBUS_TYPE_ARRAY);
     389           0 :         if (!NT_STATUS_IS_OK(status)) {
     390           0 :                 return status;
     391             :         }
     392           0 :         dbus_message_iter_recurse(iter, &array_iter);
     393             : 
     394           0 :         num_dicts = 0;
     395           0 :         while (dbus_message_iter_get_arg_type(&array_iter)
     396             :                                                         != DBUS_TYPE_INVALID) {
     397           0 :                 num_dicts++;
     398           0 :                 dicts = talloc_realloc(mem_ctx, dicts, struct snapper_dict,
     399             :                                        num_dicts);
     400           0 :                 if (dicts == NULL)
     401           0 :                         abort();
     402             : 
     403           0 :                 status = snapper_dict_unpack(mem_ctx, &array_iter,
     404           0 :                                              &dicts[num_dicts - 1]);
     405           0 :                 if (!NT_STATUS_IS_OK(status)) {
     406           0 :                         talloc_free(dicts);
     407           0 :                         return status;
     408             :                 }
     409           0 :                 dbus_message_iter_next(&array_iter);
     410             :         }
     411             : 
     412           0 :         *num_dicts_out = num_dicts;
     413           0 :         *dicts_out = dicts;
     414             : 
     415           0 :         return NT_STATUS_OK;
     416             : }
     417             : 
     418           0 : static NTSTATUS snapper_list_confs_pack(DBusMessage **req_msg_out)
     419             : {
     420             :         DBusMessage *msg;
     421             : 
     422           0 :         msg = dbus_message_new_method_call("org.opensuse.Snapper",
     423             :                                            "/org/opensuse/Snapper",
     424             :                                            "org.opensuse.Snapper",
     425             :                                            "ListConfigs");
     426           0 :         if (msg == NULL) {
     427           0 :                 DEBUG(0, ("null msg\n"));
     428           0 :                 return NT_STATUS_NO_MEMORY;
     429             :         }
     430             : 
     431             :         /* no arguments to append */
     432           0 :         *req_msg_out = msg;
     433             : 
     434           0 :         return NT_STATUS_OK;
     435             : }
     436             : 
     437           0 : static NTSTATUS snapper_conf_unpack(TALLOC_CTX *mem_ctx,
     438             :                                     DBusMessageIter *iter,
     439             :                                     struct snapper_conf *conf_out)
     440             : {
     441             :         NTSTATUS status;
     442             :         DBusMessageIter st_iter;
     443             :         char *name_encoded;
     444             :         char *mnt_encoded;
     445             : 
     446           0 :         status = snapper_type_check(iter, DBUS_TYPE_STRUCT);
     447           0 :         if (!NT_STATUS_IS_OK(status)) {
     448           0 :                 return status;
     449             :         }
     450           0 :         dbus_message_iter_recurse(iter, &st_iter);
     451             : 
     452           0 :         status = snapper_type_check_get(&st_iter, DBUS_TYPE_STRING,
     453             :                                         &name_encoded);
     454           0 :         if (!NT_STATUS_IS_OK(status)) {
     455           0 :                 return status;
     456             :         }
     457             : 
     458           0 :         status = snapper_dbus_str_decode(mem_ctx, name_encoded,
     459             :                                          &conf_out->name);
     460           0 :         if (!NT_STATUS_IS_OK(status)) {
     461           0 :                 return status;
     462             :         }
     463             : 
     464           0 :         dbus_message_iter_next(&st_iter);
     465           0 :         status = snapper_type_check_get(&st_iter, DBUS_TYPE_STRING,
     466             :                                         &mnt_encoded);
     467           0 :         if (!NT_STATUS_IS_OK(status)) {
     468           0 :                 talloc_free(conf_out->name);
     469           0 :                 return status;
     470             :         }
     471             : 
     472           0 :         status = snapper_dbus_str_decode(mem_ctx, mnt_encoded,
     473             :                                          &conf_out->mnt);
     474           0 :         if (!NT_STATUS_IS_OK(status)) {
     475           0 :                 talloc_free(conf_out->name);
     476           0 :                 return status;
     477             :         }
     478             : 
     479           0 :         dbus_message_iter_next(&st_iter);
     480           0 :         status = snapper_dict_array_unpack(mem_ctx, &st_iter,
     481             :                                            &conf_out->num_attrs,
     482             :                                            &conf_out->attrs);
     483           0 :         if (!NT_STATUS_IS_OK(status)) {
     484           0 :                 talloc_free(conf_out->mnt);
     485           0 :                 talloc_free(conf_out->name);
     486           0 :                 return status;
     487             :         }
     488             : 
     489           0 :         return NT_STATUS_OK;
     490             : }
     491             : 
     492           0 : static struct snapper_conf *snapper_conf_array_base_find(int32_t num_confs,
     493             :                                                 struct snapper_conf *confs,
     494             :                                                          const char *base)
     495             : {
     496             :         int i;
     497             : 
     498           0 :         for (i = 0; i < num_confs; i++) {
     499           0 :                 if (strcmp(confs[i].mnt, base) == 0) {
     500           0 :                         DEBUG(5, ("found snapper conf %s for path %s\n",
     501             :                                   confs[i].name, base));
     502           0 :                         return &confs[i];
     503             :                 }
     504             :         }
     505           0 :         DEBUG(5, ("config for base %s not found\n", base));
     506             : 
     507           0 :         return NULL;
     508             : }
     509             : 
     510           0 : static void snapper_conf_array_print(int32_t num_confs,
     511             :                                      struct snapper_conf *confs)
     512             : {
     513             :         int i;
     514             : 
     515           0 :         for (i = 0; i < num_confs; i++) {
     516           0 :                 DEBUG(10, ("name: %s, mnt: %s\n",
     517             :                            confs[i].name, confs[i].mnt));
     518           0 :                 snapper_dict_array_print(confs[i].num_attrs, confs[i].attrs);
     519             :         }
     520           0 : }
     521             : 
     522           0 : static NTSTATUS snapper_conf_array_unpack(TALLOC_CTX *mem_ctx,
     523             :                                           DBusMessageIter *iter,
     524             :                                           uint32_t *num_confs_out,
     525             :                                           struct snapper_conf **confs_out)
     526             : {
     527             :         uint32_t num_confs;
     528             :         NTSTATUS status;
     529           0 :         struct snapper_conf *confs = NULL;
     530             :         DBusMessageIter array_iter;
     531             : 
     532             : 
     533           0 :         status = snapper_type_check(iter, DBUS_TYPE_ARRAY);
     534           0 :         if (!NT_STATUS_IS_OK(status)) {
     535           0 :                 return status;
     536             :         }
     537           0 :         dbus_message_iter_recurse(iter, &array_iter);
     538             : 
     539           0 :         num_confs = 0;
     540           0 :         while (dbus_message_iter_get_arg_type(&array_iter)
     541             :                                                         != DBUS_TYPE_INVALID) {
     542           0 :                 num_confs++;
     543           0 :                 confs = talloc_realloc(mem_ctx, confs, struct snapper_conf,
     544             :                                        num_confs);
     545           0 :                 if (confs == NULL)
     546           0 :                         abort();
     547             : 
     548           0 :                 status = snapper_conf_unpack(confs, &array_iter,
     549           0 :                                              &confs[num_confs - 1]);
     550           0 :                 if (!NT_STATUS_IS_OK(status)) {
     551           0 :                         talloc_free(confs);
     552           0 :                         return status;
     553             :                 }
     554           0 :                 dbus_message_iter_next(&array_iter);
     555             :         }
     556             : 
     557           0 :         *num_confs_out = num_confs;
     558           0 :         *confs_out = confs;
     559             : 
     560           0 :         return NT_STATUS_OK;
     561             : }
     562             : 
     563           0 : static NTSTATUS snapper_list_confs_unpack(TALLOC_CTX *mem_ctx,
     564             :                                           DBusConnection *dconn,
     565             :                                           DBusMessage *rsp_msg,
     566             :                                           uint32_t *num_confs_out,
     567             :                                           struct snapper_conf **confs_out)
     568             : {
     569             :         NTSTATUS status;
     570             :         DBusMessageIter iter;
     571             :         int msg_type;
     572             :         uint32_t num_confs;
     573             :         struct snapper_conf *confs;
     574             :         const char *sig;
     575             : 
     576           0 :         msg_type = dbus_message_get_type(rsp_msg);
     577           0 :         if (msg_type == DBUS_MESSAGE_TYPE_ERROR) {
     578           0 :                 const char *err_str = dbus_message_get_error_name(rsp_msg);
     579           0 :                 DEBUG(0, ("list_confs error response: %s\n", err_str));
     580           0 :                 return snapper_err_ntstatus_map(err_str);
     581             :         }
     582             : 
     583           0 :         if (msg_type != DBUS_MESSAGE_TYPE_METHOD_RETURN) {
     584           0 :                 DEBUG(0, ("unexpected list_confs ret type: %d\n",
     585             :                           msg_type));
     586           0 :                 return NT_STATUS_INVALID_PARAMETER;
     587             :         }
     588             : 
     589           0 :         sig = dbus_message_get_signature(rsp_msg);
     590           0 :         if ((sig == NULL)
     591           0 :          || (strcmp(sig, SNAPPER_SIG_LIST_CONFS_RSP) != 0)) {
     592           0 :                 DEBUG(0, ("bad list confs response sig: %s, expected: %s\n",
     593             :                           (sig ? sig : "NULL"), SNAPPER_SIG_LIST_CONFS_RSP));
     594           0 :                 return NT_STATUS_INVALID_PARAMETER;
     595             :         }
     596             : 
     597           0 :         if (!dbus_message_iter_init(rsp_msg, &iter)) {
     598             :                 /* FIXME return empty? */
     599           0 :                 DEBUG(0, ("Message has no arguments!\n"));
     600           0 :                 return NT_STATUS_INVALID_PARAMETER;
     601             :         }
     602             : 
     603           0 :         status = snapper_conf_array_unpack(mem_ctx, &iter, &num_confs, &confs);
     604           0 :         if (!NT_STATUS_IS_OK(status)) {
     605           0 :                 DEBUG(0, ("failed to unpack conf array\n"));
     606           0 :                 return status;
     607             :         }
     608             : 
     609           0 :         snapper_conf_array_print(num_confs, confs);
     610             : 
     611           0 :         *num_confs_out = num_confs;
     612           0 :         *confs_out = confs;
     613             : 
     614           0 :         return NT_STATUS_OK;
     615             : }
     616             : 
     617           0 : static NTSTATUS snapper_list_snaps_pack(TALLOC_CTX *mem_ctx,
     618             :                                         char *snapper_conf,
     619             :                                         DBusMessage **req_msg_out)
     620             : {
     621             :         DBusMessage *msg;
     622             :         DBusMessageIter args;
     623             :         char *conf_encoded;
     624             :         NTSTATUS status;
     625             : 
     626           0 :         msg = dbus_message_new_method_call("org.opensuse.Snapper", /* target for the method call */
     627             :                                            "/org/opensuse/Snapper", /* object to call on */
     628             :                                            "org.opensuse.Snapper", /* interface to call on */
     629             :                                            "ListSnapshots"); /* method name */
     630           0 :         if (msg == NULL) {
     631           0 :                 DEBUG(0, ("failed to create list snaps message\n"));
     632           0 :                 return NT_STATUS_NO_MEMORY;
     633             :         }
     634             : 
     635           0 :         status = snapper_dbus_str_encode(mem_ctx, snapper_conf, &conf_encoded);
     636           0 :         if (!NT_STATUS_IS_OK(status)) {
     637           0 :                 dbus_message_unref(msg);
     638           0 :                 return status;
     639             :         }
     640             : 
     641             :         /* append arguments */
     642           0 :         dbus_message_iter_init_append(msg, &args);
     643           0 :         if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING,
     644             :                                             &conf_encoded)) {
     645           0 :                 talloc_free(conf_encoded);
     646           0 :                 dbus_message_unref(msg);
     647           0 :                 return NT_STATUS_NO_MEMORY;
     648             :         }
     649             : 
     650           0 :         *req_msg_out = msg;
     651             : 
     652           0 :         return NT_STATUS_OK;
     653             : }
     654             : 
     655           0 : static NTSTATUS snapper_snap_struct_unpack(TALLOC_CTX *mem_ctx,
     656             :                                            DBusMessageIter *iter,
     657             :                                            struct snapper_snap *snap_out)
     658             : {
     659             :         NTSTATUS status;
     660             :         DBusMessageIter st_iter;
     661             :         char *desc_encoded;
     662             :         char *cleanup_encoded;
     663             : 
     664           0 :         status = snapper_type_check(iter, DBUS_TYPE_STRUCT);
     665           0 :         if (!NT_STATUS_IS_OK(status)) {
     666           0 :                 return status;
     667             :         }
     668           0 :         dbus_message_iter_recurse(iter, &st_iter);
     669             : 
     670           0 :         status = snapper_type_check_get(&st_iter, DBUS_TYPE_UINT32,
     671           0 :                                         &snap_out->id);
     672           0 :         if (!NT_STATUS_IS_OK(status)) {
     673           0 :                 return status;
     674             :         }
     675             : 
     676           0 :         dbus_message_iter_next(&st_iter);
     677           0 :         status = snapper_type_check_get(&st_iter, DBUS_TYPE_UINT16,
     678           0 :                                         &snap_out->type);
     679           0 :         if (!NT_STATUS_IS_OK(status)) {
     680           0 :                 return status;
     681             :         }
     682             : 
     683           0 :         dbus_message_iter_next(&st_iter);
     684           0 :         status = snapper_type_check_get(&st_iter, DBUS_TYPE_UINT32,
     685           0 :                                         &snap_out->pre_id);
     686           0 :         if (!NT_STATUS_IS_OK(status)) {
     687           0 :                 return status;
     688             :         }
     689             : 
     690           0 :         dbus_message_iter_next(&st_iter);
     691           0 :         status = snapper_type_check_get(&st_iter, DBUS_TYPE_INT64,
     692           0 :                                         &snap_out->time);
     693           0 :         if (!NT_STATUS_IS_OK(status)) {
     694           0 :                 return status;
     695             :         }
     696             : 
     697           0 :         dbus_message_iter_next(&st_iter);
     698           0 :         status = snapper_type_check_get(&st_iter, DBUS_TYPE_UINT32,
     699           0 :                                         &snap_out->creator_uid);
     700           0 :         if (!NT_STATUS_IS_OK(status)) {
     701           0 :                 return status;
     702             :         }
     703             : 
     704           0 :         dbus_message_iter_next(&st_iter);
     705           0 :         status = snapper_type_check_get(&st_iter, DBUS_TYPE_STRING,
     706             :                                         &desc_encoded);
     707           0 :         if (!NT_STATUS_IS_OK(status)) {
     708           0 :                 return status;
     709             :         }
     710             : 
     711           0 :         status = snapper_dbus_str_decode(mem_ctx, desc_encoded,
     712             :                                          &snap_out->desc);
     713           0 :         if (!NT_STATUS_IS_OK(status)) {
     714           0 :                 return status;
     715             :         }
     716             : 
     717           0 :         dbus_message_iter_next(&st_iter);
     718           0 :         status = snapper_type_check_get(&st_iter, DBUS_TYPE_STRING,
     719             :                                         &cleanup_encoded);
     720           0 :         if (!NT_STATUS_IS_OK(status)) {
     721           0 :                 talloc_free(snap_out->desc);
     722           0 :                 return status;
     723             :         }
     724             : 
     725           0 :         status = snapper_dbus_str_decode(mem_ctx, cleanup_encoded,
     726             :                                          &snap_out->cleanup);
     727           0 :         if (!NT_STATUS_IS_OK(status)) {
     728           0 :                 talloc_free(snap_out->desc);
     729           0 :                 return status;
     730             :         }
     731             : 
     732           0 :         dbus_message_iter_next(&st_iter);
     733           0 :         status = snapper_dict_array_unpack(mem_ctx, &st_iter,
     734             :                                            &snap_out->num_user_data,
     735             :                                            &snap_out->user_data);
     736           0 :         if (!NT_STATUS_IS_OK(status)) {
     737           0 :                 talloc_free(snap_out->cleanup);
     738           0 :                 talloc_free(snap_out->desc);
     739           0 :                 return status;
     740             :         }
     741             : 
     742           0 :         return NT_STATUS_OK;
     743             : }
     744             : 
     745           0 : static void snapper_snap_array_print(int32_t num_snaps,
     746             :                                      struct snapper_snap *snaps)
     747             : {
     748             :         int i;
     749             : 
     750           0 :         for (i = 0; i < num_snaps; i++) {
     751           0 :                 DEBUG(10, ("id: %u, "
     752             :                            "type: %u, "
     753             :                            "pre_id: %u, "
     754             :                            "time: %ld, "
     755             :                            "creator_uid: %u, "
     756             :                            "desc: %s, "
     757             :                            "cleanup: %s\n",
     758             :                            (unsigned int)snaps[i].id,
     759             :                            (unsigned int)snaps[i].type,
     760             :                            (unsigned int)snaps[i].pre_id,
     761             :                            (long int)snaps[i].time,
     762             :                            (unsigned int)snaps[i].creator_uid,
     763             :                            snaps[i].desc,
     764             :                            snaps[i].cleanup));
     765           0 :                 snapper_dict_array_print(snaps[i].num_user_data,
     766           0 :                                          snaps[i].user_data);
     767             :         }
     768           0 : }
     769             : 
     770           0 : static NTSTATUS snapper_snap_array_unpack(TALLOC_CTX *mem_ctx,
     771             :                                           DBusMessageIter *iter,
     772             :                                           uint32_t *num_snaps_out,
     773             :                                           struct snapper_snap **snaps_out)
     774             : {
     775             :         uint32_t num_snaps;
     776             :         NTSTATUS status;
     777           0 :         struct snapper_snap *snaps = NULL;
     778             :         DBusMessageIter array_iter;
     779             : 
     780             : 
     781           0 :         status = snapper_type_check(iter, DBUS_TYPE_ARRAY);
     782           0 :         if (!NT_STATUS_IS_OK(status)) {
     783           0 :                 return status;
     784             :         }
     785           0 :         dbus_message_iter_recurse(iter, &array_iter);
     786             : 
     787           0 :         num_snaps = 0;
     788           0 :         while (dbus_message_iter_get_arg_type(&array_iter)
     789             :                                                         != DBUS_TYPE_INVALID) {
     790           0 :                 num_snaps++;
     791           0 :                 snaps = talloc_realloc(mem_ctx, snaps, struct snapper_snap,
     792             :                                        num_snaps);
     793           0 :                 if (snaps == NULL)
     794           0 :                         abort();
     795             : 
     796           0 :                 status = snapper_snap_struct_unpack(snaps, &array_iter,
     797           0 :                                                     &snaps[num_snaps - 1]);
     798           0 :                 if (!NT_STATUS_IS_OK(status)) {
     799           0 :                         talloc_free(snaps);
     800           0 :                         return status;
     801             :                 }
     802           0 :                 dbus_message_iter_next(&array_iter);
     803             :         }
     804             : 
     805           0 :         *num_snaps_out = num_snaps;
     806           0 :         *snaps_out = snaps;
     807             : 
     808           0 :         return NT_STATUS_OK;
     809             : }
     810             : 
     811           0 : static NTSTATUS snapper_list_snaps_unpack(TALLOC_CTX *mem_ctx,
     812             :                                           DBusMessage *rsp_msg,
     813             :                                           uint32_t *num_snaps_out,
     814             :                                           struct snapper_snap **snaps_out)
     815             : {
     816             :         NTSTATUS status;
     817             :         DBusMessageIter iter;
     818             :         int msg_type;
     819             :         uint32_t num_snaps;
     820             :         struct snapper_snap *snaps;
     821             :         const char *sig;
     822             : 
     823           0 :         msg_type = dbus_message_get_type(rsp_msg);
     824           0 :         if (msg_type == DBUS_MESSAGE_TYPE_ERROR) {
     825           0 :                 const char *err_str = dbus_message_get_error_name(rsp_msg);
     826           0 :                 DEBUG(0, ("list_snaps error response: %s\n", err_str));
     827           0 :                 return snapper_err_ntstatus_map(err_str);
     828             :         }
     829             : 
     830           0 :         if (msg_type != DBUS_MESSAGE_TYPE_METHOD_RETURN) {
     831           0 :                 DEBUG(0,("unexpected list_snaps ret type: %d\n",
     832             :                          msg_type));
     833           0 :                 return NT_STATUS_INVALID_PARAMETER;
     834             :         }
     835             : 
     836           0 :         sig = dbus_message_get_signature(rsp_msg);
     837           0 :         if ((sig == NULL)
     838           0 :          || (strcmp(sig, SNAPPER_SIG_LIST_SNAPS_RSP) != 0)) {
     839           0 :                 DEBUG(0, ("bad list snaps response sig: %s, "
     840             :                           "expected: %s\n",
     841             :                           (sig ? sig : "NULL"),
     842             :                           SNAPPER_SIG_LIST_SNAPS_RSP));
     843           0 :                 return NT_STATUS_INVALID_PARAMETER;
     844             :         }
     845             : 
     846             :         /* read the parameters */
     847           0 :         if (!dbus_message_iter_init(rsp_msg, &iter)) {
     848           0 :                 DEBUG(0, ("response has no arguments!\n"));
     849           0 :                 return NT_STATUS_INVALID_PARAMETER;
     850             :         }
     851             : 
     852           0 :         status = snapper_snap_array_unpack(mem_ctx, &iter, &num_snaps, &snaps);
     853           0 :         if (!NT_STATUS_IS_OK(status)) {
     854           0 :                 DEBUG(0, ("failed to unpack snap array\n"));
     855           0 :                 return NT_STATUS_INVALID_PARAMETER;
     856             :         }
     857             : 
     858           0 :         snapper_snap_array_print(num_snaps, snaps);
     859             : 
     860           0 :         *num_snaps_out = num_snaps;
     861           0 :         *snaps_out = snaps;
     862             : 
     863           0 :         return NT_STATUS_OK;
     864             : }
     865             : 
     866           0 : static NTSTATUS snapper_create_snap_pack(TALLOC_CTX *mem_ctx,
     867             :                                          const char *snapper_conf,
     868             :                                          const char *desc,
     869             :                                          uint32_t num_user_data,
     870             :                                          struct snapper_dict *user_data,
     871             :                                          DBusMessage **req_msg_out)
     872             : {
     873             :         DBusMessage *msg;
     874             :         DBusMessageIter args;
     875             :         DBusMessageIter array_iter;
     876             :         DBusMessageIter struct_iter;
     877           0 :         const char *empty = "";
     878             :         char *str_encoded;
     879             :         uint32_t i;
     880             :         bool ok;
     881             :         TALLOC_CTX *enc_ctx;
     882             :         NTSTATUS status;
     883             : 
     884           0 :         DEBUG(10, ("CreateSingleSnapshot: %s, %s, %s, num user %u\n",
     885             :                   snapper_conf, desc, empty, num_user_data));
     886             : 
     887           0 :         enc_ctx = talloc_new(mem_ctx);
     888           0 :         if (enc_ctx == NULL) {
     889           0 :                 return NT_STATUS_NO_MEMORY;
     890             :         }
     891             : 
     892           0 :         msg = dbus_message_new_method_call("org.opensuse.Snapper",
     893             :                                            "/org/opensuse/Snapper",
     894             :                                            "org.opensuse.Snapper",
     895             :                                            "CreateSingleSnapshot");
     896           0 :         if (msg == NULL) {
     897           0 :                 DEBUG(0, ("failed to create req msg\n"));
     898           0 :                 talloc_free(enc_ctx);
     899           0 :                 return NT_STATUS_NO_MEMORY;
     900             :         }
     901             : 
     902           0 :         status = snapper_dbus_str_encode(enc_ctx, snapper_conf, &str_encoded);
     903           0 :         if (!NT_STATUS_IS_OK(status)) {
     904           0 :                 dbus_message_unref(msg);
     905           0 :                 talloc_free(enc_ctx);
     906           0 :                 return status;
     907             :         }
     908             : 
     909             :         /* append arguments */
     910           0 :         dbus_message_iter_init_append(msg, &args);
     911           0 :         ok = dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING,
     912             :                                             &str_encoded);
     913           0 :         if (!ok) {
     914           0 :                 dbus_message_unref(msg);
     915           0 :                 talloc_free(enc_ctx);
     916           0 :                 return NT_STATUS_NO_MEMORY;
     917             :         }
     918             : 
     919           0 :         status = snapper_dbus_str_encode(enc_ctx, desc, &str_encoded);
     920           0 :         if (!NT_STATUS_IS_OK(status)) {
     921           0 :                 dbus_message_unref(msg);
     922           0 :                 talloc_free(enc_ctx);
     923           0 :                 return status;
     924             :         }
     925             : 
     926           0 :         ok = dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING,
     927             :                                             &str_encoded);
     928           0 :         if (!ok) {
     929           0 :                 dbus_message_unref(msg);
     930           0 :                 talloc_free(enc_ctx);
     931           0 :                 return NT_STATUS_NO_MEMORY;
     932             :         }
     933             : 
     934             :         /* cleanup - no need to encode empty string */
     935           0 :         ok = dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING,
     936             :                                             &empty);
     937           0 :         if (!ok) {
     938           0 :                 dbus_message_unref(msg);
     939           0 :                 talloc_free(enc_ctx);
     940           0 :                 return NT_STATUS_NO_MEMORY;
     941             :         }
     942             : 
     943           0 :         ok = dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY,
     944             :                                               SNAPPER_SIG_STRING_DICT,
     945             :                                               &array_iter);
     946           0 :         if (!ok) {
     947           0 :                 dbus_message_unref(msg);
     948           0 :                 talloc_free(enc_ctx);
     949           0 :                 return NT_STATUS_NO_MEMORY;
     950             :         }
     951             : 
     952           0 :         for (i = 0; i < num_user_data; i++) {
     953           0 :                 ok = dbus_message_iter_open_container(&array_iter,
     954             :                                                       DBUS_TYPE_DICT_ENTRY,
     955             :                                                       NULL, &struct_iter);
     956           0 :                 if (!ok) {
     957           0 :                         dbus_message_unref(msg);
     958           0 :                         talloc_free(enc_ctx);
     959           0 :                         return NT_STATUS_NO_MEMORY;
     960             :                 }
     961             : 
     962           0 :                 status = snapper_dbus_str_encode(enc_ctx, user_data[i].key,
     963             :                                                  &str_encoded);
     964           0 :                 if (!NT_STATUS_IS_OK(status)) {
     965           0 :                         dbus_message_unref(msg);
     966           0 :                         talloc_free(enc_ctx);
     967           0 :                         return status;
     968             :                 }
     969             : 
     970           0 :                 ok = dbus_message_iter_append_basic(&struct_iter,
     971             :                                                     DBUS_TYPE_STRING,
     972             :                                                     &str_encoded);
     973           0 :                 if (!ok) {
     974           0 :                         dbus_message_unref(msg);
     975           0 :                         talloc_free(enc_ctx);
     976           0 :                         return NT_STATUS_NO_MEMORY;
     977             :                 }
     978             : 
     979           0 :                 status = snapper_dbus_str_encode(enc_ctx, user_data[i].val,
     980             :                                                  &str_encoded);
     981           0 :                 if (!NT_STATUS_IS_OK(status)) {
     982           0 :                         dbus_message_unref(msg);
     983           0 :                         talloc_free(enc_ctx);
     984           0 :                         return status;
     985             :                 }
     986             : 
     987           0 :                 ok = dbus_message_iter_append_basic(&struct_iter,
     988             :                                                     DBUS_TYPE_STRING,
     989             :                                                     &str_encoded);
     990           0 :                 if (!ok) {
     991           0 :                         dbus_message_unref(msg);
     992           0 :                         talloc_free(enc_ctx);
     993           0 :                         return NT_STATUS_NO_MEMORY;
     994             :                 }
     995             : 
     996           0 :                 ok = dbus_message_iter_close_container(&array_iter, &struct_iter);
     997           0 :                 if (!ok) {
     998           0 :                         dbus_message_unref(msg);
     999           0 :                         talloc_free(enc_ctx);
    1000           0 :                         return NT_STATUS_NO_MEMORY;
    1001             :                 }
    1002             :         }
    1003             : 
    1004           0 :         ok = dbus_message_iter_close_container(&args, &array_iter);
    1005           0 :         if (!ok) {
    1006           0 :                 dbus_message_unref(msg);
    1007           0 :                 talloc_free(enc_ctx);
    1008           0 :                 return NT_STATUS_NO_MEMORY;
    1009             :         }
    1010             : 
    1011           0 :         *req_msg_out = msg;
    1012             : 
    1013           0 :         return NT_STATUS_OK;
    1014             : }
    1015             : 
    1016           0 : static NTSTATUS snapper_create_snap_unpack(DBusConnection *conn,
    1017             :                                            DBusMessage *rsp_msg,
    1018             :                                            uint32_t *snap_id_out)
    1019             : {
    1020             :         NTSTATUS status;
    1021             :         DBusMessageIter iter;
    1022             :         int msg_type;
    1023             :         const char *sig;
    1024             :         uint32_t snap_id;
    1025             : 
    1026           0 :         msg_type = dbus_message_get_type(rsp_msg);
    1027           0 :         if (msg_type == DBUS_MESSAGE_TYPE_ERROR) {
    1028           0 :                 const char *err_str = dbus_message_get_error_name(rsp_msg);
    1029           0 :                 DEBUG(0, ("create snap error response: %s, euid %d egid %d\n",
    1030             :                           err_str, geteuid(), getegid()));
    1031           0 :                 return snapper_err_ntstatus_map(err_str);
    1032             :         }
    1033             : 
    1034           0 :         if (msg_type != DBUS_MESSAGE_TYPE_METHOD_RETURN) {
    1035           0 :                 DEBUG(0, ("unexpected create snap ret type: %d\n",
    1036             :                           msg_type));
    1037           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1038             :         }
    1039             : 
    1040           0 :         sig = dbus_message_get_signature(rsp_msg);
    1041           0 :         if ((sig == NULL)
    1042           0 :          || (strcmp(sig, SNAPPER_SIG_CREATE_SNAP_RSP) != 0)) {
    1043           0 :                 DEBUG(0, ("bad create snap response sig: %s, expected: %s\n",
    1044             :                           (sig ? sig : "NULL"), SNAPPER_SIG_CREATE_SNAP_RSP));
    1045           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1046             :         }
    1047             : 
    1048             :         /* read the parameters */
    1049           0 :         if (!dbus_message_iter_init(rsp_msg, &iter)) {
    1050           0 :                 DEBUG(0, ("response has no arguments!\n"));
    1051           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1052             :         }
    1053             : 
    1054           0 :         status = snapper_type_check_get(&iter, DBUS_TYPE_UINT32, &snap_id);
    1055           0 :         if (!NT_STATUS_IS_OK(status)) {
    1056           0 :                 return status;
    1057             :         }
    1058           0 :         *snap_id_out = snap_id;
    1059             : 
    1060           0 :         return NT_STATUS_OK;
    1061             : }
    1062             : 
    1063           0 : static NTSTATUS snapper_del_snap_pack(TALLOC_CTX *mem_ctx,
    1064             :                                       const char *snapper_conf,
    1065             :                                       uint32_t snap_id,
    1066             :                                       DBusMessage **req_msg_out)
    1067             : {
    1068             :         DBusMessage *msg;
    1069             :         DBusMessageIter args;
    1070             :         DBusMessageIter array_iter;
    1071             :         char *conf_encoded;
    1072             :         bool ok;
    1073             :         NTSTATUS status;
    1074             : 
    1075           0 :         msg = dbus_message_new_method_call("org.opensuse.Snapper",
    1076             :                                            "/org/opensuse/Snapper",
    1077             :                                            "org.opensuse.Snapper",
    1078             :                                            "DeleteSnapshots");
    1079           0 :         if (msg == NULL) {
    1080           0 :                 DEBUG(0, ("failed to create req msg\n"));
    1081           0 :                 return NT_STATUS_NO_MEMORY;
    1082             :         }
    1083             : 
    1084           0 :         status = snapper_dbus_str_encode(mem_ctx, snapper_conf, &conf_encoded);
    1085           0 :         if (!NT_STATUS_IS_OK(status)) {
    1086           0 :                 dbus_message_unref(msg);
    1087           0 :                 return status;
    1088             :         }
    1089             : 
    1090             :         /* append arguments */
    1091           0 :         dbus_message_iter_init_append(msg, &args);
    1092           0 :         ok = dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING,
    1093             :                                             &conf_encoded);
    1094           0 :         if (!ok) {
    1095           0 :                 talloc_free(conf_encoded);
    1096           0 :                 dbus_message_unref(msg);
    1097           0 :                 return NT_STATUS_NO_MEMORY;
    1098             :         }
    1099             : 
    1100           0 :         ok = dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY,
    1101             :                                                DBUS_TYPE_UINT32_AS_STRING,
    1102             :                                                &array_iter);
    1103           0 :         if (!ok) {
    1104           0 :                 talloc_free(conf_encoded);
    1105           0 :                 dbus_message_unref(msg);
    1106           0 :                 return NT_STATUS_NO_MEMORY;
    1107             :         }
    1108             : 
    1109           0 :         ok = dbus_message_iter_append_basic(&array_iter,
    1110             :                                             DBUS_TYPE_UINT32,
    1111             :                                             &snap_id);
    1112           0 :         if (!ok) {
    1113           0 :                 talloc_free(conf_encoded);
    1114           0 :                 dbus_message_unref(msg);
    1115           0 :                 return NT_STATUS_NO_MEMORY;
    1116             :         }
    1117             : 
    1118           0 :         dbus_message_iter_close_container(&args, &array_iter);
    1119           0 :         *req_msg_out = msg;
    1120             : 
    1121           0 :         return NT_STATUS_OK;
    1122             : }
    1123             : 
    1124           0 : static NTSTATUS snapper_del_snap_unpack(DBusConnection *conn,
    1125             :                                         DBusMessage *rsp_msg)
    1126             : {
    1127             :         int msg_type;
    1128             :         const char *sig;
    1129             : 
    1130           0 :         msg_type = dbus_message_get_type(rsp_msg);
    1131           0 :         if (msg_type == DBUS_MESSAGE_TYPE_ERROR) {
    1132           0 :                 const char *err_str = dbus_message_get_error_name(rsp_msg);
    1133           0 :                 DEBUG(0, ("del snap error response: %s\n", err_str));
    1134           0 :                 return snapper_err_ntstatus_map(err_str);
    1135             :         }
    1136             : 
    1137           0 :         if (msg_type != DBUS_MESSAGE_TYPE_METHOD_RETURN) {
    1138           0 :                 DEBUG(0, ("unexpected del snap ret type: %d\n",
    1139             :                           msg_type));
    1140           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1141             :         }
    1142             : 
    1143           0 :         sig = dbus_message_get_signature(rsp_msg);
    1144           0 :         if ((sig == NULL)
    1145           0 :          || (strcmp(sig, SNAPPER_SIG_DEL_SNAPS_RSP) != 0)) {
    1146           0 :                 DEBUG(0, ("bad create snap response sig: %s, expected: %s\n",
    1147             :                           (sig ? sig : "NULL"), SNAPPER_SIG_DEL_SNAPS_RSP));
    1148           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1149             :         }
    1150             : 
    1151             :         /* no parameters in response */
    1152             : 
    1153           0 :         return NT_STATUS_OK;
    1154             : }
    1155             : 
    1156           0 : static NTSTATUS snapper_list_snaps_at_time_pack(TALLOC_CTX *mem_ctx,
    1157             :                                                 const char *snapper_conf,
    1158             :                                                 time_t time_lower,
    1159             :                                                 time_t time_upper,
    1160             :                                                 DBusMessage **req_msg_out)
    1161             : {
    1162             :         DBusMessage *msg;
    1163             :         DBusMessageIter args;
    1164             :         char *conf_encoded;
    1165             :         NTSTATUS status;
    1166             : 
    1167           0 :         msg = dbus_message_new_method_call("org.opensuse.Snapper",
    1168             :                                            "/org/opensuse/Snapper",
    1169             :                                            "org.opensuse.Snapper",
    1170             :                                            "ListSnapshotsAtTime");
    1171           0 :         if (msg == NULL) {
    1172           0 :                 DEBUG(0, ("failed to create list snaps message\n"));
    1173           0 :                 return NT_STATUS_NO_MEMORY;
    1174             :         }
    1175             : 
    1176           0 :         status = snapper_dbus_str_encode(mem_ctx, snapper_conf, &conf_encoded);
    1177           0 :         if (!NT_STATUS_IS_OK(status)) {
    1178           0 :                 dbus_message_unref(msg);
    1179           0 :                 return status;
    1180             :         }
    1181             : 
    1182           0 :         dbus_message_iter_init_append(msg, &args);
    1183           0 :         if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING,
    1184             :                                             &conf_encoded)) {
    1185           0 :                 talloc_free(conf_encoded);
    1186           0 :                 dbus_message_unref(msg);
    1187           0 :                 return NT_STATUS_NO_MEMORY;
    1188             :         }
    1189             : 
    1190           0 :         if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_INT64,
    1191             :                                             &time_lower)) {
    1192           0 :                 talloc_free(conf_encoded);
    1193           0 :                 dbus_message_unref(msg);
    1194           0 :                 return NT_STATUS_NO_MEMORY;
    1195             :         }
    1196             : 
    1197           0 :         if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_INT64,
    1198             :                                             &time_upper)) {
    1199           0 :                 talloc_free(conf_encoded);
    1200           0 :                 dbus_message_unref(msg);
    1201           0 :                 return NT_STATUS_NO_MEMORY;
    1202             :         }
    1203             : 
    1204           0 :         *req_msg_out = msg;
    1205             : 
    1206           0 :         return NT_STATUS_OK;
    1207             : }
    1208             : /* no snapper_list_snaps_at_time_unpack, use snapper_list_snaps_unpack */
    1209             : 
    1210             : /*
    1211             :  * Determine the snapper snapshot id given a path.
    1212             :  * Ideally this should be determined via a lookup.
    1213             :  */
    1214           0 : static NTSTATUS snapper_snap_path_to_id(TALLOC_CTX *mem_ctx,
    1215             :                                         const char *snap_path,
    1216             :                                         uint32_t *snap_id_out)
    1217             : {
    1218             :         char *path_dup;
    1219             :         char *str_idx;
    1220             :         uint32_t snap_id;
    1221           0 :         int error = 0;
    1222             : 
    1223           0 :         path_dup = talloc_strdup(mem_ctx, snap_path);
    1224           0 :         if (path_dup == NULL) {
    1225           0 :                 return NT_STATUS_NO_MEMORY;
    1226             :         }
    1227             : 
    1228             :         /* trim trailing '/' */
    1229           0 :         str_idx = path_dup + strlen(path_dup) - 1;
    1230           0 :         while (*str_idx == '/') {
    1231           0 :                 *str_idx = '\0';
    1232           0 :                 str_idx--;
    1233             :         }
    1234             : 
    1235           0 :         str_idx = strrchr(path_dup, '/');
    1236           0 :         if ((str_idx == NULL)
    1237           0 :          || (strcmp(str_idx + 1, "snapshot") != 0)) {
    1238           0 :                 talloc_free(path_dup);
    1239           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1240             :         }
    1241             : 
    1242           0 :         while (*str_idx == '/') {
    1243           0 :                 *str_idx = '\0';
    1244           0 :                 str_idx--;
    1245             :         }
    1246             : 
    1247           0 :         str_idx = strrchr(path_dup, '/');
    1248           0 :         if (str_idx == NULL) {
    1249           0 :                 talloc_free(path_dup);
    1250           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1251             :         }
    1252             : 
    1253           0 :         str_idx++;
    1254           0 :         snap_id = smb_strtoul(str_idx, NULL, 10, &error, SMB_STR_STANDARD);
    1255           0 :         if (error != 0) {
    1256           0 :                 talloc_free(path_dup);
    1257           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1258             :         }
    1259             : 
    1260           0 :         talloc_free(path_dup);
    1261           0 :         *snap_id_out = snap_id;
    1262           0 :         return NT_STATUS_OK;
    1263             : }
    1264             : 
    1265             : /*
    1266             :  * Determine the snapper snapshot path given an id and base.
    1267             :  * Ideally this should be determined via a lookup.
    1268             :  */
    1269           0 : static NTSTATUS snapper_snap_id_to_path(TALLOC_CTX *mem_ctx,
    1270             :                                         const char *base_path,
    1271             :                                         uint32_t snap_id,
    1272             :                                         char **snap_path_out)
    1273             : {
    1274             :         char *snap_path;
    1275             : 
    1276           0 :         snap_path = talloc_asprintf(mem_ctx, "%s/.snapshots/%u/snapshot",
    1277             :                                     base_path, snap_id);
    1278           0 :         if (snap_path == NULL) {
    1279           0 :                 return NT_STATUS_NO_MEMORY;
    1280             :         }
    1281             : 
    1282           0 :         *snap_path_out = snap_path;
    1283           0 :         return NT_STATUS_OK;
    1284             : }
    1285             : 
    1286           0 : static NTSTATUS snapper_get_conf_call(TALLOC_CTX *mem_ctx,
    1287             :                                       DBusConnection *dconn,
    1288             :                                       const char *path,
    1289             :                                       char **conf_name_out,
    1290             :                                       char **base_path_out)
    1291             : {
    1292             :         NTSTATUS status;
    1293             :         DBusMessage *req_msg;
    1294             :         DBusMessage *rsp_msg;
    1295           0 :         uint32_t num_confs = 0;
    1296           0 :         struct snapper_conf *confs = NULL;
    1297             :         struct snapper_conf *conf;
    1298             :         char *conf_name;
    1299             :         char *base_path;
    1300             : 
    1301           0 :         status = snapper_list_confs_pack(&req_msg);
    1302           0 :         if (!NT_STATUS_IS_OK(status)) {
    1303           0 :                 goto err_out;
    1304             :         }
    1305             : 
    1306           0 :         status = snapper_dbus_msg_xchng(dconn, req_msg, &rsp_msg);
    1307           0 :         if (!NT_STATUS_IS_OK(status)) {
    1308           0 :                 goto err_req_free;
    1309             :         }
    1310             : 
    1311           0 :         status = snapper_list_confs_unpack(mem_ctx, dconn, rsp_msg,
    1312             :                                            &num_confs, &confs);
    1313           0 :         if (!NT_STATUS_IS_OK(status)) {
    1314           0 :                 goto err_rsp_free;
    1315             :         }
    1316             : 
    1317             :         /*
    1318             :          * for now we only support shares where the path directly corresponds
    1319             :          * to a snapper configuration.
    1320             :          */
    1321           0 :         conf = snapper_conf_array_base_find(num_confs, confs,
    1322             :                                             path);
    1323           0 :         if (conf == NULL) {
    1324           0 :                 status = NT_STATUS_NOT_SUPPORTED;
    1325           0 :                 goto err_array_free;
    1326             :         }
    1327             : 
    1328           0 :         conf_name = talloc_strdup(mem_ctx, conf->name);
    1329           0 :         if (conf_name == NULL) {
    1330           0 :                 status = NT_STATUS_NO_MEMORY;
    1331           0 :                 goto err_array_free;
    1332             :         }
    1333           0 :         base_path = talloc_strdup(mem_ctx, conf->mnt);
    1334           0 :         if (base_path == NULL) {
    1335           0 :                 status = NT_STATUS_NO_MEMORY;
    1336           0 :                 goto err_conf_name_free;
    1337             :         }
    1338             : 
    1339           0 :         talloc_free(confs);
    1340           0 :         dbus_message_unref(rsp_msg);
    1341           0 :         dbus_message_unref(req_msg);
    1342             : 
    1343           0 :         *conf_name_out = conf_name;
    1344           0 :         *base_path_out = base_path;
    1345             : 
    1346           0 :         return NT_STATUS_OK;
    1347             : 
    1348           0 : err_conf_name_free:
    1349           0 :         talloc_free(conf_name);
    1350           0 : err_array_free:
    1351           0 :         talloc_free(confs);
    1352           0 : err_rsp_free:
    1353           0 :         dbus_message_unref(rsp_msg);
    1354           0 : err_req_free:
    1355           0 :         dbus_message_unref(req_msg);
    1356           0 : err_out:
    1357           0 :         return status;
    1358             : }
    1359             : 
    1360             : /*
    1361             :  * Check whether a path can be shadow copied. Return the base volume, allowing
    1362             :  * the caller to determine if multiple paths lie on the same base volume.
    1363             :  */
    1364           0 : static NTSTATUS snapper_snap_check_path(struct vfs_handle_struct *handle,
    1365             :                                         TALLOC_CTX *mem_ctx,
    1366             :                                         const char *service_path,
    1367             :                                         char **base_volume)
    1368             : {
    1369             :         NTSTATUS status;
    1370             :         DBusConnection *dconn;
    1371             :         char *conf_name;
    1372             :         char *base_path;
    1373             : 
    1374           0 :         dconn = snapper_dbus_conn_create();
    1375           0 :         if (dconn == NULL) {
    1376           0 :                 return NT_STATUS_UNSUCCESSFUL;
    1377             :         }
    1378             : 
    1379           0 :         status = snapper_get_conf_call(mem_ctx, dconn, service_path,
    1380             :                                        &conf_name, &base_path);
    1381           0 :         if (!NT_STATUS_IS_OK(status)) {
    1382           0 :                 goto err_conn_close;
    1383             :         }
    1384             : 
    1385           0 :         talloc_free(conf_name);
    1386           0 :         *base_volume = base_path;
    1387           0 :         snapper_dbus_conn_destroy(dconn);
    1388             : 
    1389           0 :         return NT_STATUS_OK;
    1390             : 
    1391           0 : err_conn_close:
    1392           0 :         snapper_dbus_conn_destroy(dconn);
    1393           0 :         return status;
    1394             : }
    1395             : 
    1396           0 : static NTSTATUS snapper_create_snap_call(TALLOC_CTX *mem_ctx,
    1397             :                                          DBusConnection *dconn,
    1398             :                                          const char *conf_name,
    1399             :                                          const char *base_path,
    1400             :                                          const char *snap_desc,
    1401             :                                          uint32_t num_user_data,
    1402             :                                          struct snapper_dict *user_data,
    1403             :                                          char **snap_path_out)
    1404             : {
    1405             :         NTSTATUS status;
    1406             :         DBusMessage *req_msg;
    1407             :         DBusMessage *rsp_msg;
    1408           0 :         uint32_t snap_id = 0;
    1409             :         char *snap_path;
    1410             : 
    1411           0 :         status = snapper_create_snap_pack(mem_ctx,
    1412             :                                           conf_name,
    1413             :                                           snap_desc,
    1414             :                                           num_user_data,
    1415             :                                           user_data,
    1416             :                                           &req_msg);
    1417           0 :         if (!NT_STATUS_IS_OK(status)) {
    1418           0 :                 goto err_out;
    1419             :         }
    1420             : 
    1421           0 :         status = snapper_dbus_msg_xchng(dconn, req_msg, &rsp_msg);
    1422           0 :         if (!NT_STATUS_IS_OK(status)) {
    1423           0 :                 goto err_req_free;
    1424             :         }
    1425             : 
    1426           0 :         status = snapper_create_snap_unpack(dconn, rsp_msg, &snap_id);
    1427           0 :         if (!NT_STATUS_IS_OK(status)) {
    1428           0 :                 goto err_rsp_free;
    1429             :         }
    1430             : 
    1431           0 :         status = snapper_snap_id_to_path(mem_ctx, base_path, snap_id,
    1432             :                                          &snap_path);
    1433           0 :         if (!NT_STATUS_IS_OK(status)) {
    1434           0 :                 goto err_rsp_free;
    1435             :         }
    1436             : 
    1437           0 :         dbus_message_unref(rsp_msg);
    1438           0 :         dbus_message_unref(req_msg);
    1439             : 
    1440           0 :         DEBUG(6, ("created new snapshot %u at %s\n", snap_id, snap_path));
    1441           0 :         *snap_path_out = snap_path;
    1442             : 
    1443           0 :         return NT_STATUS_OK;
    1444             : 
    1445           0 : err_rsp_free:
    1446           0 :         dbus_message_unref(rsp_msg);
    1447           0 : err_req_free:
    1448           0 :         dbus_message_unref(req_msg);
    1449           0 : err_out:
    1450           0 :         return status;
    1451             : }
    1452             : 
    1453           0 : static NTSTATUS snapper_snap_create(struct vfs_handle_struct *handle,
    1454             :                                     TALLOC_CTX *mem_ctx,
    1455             :                                     const char *base_volume,
    1456             :                                     time_t *tstamp,
    1457             :                                     bool rw,
    1458             :                                     char **_base_path,
    1459             :                                     char **_snap_path)
    1460             : {
    1461             :         DBusConnection *dconn;
    1462             :         NTSTATUS status;
    1463             :         char *conf_name;
    1464             :         char *base_path;
    1465           0 :         char *snap_path = NULL;
    1466             :         TALLOC_CTX *tmp_ctx;
    1467             : 
    1468           0 :         tmp_ctx = talloc_new(mem_ctx);
    1469           0 :         if (tmp_ctx == NULL) {
    1470           0 :                 return NT_STATUS_NO_MEMORY;
    1471             :         }
    1472             : 
    1473           0 :         dconn = snapper_dbus_conn_create();
    1474           0 :         if (dconn == NULL) {
    1475           0 :                 talloc_free(tmp_ctx);
    1476           0 :                 return NT_STATUS_UNSUCCESSFUL;
    1477             :         }
    1478             : 
    1479           0 :         status = snapper_get_conf_call(tmp_ctx, dconn, base_volume,
    1480             :                                        &conf_name, &base_path);
    1481           0 :         if (!NT_STATUS_IS_OK(status)) {
    1482           0 :                 snapper_dbus_conn_destroy(dconn);
    1483           0 :                 talloc_free(tmp_ctx);
    1484           0 :                 return status;
    1485             :         }
    1486             : 
    1487           0 :         status = snapper_create_snap_call(tmp_ctx, dconn,
    1488             :                                           conf_name, base_path,
    1489             :                                           "Snapshot created by Samba",
    1490             :                                           0, NULL,
    1491             :                                           &snap_path);
    1492           0 :         if (!NT_STATUS_IS_OK(status)) {
    1493           0 :                 snapper_dbus_conn_destroy(dconn);
    1494           0 :                 talloc_free(tmp_ctx);
    1495           0 :                 return status;
    1496             :         }
    1497             : 
    1498           0 :         snapper_dbus_conn_destroy(dconn);
    1499           0 :         *_base_path = talloc_steal(mem_ctx, base_path);
    1500           0 :         *_snap_path = talloc_steal(mem_ctx, snap_path);
    1501           0 :         talloc_free(tmp_ctx);
    1502             : 
    1503           0 :         return NT_STATUS_OK;
    1504             : }
    1505             : 
    1506           0 : static NTSTATUS snapper_delete_snap_call(TALLOC_CTX *mem_ctx,
    1507             :                                          DBusConnection *dconn,
    1508             :                                          const char *conf_name,
    1509             :                                          uint32_t snap_id)
    1510             : {
    1511             :         NTSTATUS status;
    1512           0 :         DBusMessage *req_msg = NULL;
    1513             :         DBusMessage *rsp_msg;
    1514             : 
    1515           0 :         status = snapper_del_snap_pack(mem_ctx, conf_name, snap_id, &req_msg);
    1516           0 :         if (!NT_STATUS_IS_OK(status)) {
    1517           0 :                 goto err_out;
    1518             :         }
    1519             : 
    1520           0 :         status = snapper_dbus_msg_xchng(dconn, req_msg, &rsp_msg);
    1521           0 :         if (!NT_STATUS_IS_OK(status)) {
    1522           0 :                 goto err_req_free;
    1523             :         }
    1524             : 
    1525           0 :         status = snapper_del_snap_unpack(dconn, rsp_msg);
    1526           0 :         if (!NT_STATUS_IS_OK(status)) {
    1527           0 :                 goto err_rsp_free;
    1528             :         }
    1529             : 
    1530           0 :         dbus_message_unref(rsp_msg);
    1531           0 :         dbus_message_unref(req_msg);
    1532             : 
    1533           0 :         DEBUG(6, ("deleted snapshot %u\n", snap_id));
    1534             : 
    1535           0 :         return NT_STATUS_OK;
    1536             : 
    1537           0 : err_rsp_free:
    1538           0 :         dbus_message_unref(rsp_msg);
    1539           0 : err_req_free:
    1540           0 :         dbus_message_unref(req_msg);
    1541           0 : err_out:
    1542           0 :         return status;
    1543             : }
    1544             : 
    1545           0 : static NTSTATUS snapper_snap_delete(struct vfs_handle_struct *handle,
    1546             :                                     TALLOC_CTX *mem_ctx,
    1547             :                                     char *base_path,
    1548             :                                     char *snap_path)
    1549             : {
    1550             :         DBusConnection *dconn;
    1551             :         NTSTATUS status;
    1552             :         char *conf_name;
    1553             :         char *snap_base_path;
    1554             :         uint32_t snap_id;
    1555             :         TALLOC_CTX *tmp_ctx;
    1556             : 
    1557           0 :         tmp_ctx = talloc_new(mem_ctx);
    1558           0 :         if (tmp_ctx == NULL) {
    1559           0 :                 return NT_STATUS_NO_MEMORY;
    1560             :         }
    1561             : 
    1562           0 :         dconn = snapper_dbus_conn_create();
    1563           0 :         if (dconn == NULL) {
    1564           0 :                 talloc_free(tmp_ctx);
    1565           0 :                 return NT_STATUS_UNSUCCESSFUL;
    1566             :         }
    1567             : 
    1568           0 :         status = snapper_get_conf_call(tmp_ctx, dconn, base_path,
    1569             :                                        &conf_name, &snap_base_path);
    1570           0 :         if (!NT_STATUS_IS_OK(status)) {
    1571           0 :                 snapper_dbus_conn_destroy(dconn);
    1572           0 :                 talloc_free(tmp_ctx);
    1573           0 :                 return status;
    1574             :         }
    1575             : 
    1576           0 :         status = snapper_snap_path_to_id(tmp_ctx, snap_path, &snap_id);
    1577           0 :         if (!NT_STATUS_IS_OK(status)) {
    1578           0 :                 snapper_dbus_conn_destroy(dconn);
    1579           0 :                 talloc_free(tmp_ctx);
    1580           0 :                 return status;
    1581             :         }
    1582             : 
    1583           0 :         status = snapper_delete_snap_call(tmp_ctx, dconn, conf_name, snap_id);
    1584           0 :         if (!NT_STATUS_IS_OK(status)) {
    1585           0 :                 snapper_dbus_conn_destroy(dconn);
    1586           0 :                 talloc_free(tmp_ctx);
    1587           0 :                 return status;
    1588             :         }
    1589             : 
    1590           0 :         snapper_dbus_conn_destroy(dconn);
    1591           0 :         talloc_free(tmp_ctx);
    1592             : 
    1593           0 :         return NT_STATUS_OK;
    1594             : }
    1595             : 
    1596             : /* sc_data used as parent talloc context for all labels */
    1597           0 : static int snapper_get_shadow_copy_data(struct vfs_handle_struct *handle,
    1598             :                                         struct files_struct *fsp,
    1599             :                                         struct shadow_copy_data *sc_data,
    1600             :                                         bool labels)
    1601             : {
    1602             :         DBusConnection *dconn;
    1603             :         TALLOC_CTX *tmp_ctx;
    1604             :         NTSTATUS status;
    1605             :         char *conf_name;
    1606             :         char *base_path;
    1607           0 :         DBusMessage *req_msg = NULL;
    1608             :         DBusMessage *rsp_msg;
    1609             :         uint32_t num_snaps;
    1610             :         struct snapper_snap *snaps;
    1611             :         uint32_t i;
    1612             :         uint32_t lbl_off;
    1613             : 
    1614           0 :         tmp_ctx = talloc_new(sc_data);
    1615           0 :         if (tmp_ctx == NULL) {
    1616           0 :                 status = NT_STATUS_NO_MEMORY;
    1617           0 :                 goto err_out;
    1618             :         }
    1619             : 
    1620           0 :         dconn = snapper_dbus_conn_create();
    1621           0 :         if (dconn == NULL) {
    1622           0 :                 status = NT_STATUS_UNSUCCESSFUL;
    1623           0 :                 goto err_mem_ctx_free;
    1624             :         }
    1625             : 
    1626           0 :         if (fsp->conn->connectpath == NULL) {
    1627           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    1628           0 :                 goto err_conn_free;
    1629             :         }
    1630             : 
    1631           0 :         status = snapper_get_conf_call(tmp_ctx, dconn,
    1632           0 :                                        fsp->conn->connectpath,
    1633             :                                        &conf_name,
    1634             :                                        &base_path);
    1635           0 :         if (!NT_STATUS_IS_OK(status)) {
    1636           0 :                 goto err_conn_free;
    1637             :         }
    1638             : 
    1639           0 :         status = snapper_list_snaps_pack(tmp_ctx, conf_name, &req_msg);
    1640           0 :         if (!NT_STATUS_IS_OK(status)) {
    1641           0 :                 goto err_conn_free;
    1642             :         }
    1643             : 
    1644           0 :         status = snapper_dbus_msg_xchng(dconn, req_msg, &rsp_msg);
    1645           0 :         if (!NT_STATUS_IS_OK(status)) {
    1646           0 :                 goto err_req_free;
    1647             :         }
    1648             : 
    1649           0 :         status = snapper_list_snaps_unpack(tmp_ctx, rsp_msg,
    1650             :                                            &num_snaps, &snaps);
    1651           0 :         if (!NT_STATUS_IS_OK(status)) {
    1652           0 :                 goto err_rsp_free;
    1653             :         }
    1654             :         /* we should always get at least one snapshot (current) */
    1655           0 :         if (num_snaps == 0) {
    1656           0 :                 DEBUG(1, ("zero snapshots in snap list response\n"));
    1657           0 :                 status = NT_STATUS_UNSUCCESSFUL;
    1658           0 :                 goto err_rsp_free;
    1659             :         }
    1660             : 
    1661             :         /* subtract 1, (current) snapshot is not returned */
    1662           0 :         sc_data->num_volumes = num_snaps - 1;
    1663           0 :         sc_data->labels = NULL;
    1664             : 
    1665           0 :         if ((labels == false) || (sc_data->num_volumes == 0)) {
    1666             :                 /* tokens need not be added to the labels array */
    1667             :                 goto done;
    1668             :         }
    1669             : 
    1670           0 :         sc_data->labels = talloc_array(sc_data, SHADOW_COPY_LABEL,
    1671             :                                        sc_data->num_volumes);
    1672           0 :         if (sc_data->labels == NULL) {
    1673           0 :                 status = NT_STATUS_NO_MEMORY;
    1674           0 :                 goto err_rsp_free;
    1675             :         }
    1676             : 
    1677             :         /* start at end for decending order, do not include 0 (current) */
    1678           0 :         lbl_off = 0;
    1679           0 :         for (i = num_snaps - 1; i > 0; i--) {
    1680           0 :                 char *lbl = sc_data->labels[lbl_off++];
    1681             :                 struct tm gmt_snap_time;
    1682             :                 struct tm *tm_ret;
    1683             :                 size_t str_sz;
    1684             : 
    1685           0 :                 tm_ret = gmtime_r((time_t *)&snaps[i].time, &gmt_snap_time);
    1686           0 :                 if (tm_ret == NULL) {
    1687           0 :                         status = NT_STATUS_UNSUCCESSFUL;
    1688           0 :                         goto err_labels_free;
    1689             :                 }
    1690           0 :                 str_sz = strftime(lbl, sizeof(SHADOW_COPY_LABEL),
    1691             :                                   "@GMT-%Y.%m.%d-%H.%M.%S", &gmt_snap_time);
    1692           0 :                 if (str_sz == 0) {
    1693           0 :                         status = NT_STATUS_UNSUCCESSFUL;
    1694           0 :                         goto err_labels_free;
    1695             :                 }
    1696             :         }
    1697             : 
    1698           0 : done:
    1699           0 :         talloc_free(tmp_ctx);
    1700           0 :         dbus_message_unref(rsp_msg);
    1701           0 :         dbus_message_unref(req_msg);
    1702           0 :         snapper_dbus_conn_destroy(dconn);
    1703             : 
    1704           0 :         return 0;
    1705             : 
    1706           0 : err_labels_free:
    1707           0 :         TALLOC_FREE(sc_data->labels);
    1708           0 : err_rsp_free:
    1709           0 :         dbus_message_unref(rsp_msg);
    1710           0 : err_req_free:
    1711           0 :         dbus_message_unref(req_msg);
    1712           0 : err_conn_free:
    1713           0 :         snapper_dbus_conn_destroy(dconn);
    1714           0 : err_mem_ctx_free:
    1715           0 :         talloc_free(tmp_ctx);
    1716           0 : err_out:
    1717           0 :         errno = map_errno_from_nt_status(status);
    1718           0 :         return -1;
    1719             : }
    1720             : 
    1721           0 : static bool snapper_gmt_strip_snapshot(TALLOC_CTX *mem_ctx,
    1722             :                                        struct vfs_handle_struct *handle,
    1723             :                                        const struct smb_filename *smb_fname,
    1724             :                                        time_t *ptimestamp,
    1725             :                                        char **pstripped)
    1726             : {
    1727             :         char *stripped;
    1728             : 
    1729           0 :         if (smb_fname->twrp == 0) {
    1730           0 :                 goto no_snapshot;
    1731             :         }
    1732             : 
    1733           0 :         if (pstripped != NULL) {
    1734           0 :                 stripped = talloc_strdup(mem_ctx, smb_fname->base_name);
    1735           0 :                 if (stripped == NULL) {
    1736           0 :                         return false;
    1737             :                 }
    1738           0 :                 *pstripped = stripped;
    1739             :         }
    1740             : 
    1741           0 :         *ptimestamp = nt_time_to_unix(smb_fname->twrp);
    1742           0 :         return true;
    1743           0 : no_snapshot:
    1744           0 :         *ptimestamp = 0;
    1745           0 :         return true;
    1746             : }
    1747             : 
    1748           0 : static NTSTATUS snapper_get_snap_at_time_call(TALLOC_CTX *mem_ctx,
    1749             :                                               DBusConnection *dconn,
    1750             :                                               const char *conf_name,
    1751             :                                               const char *base_path,
    1752             :                                               time_t snaptime,
    1753             :                                               char **snap_path_out)
    1754             : {
    1755             :         NTSTATUS status;
    1756           0 :         DBusMessage *req_msg = NULL;
    1757             :         DBusMessage *rsp_msg;
    1758             :         uint32_t num_snaps;
    1759             :         struct snapper_snap *snaps;
    1760             :         char *snap_path;
    1761             : 
    1762           0 :         status = snapper_list_snaps_at_time_pack(mem_ctx,
    1763             :                                                  conf_name,
    1764             :                                                  snaptime,
    1765             :                                                  snaptime,
    1766             :                                                  &req_msg);
    1767           0 :         if (!NT_STATUS_IS_OK(status)) {
    1768           0 :                 goto err_out;
    1769             :         }
    1770             : 
    1771           0 :         status = snapper_dbus_msg_xchng(dconn, req_msg, &rsp_msg);
    1772           0 :         if (!NT_STATUS_IS_OK(status)) {
    1773           0 :                 goto err_req_free;
    1774             :         }
    1775             : 
    1776           0 :         status = snapper_list_snaps_unpack(mem_ctx, rsp_msg,
    1777             :                                            &num_snaps, &snaps);
    1778           0 :         if (!NT_STATUS_IS_OK(status)) {
    1779           0 :                 goto err_rsp_free;
    1780             :         }
    1781             : 
    1782           0 :         if (num_snaps == 0) {
    1783           0 :                 DEBUG(4, ("no snapshots found with time: %lu\n",
    1784             :                           (unsigned long)snaptime));
    1785           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    1786           0 :                 goto err_snap_array_free;
    1787           0 :         } else if (num_snaps > 0) {
    1788           0 :                 DEBUG(4, ("got %u snapshots for single time %lu, using top\n",
    1789             :                           num_snaps, (unsigned long)snaptime));
    1790             :         }
    1791             : 
    1792           0 :         status = snapper_snap_id_to_path(mem_ctx, base_path, snaps[0].id,
    1793             :                                          &snap_path);
    1794           0 :         if (!NT_STATUS_IS_OK(status)) {
    1795           0 :                 goto err_snap_array_free;
    1796             :         }
    1797             : 
    1798           0 :         *snap_path_out = snap_path;
    1799           0 : err_snap_array_free:
    1800           0 :         talloc_free(snaps);
    1801           0 : err_rsp_free:
    1802           0 :         dbus_message_unref(rsp_msg);
    1803           0 : err_req_free:
    1804           0 :         dbus_message_unref(req_msg);
    1805           0 : err_out:
    1806           0 :         return status;
    1807             : }
    1808             : 
    1809           0 : static NTSTATUS snapper_snap_path_expand(struct connection_struct *conn,
    1810             :                                          TALLOC_CTX *mem_ctx,
    1811             :                                          time_t snap_time,
    1812             :                                          char **snap_dir_out)
    1813             : {
    1814             :         DBusConnection *dconn;
    1815             :         NTSTATUS status;
    1816             :         char *conf_name;
    1817             :         char *base_path;
    1818           0 :         char *snap_path = NULL;
    1819             : 
    1820           0 :         dconn = snapper_dbus_conn_create();
    1821           0 :         if (dconn == NULL) {
    1822           0 :                 status = NT_STATUS_UNSUCCESSFUL;
    1823           0 :                 goto err_out;
    1824             :         }
    1825             : 
    1826           0 :         if (conn->connectpath == NULL) {
    1827           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    1828           0 :                 goto err_conn_free;
    1829             :         }
    1830             : 
    1831           0 :         status = snapper_get_conf_call(mem_ctx, dconn,
    1832           0 :                                        conn->connectpath,
    1833             :                                        &conf_name,
    1834             :                                        &base_path);
    1835           0 :         if (!NT_STATUS_IS_OK(status)) {
    1836           0 :                 goto err_conn_free;
    1837             :         }
    1838             : 
    1839           0 :         status = snapper_get_snap_at_time_call(mem_ctx, dconn,
    1840             :                                                conf_name, base_path, snap_time,
    1841             :                                                &snap_path);
    1842           0 :         if (!NT_STATUS_IS_OK(status)) {
    1843           0 :                 goto err_conf_name_free;
    1844             :         }
    1845             : 
    1846             :         /* confirm snapshot path is nested under base path */
    1847           0 :         if (strncmp(snap_path, base_path, strlen(base_path)) != 0) {
    1848           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    1849           0 :                 goto err_snap_path_free;
    1850             :         }
    1851             : 
    1852           0 :         talloc_free(conf_name);
    1853           0 :         talloc_free(base_path);
    1854           0 :         snapper_dbus_conn_destroy(dconn);
    1855           0 :         *snap_dir_out = snap_path;
    1856             : 
    1857           0 :         return NT_STATUS_OK;
    1858             : 
    1859           0 : err_snap_path_free:
    1860           0 :         talloc_free(snap_path);
    1861           0 : err_conf_name_free:
    1862           0 :         talloc_free(conf_name);
    1863           0 :         talloc_free(base_path);
    1864           0 : err_conn_free:
    1865           0 :         snapper_dbus_conn_destroy(dconn);
    1866           0 : err_out:
    1867           0 :         return status;
    1868             : }
    1869             : 
    1870           0 : static char *snapper_gmt_convert(TALLOC_CTX *mem_ctx,
    1871             :                              struct vfs_handle_struct *handle,
    1872             :                              const char *name, time_t timestamp)
    1873             : {
    1874           0 :         char *snap_path = NULL;
    1875           0 :         char *path = NULL;
    1876             :         NTSTATUS status;
    1877             :         int saved_errno;
    1878             : 
    1879           0 :         status = snapper_snap_path_expand(handle->conn, mem_ctx, timestamp,
    1880             :                                           &snap_path);
    1881           0 :         if (!NT_STATUS_IS_OK(status)) {
    1882           0 :                 errno = map_errno_from_nt_status(status);
    1883           0 :                 goto err_out;
    1884             :         }
    1885             : 
    1886           0 :         path = talloc_asprintf(mem_ctx, "%s/%s", snap_path, name);
    1887           0 :         if (path == NULL) {
    1888           0 :                 errno = ENOMEM;
    1889           0 :                 goto err_snap_path_free;
    1890             :         }
    1891             : 
    1892           0 :         DEBUG(10, ("converted %s/%s @ time to %s\n",
    1893             :                    handle->conn->connectpath, name, path));
    1894           0 :         return path;
    1895             : 
    1896           0 : err_snap_path_free:
    1897           0 :         saved_errno = errno;
    1898           0 :         talloc_free(snap_path);
    1899           0 :         errno = saved_errno;
    1900           0 : err_out:
    1901           0 :         return NULL;
    1902             : }
    1903             : 
    1904           0 : static int snapper_gmt_renameat(vfs_handle_struct *handle,
    1905             :                         files_struct *srcfsp,
    1906             :                         const struct smb_filename *smb_fname_src,
    1907             :                         files_struct *dstfsp,
    1908             :                         const struct smb_filename *smb_fname_dst)
    1909             : {
    1910             :         time_t timestamp_src, timestamp_dst;
    1911             : 
    1912           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
    1913             :                                         smb_fname_src,
    1914             :                                         &timestamp_src, NULL)) {
    1915           0 :                 return -1;
    1916             :         }
    1917           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
    1918             :                                         smb_fname_dst,
    1919             :                                         &timestamp_dst, NULL)) {
    1920           0 :                 return -1;
    1921             :         }
    1922           0 :         if (timestamp_src != 0) {
    1923           0 :                 errno = EXDEV;
    1924           0 :                 return -1;
    1925             :         }
    1926           0 :         if (timestamp_dst != 0) {
    1927           0 :                 errno = EROFS;
    1928           0 :                 return -1;
    1929             :         }
    1930           0 :         return SMB_VFS_NEXT_RENAMEAT(handle,
    1931             :                         srcfsp,
    1932             :                         smb_fname_src,
    1933             :                         dstfsp,
    1934             :                         smb_fname_dst);
    1935             : }
    1936             : 
    1937           0 : static int snapper_gmt_symlinkat(vfs_handle_struct *handle,
    1938             :                                 const struct smb_filename *link_contents,
    1939             :                                 struct files_struct *dirfsp,
    1940             :                                 const struct smb_filename *new_smb_fname)
    1941             : {
    1942           0 :         time_t timestamp_old = 0;
    1943           0 :         time_t timestamp_new = 0;
    1944             : 
    1945           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(),
    1946             :                                 handle,
    1947             :                                 link_contents,
    1948             :                                 &timestamp_old,
    1949             :                                 NULL)) {
    1950           0 :                 return -1;
    1951             :         }
    1952           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(),
    1953             :                                 handle,
    1954             :                                 new_smb_fname,
    1955             :                                 &timestamp_new,
    1956             :                                 NULL)) {
    1957           0 :                 return -1;
    1958             :         }
    1959           0 :         if ((timestamp_old != 0) || (timestamp_new != 0)) {
    1960           0 :                 errno = EROFS;
    1961           0 :                 return -1;
    1962             :         }
    1963           0 :         return SMB_VFS_NEXT_SYMLINKAT(handle,
    1964             :                         link_contents,
    1965             :                         dirfsp,
    1966             :                         new_smb_fname);
    1967             : }
    1968             : 
    1969           0 : static int snapper_gmt_linkat(vfs_handle_struct *handle,
    1970             :                                 files_struct *srcfsp,
    1971             :                                 const struct smb_filename *old_smb_fname,
    1972             :                                 files_struct *dstfsp,
    1973             :                                 const struct smb_filename *new_smb_fname,
    1974             :                                 int flags)
    1975             : {
    1976           0 :         time_t timestamp_old = 0;
    1977           0 :         time_t timestamp_new = 0;
    1978             : 
    1979           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(),
    1980             :                                 handle,
    1981             :                                 old_smb_fname,
    1982             :                                 &timestamp_old,
    1983             :                                 NULL)) {
    1984           0 :                 return -1;
    1985             :         }
    1986           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(),
    1987             :                                 handle,
    1988             :                                 new_smb_fname,
    1989             :                                 &timestamp_new,
    1990             :                                 NULL)) {
    1991           0 :                 return -1;
    1992             :         }
    1993           0 :         if ((timestamp_old != 0) || (timestamp_new != 0)) {
    1994           0 :                 errno = EROFS;
    1995           0 :                 return -1;
    1996             :         }
    1997           0 :         return SMB_VFS_NEXT_LINKAT(handle,
    1998             :                                 srcfsp,
    1999             :                                 old_smb_fname,
    2000             :                                 dstfsp,
    2001             :                                 new_smb_fname,
    2002             :                                 flags);
    2003             : }
    2004             : 
    2005           0 : static int snapper_gmt_stat(vfs_handle_struct *handle,
    2006             :                             struct smb_filename *smb_fname)
    2007             : {
    2008             :         time_t timestamp;
    2009             :         char *stripped, *tmp;
    2010             :         int ret, saved_errno;
    2011             : 
    2012           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
    2013             :                                         smb_fname,
    2014             :                                         &timestamp, &stripped)) {
    2015           0 :                 return -1;
    2016             :         }
    2017           0 :         if (timestamp == 0) {
    2018           0 :                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
    2019             :         }
    2020             : 
    2021           0 :         tmp = smb_fname->base_name;
    2022           0 :         smb_fname->base_name = snapper_gmt_convert(talloc_tos(), handle,
    2023             :                                                    stripped, timestamp);
    2024           0 :         TALLOC_FREE(stripped);
    2025             : 
    2026           0 :         if (smb_fname->base_name == NULL) {
    2027           0 :                 smb_fname->base_name = tmp;
    2028           0 :                 return -1;
    2029             :         }
    2030             : 
    2031           0 :         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
    2032           0 :         saved_errno = errno;
    2033             : 
    2034           0 :         TALLOC_FREE(smb_fname->base_name);
    2035           0 :         smb_fname->base_name = tmp;
    2036             : 
    2037           0 :         errno = saved_errno;
    2038           0 :         return ret;
    2039             : }
    2040             : 
    2041           0 : static int snapper_gmt_lstat(vfs_handle_struct *handle,
    2042             :                              struct smb_filename *smb_fname)
    2043             : {
    2044             :         time_t timestamp;
    2045             :         char *stripped, *tmp;
    2046             :         int ret, saved_errno;
    2047             : 
    2048           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
    2049             :                                         smb_fname,
    2050             :                                         &timestamp, &stripped)) {
    2051           0 :                 return -1;
    2052             :         }
    2053           0 :         if (timestamp == 0) {
    2054           0 :                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
    2055             :         }
    2056             : 
    2057           0 :         tmp = smb_fname->base_name;
    2058           0 :         smb_fname->base_name = snapper_gmt_convert(talloc_tos(), handle,
    2059             :                                                    stripped, timestamp);
    2060           0 :         TALLOC_FREE(stripped);
    2061             : 
    2062           0 :         if (smb_fname->base_name == NULL) {
    2063           0 :                 smb_fname->base_name = tmp;
    2064           0 :                 return -1;
    2065             :         }
    2066             : 
    2067           0 :         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
    2068           0 :         saved_errno = errno;
    2069             : 
    2070           0 :         TALLOC_FREE(smb_fname->base_name);
    2071           0 :         smb_fname->base_name = tmp;
    2072             : 
    2073           0 :         errno = saved_errno;
    2074           0 :         return ret;
    2075             : }
    2076             : 
    2077           0 : static int snapper_gmt_openat(struct vfs_handle_struct *handle,
    2078             :                               const struct files_struct *dirfsp,
    2079             :                               const struct smb_filename *smb_fname_in,
    2080             :                               struct files_struct *fsp,
    2081             :                               int flags,
    2082             :                               mode_t mode)
    2083             : {
    2084           0 :         struct smb_filename *smb_fname = NULL;
    2085             :         time_t timestamp;
    2086           0 :         char *stripped = NULL;
    2087             :         int ret;
    2088           0 :         int saved_errno = 0;
    2089             : 
    2090           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
    2091             :                                         smb_fname_in,
    2092             :                                         &timestamp, &stripped)) {
    2093           0 :                 return -1;
    2094             :         }
    2095           0 :         if (timestamp == 0) {
    2096           0 :                 return SMB_VFS_NEXT_OPENAT(handle,
    2097             :                                            dirfsp,
    2098             :                                            smb_fname_in,
    2099             :                                            fsp,
    2100             :                                            flags,
    2101             :                                            mode);
    2102             :         }
    2103             : 
    2104           0 :         smb_fname = cp_smb_filename(talloc_tos(), smb_fname_in);
    2105           0 :         if (smb_fname == NULL) {
    2106           0 :                 TALLOC_FREE(stripped);
    2107           0 :                 return -1;
    2108             :         }
    2109             : 
    2110           0 :         smb_fname->base_name = snapper_gmt_convert(smb_fname, handle,
    2111             :                                                    stripped, timestamp);
    2112           0 :         TALLOC_FREE(stripped);
    2113             : 
    2114           0 :         if (smb_fname->base_name == NULL) {
    2115           0 :                 TALLOC_FREE(smb_fname);
    2116           0 :                 errno = ENOMEM;
    2117           0 :                 return -1;
    2118             :         }
    2119             : 
    2120           0 :         ret = SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname, fsp, flags, mode);
    2121           0 :         if (ret == -1) {
    2122           0 :                 saved_errno = errno;
    2123             :         }
    2124           0 :         TALLOC_FREE(smb_fname);
    2125           0 :         if (saved_errno != 0) {
    2126           0 :                 errno = saved_errno;
    2127             :         }
    2128           0 :         return ret;
    2129             : }
    2130             : 
    2131           0 : static int snapper_gmt_unlinkat(vfs_handle_struct *handle,
    2132             :                         struct files_struct *dirfsp,
    2133             :                         const struct smb_filename *smb_fname,
    2134             :                         int flags)
    2135             : {
    2136           0 :         time_t timestamp = 0;
    2137             : 
    2138           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
    2139             :                                         smb_fname,
    2140             :                                         &timestamp, NULL)) {
    2141           0 :                 return -1;
    2142             :         }
    2143           0 :         if (timestamp != 0) {
    2144           0 :                 errno = EROFS;
    2145           0 :                 return -1;
    2146             :         }
    2147           0 :         return SMB_VFS_NEXT_UNLINKAT(handle,
    2148             :                         dirfsp,
    2149             :                         smb_fname,
    2150             :                         flags);
    2151             : }
    2152             : 
    2153           0 : static int snapper_gmt_fchmod(vfs_handle_struct *handle,
    2154             :                        struct files_struct *fsp,
    2155             :                        mode_t mode)
    2156             : {
    2157           0 :         time_t timestamp = 0;
    2158           0 :         const struct smb_filename *smb_fname = NULL;
    2159             : 
    2160           0 :         smb_fname = fsp->fsp_name;
    2161             : 
    2162           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(),
    2163             :                                         handle,
    2164             :                                         smb_fname,
    2165             :                                         &timestamp,
    2166             :                                         NULL)) {
    2167           0 :                 return -1;
    2168             :         }
    2169             : 
    2170           0 :         if (timestamp != 0) {
    2171           0 :                 errno = EROFS;
    2172           0 :                 return -1;
    2173             :         }
    2174           0 :         return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
    2175             : }
    2176             : 
    2177           0 : static int snapper_gmt_chdir(vfs_handle_struct *handle,
    2178             :                         const struct smb_filename *smb_fname)
    2179             : {
    2180           0 :         time_t timestamp = 0;
    2181           0 :         char *stripped = NULL;
    2182             :         int ret;
    2183           0 :         int saved_errno = 0;
    2184           0 :         char *conv = NULL;
    2185           0 :         struct smb_filename *conv_smb_fname = NULL;
    2186             : 
    2187           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(),
    2188             :                                 handle,
    2189             :                                 smb_fname,
    2190             :                                 &timestamp,
    2191             :                                 &stripped)) {
    2192           0 :                 return -1;
    2193             :         }
    2194           0 :         if (timestamp == 0) {
    2195           0 :                 return SMB_VFS_NEXT_CHDIR(handle, smb_fname);
    2196             :         }
    2197           0 :         conv = snapper_gmt_convert(talloc_tos(), handle, stripped, timestamp);
    2198           0 :         TALLOC_FREE(stripped);
    2199           0 :         if (conv == NULL) {
    2200           0 :                 return -1;
    2201             :         }
    2202           0 :         conv_smb_fname = synthetic_smb_fname(talloc_tos(),
    2203             :                                         conv,
    2204             :                                         NULL,
    2205             :                                         NULL,
    2206             :                                         0,
    2207             :                                         smb_fname->flags);
    2208           0 :         if (conv_smb_fname == NULL) {
    2209           0 :                 TALLOC_FREE(conv);
    2210           0 :                 errno = ENOMEM;
    2211           0 :                 return -1;
    2212             :         }
    2213           0 :         ret = SMB_VFS_NEXT_CHDIR(handle, conv_smb_fname);
    2214           0 :         if (ret == -1) {
    2215           0 :                 saved_errno = errno;
    2216             :         }
    2217           0 :         TALLOC_FREE(conv);
    2218           0 :         TALLOC_FREE(conv_smb_fname);
    2219           0 :         if (saved_errno != 0) {
    2220           0 :                 errno = saved_errno;
    2221             :         }
    2222           0 :         return ret;
    2223             : }
    2224             : 
    2225           0 : static int snapper_gmt_fntimes(vfs_handle_struct *handle,
    2226             :                                files_struct *fsp,
    2227             :                                struct smb_file_time *ft)
    2228             : {
    2229           0 :         time_t timestamp = 0;
    2230             : 
    2231           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(),
    2232             :                                         handle,
    2233           0 :                                         fsp->fsp_name,
    2234             :                                         &timestamp,
    2235             :                                         NULL)) {
    2236           0 :                 return -1;
    2237             :         }
    2238             : 
    2239           0 :         if (timestamp != 0) {
    2240           0 :                 errno = EROFS;
    2241           0 :                 return -1;
    2242             :         }
    2243             : 
    2244           0 :         return SMB_VFS_NEXT_FNTIMES(handle, fsp, ft);
    2245             : }
    2246             : 
    2247           0 : static int snapper_gmt_readlinkat(vfs_handle_struct *handle,
    2248             :                                 const struct files_struct *dirfsp,
    2249             :                                 const struct smb_filename *smb_fname,
    2250             :                                 char *buf,
    2251             :                                 size_t bufsiz)
    2252             : {
    2253           0 :         time_t timestamp = 0;
    2254             :         int ret;
    2255           0 :         int saved_errno = 0;
    2256           0 :         struct smb_filename *full_fname = NULL;
    2257             : 
    2258             :         /*
    2259             :          * Now this function only looks at smb_fname->twrp
    2260             :          * we don't need to copy out the path. Just use
    2261             :          * smb_fname->base_name directly.
    2262             :          */
    2263           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
    2264             :                                         smb_fname,
    2265             :                                         &timestamp, NULL)) {
    2266           0 :                 return -1;
    2267             :         }
    2268           0 :         if (timestamp == 0) {
    2269           0 :                 return SMB_VFS_NEXT_READLINKAT(handle,
    2270             :                                 dirfsp,
    2271             :                                 smb_fname,
    2272             :                                 buf,
    2273             :                                 bufsiz);
    2274             :         }
    2275           0 :         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
    2276             :                                 dirfsp,
    2277             :                                 smb_fname);
    2278           0 :         if (full_fname == NULL) {
    2279           0 :                 return -1;
    2280             :         }
    2281             : 
    2282             :         /* Find the snapshot path from the full pathname. */
    2283           0 :         full_fname->base_name = snapper_gmt_convert(full_fname,
    2284             :                                         handle,
    2285           0 :                                         full_fname->base_name,
    2286             :                                         timestamp);
    2287           0 :         if (full_fname->base_name == NULL) {
    2288           0 :                 TALLOC_FREE(full_fname);
    2289           0 :                 return -1;
    2290             :         }
    2291           0 :         ret = SMB_VFS_NEXT_READLINKAT(handle,
    2292             :                                 handle->conn->cwd_fsp,
    2293             :                                 full_fname,
    2294             :                                 buf,
    2295             :                                 bufsiz);
    2296           0 :         if (ret == -1) {
    2297           0 :                 saved_errno = errno;
    2298             :         }
    2299           0 :         TALLOC_FREE(full_fname);
    2300           0 :         if (saved_errno != 0) {
    2301           0 :                 errno = saved_errno;
    2302             :         }
    2303           0 :         return ret;
    2304             : }
    2305             : 
    2306           0 : static int snapper_gmt_mknodat(vfs_handle_struct *handle,
    2307             :                         files_struct *dirfsp,
    2308             :                         const struct smb_filename *smb_fname,
    2309             :                         mode_t mode,
    2310             :                         SMB_DEV_T dev)
    2311             : {
    2312           0 :         time_t timestamp = (time_t)0;
    2313             : 
    2314           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
    2315             :                                         smb_fname,
    2316             :                                         &timestamp, NULL)) {
    2317           0 :                 return -1;
    2318             :         }
    2319           0 :         if (timestamp != 0) {
    2320           0 :                 errno = EROFS;
    2321           0 :                 return -1;
    2322             :         }
    2323           0 :         return SMB_VFS_NEXT_MKNODAT(handle,
    2324             :                         dirfsp,
    2325             :                         smb_fname,
    2326             :                         mode,
    2327             :                         dev);
    2328             : }
    2329             : 
    2330           0 : static struct smb_filename *snapper_gmt_realpath(vfs_handle_struct *handle,
    2331             :                                 TALLOC_CTX *ctx,
    2332             :                                 const struct smb_filename *smb_fname)
    2333             : {
    2334           0 :         time_t timestamp = 0;
    2335           0 :         char *stripped = NULL;
    2336           0 :         struct smb_filename *result_fname = NULL;
    2337           0 :         struct smb_filename *conv_smb_fname = NULL;
    2338           0 :         int saved_errno = 0;
    2339             : 
    2340           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
    2341             :                                         smb_fname,
    2342             :                                         &timestamp, &stripped)) {
    2343           0 :                 goto done;
    2344             :         }
    2345           0 :         if (timestamp == 0) {
    2346           0 :                 return SMB_VFS_NEXT_REALPATH(handle, ctx, smb_fname);
    2347             :         }
    2348             : 
    2349           0 :         conv_smb_fname = cp_smb_filename(talloc_tos(), smb_fname);
    2350           0 :         if (conv_smb_fname == NULL) {
    2351           0 :                 goto done;
    2352             :         }
    2353           0 :         conv_smb_fname->base_name = snapper_gmt_convert(conv_smb_fname, handle,
    2354             :                                               stripped, timestamp);
    2355           0 :         if (conv_smb_fname->base_name == NULL) {
    2356           0 :                 goto done;
    2357             :         }
    2358             : 
    2359           0 :         result_fname = SMB_VFS_NEXT_REALPATH(handle, ctx, conv_smb_fname);
    2360             : 
    2361           0 : done:
    2362           0 :         if (result_fname == NULL) {
    2363           0 :                 saved_errno = errno;
    2364             :         }
    2365           0 :         TALLOC_FREE(conv_smb_fname);
    2366           0 :         TALLOC_FREE(stripped);
    2367           0 :         if (saved_errno != 0) {
    2368           0 :                 errno = saved_errno;
    2369             :         }
    2370           0 :         return result_fname;
    2371             : }
    2372             : 
    2373           0 : static int snapper_gmt_mkdirat(vfs_handle_struct *handle,
    2374             :                                 struct files_struct *dirfsp,
    2375             :                                 const struct smb_filename *fname,
    2376             :                                 mode_t mode)
    2377             : {
    2378           0 :         time_t timestamp = 0;
    2379             : 
    2380           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(), handle, fname,
    2381             :                                         &timestamp, NULL)) {
    2382           0 :                 return -1;
    2383             :         }
    2384           0 :         if (timestamp != 0) {
    2385           0 :                 errno = EROFS;
    2386           0 :                 return -1;
    2387             :         }
    2388           0 :         return SMB_VFS_NEXT_MKDIRAT(handle,
    2389             :                         dirfsp,
    2390             :                         fname,
    2391             :                         mode);
    2392             : }
    2393             : 
    2394           0 : static int snapper_gmt_fchflags(vfs_handle_struct *handle,
    2395             :                                 struct files_struct *fsp,
    2396             :                                 unsigned int flags)
    2397             : {
    2398           0 :         time_t timestamp = 0;
    2399             : 
    2400           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
    2401           0 :                                 fsp->fsp_name, &timestamp, NULL)) {
    2402           0 :                 return -1;
    2403             :         }
    2404           0 :         if (timestamp != 0) {
    2405           0 :                 errno = EROFS;
    2406           0 :                 return -1;
    2407             :         }
    2408           0 :         return SMB_VFS_NEXT_FCHFLAGS(handle, fsp, flags);
    2409             : }
    2410             : 
    2411           0 : static int snapper_gmt_fsetxattr(struct vfs_handle_struct *handle,
    2412             :                                 struct files_struct *fsp,
    2413             :                                 const char *aname, const void *value,
    2414             :                                 size_t size, int flags)
    2415             : {
    2416           0 :         time_t timestamp = 0;
    2417           0 :         const struct smb_filename *smb_fname = NULL;
    2418             : 
    2419           0 :         smb_fname = fsp->fsp_name;
    2420             : 
    2421           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(),
    2422             :                                         handle,
    2423             :                                         smb_fname,
    2424             :                                         &timestamp,
    2425             :                                         NULL)) {
    2426           0 :                 return -1;
    2427             :         }
    2428           0 :         if (timestamp != 0) {
    2429           0 :                 errno = EROFS;
    2430           0 :                 return -1;
    2431             :         }
    2432           0 :         return SMB_VFS_NEXT_FSETXATTR(handle, fsp,
    2433             :                                 aname, value, size, flags);
    2434             : }
    2435             : 
    2436           0 : static int snapper_gmt_get_real_filename(struct vfs_handle_struct *handle,
    2437             :                                          const struct smb_filename *fpath,
    2438             :                                          const char *name,
    2439             :                                          TALLOC_CTX *mem_ctx,
    2440             :                                          char **found_name)
    2441             : {
    2442             :         time_t timestamp;
    2443             :         char *stripped;
    2444             :         ssize_t ret;
    2445             :         int saved_errno;
    2446             :         char *conv;
    2447             :         struct smb_filename conv_fname;
    2448             : 
    2449           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(), handle, fpath,
    2450             :                                         &timestamp, &stripped)) {
    2451           0 :                 return -1;
    2452             :         }
    2453           0 :         if (timestamp == 0) {
    2454           0 :                 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, fpath, name,
    2455             :                                                       mem_ctx, found_name);
    2456             :         }
    2457           0 :         if (stripped[0] == '\0') {
    2458           0 :                 *found_name = talloc_strdup(mem_ctx, name);
    2459           0 :                 if (*found_name == NULL) {
    2460           0 :                         errno = ENOMEM;
    2461           0 :                         return -1;
    2462             :                 }
    2463           0 :                 return 0;
    2464             :         }
    2465           0 :         conv = snapper_gmt_convert(talloc_tos(), handle, stripped, timestamp);
    2466           0 :         TALLOC_FREE(stripped);
    2467           0 :         if (conv == NULL) {
    2468           0 :                 return -1;
    2469             :         }
    2470             : 
    2471           0 :         conv_fname = (struct smb_filename) {
    2472             :                 .base_name = conv,
    2473             :         };
    2474             : 
    2475           0 :         ret = SMB_VFS_NEXT_GET_REAL_FILENAME(handle, &conv_fname, name,
    2476             :                                              mem_ctx, found_name);
    2477           0 :         saved_errno = errno;
    2478           0 :         TALLOC_FREE(conv);
    2479           0 :         errno = saved_errno;
    2480           0 :         return ret;
    2481             : }
    2482             : 
    2483           0 : static uint64_t snapper_gmt_disk_free(vfs_handle_struct *handle,
    2484             :                                 const struct smb_filename *smb_fname,
    2485             :                                 uint64_t *bsize,
    2486             :                                 uint64_t *dfree,
    2487             :                                 uint64_t *dsize)
    2488             : {
    2489           0 :         time_t timestamp = 0;
    2490           0 :         char *stripped = NULL;
    2491             :         uint64_t ret;
    2492           0 :         int saved_errno = 0;
    2493           0 :         char *conv = NULL;
    2494           0 :         struct smb_filename *conv_smb_fname = NULL;
    2495             : 
    2496           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
    2497             :                         smb_fname, &timestamp, &stripped)) {
    2498           0 :                 return (uint64_t)-1;
    2499             :         }
    2500           0 :         if (timestamp == 0) {
    2501           0 :                 return SMB_VFS_NEXT_DISK_FREE(handle, smb_fname,
    2502             :                                               bsize, dfree, dsize);
    2503             :         }
    2504             : 
    2505           0 :         conv = snapper_gmt_convert(talloc_tos(), handle, stripped, timestamp);
    2506           0 :         TALLOC_FREE(stripped);
    2507           0 :         if (conv == NULL) {
    2508           0 :                 return (uint64_t)-1;
    2509             :         }
    2510           0 :         conv_smb_fname = synthetic_smb_fname(talloc_tos(),
    2511             :                                         conv,
    2512             :                                         NULL,
    2513             :                                         NULL,
    2514             :                                         0,
    2515             :                                         smb_fname->flags);
    2516           0 :         if (conv_smb_fname == NULL) {
    2517           0 :                 TALLOC_FREE(conv);
    2518           0 :                 errno = ENOMEM;
    2519           0 :                 return (uint64_t)-1;
    2520             :         }
    2521             : 
    2522           0 :         ret = SMB_VFS_NEXT_DISK_FREE(handle, conv_smb_fname,
    2523             :                                 bsize, dfree, dsize);
    2524             : 
    2525           0 :         if (ret == (uint64_t)-1) {
    2526           0 :                 saved_errno = errno;
    2527             :         }
    2528           0 :         TALLOC_FREE(conv_smb_fname);
    2529           0 :         if (saved_errno != 0) {
    2530           0 :                 errno = saved_errno;
    2531             :         }
    2532           0 :         return ret;
    2533             : }
    2534             : 
    2535           0 : static int snapper_gmt_get_quota(vfs_handle_struct *handle,
    2536             :                         const struct smb_filename *smb_fname,
    2537             :                         enum SMB_QUOTA_TYPE qtype,
    2538             :                         unid_t id,
    2539             :                         SMB_DISK_QUOTA *dq)
    2540             : {
    2541           0 :         time_t timestamp = 0;
    2542           0 :         char *stripped = NULL;
    2543             :         int ret;
    2544           0 :         int saved_errno = 0;
    2545           0 :         char *conv = NULL;
    2546           0 :         struct smb_filename *conv_smb_fname = NULL;
    2547             : 
    2548           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
    2549             :                                 smb_fname, &timestamp, &stripped)) {
    2550           0 :                 return -1;
    2551             :         }
    2552           0 :         if (timestamp == 0) {
    2553           0 :                 return SMB_VFS_NEXT_GET_QUOTA(handle, smb_fname, qtype, id, dq);
    2554             :         }
    2555             : 
    2556           0 :         conv = snapper_gmt_convert(talloc_tos(), handle, stripped, timestamp);
    2557           0 :         TALLOC_FREE(stripped);
    2558           0 :         if (conv == NULL) {
    2559           0 :                 return -1;
    2560             :         }
    2561           0 :         conv_smb_fname = synthetic_smb_fname(talloc_tos(),
    2562             :                                         conv,
    2563             :                                         NULL,
    2564             :                                         NULL,
    2565             :                                         0,
    2566             :                                         smb_fname->flags);
    2567           0 :         TALLOC_FREE(conv);
    2568           0 :         if (conv_smb_fname == NULL) {
    2569           0 :                 errno = ENOMEM;
    2570           0 :                 return -1;
    2571             :         }
    2572             : 
    2573           0 :         ret = SMB_VFS_NEXT_GET_QUOTA(handle, conv_smb_fname, qtype, id, dq);
    2574             : 
    2575           0 :         if (ret == -1) {
    2576           0 :                 saved_errno = errno;
    2577             :         }
    2578           0 :         TALLOC_FREE(conv_smb_fname);
    2579           0 :         if (saved_errno != 0) {
    2580           0 :                 errno = saved_errno;
    2581             :         }
    2582           0 :         return ret;
    2583             : }
    2584             : 
    2585           0 : static NTSTATUS snapper_create_dfs_pathat(struct vfs_handle_struct *handle,
    2586             :                                 struct files_struct *dirfsp,
    2587             :                                 const struct smb_filename *smb_fname,
    2588             :                                 const struct referral *reflist,
    2589             :                                 size_t referral_count)
    2590             : {
    2591           0 :         time_t timestamp = 0;
    2592             : 
    2593           0 :         if (!snapper_gmt_strip_snapshot(talloc_tos(),
    2594             :                                         handle,
    2595             :                                         smb_fname,
    2596             :                                         &timestamp,
    2597             :                                         NULL)) {
    2598           0 :                 return NT_STATUS_NO_MEMORY;
    2599             :         }
    2600           0 :         if (timestamp != 0) {
    2601           0 :                 return NT_STATUS_MEDIA_WRITE_PROTECTED;
    2602             :         }
    2603           0 :         return SMB_VFS_NEXT_CREATE_DFS_PATHAT(handle,
    2604             :                         dirfsp,
    2605             :                         smb_fname,
    2606             :                         reflist,
    2607             :                         referral_count);
    2608             : }
    2609             : 
    2610             : static struct vfs_fn_pointers snapper_fns = {
    2611             :         .snap_check_path_fn = snapper_snap_check_path,
    2612             :         .snap_create_fn = snapper_snap_create,
    2613             :         .snap_delete_fn = snapper_snap_delete,
    2614             :         .get_shadow_copy_data_fn = snapper_get_shadow_copy_data,
    2615             :         .create_dfs_pathat_fn = snapper_create_dfs_pathat,
    2616             :         .disk_free_fn = snapper_gmt_disk_free,
    2617             :         .get_quota_fn = snapper_gmt_get_quota,
    2618             :         .renameat_fn = snapper_gmt_renameat,
    2619             :         .linkat_fn = snapper_gmt_linkat,
    2620             :         .symlinkat_fn = snapper_gmt_symlinkat,
    2621             :         .stat_fn = snapper_gmt_stat,
    2622             :         .lstat_fn = snapper_gmt_lstat,
    2623             :         .openat_fn = snapper_gmt_openat,
    2624             :         .unlinkat_fn = snapper_gmt_unlinkat,
    2625             :         .fchmod_fn = snapper_gmt_fchmod,
    2626             :         .chdir_fn = snapper_gmt_chdir,
    2627             :         .fntimes_fn = snapper_gmt_fntimes,
    2628             :         .readlinkat_fn = snapper_gmt_readlinkat,
    2629             :         .mknodat_fn = snapper_gmt_mknodat,
    2630             :         .realpath_fn = snapper_gmt_realpath,
    2631             :         .mkdirat_fn = snapper_gmt_mkdirat,
    2632             :         .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
    2633             :         .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
    2634             :         .fsetxattr_fn = snapper_gmt_fsetxattr,
    2635             :         .fchflags_fn = snapper_gmt_fchflags,
    2636             :         .get_real_filename_fn = snapper_gmt_get_real_filename,
    2637             : };
    2638             : 
    2639             : static_decl_vfs;
    2640          20 : NTSTATUS vfs_snapper_init(TALLOC_CTX *ctx)
    2641             : {
    2642          20 :         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
    2643             :                                 "snapper", &snapper_fns);
    2644             : }

Generated by: LCOV version 1.13