]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
db: write via array indexing doesn't work
authorDave Chinner <dchinner@redhat.com>
Thu, 8 Sep 2016 00:22:19 +0000 (10:22 +1000)
committerDave Chinner <david@fromorbit.com>
Thu, 8 Sep 2016 00:22:19 +0000 (10:22 +1000)
This command to write a specific AGFL index:

# xfs_db -x -c "agfl 0" -c "write -d bno[32] 78" /dev/ram0

doesn't write to array index 32 - it incorrectly writes to
/somewhere/ in the entire array range.

The issue here is that the write_struct() code assumes that the
object it is printing always a structure member and any array
indexes will be exposed as children of the parent type. This works
just fine for structures with internal arrays, but when the type
being decoded is an array, we get a direct reference to the offset
to be written in the parent object.

Hence we need to take into account the array index returned by the
parent object parsing when calculating the size of the region to be
modified rather than using fcount() as that results in the size
always being set to the size of the entire array and the
modification being written to the wrong place.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
db/write.c

index 82a0c746cd61cb6cdea35daa230eecdc164c061b..5c83874f17fe880c4596274ee7bd8d96f832f633 100644 (file)
@@ -701,8 +701,24 @@ write_struct(
                sfl = sfl->child;
        }
 
+       /*
+        * For structures, fsize * fcount tells us the size of the region we are
+        * modifying, which is usually a single structure member and is pointed
+        * to by the last child in the list.
+        *
+        * However, if the base structure is an array and we have a direct index
+        * into the array (e.g. write bno[5]) then we are returned a single
+        * flist object with the offset pointing directly at the location we
+        * need to modify. The length of the object we are modifying is then
+        * determined by the size of the individual array entry (fsize) and the
+        * indexes defined in the object, not the overall size of the array
+        * (which is what fcount returns).
+        */
        bit_length = fsize(sfl->fld, iocur_top->data, parentoffset, 0);
-       bit_length *= fcount(sfl->fld, iocur_top->data, parentoffset);
+       if (sfl->fld->flags & FLD_ARRAY)
+               bit_length *= sfl->high - sfl->low + 1;
+       else
+               bit_length *= fcount(sfl->fld, iocur_top->data, parentoffset);
 
        /* convert this to a generic conversion routine */
        /* should be able to handle str, num, or even labels */