2 Copyright (C) 2007-2012 Proxmox Server Solutions GmbH
4 Copyright: vzdump is under GNU GPL, the GNU General Public License.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; version 2 dated June, 1991.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
20 Author: Dietmar Maurer <dietmar@proxmox.com>
22 NOTE: the tar specific code is copied from the GNU tar package (just
23 slighly modified to fit our needs).
28 #include <sys/types.h>
45 #define BUFFER_BLOCKS 32
52 char buffer
[BUFFER_BLOCKS
*BLOCKSIZE
];
57 /* OLDGNU_MAGIC uses both magic and version fields, which are contiguous. */
58 #define OLDGNU_MAGIC "ustar " /* 7 chars and a null */
62 char name
[100]; /* 0 */
63 char mode
[8]; /* 100 */
64 char uid
[8]; /* 108 */
65 char gid
[8]; /* 116 */
66 char size
[12]; /* 124 */
67 char mtime
[12]; /* 136 */
68 char chksum
[8]; /* 148 */
69 char typeflag
; /* 156 */
70 char linkname
[100]; /* 157 */
71 char magic
[6]; /* 257 */
72 char version
[2]; /* 263 */
73 char uname
[32]; /* 265 */
74 char gname
[32]; /* 297 */
75 char devmajor
[8]; /* 329 */
76 char devminor
[8]; /* 337 */
77 char prefix
[155]; /* 345 */
83 char offset
[12]; /* 0 */
84 char numbytes
[12]; /* 12 */
90 char unused_pad1
[345]; /* 0 */
91 char atime
[12]; /* 345 Incr. archive: atime of the file */
92 char ctime
[12]; /* 357 Incr. archive: ctime of the file */
93 char offset
[12]; /* 369 Multivolume archive: the offset of
94 the start of this volume */
95 char longnames
[4]; /* 381 Not used */
96 char unused_pad2
; /* 385 */
99 char isextended
; /* 482 Sparse file: Extension sparse header
101 char realsize
[12]; /* 483 Sparse file: Real size*/
107 struct sparse sp
[21]; /* 0 */
108 char isextended
; /* 504 */
114 char buffer
[BLOCKSIZE
];
115 struct posix_header header
;
116 struct oldgnu_header oldgnu_header
;
117 struct sparse_header sparse_header
;
129 size_t effective_size
;
132 struct sp_entry
*map
;
144 fprintf (stderr
, "received signal - terminate process\n");
150 struct sp_array
*ma
= malloc (sizeof (struct sp_array
));
152 fprintf (stderr
, "ERROR: memory allocation failure\n");
156 ma
->effective_size
= 0;
159 ma
->map
= malloc (ma
->size
* sizeof (struct sp_entry
));
161 fprintf (stderr
, "ERROR: memory allocation failure\n");
168 sparray_resize (struct sp_array
*ma
)
171 if (!(ma
->map
= realloc (ma
->map
, ma
->size
* sizeof (struct sp_entry
)))) {
172 fprintf (stderr
, "ERROR: memory allocation failure\n");
178 sparray_add (struct sp_array
*ma
, off_t offset
, size_t bytes
)
181 if (ma
->avail
== ma
->size
) {
184 ma
->map
[ma
->avail
].offset
= offset
;
185 ma
->map
[ma
->avail
].bytes
= bytes
;
190 to_base256 (uintmax_t value
, char *where
, size_t size
)
198 where
[i
--] = v
& ((1 << 8) - 1);
204 to_octal (uintmax_t value
, char *where
, size_t size
)
211 where
[--i
] = '0' + (v
& ((1 << 3) - 1));
216 /* The maximum uintmax_t value that can be represented with DIGITS digits,
217 assuming that each digit is BITS_PER_DIGIT wide. */
218 #define MAX_VAL_WITH_DIGITS(digits, bits_per_digit) \
219 ((digits) * (bits_per_digit) < sizeof (uintmax_t) * 8 \
220 ? ((uintmax_t) 1 << ((digits) * (bits_per_digit))) - 1 \
223 /* The maximum uintmax_t value that can be represented with octal
224 digits and a trailing NUL in BUFFER. */
225 #define MAX_OCTAL_VAL(buffer) MAX_VAL_WITH_DIGITS (sizeof (buffer) - 1, 3)
228 off12_to_chars (char *p
, off_t v
)
231 fprintf (stderr
, "ERROR: internal error - got negative offset\n");
235 uintmax_t value
= (uintmax_t) v
;
237 if (value
<= MAX_VAL_WITH_DIGITS (11, 3)) {
238 to_octal (value
, p
, 12);
240 to_base256 (value
, p
, 12);
245 buffer_block(struct writebuffer
*wbuf
)
247 size_t space
= sizeof (wbuf
->buffer
) - wbuf
->bpos
;
250 if (space
>= BLOCKSIZE
) {
251 blk
= wbuf
->buffer
+ wbuf
->bpos
;
252 wbuf
->bpos
+= BLOCKSIZE
;
254 full_write (wbuf
->fd
, wbuf
->buffer
, wbuf
->bpos
);
255 wbuf
->total
+= wbuf
->bpos
;
256 wbuf
->bpos
= BLOCKSIZE
;
265 struct writebuffer
*wbuf
= calloc (1, sizeof (struct writebuffer
));
268 fprintf (stderr
, "ERROR: memory allocation failure\n");
278 buffer_flush(struct writebuffer
*wbuf
)
280 full_write (wbuf
->fd
, wbuf
->buffer
, wbuf
->bpos
);
281 wbuf
->total
+= wbuf
->bpos
;
286 dump_header (struct writebuffer
*wbuf
, const char *filename
, time_t mtime
, struct sp_array
*ma
)
288 union block
*blk
= (union block
*)buffer_block (wbuf
);
289 memset (blk
->buffer
, 0, BLOCKSIZE
);
291 if (strlen(filename
)>98) {
292 fprintf (stderr
, "ERROR: filename '%s' too long\n", filename
);
296 strncpy (blk
->header
.name
, filename
, 100);
298 sprintf (blk
->header
.mode
, "%07o", 0644);
299 sprintf (blk
->header
.uid
, "%07o", 0);
300 sprintf (blk
->header
.gid
, "%07o", 0);
301 off12_to_chars (blk
->header
.mtime
, mtime
);
303 memcpy (blk
->header
.chksum
, " ", 8);
305 blk
->header
.typeflag
= ma
->avail
? 'S' : '0';
307 sprintf (blk
->header
.magic
, "%s", OLDGNU_MAGIC
);
309 sprintf (blk
->header
.uname
, "%s", "root");
310 sprintf (blk
->header
.gname
, "%s", "root");
313 if (ind
< ma
->avail
) {
315 for (i
= 0;i
< 4 && ind
< ma
->avail
; i
++, ind
++) {
316 off12_to_chars (blk
->oldgnu_header
.sp
[i
].offset
, ma
->map
[ind
].offset
);
317 off12_to_chars (blk
->oldgnu_header
.sp
[i
].numbytes
, ma
->map
[ind
].bytes
);
322 blk
->oldgnu_header
.isextended
= 1;
324 off12_to_chars (blk
->header
.size
, ma
->effective_size
);
325 off12_to_chars (blk
->oldgnu_header
.realsize
, ma
->real_size
);
328 char *p
= blk
->buffer
;
330 for (i
= BLOCKSIZE
; i
-- != 0; )
333 sprintf (blk
->header
.chksum
, "%6o", sum
);
335 while (ind
< ma
->avail
) {
336 blk
= (union block
*)buffer_block (wbuf
);
337 memset (blk
->buffer
, 0, BLOCKSIZE
);
339 for (i
= 0;i
< 21 && ind
< ma
->avail
; i
++, ind
++) {
340 off12_to_chars (blk
->sparse_header
.sp
[i
].offset
, ma
->map
[ind
].offset
);
341 off12_to_chars (blk
->sparse_header
.sp
[i
].numbytes
, ma
->map
[ind
].bytes
);
344 blk
->sparse_header
.isextended
= 1;
350 scan_sparse_file (int fd
, struct sp_array
*ma
)
352 char buffer
[BLOCKSIZE
];
359 if (lseek (fd
, 0, SEEK_SET
) < 0)
362 while ((count
= full_read (fd
, buffer
, sizeof (buffer
))) > 0) {
363 if (block_is_zero (buffer
, count
)) {
365 sparray_add (ma
, sp_offset
, sp_bytes
);
380 sparray_add (ma
, sp_offset
, sp_bytes
);
382 ma
->real_size
= offset
;
383 ma
->effective_size
= file_size
;
389 dump_sparse_file (int fd
, struct writebuffer
*wbuf
, struct sp_array
*ma
)
391 if (lseek (fd
, 0, SEEK_SET
) < 0)
395 size_t dumped_size
= 0;
396 for (i
= 0; i
< ma
->avail
; i
++) {
397 struct sp_entry
*e
= &ma
->map
[i
];
398 if (lseek (fd
, e
->offset
, SEEK_SET
) < 0)
401 off_t bytes_left
= e
->bytes
;
403 while (bytes_left
> 0) {
404 size_t bufsize
= (bytes_left
> BLOCKSIZE
) ? BLOCKSIZE
: bytes_left
;
407 char *blkbuf
= buffer_block (wbuf
);
408 if ((bytes_read
= full_read (fd
, blkbuf
, bufsize
)) < 0) {
413 fprintf (stderr
, "ERROR: got unexpected EOF\n");
417 memset (blkbuf
+ bytes_read
, 0, BLOCKSIZE
- bytes_read
);
419 dumped_size
+= bytes_read
;
421 bytes_left
-= bytes_read
;
429 main (int argc
, char **argv
)
435 int option_index
= 0;
436 static struct option long_options
[] = {
437 {"sparse", 0, 0, 's'},
438 {"output", 1, 0, 'o'},
442 char c
= getopt_long (argc
, argv
, "so:", long_options
, &option_index
);
454 fprintf (stderr
, "?? getopt returned character code 0%o ??\n", c
);
459 int numargs
= argc
- optind
;
460 if (numargs
<= 0 || (numargs
% 2)) {
461 fprintf (stderr
, "wrong number of arguments\n");
465 time_t starttime
= time(NULL
);
470 if ((outfd
= open(outname
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0644)) == -1) {
471 fprintf (stderr
, "unable to open archive '%s' - %s\n",
472 outname
, strerror (errno
));
477 outfd
= fileno (stdout
);
480 setsig(&sa
, SIGINT
, term_handler
, SA_RESTART
);
481 setsig(&sa
, SIGQUIT
, term_handler
, SA_RESTART
);
482 setsig(&sa
, SIGTERM
, term_handler
, SA_RESTART
);
483 setsig(&sa
, SIGPIPE
, term_handler
, SA_RESTART
);
485 int saved_optind
= optind
;
486 while (optind
< argc
) {
487 char *source
= argv
[optind
];
491 if (stat (source
, &fs
) != 0) {
492 fprintf (stderr
, "unable to read '%s' - %s\n",
493 source
, strerror (errno
));
497 if (!(S_ISREG(fs
.st_mode
) || S_ISBLK(fs
.st_mode
))) {
498 fprintf (stderr
, "unable to read '%s' - not a file or block device\n",
504 optind
= saved_optind
;
506 struct writebuffer
*wbuf
= buffer_new (outfd
);
508 while (optind
< argc
) {
509 char *source
= argv
[optind
++];
510 char *archivename
= argv
[optind
++];
514 fprintf (stderr
, "adding '%s' to archive ('%s')\n", source
, archivename
);
516 if ((fd
= open(source
, O_RDONLY
)) == -1) {
517 fprintf (stderr
, "unable to open '%s' - %s\n",
518 source
, strerror (errno
));
524 if (fstat (fd
, &fs
) != 0) {
525 fprintf (stderr
, "unable to stat '%s' - %s\n",
526 source
, strerror (errno
));
530 time_t ctime
= fs
.st_mtime
;
532 struct sp_array
*ma
= sparray_new();
533 if (sparse
&& !S_ISBLK(fs
.st_mode
)) {
534 if (!scan_sparse_file (fd
, ma
)) {
535 fprintf (stderr
, "scanning '%s' failed\n", source
);
539 off_t file_size
= lseek(fd
, 0, SEEK_END
);
541 fprintf (stderr
, "unable to get file size of '%s'\n", source
);
544 sparray_add (ma
, 0, file_size
);
545 ma
->real_size
= file_size
;
546 ma
->effective_size
= file_size
;
549 dump_header (wbuf
, archivename
, ctime
, ma
);
551 if (!dump_sparse_file (fd
, wbuf
, ma
)) {
552 fprintf (stderr
, "writing '%s' to archive failed\n", source
);
563 char *buf
= buffer_block (wbuf
);
564 memset (buf
, 0, BLOCKSIZE
);
565 buf
= buffer_block (wbuf
);
566 memset (buf
, 0, BLOCKSIZE
);
572 time_t delay
= time(NULL
) - starttime
;
573 if (delay
<= 0) delay
= 1;
575 fprintf (stderr
, "Total bytes written: %zu (%.2f MiB/s)\n", wbuf
->total
,
576 (wbuf
->total
/(1024*1024))/(float)delay
);