+2005-01-25 Theodore Ts'o <tytso@mit.edu>
+
+ * ext2fs.h: Add definition of struct ext2_inode_large
+
+ * ext2_fs.h: Add new function prototypes
+
+ * ext_attr.c (ext2fs_read_ext_attr, ext2fs_write_ext_attr): The
+ ext2fs_swap_ext_attr() has been moved to swapfs.c, and
+ given a new argument, has_header.
+
+ * swapfs.c (ext2fs_swap_ext_attr): Moved from ext_attr.c, and
+ takes an argument which controls whether or not there is
+ an EA header which needs to be byteswaped.
+ (ext2fs_swap_inode_full): New function which byte-swaps
+ the EA in inode.
+
+ * inode.c (ext2fs_get_next_inode_full, ext2fs_read_inode_full,
+ ext2fs_write_inode_full): New functions, originally from
+ Alex Tomas, but which needed to be substantially fixed so
+ that the tests wouldn't cause major stack overwrite bugs
+ in byte-swapping is enabled.
+
2005-01-18 Theodore Ts'o <tytso@mit.edu>
* Makefile.in: Fix the kernel compile-time echo commands to be
} osd2; /* OS dependent 2 */
};
+/*
+ * Permanent part of an large inode on the disk
+ */
+struct ext2_inode_large {
+ __u16 i_mode; /* File mode */
+ __u16 i_uid; /* Low 16 bits of Owner Uid */
+ __u32 i_size; /* Size in bytes */
+ __u32 i_atime; /* Access time */
+ __u32 i_ctime; /* Creation time */
+ __u32 i_mtime; /* Modification time */
+ __u32 i_dtime; /* Deletion Time */
+ __u16 i_gid; /* Low 16 bits of Group Id */
+ __u16 i_links_count; /* Links count */
+ __u32 i_blocks; /* Blocks count */
+ __u32 i_flags; /* File flags */
+ union {
+ struct {
+ __u32 l_i_reserved1;
+ } linux1;
+ struct {
+ __u32 h_i_translator;
+ } hurd1;
+ struct {
+ __u32 m_i_reserved1;
+ } masix1;
+ } osd1; /* OS dependent 1 */
+ __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
+ __u32 i_generation; /* File version (for NFS) */
+ __u32 i_file_acl; /* File ACL */
+ __u32 i_dir_acl; /* Directory ACL */
+ __u32 i_faddr; /* Fragment address */
+ union {
+ struct {
+ __u8 l_i_frag; /* Fragment number */
+ __u8 l_i_fsize; /* Fragment size */
+ __u16 i_pad1;
+ __u16 l_i_uid_high; /* these 2 fields */
+ __u16 l_i_gid_high; /* were reserved2[0] */
+ __u32 l_i_reserved2;
+ } linux2;
+ struct {
+ __u8 h_i_frag; /* Fragment number */
+ __u8 h_i_fsize; /* Fragment size */
+ __u16 h_i_mode_high;
+ __u16 h_i_uid_high;
+ __u16 h_i_gid_high;
+ __u32 h_i_author;
+ } hurd2;
+ struct {
+ __u8 m_i_frag; /* Fragment number */
+ __u8 m_i_fsize; /* Fragment size */
+ __u16 m_pad1;
+ __u32 m_i_reserved2[2];
+ } masix2;
+ } osd2; /* OS dependent 2 */
+ __u16 i_extra_isize;
+ __u16 i_pad1;
+};
+
#define i_size_high i_dir_acl
#if defined(__KERNEL__) || defined(__linux__)
extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir);
/* ext_attr.c */
-void ext2fs_swap_ext_attr(ext2_filsys fs, char *to, char *from);
extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf);
extern errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block,
void *buf);
/* inode.c */
extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
+extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan,
+ ext2_ino_t *ino,
+ struct ext2_inode *inode,
+ int bufsize);
extern errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
ext2_inode_scan *ret_scan);
extern void ext2fs_close_inode_scan(ext2_inode_scan scan);
void *done_group_data);
extern int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
int clear_flags);
+extern errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode * inode,
+ int bufsize);
extern errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode * inode);
+extern errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode * inode,
+ int bufsize);
extern errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode * inode);
extern errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks);
ext2fs_generic_bitmap *dest);
/* swapfs.c */
+extern void ext2fs_swap_ext_attr(char *to, char *from, int bufsize,
+ int has_header);
extern void ext2fs_swap_super(struct ext2_super_block * super);
extern void ext2fs_swap_group_desc(struct ext2_group_desc *gdp);
+extern void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
+ struct ext2_inode_large *f, int hostorder,
+ int bufsize);
extern void ext2fs_swap_inode(ext2_filsys fs,struct ext2_inode *t,
struct ext2_inode *f, int hostorder);
#include "ext2fs.h"
-#ifdef EXT2FS_ENABLE_SWAPFS
-void ext2fs_swap_ext_attr(ext2_filsys fs, char *to, char *from)
-{
- struct ext2_ext_attr_header *from_header =
- (struct ext2_ext_attr_header *)from;
- struct ext2_ext_attr_header *to_header =
- (struct ext2_ext_attr_header *)to;
- struct ext2_ext_attr_entry *from_entry, *to_entry;
- char *from_end = (char *)from_header + fs->blocksize;
- int n;
-
- if (to_header != from_header)
- memcpy(to_header, from_header, fs->blocksize);
-
- to_header->h_magic = ext2fs_swab32(from_header->h_magic);
- to_header->h_blocks = ext2fs_swab32(from_header->h_blocks);
- to_header->h_refcount = ext2fs_swab32(from_header->h_refcount);
- for (n=0; n<4; n++)
- to_header->h_reserved[n] =
- ext2fs_swab32(from_header->h_reserved[n]);
-
- from_entry = (struct ext2_ext_attr_entry *)(from_header+1);
- to_entry = (struct ext2_ext_attr_entry *)(to_header+1);
- while ((char *)from_entry < from_end && *(__u32 *)from_entry) {
- to_entry->e_value_offs =
- ext2fs_swab16(from_entry->e_value_offs);
- to_entry->e_value_block =
- ext2fs_swab32(from_entry->e_value_block);
- to_entry->e_value_size =
- ext2fs_swab32(from_entry->e_value_size);
- from_entry = EXT2_EXT_ATTR_NEXT(from_entry);
- to_entry = EXT2_EXT_ATTR_NEXT(to_entry);
- }
-}
-#endif
-
errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf)
{
errcode_t retval;
#ifdef EXT2FS_ENABLE_SWAPFS
if ((fs->flags & (EXT2_FLAG_SWAP_BYTES|
EXT2_FLAG_SWAP_BYTES_READ)) != 0)
- ext2fs_swap_ext_attr(fs, buf, buf);
+ ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1);
#endif
return 0;
}
if (retval)
return retval;
write_buf = buf;
- ext2fs_swap_ext_attr(fs, buf, inbuf);
+ ext2fs_swap_ext_attr(buf, inbuf, fs->blocksize, 1);
} else
#endif
write_buf = (char *) inbuf;
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
}
#endif
-errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
- struct ext2_inode *inode)
+errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
+ struct ext2_inode *inode, int bufsize)
{
errcode_t retval;
int extra_bytes = 0;
#ifdef EXT2FS_ENABLE_SWAPFS
if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
(scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
- ext2fs_swap_inode(scan->fs, inode,
- (struct ext2_inode *) scan->temp_buffer, 0);
+ ext2fs_swap_inode_full(scan->fs,
+ (struct ext2_inode_large *) inode,
+ (struct ext2_inode_large *) scan->temp_buffer,
+ 0, bufsize);
else
#endif
*inode = *((struct ext2_inode *) scan->temp_buffer);
#ifdef EXT2FS_ENABLE_SWAPFS
if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
(scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
- ext2fs_swap_inode(scan->fs, inode,
- (struct ext2_inode *) scan->ptr, 0);
+ ext2fs_swap_inode_full(scan->fs,
+ (struct ext2_inode_large *) inode,
+ (struct ext2_inode_large *) scan->ptr,
+ 0, bufsize);
else
#endif
- *inode = *((struct ext2_inode *) scan->ptr);
+ memcpy(inode, scan->ptr, bufsize);
scan->ptr += scan->inode_size;
scan->bytes_left -= scan->inode_size;
if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
return retval;
}
+errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
+ struct ext2_inode *inode)
+{
+ return ext2fs_get_next_inode_full(scan, ino, inode,
+ sizeof(struct ext2_inode));
+}
+
/*
* Functions to read and write a single inode.
*/
-errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino,
- struct ext2_inode * inode)
+errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode * inode, int bufsize)
{
unsigned long group, block, block_nr, offset;
char *ptr;
errcode_t retval;
- int clen, i, inodes_per_block;
- unsigned int length;
+ int clen, i, inodes_per_block, length;
io_channel io;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
return retval;
}
/* Check to see if it's in the inode cache */
- for (i=0; i < fs->icache->cache_size; i++) {
- if (fs->icache->cache[i].ino == ino) {
- *inode = fs->icache->cache[i].inode;
- return 0;
+ if (bufsize == sizeof(struct ext2_inode)) {
+ /* only old good inode can be retrieve from the cache */
+ for (i=0; i < fs->icache->cache_size; i++) {
+ if (fs->icache->cache[i].ino == ino) {
+ *inode = fs->icache->cache[i].inode;
+ return 0;
+ }
}
}
if ((ino == 0) || (ino > fs->super->s_inodes_count))
block;
io = fs->io;
}
- if (block_nr != fs->icache->buffer_blk) {
- retval = io_channel_read_blk(io, block_nr, 1,
- fs->icache->buffer);
- if (retval)
- return retval;
- fs->icache->buffer_blk = block_nr;
- }
offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
- ptr = ((char *) fs->icache->buffer) + (unsigned) offset;
- memset(inode, 0, sizeof(struct ext2_inode));
length = EXT2_INODE_SIZE(fs->super);
- if (length > sizeof(struct ext2_inode))
- length = sizeof(struct ext2_inode);
-
- if ((offset + length) > (unsigned) EXT2_BLOCK_SIZE(fs->super)) {
- clen = (int) (EXT2_BLOCK_SIZE(fs->super) - offset);
- memcpy((char *) inode, ptr, clen);
- length -= clen;
-
- retval = io_channel_read_blk(io, block_nr+1, 1,
- fs->icache->buffer);
- if (retval) {
- fs->icache->buffer_blk = 0;
- return retval;
+ if (bufsize < length)
+ length = bufsize;
+
+ ptr = (char *) inode;
+ while (length) {
+ clen = length;
+ if ((offset + length) > fs->blocksize)
+ clen = fs->blocksize - offset;
+
+ if (block_nr != fs->icache->buffer_blk) {
+ retval = io_channel_read_blk(io, block_nr, 1,
+ fs->icache->buffer);
+ if (retval)
+ return retval;
+ fs->icache->buffer_blk = block_nr;
}
- fs->icache->buffer_blk = block_nr+1;
-
- memcpy(((char *) inode) + clen,
- fs->icache->buffer, length);
- } else
- memcpy((char *) inode, ptr, length);
-
+
+ memcpy(ptr, ((char *) fs->icache->buffer) + (unsigned) offset,
+ clen);
+
+ offset = 0;
+ length -= clen;
+ ptr += clen;
+ block_nr++;
+ }
+
#ifdef EXT2FS_ENABLE_SWAPFS
if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
(fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
- ext2fs_swap_inode(fs, inode, inode, 0);
+ ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) inode,
+ (struct ext2_inode_large *) inode,
+ 0, length);
#endif
/* Update the inode cache */
return 0;
}
-errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
- struct ext2_inode * inode)
+errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode * inode)
+{
+ return ext2fs_read_inode_full(fs, ino, inode,
+ sizeof(struct ext2_inode));
+}
+
+errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode * inode, int bufsize)
{
unsigned long group, block, block_nr, offset;
- errcode_t retval;
- struct ext2_inode temp_inode;
+ errcode_t retval = 0;
+ struct ext2_inode_large temp_inode, *w_inode;
char *ptr;
- int clen, i;
- unsigned int length;
+ int clen, i, length;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
if ((ino == 0) || (ino > fs->super->s_inodes_count))
return EXT2_ET_BAD_INODE_NUM;
+ length = bufsize;
+ if (length < EXT2_INODE_SIZE(fs->super))
+ length = EXT2_INODE_SIZE(fs->super);
+
+ if (length > (int) sizeof(struct ext2_inode_large)) {
+ w_inode = malloc(length);
+ if (!w_inode)
+ return ENOMEM;
+ } else
+ w_inode = &temp_inode;
+ memset(w_inode, 0, length);
+
#ifdef EXT2FS_ENABLE_SWAPFS
if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
(fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
- ext2fs_swap_inode(fs, &temp_inode, inode, 1);
+ ext2fs_swap_inode_full(fs, w_inode,
+ (struct ext2_inode_large *) inode,
+ 1, bufsize);
else
#endif
- memcpy(&temp_inode, inode, sizeof(struct ext2_inode));
+ memcpy(w_inode, inode, bufsize);
group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
if (!fs->group_desc[(unsigned) group].bg_inode_table)
return EXT2_ET_MISSING_INODE_TABLE;
block_nr = fs->group_desc[(unsigned) group].bg_inode_table + block;
+
offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
- ptr = (char *) fs->icache->buffer + (unsigned) offset;
length = EXT2_INODE_SIZE(fs->super);
- clen = length;
- if (length > sizeof(struct ext2_inode))
- length = sizeof(struct ext2_inode);
-
- if (fs->icache->buffer_blk != block_nr) {
- retval = io_channel_read_blk(fs->io, block_nr, 1,
- fs->icache->buffer);
- if (retval)
- return retval;
- fs->icache->buffer_blk = block_nr;
- }
-
- if ((offset + length) > (unsigned) EXT2_BLOCK_SIZE(fs->super)) {
- clen = (int) (EXT2_BLOCK_SIZE(fs->super) - offset);
- length -= clen;
- } else {
- length = 0;
- }
- memcpy(ptr, &temp_inode, clen);
- retval = io_channel_write_blk(fs->io, block_nr, 1, fs->icache->buffer);
- if (retval)
- return retval;
+ if (length > bufsize)
+ length = bufsize;
- if (length) {
- retval = io_channel_read_blk(fs->io, ++block_nr, 1,
- fs->icache->buffer);
- if (retval) {
- fs->icache->buffer_blk = 0;
- return retval;
+ ptr = (char *) w_inode;
+
+ while (length) {
+ clen = length;
+ if ((offset + length) > fs->blocksize)
+ clen = fs->blocksize - offset;
+
+ if (fs->icache->buffer_blk != block_nr) {
+ retval = io_channel_read_blk(fs->io, block_nr, 1,
+ fs->icache->buffer);
+ if (retval)
+ goto errout;
+ fs->icache->buffer_blk = block_nr;
}
- fs->icache->buffer_blk = block_nr;
- memcpy(fs->icache->buffer, ((char *) &temp_inode) + clen,
- length);
- retval = io_channel_write_blk(fs->io, block_nr, 1,
+
+ memcpy((char *) fs->icache->buffer + (unsigned) offset,
+ ptr, clen);
+
+ retval = io_channel_write_blk(fs->io, block_nr, 1,
fs->icache->buffer);
if (retval)
- return retval;
+ goto errout;
+
+ offset = 0;
+ ptr += clen;
+ length -= clen;
+ block_nr++;
}
-
+
fs->flags |= EXT2_FLAG_CHANGED;
- return 0;
+errout:
+ if (w_inode && w_inode != &temp_inode)
+ free(w_inode);
+ return retval;
}
+errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode *inode)
+{
+ return ext2fs_write_inode_full(fs, ino, inode,
+ sizeof(struct ext2_inode));
+}
+
errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)
{
struct ext2_inode inode;
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
+#include <string.h>
#include <time.h>
#include "ext2_fs.h"
#include "ext2fs.h"
+#include <ext2fs/ext2_ext_attr.h>
#ifdef EXT2FS_ENABLE_SWAPFS
void ext2fs_swap_super(struct ext2_super_block * sb)
gdp->bg_used_dirs_count = ext2fs_swab16(gdp->bg_used_dirs_count);
}
-void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode *t,
- struct ext2_inode *f, int hostorder)
+void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, int has_header)
+{
+ struct ext2_ext_attr_header *from_header =
+ (struct ext2_ext_attr_header *)from;
+ struct ext2_ext_attr_header *to_header =
+ (struct ext2_ext_attr_header *)to;
+ struct ext2_ext_attr_entry *from_entry, *to_entry;
+ char *from_end = (char *)from_header + bufsize;
+ int n;
+
+ if (to_header != from_header)
+ memcpy(to_header, from_header, bufsize);
+
+ from_entry = (struct ext2_ext_attr_entry *)from_header;
+ to_entry = (struct ext2_ext_attr_entry *)to_header;
+
+ if (has_header) {
+ to_header->h_magic = ext2fs_swab32(from_header->h_magic);
+ to_header->h_blocks = ext2fs_swab32(from_header->h_blocks);
+ to_header->h_refcount = ext2fs_swab32(from_header->h_refcount);
+ for (n=0; n<4; n++)
+ to_header->h_reserved[n] =
+ ext2fs_swab32(from_header->h_reserved[n]);
+ from_entry = (struct ext2_ext_attr_entry *)(from_header+1);
+ to_entry = (struct ext2_ext_attr_entry *)(to_header+1);
+ }
+
+ while ((char *)from_entry < from_end && *(__u32 *)from_entry) {
+ to_entry->e_value_offs =
+ ext2fs_swab16(from_entry->e_value_offs);
+ to_entry->e_value_block =
+ ext2fs_swab32(from_entry->e_value_block);
+ to_entry->e_value_size =
+ ext2fs_swab32(from_entry->e_value_size);
+ from_entry = EXT2_EXT_ATTR_NEXT(from_entry);
+ to_entry = EXT2_EXT_ATTR_NEXT(to_entry);
+ }
+}
+
+void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
+ struct ext2_inode_large *f, int hostorder,
+ int bufsize)
{
unsigned i;
int islnk = 0;
-
+ __u32 *eaf, *eat;
+
if (hostorder && LINUX_S_ISLNK(f->i_mode))
islnk = 1;
t->i_mode = ext2fs_swab16(f->i_mode);
t->i_flags = ext2fs_swab32(f->i_flags);
t->i_file_acl = ext2fs_swab32(f->i_file_acl);
t->i_dir_acl = ext2fs_swab32(f->i_dir_acl);
- if (!islnk || ext2fs_inode_data_blocks(fs, t)) {
+ if (!islnk || ext2fs_inode_data_blocks(fs, (struct ext2_inode *)t)) {
for (i = 0; i < EXT2_N_BLOCKS; i++)
t->i_block[i] = ext2fs_swab32(f->i_block[i]);
} else if (t != f) {
ext2fs_swab32(f->osd2.masix2.m_i_reserved2[1]);
break;
}
+
+ if (bufsize < (int) (sizeof(struct ext2_inode) + sizeof(__u16)))
+ return; /* no i_extra_isize field */
+
+ t->i_extra_isize = ext2fs_swab16(f->i_extra_isize);
+ if (t->i_extra_isize > EXT2_INODE_SIZE(fs->super) -
+ sizeof(struct ext2_inode)) {
+ /* this is error case: i_extra_size is too large */
+ return;
+ }
+
+ i = sizeof(struct ext2_inode) + t->i_extra_isize + sizeof(__u32);
+ if (bufsize < (int) i)
+ return; /* no space for EA magic */
+
+ eaf = (__u32 *) (((char *) f) + sizeof(struct ext2_inode) +
+ f->i_extra_isize);
+
+ if (ext2fs_swab32(*eaf) != EXT2_EXT_ATTR_MAGIC)
+ return; /* it seems no magic here */
+
+ eat = (__u32 *) (((char *) t) + sizeof(struct ext2_inode) +
+ f->i_extra_isize);
+ *eat = ext2fs_swab32(*eaf);
+
+ /* convert EA(s) */
+ ext2fs_swap_ext_attr((char *) (eat + 1), (char *) (eaf + 1),
+ bufsize - sizeof(struct ext2_inode) -
+ t->i_extra_isize - sizeof(__u32), 0);
+
}
+
+void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode *t,
+ struct ext2_inode *f, int hostorder)
+{
+ ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) t,
+ (struct ext2_inode_large *) f, hostorder,
+ sizeof(struct ext2_inode));
+}
+
#endif