Fix handling of uncompressed blocks on squashfs and break 4G limit.
* grub-core/fs/squash4.c (grub_squash_super): Add block_size. Remove unused flags. (grub_squash_inode): Add long_file and block_size. (grub_squash_cache_inode): New struct. (grub_squash_dirent): Make types into enum. (SQUASH_TYPE_LONG_REGULAR): New type. (grub_squash_frag_desc): Add field size. (SQUASH_BLOCK_FLAGS): New enum. (grub_squash_data): Use grub_squash_cache_inode. (grub_fshelp_node): Make ino_chunk 64-bit. (read_chunk): Minor argument change. All users updated. (squash_mount): Use correct le_to_cpu. (grub_squash_open): Handle LONG_REGULAR. (direct_read): New function. (grub_squash_read_data): Handle blocks correctly.
This commit is contained in:
parent
9f326fba96
commit
9f12e664cc
2 changed files with 223 additions and 51 deletions
20
ChangeLog
20
ChangeLog
|
@ -1,3 +1,23 @@
|
|||
2011-10-25 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
Fix handling of uncompressed blocks on squashfs and break 4G limit.
|
||||
|
||||
* grub-core/fs/squash4.c (grub_squash_super): Add block_size. Remove
|
||||
unused flags.
|
||||
(grub_squash_inode): Add long_file and block_size.
|
||||
(grub_squash_cache_inode): New struct.
|
||||
(grub_squash_dirent): Make types into enum.
|
||||
(SQUASH_TYPE_LONG_REGULAR): New type.
|
||||
(grub_squash_frag_desc): Add field size.
|
||||
(SQUASH_BLOCK_FLAGS): New enum.
|
||||
(grub_squash_data): Use grub_squash_cache_inode.
|
||||
(grub_fshelp_node): Make ino_chunk 64-bit.
|
||||
(read_chunk): Minor argument change. All users updated.
|
||||
(squash_mount): Use correct le_to_cpu.
|
||||
(grub_squash_open): Handle LONG_REGULAR.
|
||||
(direct_read): New function.
|
||||
(grub_squash_read_data): Handle blocks correctly.
|
||||
|
||||
2011-10-25 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
* grub-core/kern/disk.c (grub_disk_read_small): Fix memory leak.
|
||||
|
|
|
@ -42,7 +42,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
|
|||
exttblptr RAW superblock
|
||||
|
||||
UID/GID table is the array ot uint32_t
|
||||
unk1 contains pointer to unk3 followed by some chunk.
|
||||
unk1 contains pointer to fragment table followed by some chunk.
|
||||
unk2 containts one uint64_t
|
||||
*/
|
||||
|
||||
|
@ -52,13 +52,9 @@ struct grub_squash_super
|
|||
#define SQUASH_MAGIC 0x73717368
|
||||
grub_uint32_t dummy1;
|
||||
grub_uint32_t creation_time;
|
||||
grub_uint32_t dummy2;
|
||||
grub_uint32_t block_size;
|
||||
grub_uint64_t dummy3;
|
||||
grub_uint8_t flags;
|
||||
#define SQUASH_FLAG_UNCOMPRESSED_INODES 1
|
||||
#define SQUASH_FLAG_UNCOMPRESSED_DATA 2
|
||||
#define SQUASH_FLAG_UNCOMPRESSED_FRAGMENTS 8
|
||||
grub_uint8_t dummy4[7];
|
||||
grub_uint64_t dummy4;
|
||||
grub_uint16_t root_ino_offset;
|
||||
grub_uint32_t root_ino_chunk;
|
||||
grub_uint16_t dummy5;
|
||||
|
@ -71,7 +67,6 @@ struct grub_squash_super
|
|||
grub_uint64_t unk2offset;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/* Chunk-based */
|
||||
struct grub_squash_inode
|
||||
{
|
||||
|
@ -87,7 +82,18 @@ struct grub_squash_inode
|
|||
grub_uint32_t fragment;
|
||||
grub_uint32_t offset;
|
||||
grub_uint32_t size;
|
||||
grub_uint32_t block_size[0];
|
||||
} __attribute__ ((packed)) file;
|
||||
struct {
|
||||
grub_uint32_t dummy;
|
||||
grub_uint64_t chunk;
|
||||
grub_uint64_t size;
|
||||
grub_uint32_t dummy2[3];
|
||||
grub_uint32_t fragment;
|
||||
grub_uint32_t offset;
|
||||
grub_uint32_t dummy3;
|
||||
grub_uint32_t block_size[0];
|
||||
} __attribute__ ((packed)) long_file;
|
||||
struct {
|
||||
grub_uint32_t dummy1;
|
||||
grub_uint32_t chunk;
|
||||
|
@ -104,6 +110,15 @@ struct grub_squash_inode
|
|||
} __attribute__ ((packed));
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct grub_squash_cache_inode
|
||||
{
|
||||
struct grub_squash_inode ino;
|
||||
grub_disk_addr_t ino_chunk;
|
||||
grub_uint16_t ino_offset;
|
||||
grub_uint32_t *block_sizes;
|
||||
grub_disk_addr_t *cumulated_block_sizes;
|
||||
};
|
||||
|
||||
/* Chunk-based. */
|
||||
struct grub_squash_dirent_header
|
||||
{
|
||||
|
@ -117,29 +132,46 @@ struct grub_squash_dirent
|
|||
grub_uint16_t ino_offset;
|
||||
grub_uint16_t dummy;
|
||||
grub_uint16_t type;
|
||||
#define SQUASH_TYPE_DIR 1
|
||||
#define SQUASH_TYPE_REGULAR 2
|
||||
#define SQUASH_TYPE_SYMLINK 3
|
||||
/* Actually the value is the length of name - 1. */
|
||||
grub_uint16_t namelen;
|
||||
char name[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
enum
|
||||
{
|
||||
SQUASH_TYPE_DIR = 1,
|
||||
SQUASH_TYPE_REGULAR = 2,
|
||||
SQUASH_TYPE_SYMLINK = 3,
|
||||
SQUASH_TYPE_LONG_REGULAR = 9,
|
||||
};
|
||||
|
||||
|
||||
struct grub_squash_frag_desc
|
||||
{
|
||||
grub_uint64_t offset;
|
||||
grub_uint64_t dummy;
|
||||
grub_uint32_t size;
|
||||
grub_uint32_t dummy;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
enum
|
||||
{
|
||||
SQUASH_CHUNK_FLAGS = 0x8000,
|
||||
SQUASH_CHUNK_UNCOMPRESSED = 0x8000
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SQUASH_BLOCK_FLAGS = 0x1000000,
|
||||
SQUASH_BLOCK_UNCOMPRESSED = 0x1000000
|
||||
};
|
||||
|
||||
#define SQUASH_CHUNK_SIZE 0x2000
|
||||
#define SQUASH_CHUNK_FLAGS 0x8000
|
||||
#define SQUASH_CHUNK_UNCOMPRESSED 0x8000
|
||||
|
||||
struct grub_squash_data
|
||||
{
|
||||
grub_disk_t disk;
|
||||
struct grub_squash_super sb;
|
||||
struct grub_squash_inode ino;
|
||||
struct grub_squash_cache_inode ino;
|
||||
grub_uint64_t fragments;
|
||||
};
|
||||
|
||||
|
@ -147,12 +179,12 @@ struct grub_fshelp_node
|
|||
{
|
||||
struct grub_squash_data *data;
|
||||
struct grub_squash_inode ino;
|
||||
grub_uint32_t ino_chunk;
|
||||
grub_disk_addr_t ino_chunk;
|
||||
grub_uint16_t ino_offset;
|
||||
};
|
||||
|
||||
static grub_err_t
|
||||
read_chunk (grub_disk_t disk, void *buf, grub_size_t len,
|
||||
read_chunk (struct grub_squash_data *data, void *buf, grub_size_t len,
|
||||
grub_uint64_t chunk, grub_off_t offset)
|
||||
{
|
||||
grub_uint64_t chunk_start;
|
||||
|
@ -164,7 +196,8 @@ read_chunk (grub_disk_t disk, void *buf, grub_size_t len,
|
|||
grub_err_t err;
|
||||
while (1)
|
||||
{
|
||||
err = grub_disk_read (disk, chunk_start >> GRUB_DISK_SECTOR_BITS,
|
||||
err = grub_disk_read (data->disk,
|
||||
chunk_start >> GRUB_DISK_SECTOR_BITS,
|
||||
chunk_start & (GRUB_DISK_SECTOR_SIZE - 1),
|
||||
sizeof (d), &d);
|
||||
if (err)
|
||||
|
@ -182,7 +215,7 @@ read_chunk (grub_disk_t disk, void *buf, grub_size_t len,
|
|||
if (grub_le_to_cpu16 (d) & SQUASH_CHUNK_UNCOMPRESSED)
|
||||
{
|
||||
grub_disk_addr_t a = chunk_start + 2 + offset;
|
||||
err = grub_disk_read (disk, (a >> GRUB_DISK_SECTOR_BITS),
|
||||
err = grub_disk_read (data->disk, (a >> GRUB_DISK_SECTOR_BITS),
|
||||
a & (GRUB_DISK_SECTOR_SIZE - 1),
|
||||
csize, buf);
|
||||
if (err)
|
||||
|
@ -197,7 +230,7 @@ read_chunk (grub_disk_t disk, void *buf, grub_size_t len,
|
|||
if (!tmp)
|
||||
return grub_errno;
|
||||
/* FIXME: buffer uncompressed data. */
|
||||
err = grub_disk_read (disk, (a >> GRUB_DISK_SECTOR_BITS),
|
||||
err = grub_disk_read (data->disk, (a >> GRUB_DISK_SECTOR_BITS),
|
||||
a & (GRUB_DISK_SECTOR_SIZE - 1),
|
||||
bsize, tmp);
|
||||
if (err)
|
||||
|
@ -240,9 +273,10 @@ squash_mount (grub_disk_t disk)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
err = grub_disk_read (disk, grub_le_to_cpu32 (sb.unk1offset)
|
||||
err = grub_disk_read (disk,
|
||||
grub_le_to_cpu64 (sb.unk1offset)
|
||||
>> GRUB_DISK_SECTOR_BITS,
|
||||
grub_le_to_cpu32 (sb.unk1offset)
|
||||
grub_le_to_cpu64 (sb.unk1offset)
|
||||
& (GRUB_DISK_SECTOR_SIZE - 1), sizeof (frag), &frag);
|
||||
if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
|
||||
grub_error (GRUB_ERR_BAD_FS, "not a squash4");
|
||||
|
@ -254,7 +288,7 @@ squash_mount (grub_disk_t disk)
|
|||
return NULL;
|
||||
data->sb = sb;
|
||||
data->disk = disk;
|
||||
data->fragments = frag;
|
||||
data->fragments = grub_le_to_cpu64 (frag);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
@ -266,7 +300,7 @@ grub_squash_read_symlink (grub_fshelp_node_t node)
|
|||
grub_err_t err;
|
||||
ret = grub_malloc (grub_le_to_cpu32 (node->ino.symlink.namelen) + 1);
|
||||
|
||||
err = read_chunk (node->data->disk, ret,
|
||||
err = read_chunk (node->data, ret,
|
||||
grub_le_to_cpu32 (node->ino.symlink.namelen),
|
||||
grub_le_to_cpu64 (node->data->sb.inodeoffset)
|
||||
+ node->ino_chunk,
|
||||
|
@ -300,7 +334,7 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir,
|
|||
struct grub_squash_dirent_header dh;
|
||||
grub_err_t err;
|
||||
|
||||
err = read_chunk (dir->data->disk, &dh, sizeof (dh),
|
||||
err = read_chunk (dir->data, &dh, sizeof (dh),
|
||||
grub_le_to_cpu64 (dir->data->sb.diroffset)
|
||||
+ grub_le_to_cpu32 (dir->ino.dir.chunk), off);
|
||||
if (err)
|
||||
|
@ -315,14 +349,14 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir,
|
|||
struct grub_squash_dirent di;
|
||||
struct grub_squash_inode ino;
|
||||
|
||||
err = read_chunk (dir->data->disk, &di, sizeof (di),
|
||||
err = read_chunk (dir->data, &di, sizeof (di),
|
||||
grub_le_to_cpu64 (dir->data->sb.diroffset)
|
||||
+ grub_le_to_cpu32 (dir->ino.dir.chunk), off);
|
||||
if (err)
|
||||
return 0;
|
||||
off += sizeof (di);
|
||||
|
||||
err = read_chunk (dir->data->disk, &ino, sizeof (ino),
|
||||
err = read_chunk (dir->data, &ino, sizeof (ino),
|
||||
grub_le_to_cpu64 (dir->data->sb.inodeoffset)
|
||||
+ grub_le_to_cpu32 (dh.ino_chunk),
|
||||
grub_cpu_to_le16 (di.ino_offset));
|
||||
|
@ -332,7 +366,7 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir,
|
|||
buf = grub_malloc (grub_le_to_cpu16 (di.namelen) + 2);
|
||||
if (!buf)
|
||||
return 0;
|
||||
err = read_chunk (dir->data->disk, buf,
|
||||
err = read_chunk (dir->data, buf,
|
||||
grub_le_to_cpu16 (di.namelen) + 1,
|
||||
grub_le_to_cpu64 (dir->data->sb.diroffset)
|
||||
+ grub_le_to_cpu32 (dir->ino.dir.chunk), off);
|
||||
|
@ -370,7 +404,7 @@ make_root_node (struct grub_squash_data *data, struct grub_fshelp_node *root)
|
|||
grub_memset (root, 0, sizeof (*root));
|
||||
root->data = data;
|
||||
|
||||
return read_chunk (data->disk, &root->ino, sizeof (root->ino),
|
||||
return read_chunk (data, &root->ino, sizeof (root->ino),
|
||||
grub_le_to_cpu64 (data->sb.inodeoffset)
|
||||
+ grub_le_to_cpu16 (data->sb.root_ino_chunk),
|
||||
grub_cpu_to_le16 (data->sb.root_ino_offset));
|
||||
|
@ -445,48 +479,166 @@ grub_squash_open (struct grub_file *file, const char *name)
|
|||
}
|
||||
|
||||
file->data = data;
|
||||
data->ino = fdiro->ino;
|
||||
file->size = grub_le_to_cpu32 (fdiro->ino.file.size);
|
||||
data->ino.ino = fdiro->ino;
|
||||
data->ino.block_sizes = NULL;
|
||||
data->ino.cumulated_block_sizes = NULL;
|
||||
data->ino.ino_chunk = fdiro->ino_chunk;
|
||||
data->ino.ino_offset = fdiro->ino_offset;
|
||||
|
||||
if (fdiro->ino.type
|
||||
== grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR))
|
||||
file->size = grub_le_to_cpu64 (fdiro->ino.long_file.size);
|
||||
else
|
||||
file->size = grub_le_to_cpu32 (fdiro->ino.file.size);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
direct_read (struct grub_squash_data *data,
|
||||
struct grub_squash_cache_inode *ino,
|
||||
grub_off_t off, char *buf, grub_size_t len)
|
||||
{
|
||||
grub_err_t err;
|
||||
grub_off_t cumulated_uncompressed_size = 0;
|
||||
grub_uint64_t a;
|
||||
grub_size_t i;
|
||||
grub_size_t origlen = len;
|
||||
|
||||
if (ino->ino.type == grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR))
|
||||
a = grub_le_to_cpu64 (ino->ino.long_file.chunk);
|
||||
else
|
||||
a = grub_le_to_cpu32 (ino->ino.file.chunk);
|
||||
|
||||
if (!ino->block_sizes)
|
||||
{
|
||||
grub_off_t total_size;
|
||||
grub_size_t total_blocks;
|
||||
grub_size_t block_offset;
|
||||
if (ino->ino.type
|
||||
== grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR))
|
||||
{
|
||||
total_size = grub_le_to_cpu64 (ino->ino.long_file.size);
|
||||
block_offset = ((char *) &ino->ino.long_file.block_size
|
||||
- (char *) &ino->ino);
|
||||
}
|
||||
else
|
||||
{
|
||||
total_size = grub_le_to_cpu32 (ino->ino.file.size);
|
||||
block_offset = ((char *) &ino->ino.file.block_size
|
||||
- (char *) &ino->ino);
|
||||
}
|
||||
total_blocks = grub_divmod64 (total_size
|
||||
+ grub_le_to_cpu32 (data->sb.block_size) - 1,
|
||||
grub_le_to_cpu32 (data->sb.block_size),
|
||||
0);
|
||||
ino->block_sizes = grub_malloc (total_blocks
|
||||
* sizeof (ino->block_sizes[0]));
|
||||
ino->cumulated_block_sizes = grub_malloc (total_blocks
|
||||
* sizeof (ino->cumulated_block_sizes[0]));
|
||||
if (!ino->block_sizes || !ino->cumulated_block_sizes)
|
||||
{
|
||||
grub_free (ino->block_sizes);
|
||||
grub_free (ino->cumulated_block_sizes);
|
||||
ino->block_sizes = 0;
|
||||
ino->cumulated_block_sizes = 0;
|
||||
return -1;
|
||||
}
|
||||
err = read_chunk (data, ino->block_sizes,
|
||||
total_blocks * sizeof (ino->block_sizes[0]),
|
||||
grub_le_to_cpu64 (data->sb.inodeoffset)
|
||||
+ ino->ino_chunk,
|
||||
ino->ino_offset + block_offset);
|
||||
if (err)
|
||||
{
|
||||
grub_free (ino->block_sizes);
|
||||
grub_free (ino->cumulated_block_sizes);
|
||||
ino->block_sizes = 0;
|
||||
ino->cumulated_block_sizes = 0;
|
||||
return -1;
|
||||
}
|
||||
ino->cumulated_block_sizes[0] = 0;
|
||||
for (i = 1; i < total_blocks; i++)
|
||||
ino->cumulated_block_sizes[i] = ino->cumulated_block_sizes[i - 1]
|
||||
+ (grub_le_to_cpu32 (ino->block_sizes[i - 1]) & ~SQUASH_BLOCK_FLAGS);
|
||||
}
|
||||
|
||||
if (a == 0)
|
||||
a = sizeof (struct grub_squash_super);
|
||||
i = grub_divmod64 (off, grub_le_to_cpu32 (data->sb.block_size), 0);
|
||||
cumulated_uncompressed_size = grub_le_to_cpu32 (data->sb.block_size)
|
||||
* (grub_disk_addr_t) i;
|
||||
while (cumulated_uncompressed_size < off + len)
|
||||
{
|
||||
grub_size_t boff, read;
|
||||
boff = off - cumulated_uncompressed_size;
|
||||
read = grub_le_to_cpu32 (data->sb.block_size) - boff;
|
||||
if (read > len)
|
||||
read = len;
|
||||
if (!(ino->block_sizes[i] & SQUASH_BLOCK_UNCOMPRESSED))
|
||||
err = grub_zlib_disk_read (data->disk,
|
||||
ino->cumulated_block_sizes[i] + a,
|
||||
boff, buf, read);
|
||||
else
|
||||
err = grub_disk_read (data->disk,
|
||||
(ino->cumulated_block_sizes[i] + a + boff)
|
||||
>> GRUB_DISK_SECTOR_BITS,
|
||||
(ino->cumulated_block_sizes[i] + a + boff)
|
||||
& (GRUB_DISK_SECTOR_SIZE - 1),
|
||||
read, buf);
|
||||
if (err)
|
||||
return -1;
|
||||
off += read;
|
||||
len -= read;
|
||||
buf += read;
|
||||
cumulated_uncompressed_size += grub_le_to_cpu32 (data->sb.block_size);
|
||||
i++;
|
||||
}
|
||||
return origlen;
|
||||
}
|
||||
|
||||
|
||||
static grub_ssize_t
|
||||
grub_squash_read_data (struct grub_squash_data *data,
|
||||
grub_disk_t disk, const struct grub_squash_inode *ino,
|
||||
struct grub_squash_cache_inode *ino,
|
||||
grub_off_t off, char *buf, grub_size_t len)
|
||||
{
|
||||
grub_err_t err;
|
||||
grub_uint64_t a, b;
|
||||
grub_uint32_t fragment;
|
||||
int compressed = 0;
|
||||
struct grub_squash_frag_desc frag;
|
||||
|
||||
if (grub_le_to_cpu16 (ino->file.fragment) == 0xffff)
|
||||
if (ino->ino.type == grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR))
|
||||
{
|
||||
if (grub_le_to_cpu32 (ino->file.chunk))
|
||||
a = grub_le_to_cpu32 (ino->file.chunk);
|
||||
else
|
||||
a = sizeof (struct grub_squash_super);
|
||||
compressed = !(data->sb.flags & SQUASH_FLAG_UNCOMPRESSED_DATA);
|
||||
a = grub_le_to_cpu64 (ino->ino.long_file.chunk);
|
||||
fragment = grub_le_to_cpu32 (ino->ino.long_file.fragment);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct grub_squash_frag_desc frag;
|
||||
err = read_chunk (disk, &frag, sizeof (frag),
|
||||
data->fragments, sizeof (frag)
|
||||
* grub_le_to_cpu16 (ino->file.fragment));
|
||||
if (err)
|
||||
return -1;
|
||||
a = grub_le_to_cpu64 (frag.offset) + grub_le_to_cpu32 (ino->file.chunk);
|
||||
compressed = !(data->sb.flags & SQUASH_FLAG_UNCOMPRESSED_FRAGMENTS);
|
||||
a = grub_le_to_cpu32 (ino->ino.file.chunk);
|
||||
fragment = grub_le_to_cpu32 (ino->ino.file.fragment);
|
||||
}
|
||||
|
||||
b = grub_le_to_cpu32 (data->ino.file.offset) + off;
|
||||
|
||||
if (fragment == 0xffffffff)
|
||||
return direct_read (data, ino, off, buf, len);
|
||||
|
||||
err = read_chunk (data, &frag, sizeof (frag),
|
||||
data->fragments, sizeof (frag) * fragment);
|
||||
if (err)
|
||||
return -1;
|
||||
a += grub_le_to_cpu64 (frag.offset);
|
||||
compressed = !(frag.size & SQUASH_BLOCK_UNCOMPRESSED);
|
||||
if (ino->ino.type == grub_cpu_to_le16_compile_time (SQUASH_TYPE_LONG_REGULAR))
|
||||
b = grub_le_to_cpu64 (ino->ino.long_file.offset) + off;
|
||||
else
|
||||
b = grub_le_to_cpu32 (ino->ino.file.offset) + off;
|
||||
|
||||
/* FIXME: cache uncompressed chunks. */
|
||||
if (compressed)
|
||||
err = grub_zlib_disk_read (disk, a, b, buf, len);
|
||||
err = grub_zlib_disk_read (data->disk, a, b, buf, len);
|
||||
else
|
||||
err = grub_disk_read (disk, (a + b) >> GRUB_DISK_SECTOR_BITS,
|
||||
err = grub_disk_read (data->disk, (a + b) >> GRUB_DISK_SECTOR_BITS,
|
||||
(a + b) & (GRUB_DISK_SECTOR_SIZE - 1), len, buf);
|
||||
if (err)
|
||||
return -1;
|
||||
|
@ -498,7 +650,7 @@ grub_squash_read (grub_file_t file, char *buf, grub_size_t len)
|
|||
{
|
||||
struct grub_squash_data *data = file->data;
|
||||
|
||||
return grub_squash_read_data (data, file->device->disk, &data->ino,
|
||||
return grub_squash_read_data (data, &data->ino,
|
||||
file->offset, buf, len);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue