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 0 : 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 0 : != 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 0 : != 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 0 : != 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 0 : 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 descending 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 : ×tamp_src, NULL)) {
1915 0 : return -1;
1916 : }
1917 0 : if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
1918 : smb_fname_dst,
1919 : ×tamp_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 : ×tamp_old,
1949 : NULL)) {
1950 0 : return -1;
1951 : }
1952 0 : if (!snapper_gmt_strip_snapshot(talloc_tos(),
1953 : handle,
1954 : new_smb_fname,
1955 : ×tamp_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 : ×tamp_old,
1983 : NULL)) {
1984 0 : return -1;
1985 : }
1986 0 : if (!snapper_gmt_strip_snapshot(talloc_tos(),
1987 : handle,
1988 : new_smb_fname,
1989 : ×tamp_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 : ×tamp, &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 : ×tamp, &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 : const struct vfs_open_how *how)
2082 : {
2083 0 : struct smb_filename *smb_fname = NULL;
2084 : time_t timestamp;
2085 0 : char *stripped = NULL;
2086 : int ret;
2087 0 : int saved_errno = 0;
2088 :
2089 0 : if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
2090 : smb_fname_in,
2091 : ×tamp, &stripped)) {
2092 0 : return -1;
2093 : }
2094 0 : if (timestamp == 0) {
2095 0 : return SMB_VFS_NEXT_OPENAT(handle,
2096 : dirfsp,
2097 : smb_fname_in,
2098 : fsp,
2099 : how);
2100 : }
2101 :
2102 0 : smb_fname = cp_smb_filename(talloc_tos(), smb_fname_in);
2103 0 : if (smb_fname == NULL) {
2104 0 : TALLOC_FREE(stripped);
2105 0 : return -1;
2106 : }
2107 :
2108 0 : smb_fname->base_name = snapper_gmt_convert(smb_fname, handle,
2109 : stripped, timestamp);
2110 0 : TALLOC_FREE(stripped);
2111 :
2112 0 : if (smb_fname->base_name == NULL) {
2113 0 : TALLOC_FREE(smb_fname);
2114 0 : errno = ENOMEM;
2115 0 : return -1;
2116 : }
2117 :
2118 0 : ret = SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname, fsp, how);
2119 0 : if (ret == -1) {
2120 0 : saved_errno = errno;
2121 : }
2122 0 : TALLOC_FREE(smb_fname);
2123 0 : if (saved_errno != 0) {
2124 0 : errno = saved_errno;
2125 : }
2126 0 : return ret;
2127 : }
2128 :
2129 0 : static int snapper_gmt_unlinkat(vfs_handle_struct *handle,
2130 : struct files_struct *dirfsp,
2131 : const struct smb_filename *smb_fname,
2132 : int flags)
2133 : {
2134 0 : time_t timestamp = 0;
2135 :
2136 0 : if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
2137 : smb_fname,
2138 : ×tamp, NULL)) {
2139 0 : return -1;
2140 : }
2141 0 : if (timestamp != 0) {
2142 0 : errno = EROFS;
2143 0 : return -1;
2144 : }
2145 0 : return SMB_VFS_NEXT_UNLINKAT(handle,
2146 : dirfsp,
2147 : smb_fname,
2148 : flags);
2149 : }
2150 :
2151 0 : static int snapper_gmt_fchmod(vfs_handle_struct *handle,
2152 : struct files_struct *fsp,
2153 : mode_t mode)
2154 : {
2155 0 : time_t timestamp = 0;
2156 0 : const struct smb_filename *smb_fname = NULL;
2157 :
2158 0 : smb_fname = fsp->fsp_name;
2159 :
2160 0 : if (!snapper_gmt_strip_snapshot(talloc_tos(),
2161 : handle,
2162 : smb_fname,
2163 : ×tamp,
2164 : NULL)) {
2165 0 : return -1;
2166 : }
2167 :
2168 0 : if (timestamp != 0) {
2169 0 : errno = EROFS;
2170 0 : return -1;
2171 : }
2172 0 : return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
2173 : }
2174 :
2175 0 : static int snapper_gmt_chdir(vfs_handle_struct *handle,
2176 : const struct smb_filename *smb_fname)
2177 : {
2178 0 : time_t timestamp = 0;
2179 0 : char *stripped = NULL;
2180 : int ret;
2181 0 : int saved_errno = 0;
2182 0 : char *conv = NULL;
2183 0 : struct smb_filename *conv_smb_fname = NULL;
2184 :
2185 0 : if (!snapper_gmt_strip_snapshot(talloc_tos(),
2186 : handle,
2187 : smb_fname,
2188 : ×tamp,
2189 : &stripped)) {
2190 0 : return -1;
2191 : }
2192 0 : if (timestamp == 0) {
2193 0 : return SMB_VFS_NEXT_CHDIR(handle, smb_fname);
2194 : }
2195 0 : conv = snapper_gmt_convert(talloc_tos(), handle, stripped, timestamp);
2196 0 : TALLOC_FREE(stripped);
2197 0 : if (conv == NULL) {
2198 0 : return -1;
2199 : }
2200 0 : conv_smb_fname = synthetic_smb_fname(talloc_tos(),
2201 : conv,
2202 : NULL,
2203 : NULL,
2204 : 0,
2205 0 : smb_fname->flags);
2206 0 : if (conv_smb_fname == NULL) {
2207 0 : TALLOC_FREE(conv);
2208 0 : errno = ENOMEM;
2209 0 : return -1;
2210 : }
2211 0 : ret = SMB_VFS_NEXT_CHDIR(handle, conv_smb_fname);
2212 0 : if (ret == -1) {
2213 0 : saved_errno = errno;
2214 : }
2215 0 : TALLOC_FREE(conv);
2216 0 : TALLOC_FREE(conv_smb_fname);
2217 0 : if (saved_errno != 0) {
2218 0 : errno = saved_errno;
2219 : }
2220 0 : return ret;
2221 : }
2222 :
2223 0 : static int snapper_gmt_fntimes(vfs_handle_struct *handle,
2224 : files_struct *fsp,
2225 : struct smb_file_time *ft)
2226 : {
2227 0 : time_t timestamp = 0;
2228 :
2229 0 : if (!snapper_gmt_strip_snapshot(talloc_tos(),
2230 : handle,
2231 0 : fsp->fsp_name,
2232 : ×tamp,
2233 : NULL)) {
2234 0 : return -1;
2235 : }
2236 :
2237 0 : if (timestamp != 0) {
2238 0 : errno = EROFS;
2239 0 : return -1;
2240 : }
2241 :
2242 0 : return SMB_VFS_NEXT_FNTIMES(handle, fsp, ft);
2243 : }
2244 :
2245 0 : static int snapper_gmt_readlinkat(vfs_handle_struct *handle,
2246 : const struct files_struct *dirfsp,
2247 : const struct smb_filename *smb_fname,
2248 : char *buf,
2249 : size_t bufsiz)
2250 : {
2251 0 : time_t timestamp = 0;
2252 : int ret;
2253 0 : int saved_errno = 0;
2254 0 : struct smb_filename *full_fname = NULL;
2255 :
2256 : /*
2257 : * Now this function only looks at smb_fname->twrp
2258 : * we don't need to copy out the path. Just use
2259 : * smb_fname->base_name directly.
2260 : */
2261 0 : if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
2262 : smb_fname,
2263 : ×tamp, NULL)) {
2264 0 : return -1;
2265 : }
2266 0 : if (timestamp == 0) {
2267 0 : return SMB_VFS_NEXT_READLINKAT(handle,
2268 : dirfsp,
2269 : smb_fname,
2270 : buf,
2271 : bufsiz);
2272 : }
2273 0 : full_fname = full_path_from_dirfsp_atname(talloc_tos(),
2274 : dirfsp,
2275 : smb_fname);
2276 0 : if (full_fname == NULL) {
2277 0 : return -1;
2278 : }
2279 :
2280 : /* Find the snapshot path from the full pathname. */
2281 0 : full_fname->base_name = snapper_gmt_convert(full_fname,
2282 : handle,
2283 0 : full_fname->base_name,
2284 : timestamp);
2285 0 : if (full_fname->base_name == NULL) {
2286 0 : TALLOC_FREE(full_fname);
2287 0 : return -1;
2288 : }
2289 0 : ret = SMB_VFS_NEXT_READLINKAT(handle,
2290 : handle->conn->cwd_fsp,
2291 : full_fname,
2292 : buf,
2293 : bufsiz);
2294 0 : if (ret == -1) {
2295 0 : saved_errno = errno;
2296 : }
2297 0 : TALLOC_FREE(full_fname);
2298 0 : if (saved_errno != 0) {
2299 0 : errno = saved_errno;
2300 : }
2301 0 : return ret;
2302 : }
2303 :
2304 0 : static int snapper_gmt_mknodat(vfs_handle_struct *handle,
2305 : files_struct *dirfsp,
2306 : const struct smb_filename *smb_fname,
2307 : mode_t mode,
2308 : SMB_DEV_T dev)
2309 : {
2310 0 : time_t timestamp = (time_t)0;
2311 :
2312 0 : if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
2313 : smb_fname,
2314 : ×tamp, NULL)) {
2315 0 : return -1;
2316 : }
2317 0 : if (timestamp != 0) {
2318 0 : errno = EROFS;
2319 0 : return -1;
2320 : }
2321 0 : return SMB_VFS_NEXT_MKNODAT(handle,
2322 : dirfsp,
2323 : smb_fname,
2324 : mode,
2325 : dev);
2326 : }
2327 :
2328 0 : static struct smb_filename *snapper_gmt_realpath(vfs_handle_struct *handle,
2329 : TALLOC_CTX *ctx,
2330 : const struct smb_filename *smb_fname)
2331 : {
2332 0 : time_t timestamp = 0;
2333 0 : char *stripped = NULL;
2334 0 : struct smb_filename *result_fname = NULL;
2335 0 : struct smb_filename *conv_smb_fname = NULL;
2336 0 : int saved_errno = 0;
2337 :
2338 0 : if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
2339 : smb_fname,
2340 : ×tamp, &stripped)) {
2341 0 : goto done;
2342 : }
2343 0 : if (timestamp == 0) {
2344 0 : return SMB_VFS_NEXT_REALPATH(handle, ctx, smb_fname);
2345 : }
2346 :
2347 0 : conv_smb_fname = cp_smb_filename(talloc_tos(), smb_fname);
2348 0 : if (conv_smb_fname == NULL) {
2349 0 : goto done;
2350 : }
2351 0 : conv_smb_fname->base_name = snapper_gmt_convert(conv_smb_fname, handle,
2352 : stripped, timestamp);
2353 0 : if (conv_smb_fname->base_name == NULL) {
2354 0 : goto done;
2355 : }
2356 :
2357 0 : result_fname = SMB_VFS_NEXT_REALPATH(handle, ctx, conv_smb_fname);
2358 :
2359 0 : done:
2360 0 : if (result_fname == NULL) {
2361 0 : saved_errno = errno;
2362 : }
2363 0 : TALLOC_FREE(conv_smb_fname);
2364 0 : TALLOC_FREE(stripped);
2365 0 : if (saved_errno != 0) {
2366 0 : errno = saved_errno;
2367 : }
2368 0 : return result_fname;
2369 : }
2370 :
2371 0 : static int snapper_gmt_mkdirat(vfs_handle_struct *handle,
2372 : struct files_struct *dirfsp,
2373 : const struct smb_filename *fname,
2374 : mode_t mode)
2375 : {
2376 0 : time_t timestamp = 0;
2377 :
2378 0 : if (!snapper_gmt_strip_snapshot(talloc_tos(), handle, fname,
2379 : ×tamp, NULL)) {
2380 0 : return -1;
2381 : }
2382 0 : if (timestamp != 0) {
2383 0 : errno = EROFS;
2384 0 : return -1;
2385 : }
2386 0 : return SMB_VFS_NEXT_MKDIRAT(handle,
2387 : dirfsp,
2388 : fname,
2389 : mode);
2390 : }
2391 :
2392 0 : static int snapper_gmt_fchflags(vfs_handle_struct *handle,
2393 : struct files_struct *fsp,
2394 : unsigned int flags)
2395 : {
2396 0 : time_t timestamp = 0;
2397 :
2398 0 : if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
2399 0 : fsp->fsp_name, ×tamp, NULL)) {
2400 0 : return -1;
2401 : }
2402 0 : if (timestamp != 0) {
2403 0 : errno = EROFS;
2404 0 : return -1;
2405 : }
2406 0 : return SMB_VFS_NEXT_FCHFLAGS(handle, fsp, flags);
2407 : }
2408 :
2409 0 : static int snapper_gmt_fsetxattr(struct vfs_handle_struct *handle,
2410 : struct files_struct *fsp,
2411 : const char *aname, const void *value,
2412 : size_t size, int flags)
2413 : {
2414 0 : time_t timestamp = 0;
2415 0 : const struct smb_filename *smb_fname = NULL;
2416 :
2417 0 : smb_fname = fsp->fsp_name;
2418 :
2419 0 : if (!snapper_gmt_strip_snapshot(talloc_tos(),
2420 : handle,
2421 : smb_fname,
2422 : ×tamp,
2423 : NULL)) {
2424 0 : return -1;
2425 : }
2426 0 : if (timestamp != 0) {
2427 0 : errno = EROFS;
2428 0 : return -1;
2429 : }
2430 0 : return SMB_VFS_NEXT_FSETXATTR(handle, fsp,
2431 : aname, value, size, flags);
2432 : }
2433 :
2434 0 : static NTSTATUS snapper_gmt_get_real_filename_at(
2435 : struct vfs_handle_struct *handle,
2436 : struct files_struct *dirfsp,
2437 : const char *name,
2438 : TALLOC_CTX *mem_ctx,
2439 : char **found_name)
2440 : {
2441 : time_t timestamp;
2442 : char *stripped;
2443 : char *conv;
2444 0 : struct smb_filename *conv_fname = NULL;
2445 : NTSTATUS status;
2446 : bool ok;
2447 :
2448 0 : ok = snapper_gmt_strip_snapshot(
2449 0 : talloc_tos(), handle, dirfsp->fsp_name,×tamp, &stripped);
2450 0 : if (!ok) {
2451 0 : return NT_STATUS_NO_MEMORY;
2452 : }
2453 0 : if (timestamp == 0) {
2454 0 : return SMB_VFS_NEXT_GET_REAL_FILENAME_AT(
2455 : handle, dirfsp, name, 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 : return NT_STATUS_NO_MEMORY;
2461 : }
2462 0 : return NT_STATUS_OK;
2463 : }
2464 0 : conv = snapper_gmt_convert(talloc_tos(), handle, stripped, timestamp);
2465 0 : TALLOC_FREE(stripped);
2466 0 : if (conv == NULL) {
2467 0 : return map_nt_error_from_unix(errno);
2468 : }
2469 :
2470 0 : status = synthetic_pathref(
2471 : talloc_tos(),
2472 0 : dirfsp->conn->cwd_fsp,
2473 : conv,
2474 : NULL,
2475 : NULL,
2476 : 0,
2477 : 0,
2478 : &conv_fname);
2479 :
2480 0 : status = SMB_VFS_NEXT_GET_REAL_FILENAME_AT(
2481 : handle, conv_fname->fsp, name, mem_ctx, found_name);
2482 0 : TALLOC_FREE(conv);
2483 0 : return status;
2484 : }
2485 :
2486 0 : static uint64_t snapper_gmt_disk_free(vfs_handle_struct *handle,
2487 : const struct smb_filename *smb_fname,
2488 : uint64_t *bsize,
2489 : uint64_t *dfree,
2490 : uint64_t *dsize)
2491 : {
2492 0 : time_t timestamp = 0;
2493 0 : char *stripped = NULL;
2494 : uint64_t ret;
2495 0 : int saved_errno = 0;
2496 0 : char *conv = NULL;
2497 0 : struct smb_filename *conv_smb_fname = NULL;
2498 :
2499 0 : if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
2500 : smb_fname, ×tamp, &stripped)) {
2501 0 : return (uint64_t)-1;
2502 : }
2503 0 : if (timestamp == 0) {
2504 0 : return SMB_VFS_NEXT_DISK_FREE(handle, smb_fname,
2505 : bsize, dfree, dsize);
2506 : }
2507 :
2508 0 : conv = snapper_gmt_convert(talloc_tos(), handle, stripped, timestamp);
2509 0 : TALLOC_FREE(stripped);
2510 0 : if (conv == NULL) {
2511 0 : return (uint64_t)-1;
2512 : }
2513 0 : conv_smb_fname = synthetic_smb_fname(talloc_tos(),
2514 : conv,
2515 : NULL,
2516 : NULL,
2517 : 0,
2518 0 : smb_fname->flags);
2519 0 : if (conv_smb_fname == NULL) {
2520 0 : TALLOC_FREE(conv);
2521 0 : errno = ENOMEM;
2522 0 : return (uint64_t)-1;
2523 : }
2524 :
2525 0 : ret = SMB_VFS_NEXT_DISK_FREE(handle, conv_smb_fname,
2526 : bsize, dfree, dsize);
2527 :
2528 0 : if (ret == (uint64_t)-1) {
2529 0 : saved_errno = errno;
2530 : }
2531 0 : TALLOC_FREE(conv_smb_fname);
2532 0 : if (saved_errno != 0) {
2533 0 : errno = saved_errno;
2534 : }
2535 0 : return ret;
2536 : }
2537 :
2538 0 : static int snapper_gmt_get_quota(vfs_handle_struct *handle,
2539 : const struct smb_filename *smb_fname,
2540 : enum SMB_QUOTA_TYPE qtype,
2541 : unid_t id,
2542 : SMB_DISK_QUOTA *dq)
2543 : {
2544 0 : time_t timestamp = 0;
2545 0 : char *stripped = NULL;
2546 : int ret;
2547 0 : int saved_errno = 0;
2548 0 : char *conv = NULL;
2549 0 : struct smb_filename *conv_smb_fname = NULL;
2550 :
2551 0 : if (!snapper_gmt_strip_snapshot(talloc_tos(), handle,
2552 : smb_fname, ×tamp, &stripped)) {
2553 0 : return -1;
2554 : }
2555 0 : if (timestamp == 0) {
2556 0 : return SMB_VFS_NEXT_GET_QUOTA(handle, smb_fname, qtype, id, dq);
2557 : }
2558 :
2559 0 : conv = snapper_gmt_convert(talloc_tos(), handle, stripped, timestamp);
2560 0 : TALLOC_FREE(stripped);
2561 0 : if (conv == NULL) {
2562 0 : return -1;
2563 : }
2564 0 : conv_smb_fname = synthetic_smb_fname(talloc_tos(),
2565 : conv,
2566 : NULL,
2567 : NULL,
2568 : 0,
2569 0 : smb_fname->flags);
2570 0 : TALLOC_FREE(conv);
2571 0 : if (conv_smb_fname == NULL) {
2572 0 : errno = ENOMEM;
2573 0 : return -1;
2574 : }
2575 :
2576 0 : ret = SMB_VFS_NEXT_GET_QUOTA(handle, conv_smb_fname, qtype, id, dq);
2577 :
2578 0 : if (ret == -1) {
2579 0 : saved_errno = errno;
2580 : }
2581 0 : TALLOC_FREE(conv_smb_fname);
2582 0 : if (saved_errno != 0) {
2583 0 : errno = saved_errno;
2584 : }
2585 0 : return ret;
2586 : }
2587 :
2588 0 : static NTSTATUS snapper_create_dfs_pathat(struct vfs_handle_struct *handle,
2589 : struct files_struct *dirfsp,
2590 : const struct smb_filename *smb_fname,
2591 : const struct referral *reflist,
2592 : size_t referral_count)
2593 : {
2594 0 : time_t timestamp = 0;
2595 :
2596 0 : if (!snapper_gmt_strip_snapshot(talloc_tos(),
2597 : handle,
2598 : smb_fname,
2599 : ×tamp,
2600 : NULL)) {
2601 0 : return NT_STATUS_NO_MEMORY;
2602 : }
2603 0 : if (timestamp != 0) {
2604 0 : return NT_STATUS_MEDIA_WRITE_PROTECTED;
2605 : }
2606 0 : return SMB_VFS_NEXT_CREATE_DFS_PATHAT(handle,
2607 : dirfsp,
2608 : smb_fname,
2609 : reflist,
2610 : referral_count);
2611 : }
2612 :
2613 : static struct vfs_fn_pointers snapper_fns = {
2614 : .snap_check_path_fn = snapper_snap_check_path,
2615 : .snap_create_fn = snapper_snap_create,
2616 : .snap_delete_fn = snapper_snap_delete,
2617 : .get_shadow_copy_data_fn = snapper_get_shadow_copy_data,
2618 : .create_dfs_pathat_fn = snapper_create_dfs_pathat,
2619 : .disk_free_fn = snapper_gmt_disk_free,
2620 : .get_quota_fn = snapper_gmt_get_quota,
2621 : .renameat_fn = snapper_gmt_renameat,
2622 : .linkat_fn = snapper_gmt_linkat,
2623 : .symlinkat_fn = snapper_gmt_symlinkat,
2624 : .stat_fn = snapper_gmt_stat,
2625 : .lstat_fn = snapper_gmt_lstat,
2626 : .openat_fn = snapper_gmt_openat,
2627 : .unlinkat_fn = snapper_gmt_unlinkat,
2628 : .fchmod_fn = snapper_gmt_fchmod,
2629 : .chdir_fn = snapper_gmt_chdir,
2630 : .fntimes_fn = snapper_gmt_fntimes,
2631 : .readlinkat_fn = snapper_gmt_readlinkat,
2632 : .mknodat_fn = snapper_gmt_mknodat,
2633 : .realpath_fn = snapper_gmt_realpath,
2634 : .mkdirat_fn = snapper_gmt_mkdirat,
2635 : .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
2636 : .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
2637 : .fsetxattr_fn = snapper_gmt_fsetxattr,
2638 : .fchflags_fn = snapper_gmt_fchflags,
2639 : .get_real_filename_at_fn = snapper_gmt_get_real_filename_at,
2640 : };
2641 :
2642 : static_decl_vfs;
2643 27 : NTSTATUS vfs_snapper_init(TALLOC_CTX *ctx)
2644 : {
2645 27 : return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2646 : "snapper", &snapper_fns);
2647 : }
|