diff options
Diffstat (limited to 'ext2fs/dir.c')
-rw-r--r-- | ext2fs/dir.c | 58 |
1 files changed, 42 insertions, 16 deletions
diff --git a/ext2fs/dir.c b/ext2fs/dir.c index 5e6e1a53..4523071d 100644 --- a/ext2fs/dir.c +++ b/ext2fs/dir.c @@ -80,6 +80,10 @@ struct dirstat /* For stat HERE_TIS, type REMOVE, this is the address of the immediately previous direct in this directory block, or zero if this is the first. */ struct ext2_dir_entry *preventry; + + /* For stat COMPRESS, this is the number of bytes needed to be copied + in order to undertake the compression. */ + size_t nbytes; }; size_t diskfs_dirstat_size = sizeof (struct dirstat); @@ -318,17 +322,22 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name, { int nfree = 0; int needed = 0; - int countup = 0; vm_address_t currentoff, prevoff; - struct ext2_dir_entry *entry; + struct ext2_dir_entry *entry = 0; int nentries = 0; - - if (ds && ds->stat == LOOKING) + size_t nbytes = 0; + int looking = 0; + int countcopies = 0; + int consider_compress = 0; + + if (ds && (ds->stat == LOOKING + || ds->stat == COMPRESS)) { - countup = 1; + looking = 1; + countcopies = 1; needed = EXT2_DIR_REC_LEN (namelen); } - + for (currentoff = blockaddr, prevoff = 0; currentoff < blockaddr + DIRBLKSIZ; prevoff = currentoff, currentoff += entry->rec_len) @@ -348,35 +357,41 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name, return ENOENT; } - if (countup) + if (looking || countcopies) { int thisfree; + /* Count how much free space this entry has in it. */ if (entry->inode == 0) thisfree = entry->rec_len; else thisfree = entry->rec_len - EXT2_DIR_REC_LEN (entry->name_len); + + /* If this isn't at the front of the block, then it will + have to be copied if we do a compression; count the + number of bytes there too. */ + if (countcopies && currentoff != blockaddr) + nbytes += EXT2_DIR_REC_LEN (entry->name_len); + if (ds->stat == COMPRESS && nbytes > ds->nbytes) + /* The previously found compress is better than + this one, so don't bother counting any more. */ + countcopies = 0; + if (thisfree >= needed) { ds->type = CREATE; ds->stat = entry->inode == 0 ? TAKE : SHRINK; ds->entry = entry; ds->idx = idx; - countup = 0; + looking = countcopies = 0; } else { nfree += thisfree; if (nfree >= needed) - { - ds->type = CREATE; - ds->stat = COMPRESS; - ds->entry = (struct ext2_dir_entry *) blockaddr; - ds->idx = idx; - countup = 0; - } - } + consider_compress = 1; + } } if (entry->inode) @@ -389,6 +404,17 @@ dirscanblock (vm_address_t blockaddr, struct node *dp, int idx, char *name, break; } + if (consider_compress + && (ds->type == LOOKING + || (ds->type == COMPRESS && ds->nbytes > nbytes))) + { + ds->type = CREATE; + ds->stat = COMPRESS; + ds->entry = (struct ext2_dir_entry *) blockaddr; + ds->idx = idx; + ds->nbytes = nbytes; + } + if (currentoff >= blockaddr + DIRBLKSIZ) { int i; |