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