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;}
    }

Reply via email to