btrfs-progs: send-stream: check number of read bytes from stream
[platform/upstream/btrfs-progs.git] / send-stream.c
1 /*
2  * Copyright (C) 2012 Alexander Block.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public
6  * License v2 as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public
14  * License along with this program; if not, write to the
15  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16  * Boston, MA 021110-1307, USA.
17  */
18
19 #include <uuid/uuid.h>
20 #include <unistd.h>
21
22 #include "send.h"
23 #include "send-stream.h"
24 #include "crc32c.h"
25 #include "utils.h"
26
27 struct btrfs_send_stream {
28         int fd;
29         char read_buf[BTRFS_SEND_BUF_SIZE];
30
31         int cmd;
32         struct btrfs_cmd_header *cmd_hdr;
33         struct btrfs_tlv_header *cmd_attrs[BTRFS_SEND_A_MAX + 1];
34         u32 version;
35
36         struct btrfs_send_ops *ops;
37         void *user;
38 };
39
40 /*
41  * Read len bytes to buf.
42  * Return:
43  *   0 - success
44  * < 0 - negative errno in case of error
45  * > 0 - no data read, EOF
46  */
47 static int read_buf(struct btrfs_send_stream *sctx, char *buf, size_t len)
48 {
49         int ret;
50         size_t pos = 0;
51
52         while (pos < len) {
53                 ssize_t rbytes;
54
55                 rbytes = read(sctx->fd, buf + pos, len - pos);
56                 if (rbytes < 0) {
57                         ret = -errno;
58                         error("read from stream failed: %s",
59                                         strerror(-ret));
60                         goto out;
61                 }
62                 if (rbytes == 0) {
63                         ret = 1;
64                         goto out_eof;
65                 }
66                 pos += rbytes;
67         }
68         ret = 0;
69
70 out_eof:
71         if (pos < len) {
72                 error("short read from stream: expected %zu read %zu", len, pos);
73                 ret = -EIO;
74         }
75
76 out:
77         return ret;
78 }
79
80 /*
81  * Reads a single command from kernel space and decodes the TLV's into
82  * sctx->cmd_attrs
83  *
84  * Returns:
85  *   0 - success
86  * < 0 - an error in the command
87  */
88 static int read_cmd(struct btrfs_send_stream *sctx)
89 {
90         int ret;
91         u16 cmd;
92         u32 cmd_len;
93         char *data;
94         u32 pos;
95         u32 crc;
96         u32 crc2;
97
98         memset(sctx->cmd_attrs, 0, sizeof(sctx->cmd_attrs));
99
100         ASSERT(sizeof(*sctx->cmd_hdr) <= sizeof(sctx->read_buf));
101         ret = read_buf(sctx, sctx->read_buf, sizeof(*sctx->cmd_hdr));
102         if (ret < 0)
103                 goto out;
104         if (ret) {
105                 ret = -EINVAL;
106                 error("unexpected EOF in stream");
107                 goto out;
108         }
109
110         sctx->cmd_hdr = (struct btrfs_cmd_header *)sctx->read_buf;
111         cmd = le16_to_cpu(sctx->cmd_hdr->cmd);
112         cmd_len = le32_to_cpu(sctx->cmd_hdr->len);
113
114         if (cmd_len + sizeof(*sctx->cmd_hdr) >= sizeof(sctx->read_buf)) {
115                 ret = -EINVAL;
116                 error("command length %u too big for buffer %zu",
117                                 cmd_len, sizeof(sctx->read_buf));
118                 goto out;
119         }
120
121         data = sctx->read_buf + sizeof(*sctx->cmd_hdr);
122         ret = read_buf(sctx, data, cmd_len);
123         if (ret < 0)
124                 goto out;
125         if (ret) {
126                 ret = -EINVAL;
127                 error("unexpected EOF in stream");
128                 goto out;
129         }
130
131         crc = le32_to_cpu(sctx->cmd_hdr->crc);
132         sctx->cmd_hdr->crc = 0;
133
134         crc2 = crc32c(0, (unsigned char*)sctx->read_buf,
135                         sizeof(*sctx->cmd_hdr) + cmd_len);
136
137         if (crc != crc2) {
138                 ret = -EINVAL;
139                 error("crc32 mismatch in command");
140                 goto out;
141         }
142
143         pos = 0;
144         while (pos < cmd_len) {
145                 struct btrfs_tlv_header *tlv_hdr;
146                 u16 tlv_type;
147                 u16 tlv_len;
148
149                 tlv_hdr = (struct btrfs_tlv_header *)data;
150                 tlv_type = le16_to_cpu(tlv_hdr->tlv_type);
151                 tlv_len = le16_to_cpu(tlv_hdr->tlv_len);
152
153                 if (tlv_type == 0 || tlv_type > BTRFS_SEND_A_MAX
154                     || tlv_len > BTRFS_SEND_BUF_SIZE) {
155                         error("invalid tlv in cmd tlv_type = %hu, tlv_len = %hu",
156                                         tlv_type, tlv_len);
157                         ret = -EINVAL;
158                         goto out;
159                 }
160
161                 sctx->cmd_attrs[tlv_type] = tlv_hdr;
162
163                 data += sizeof(*tlv_hdr) + tlv_len;
164                 pos += sizeof(*tlv_hdr) + tlv_len;
165         }
166
167         sctx->cmd = cmd;
168         ret = 0;
169
170 out:
171         return ret;
172 }
173
174 static int tlv_get(struct btrfs_send_stream *sctx, int attr, void **data, int *len)
175 {
176         int ret;
177         struct btrfs_tlv_header *hdr;
178
179         if (attr <= 0 || attr > BTRFS_SEND_A_MAX) {
180                 error("invalid attribute requested, attr = %d", attr);
181                 ret = -EINVAL;
182                 goto out;
183         }
184
185         hdr = sctx->cmd_attrs[attr];
186         if (!hdr) {
187                 error("attribute %d requested but not present", attr);
188                 ret = -ENOENT;
189                 goto out;
190         }
191
192         *len = le16_to_cpu(hdr->tlv_len);
193         *data = hdr + 1;
194
195         ret = 0;
196
197 out:
198         return ret;
199 }
200
201 #define __TLV_GOTO_FAIL(expr) \
202         if ((ret = expr) < 0) \
203                 goto tlv_get_failed;
204
205 #define __TLV_DO_WHILE_GOTO_FAIL(expr) \
206         do { \
207                 __TLV_GOTO_FAIL(expr) \
208         } while (0)
209
210
211 #define TLV_GET(s, attr, data, len) \
212         __TLV_DO_WHILE_GOTO_FAIL(tlv_get(s, attr, data, len))
213
214 #define TLV_CHECK_LEN(expected, got) \
215         do { \
216                 if (expected != got) { \
217                         error("invalid size for attribute, " \
218                                         "expected = %d, got = %d", \
219                                         (int)expected, (int)got); \
220                         ret = -EINVAL; \
221                         goto tlv_get_failed; \
222                 } \
223         } while (0)
224
225 #define TLV_GET_INT(s, attr, bits, v) \
226         do { \
227                 __le##bits *__tmp; \
228                 int __len; \
229                 TLV_GET(s, attr, (void**)&__tmp, &__len); \
230                 TLV_CHECK_LEN(sizeof(*__tmp), __len); \
231                 *v = get_unaligned_le##bits(__tmp); \
232         } while (0)
233
234 #define TLV_GET_U8(s, attr, v) TLV_GET_INT(s, attr, 8, v)
235 #define TLV_GET_U16(s, attr, v) TLV_GET_INT(s, attr, 16, v)
236 #define TLV_GET_U32(s, attr, v) TLV_GET_INT(s, attr, 32, v)
237 #define TLV_GET_U64(s, attr, v) TLV_GET_INT(s, attr, 64, v)
238
239 static int tlv_get_string(struct btrfs_send_stream *sctx, int attr, char **str)
240 {
241         int ret;
242         void *data;
243         int len = 0;
244
245         TLV_GET(sctx, attr, &data, &len);
246
247         *str = malloc(len + 1);
248         if (!*str)
249                 return -ENOMEM;
250
251         memcpy(*str, data, len);
252         (*str)[len] = 0;
253         ret = 0;
254
255 tlv_get_failed:
256         return ret;
257 }
258 #define TLV_GET_STRING(s, attr, str) \
259         __TLV_DO_WHILE_GOTO_FAIL(tlv_get_string(s, attr, str))
260
261 static int tlv_get_timespec(struct btrfs_send_stream *sctx,
262                             int attr, struct timespec *ts)
263 {
264         int ret;
265         int len;
266         struct btrfs_timespec *bts;
267
268         TLV_GET(sctx, attr, (void**)&bts, &len);
269         TLV_CHECK_LEN(sizeof(*bts), len);
270
271         ts->tv_sec = le64_to_cpu(bts->sec);
272         ts->tv_nsec = le32_to_cpu(bts->nsec);
273         ret = 0;
274
275 tlv_get_failed:
276         return ret;
277 }
278 #define TLV_GET_TIMESPEC(s, attr, ts) \
279         __TLV_DO_WHILE_GOTO_FAIL(tlv_get_timespec(s, attr, ts))
280
281 static int tlv_get_uuid(struct btrfs_send_stream *sctx, int attr, u8 *uuid)
282 {
283         int ret;
284         int len;
285         void *data;
286
287         TLV_GET(sctx, attr, &data, &len);
288         TLV_CHECK_LEN(BTRFS_UUID_SIZE, len);
289         memcpy(uuid, data, BTRFS_UUID_SIZE);
290
291         ret = 0;
292
293 tlv_get_failed:
294         return ret;
295 }
296 #define TLV_GET_UUID(s, attr, uuid) \
297         __TLV_DO_WHILE_GOTO_FAIL(tlv_get_uuid(s, attr, uuid))
298
299 static int read_and_process_cmd(struct btrfs_send_stream *sctx)
300 {
301         int ret;
302         char *path = NULL;
303         char *path_to = NULL;
304         char *clone_path = NULL;
305         char *xattr_name = NULL;
306         void *xattr_data = NULL;
307         void *data = NULL;
308         struct timespec at;
309         struct timespec ct;
310         struct timespec mt;
311         u8 uuid[BTRFS_UUID_SIZE];
312         u8 clone_uuid[BTRFS_UUID_SIZE];
313         u64 tmp;
314         u64 tmp2;
315         u64 ctransid;
316         u64 clone_ctransid;
317         u64 mode;
318         u64 dev;
319         u64 clone_offset;
320         u64 offset;
321         int len;
322         int xattr_len;
323
324         ret = read_cmd(sctx);
325         if (ret)
326                 goto out;
327
328         switch (sctx->cmd) {
329         case BTRFS_SEND_C_SUBVOL:
330                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
331                 TLV_GET_UUID(sctx, BTRFS_SEND_A_UUID, uuid);
332                 TLV_GET_U64(sctx, BTRFS_SEND_A_CTRANSID, &ctransid);
333                 ret = sctx->ops->subvol(path, uuid, ctransid, sctx->user);
334                 break;
335         case BTRFS_SEND_C_SNAPSHOT:
336                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
337                 TLV_GET_UUID(sctx, BTRFS_SEND_A_UUID, uuid);
338                 TLV_GET_U64(sctx, BTRFS_SEND_A_CTRANSID, &ctransid);
339                 TLV_GET_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, clone_uuid);
340                 TLV_GET_U64(sctx, BTRFS_SEND_A_CLONE_CTRANSID, &clone_ctransid);
341                 ret = sctx->ops->snapshot(path, uuid, ctransid, clone_uuid,
342                                 clone_ctransid, sctx->user);
343                 break;
344         case BTRFS_SEND_C_MKFILE:
345                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
346                 ret = sctx->ops->mkfile(path, sctx->user);
347                 break;
348         case BTRFS_SEND_C_MKDIR:
349                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
350                 ret = sctx->ops->mkdir(path, sctx->user);
351                 break;
352         case BTRFS_SEND_C_MKNOD:
353                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
354                 TLV_GET_U64(sctx, BTRFS_SEND_A_MODE, &mode);
355                 TLV_GET_U64(sctx, BTRFS_SEND_A_RDEV, &dev);
356                 ret = sctx->ops->mknod(path, mode, dev, sctx->user);
357                 break;
358         case BTRFS_SEND_C_MKFIFO:
359                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
360                 ret = sctx->ops->mkfifo(path, sctx->user);
361                 break;
362         case BTRFS_SEND_C_MKSOCK:
363                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
364                 ret = sctx->ops->mksock(path, sctx->user);
365                 break;
366         case BTRFS_SEND_C_SYMLINK:
367                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
368                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH_LINK, &path_to);
369                 ret = sctx->ops->symlink(path, path_to, sctx->user);
370                 break;
371         case BTRFS_SEND_C_RENAME:
372                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
373                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH_TO, &path_to);
374                 ret = sctx->ops->rename(path, path_to, sctx->user);
375                 break;
376         case BTRFS_SEND_C_LINK:
377                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
378                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH_LINK, &path_to);
379                 ret = sctx->ops->link(path, path_to, sctx->user);
380                 break;
381         case BTRFS_SEND_C_UNLINK:
382                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
383                 ret = sctx->ops->unlink(path, sctx->user);
384                 break;
385         case BTRFS_SEND_C_RMDIR:
386                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
387                 ret = sctx->ops->rmdir(path, sctx->user);
388                 break;
389         case BTRFS_SEND_C_WRITE:
390                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
391                 TLV_GET_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, &offset);
392                 TLV_GET(sctx, BTRFS_SEND_A_DATA, &data, &len);
393                 ret = sctx->ops->write(path, data, offset, len, sctx->user);
394                 break;
395         case BTRFS_SEND_C_CLONE:
396                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
397                 TLV_GET_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, &offset);
398                 TLV_GET_U64(sctx, BTRFS_SEND_A_CLONE_LEN, &len);
399                 TLV_GET_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, clone_uuid);
400                 TLV_GET_U64(sctx, BTRFS_SEND_A_CLONE_CTRANSID, &clone_ctransid);
401                 TLV_GET_STRING(sctx, BTRFS_SEND_A_CLONE_PATH, &clone_path);
402                 TLV_GET_U64(sctx, BTRFS_SEND_A_CLONE_OFFSET, &clone_offset);
403                 ret = sctx->ops->clone(path, offset, len, clone_uuid,
404                                 clone_ctransid, clone_path, clone_offset,
405                                 sctx->user);
406                 break;
407         case BTRFS_SEND_C_SET_XATTR:
408                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
409                 TLV_GET_STRING(sctx, BTRFS_SEND_A_XATTR_NAME, &xattr_name);
410                 TLV_GET(sctx, BTRFS_SEND_A_XATTR_DATA, &xattr_data, &xattr_len);
411                 ret = sctx->ops->set_xattr(path, xattr_name, xattr_data,
412                                 xattr_len, sctx->user);
413                 break;
414         case BTRFS_SEND_C_REMOVE_XATTR:
415                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
416                 TLV_GET_STRING(sctx, BTRFS_SEND_A_XATTR_NAME, &xattr_name);
417                 ret = sctx->ops->remove_xattr(path, xattr_name, sctx->user);
418                 break;
419         case BTRFS_SEND_C_TRUNCATE:
420                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
421                 TLV_GET_U64(sctx, BTRFS_SEND_A_SIZE, &tmp);
422                 ret = sctx->ops->truncate(path, tmp, sctx->user);
423                 break;
424         case BTRFS_SEND_C_CHMOD:
425                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
426                 TLV_GET_U64(sctx, BTRFS_SEND_A_MODE, &tmp);
427                 ret = sctx->ops->chmod(path, tmp, sctx->user);
428                 break;
429         case BTRFS_SEND_C_CHOWN:
430                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
431                 TLV_GET_U64(sctx, BTRFS_SEND_A_UID, &tmp);
432                 TLV_GET_U64(sctx, BTRFS_SEND_A_GID, &tmp2);
433                 ret = sctx->ops->chown(path, tmp, tmp2, sctx->user);
434                 break;
435         case BTRFS_SEND_C_UTIMES:
436                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
437                 TLV_GET_TIMESPEC(sctx, BTRFS_SEND_A_ATIME, &at);
438                 TLV_GET_TIMESPEC(sctx, BTRFS_SEND_A_MTIME, &mt);
439                 TLV_GET_TIMESPEC(sctx, BTRFS_SEND_A_CTIME, &ct);
440                 ret = sctx->ops->utimes(path, &at, &mt, &ct, sctx->user);
441                 break;
442         case BTRFS_SEND_C_UPDATE_EXTENT:
443                 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
444                 TLV_GET_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, &offset);
445                 TLV_GET_U64(sctx, BTRFS_SEND_A_SIZE, &tmp);
446                 ret = sctx->ops->update_extent(path, offset, tmp, sctx->user);
447                 break;
448         case BTRFS_SEND_C_END:
449                 ret = 1;
450                 break;
451         }
452
453 tlv_get_failed:
454 out:
455         free(path);
456         free(path_to);
457         free(clone_path);
458         free(xattr_name);
459         return ret;
460 }
461
462 /*
463  * If max_errors is 0, then don't stop processing the stream if one of the
464  * callbacks in btrfs_send_ops structure returns an error. If greater than
465  * zero, stop after max_errors errors happened.
466  */
467 int btrfs_read_and_process_send_stream(int fd,
468                                        struct btrfs_send_ops *ops, void *user,
469                                        int honor_end_cmd,
470                                        u64 max_errors)
471 {
472         int ret;
473         struct btrfs_send_stream sctx;
474         struct btrfs_stream_header hdr;
475         u64 errors = 0;
476         int last_err = 0;
477
478         sctx.fd = fd;
479         sctx.ops = ops;
480         sctx.user = user;
481
482         ret = read_buf(&sctx, (char*)&hdr, sizeof(hdr));
483         if (ret < 0)
484                 goto out;
485         if (ret) {
486                 ret = 1;
487                 goto out;
488         }
489
490         if (strcmp(hdr.magic, BTRFS_SEND_STREAM_MAGIC)) {
491                 ret = -EINVAL;
492                 error("unexpected header");
493                 goto out;
494         }
495
496         sctx.version = le32_to_cpu(hdr.version);
497         if (sctx.version > BTRFS_SEND_STREAM_VERSION) {
498                 ret = -EINVAL;
499                 error("stream version %d not supported, please use newer version",
500                                 sctx.version);
501                 goto out;
502         }
503
504         while (1) {
505                 ret = read_and_process_cmd(&sctx);
506                 if (ret < 0) {
507                         last_err = ret;
508                         errors++;
509                         if (max_errors > 0 && errors >= max_errors)
510                                 goto out;
511                 } else if (ret > 0) {
512                         if (!honor_end_cmd)
513                                 ret = 0;
514                         goto out;
515                 }
516         }
517
518 out:
519         if (last_err && !ret)
520                 ret = last_err;
521
522         return ret;
523 }