Package: xorriso Version: 1.5.0-1 Severity: wishlist Control: found -1 1.5.2-1
[Please do not Cc: me, for I’m “on the list,” so to say, and I try to reserve my inbox for private communication only. I’d have set up Mail-Followup-To:, but there doesn’t seem to be a way to make it point to the report being filed.] I’m filing this bug against versions from oldstable and stable, for that’s so far the only Debian packages’ versions I’ve tested for this issue. Regardless, given that the behavior is the same for a recent Git revision, and that there doesn’t seem to be any relevant Debian-specific patches under [1], it stands to reason that the requested feature is not available in Debian testing and Sid, either. [1] http://sources.debian.org/src/libisoburn/1.5.4-2/debian/patches/ It would be handy to be able to use xorriso(1) to backup (portions) of block devices to optical media; yet it doesn’t seem to be supported. E. g., on Buster: bash$ xorriso -dev stdio:/tmp/cd"$RANDOM".image -follow link \ -cut-out /dev/vgjubca-bk-i/lvepeci-x626512db 37M 13M lvxxx_37m+13m \ -find / -exec lsdl -- -commit xorriso 1.5.0 : RockRidge filesystem manipulator, libburnia project. Drive current: -dev 'stdio:/tmp/cd4973.image' Media current: stdio file, overwriteable Media status : is blank Media summary: 0 sessions, 0 data blocks, 0 data, XXXm free xorriso : FAILURE : -cut_out: Unsupported file type (block_device) with '/dev/vgjubca-bk-i/lvepeci-x626512db' : No such file or directory xorriso : aborting : -abort_on 'FAILURE' encountered 'FAILURE' bash$ On Bullseye: bash$ xorriso -dev stdio:/tmp/cd"$RANDOM".image -follow link \ -cut-out /dev/vgjubca-bk-i/lvepeci-x626512db 37M 13M lvxxx_37m+13m \ -find / -exec lsdl -- -commit xorriso 1.5.2 : RockRidge filesystem manipulator, libburnia project. Drive current: -dev 'stdio:/tmp/cd1415.image' Media current: stdio file, overwriteable Media status : is blank Media summary: 0 sessions, 0 data blocks, 0 data, XXXm free xorriso : FAILURE : -cut_out: Unsupported file type (block_device) with '/dev/vgjubca-bk-i/lvepeci-x626512db' : No such file or directory xorriso : aborting : -abort_on 'FAILURE' encountered 'FAILURE' bash$ The problem is due to /both/ libisoburn (to a lesser degree) and libisofs relying on struct stat .st_size field (and the respective S_ISREG check.) I’ve made a very crude patch (MIMEd) that replaces the st_size checks for non-regular files with checks against the size reported by lseek (, 0, SEEK_END), if available; and in some cases forgoes the check for non-regular files altogether. Consider, e. g.: bash$ xorriso -dev stdio:/tmp/cd"$RANDOM".image -follow link \ -cut-out /dev/vgjubca-bk-i/lvepeci-x626512db 37M 13M lvxxx_37m+13m -find / -exec lsdl -- -commit xorriso 1.5.5 : RockRidge filesystem manipulator, libburnia project. Drive current: -dev 'stdio:/tmp/cd14597.image' Media current: stdio file, overwriteable Media status : is blank Media summary: 0 sessions, 0 data blocks, 0 data, XXXm free drwxr-xr-x 1 0 0 0 Apr 24 10:16 '/' -rw-rw---- 1 0 6 13631488 Apr 10 10:58 '/lvxxx_37m+13m' xorriso : UPDATE : Writing: 3985s 58.2% fifo 0% buf 50% ISO image produced: 6679 sectors Written to medium : 6848 sectors at LBA 32 Writing to 'stdio:/tmp/cd14597.image' completed successfully. xorriso : NOTE : Re-assessing -outdev 'stdio:/tmp/cd14597.image' xorriso : NOTE : Loading ISO image tree from LBA 0 xorriso : UPDATE : 1 nodes read in 1 seconds Drive current: -dev 'stdio:/tmp/cd14597.image' Media current: stdio file, overwriteable Media status : is written , is appendable Media summary: 1 session, 6679 data blocks, 13.0m data, XXXm free Volume id : 'ISOIMAGE' bash$ Checking if the intended data was indeed written to the image with icat(1): bash$ /usr/bin/time -- cmp -n 13M -i 37M:0 -- \ /dev/vgjubca-bk-i/lvepeci-x626512db \ <(icat /tmp/cd14597.image 1) 0.01user 0.04system 0:00.18elapsed 29%CPU (0avgtext+0avgdata 1088maxresident)k 27112inputs+0outputs (0major+95minor)pagefaults 0swaps bash$ -- FSF associate member #7257 http://am-1.org/~ivan/
--- ./libisofs-da002915/libisofs/stream.c.~1~ 2022-04-23 07:32:44 +0000 +++ ./libisofs-da002915/libisofs/stream.c 2022-04-24 08:39:06.352583604 +0000 @@ -34,11 +34,27 @@ ino_t cut_out_serial_id = (ino_t)1; static +off_t fsrc_lseek_end_off(IsoFileSource *src) +{ + /** For non-regular files, we check seekability + and obtain SEEK_END position to use as size */ + off_t end, old, reset; + old = iso_file_source_lseek (src, 0, 1); + if (old < 0) { return -1; } + end = iso_file_source_lseek (src, 0, 2); + if (end < 0) { return -1; } + reset = iso_file_source_lseek (src, old, 0); + if (reset != old) { return -1; } + return end; +} + +static int fsrc_open(IsoStream *stream) { int ret; struct stat info; off_t esize; + off_t orig_size; IsoFileSource *src; if (stream == NULL) { return ISO_NULL_POINTER; @@ -53,10 +69,14 @@ return ret; } esize = ((FSrcStreamData*)stream->data)->size; - if (info.st_size == esize) { + orig_size = (S_ISREG (info.st_mode) ? info.st_size + : fsrc_lseek_end_off (src)); + if (orig_size < 0) { + return 3; /* FIXME: ? */ + } else if (orig_size == esize) { return ISO_SUCCESS; } else { - return (esize > info.st_size) ? 3 : 2; + return (esize > orig_size) ? 3 : 2; } } @@ -107,6 +127,7 @@ if (ret < 0) { return ret; } + /** FIXME: allow other (seekable) files as well? */ if (S_ISREG(info.st_mode) || S_ISBLK(info.st_mode)) { return 1; } else { @@ -144,6 +165,7 @@ int ret; struct stat info; IsoFileSource *src; + off_t orig_size; if (stream == NULL) { return ISO_NULL_POINTER; @@ -154,7 +176,13 @@ return ret; } - ((FSrcStreamData*)stream->data)->size = info.st_size; + /** FIXME: assuming file is open */ + orig_size = (S_ISREG (info.st_mode) ? info.st_size + : fsrc_lseek_end_off (src)); + if (orig_size < 0) { + return 3; /* FIXME: ? */ + } + ((FSrcStreamData*)stream->data)->size = orig_size; return ISO_SUCCESS; } @@ -228,6 +256,7 @@ struct stat info; IsoStream *str; FSrcStreamData *data; + off_t orig_size; if (src == NULL || stream == NULL) { return ISO_NULL_POINTER; @@ -259,7 +288,12 @@ /* take the ref to IsoFileSource */ data->src = src; - data->size = info.st_size; + orig_size = (S_ISREG (info.st_mode) ? info.st_size + : fsrc_lseek_end_off (src)); + if (orig_size < 0) { + return 3; /* FIXME: ? */ + } + data->size = orig_size; /* get the id numbers */ { @@ -332,6 +366,7 @@ struct stat info; IsoFileSource *src; struct cut_out_stream *data; + off_t orig_size; if (stream == NULL) { return ISO_NULL_POINTER; @@ -348,11 +383,17 @@ return ret; } + orig_size = (S_ISREG (info.st_mode) ? info.st_size + : fsrc_lseek_end_off (src)); + if (orig_size < 0) { + return 3; /* FIXME: ? */ + } + { off_t ret; - if (data->offset > info.st_size) { + if (data->offset > orig_size) { /* file is smaller than expected */ - ret = iso_file_source_lseek(src, info.st_size, 0); + ret = iso_file_source_lseek(src, orig_size, 0); } else { ret = iso_file_source_lseek(src, data->offset, 0); } @@ -361,7 +402,7 @@ } } data->pos = 0; - if (data->offset + data->size > info.st_size) { + if (data->offset + data->size > orig_size) { return 3; /* file smaller than expected */ } else { return ISO_SUCCESS; @@ -511,6 +552,7 @@ struct stat info; IsoStream *str; struct cut_out_stream *data; + off_t orig_size; if (src == NULL || stream == NULL) { return ISO_NULL_POINTER; @@ -523,10 +565,12 @@ if (r < 0) { return r; } - if (!S_ISREG(info.st_mode)) { + if (S_ISDIR(info.st_mode) || S_ISLNK(info.st_mode)) { return ISO_WRONG_ARG_VALUE; } - if (offset > info.st_size) { + /** FIXME: we are deferring the size check until file is open */ + orig_size = S_ISREG(info.st_mode) ? info.st_size : offset + size; + if (offset > orig_size) { return ISO_FILE_OFFSET_TOO_BIG; } @@ -551,7 +595,7 @@ iso_file_source_ref(src); data->offset = offset; - data->size = MIN(info.st_size - offset, size); + data->size = MIN(orig_size - offset, size); /* get the id numbers */ data->dev_id = (dev_t) 0; --- ./libisofs-da002915/libisofs/tree.c.~1~ 2022-04-23 07:32:44 +0000 +++ ./libisofs-da002915/libisofs/tree.c 2022-04-24 08:35:27.074640138 +0000 @@ -715,10 +715,12 @@ iso_file_source_unref(src); return result; } - if (!S_ISREG(info.st_mode)) { + if (S_ISDIR(info.st_mode) || S_ISLNK(info.st_mode)) { return ISO_WRONG_ARG_VALUE; } - if (offset >= info.st_size) { + /** FIXME: we are deferring the size check until the file is open + (much later) */ + if (S_ISREG(info.st_mode) && offset >= info.st_size) { return ISO_WRONG_ARG_VALUE; } --- ./libisoburn-0ef65a78/xorriso/iso_manip.c.~1~ 2022-04-23 12:09:30 +0000 +++ ./libisoburn-0ef65a78/xorriso/iso_manip.c 2022-04-23 19:53:16.321006540 +0000 @@ -163,6 +163,22 @@ } +static off_t get_seek_end_off(char *eff_source, struct stat *stbuf) +{ + if(S_ISREG(stbuf->st_mode)) { + return stbuf->st_size; + } else if(S_ISDIR(stbuf->st_mode) /* NB: -follow processed elsewhere? */ + || S_ISLNK(stbuf->st_mode)) { + return -1; + } + int fd= open(eff_source, O_RDONLY); + if(fd < 0) { return -1; } + off_t r= lseek(fd, 0, SEEK_END); + close(fd); + return r; +} + + /* @param flag bit0= ISO_NODE_NAME_NOT_UNIQUE exception mode: Do not issue message. Return existing node into *node. @@ -186,8 +202,9 @@ eff_name= img_name; if(lstat(disk_path, &stbuf) != -1) { stbuf_valid= 1; - if(S_ISREG(stbuf.st_mode)) - size= stbuf.st_size; + if((size= get_seek_end_off(disk_path, &stbuf)) < 0) { + size= 0; + } } if((int) strlen(eff_name) > xorriso->file_name_limit) { Xorriso_alloc_meM(trunc_name, char, SfileadrL); @@ -1265,12 +1282,13 @@ {ret= 0; goto ex;} } } - if(S_ISREG(stbuf.st_mode)) { - if(stbuf.st_size<startbyte) { + off_t s_z; /* allow backup of any seekable files, such as block devices */ + if((s_z= get_seek_end_off(eff_source, &stbuf)) >= 0) { + if(s_z<startbyte) { Xorriso_msgs_submit(xorriso, 0, eff_source, 0, "ERRFILE", 0); sprintf(xorriso->info_text, "-cut_out: Byte offset %.f larger than file size %.f", - (double) startbyte, (double) stbuf.st_size); + (double) startbyte, (double) s_z); Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "SORRY", 0); {ret= 0; goto ex;} }