summaryrefslogtreecommitdiff
path: root/ext2fs/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext2fs/dir.c')
-rw-r--r--ext2fs/dir.c58
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;