--- linux-privs/fs/ext2/res_fork.c.orig Mon Apr 14 20:29:51 1997 +++ linux-privs/fs/ext2/res_fork.c Wed Apr 23 19:49:12 1997 @@ -220,7 +220,7 @@ sz); err = 0; } - brelse(bh); /* tidy up */ + brelse(bh); /* tidy up */ return err; } @@ -233,6 +233,7 @@ /* jump to the next header in this block */ res.rf_data += len; + /* XXX: BLOCK_SIZE ->? inode->i_sb->s_blocksize */ if (res.rf_data > BLOCK_SIZE + (__u8 *) bh->b_data) { ext2_error(inode->i_sb, "ext2_get_resource", "corrupted resource fork (%u)", @@ -287,14 +288,14 @@ int ext2_put_resource(struct inode *inode, const struct resource_struct * const resource) { - __u32 block, first, goal; + __u32 block, first, goal, before; union ext2_rfork_reader res; int err, flags; struct buffer_head *bh; - if(!(inode->i_sb->u.ext2_sb.s_feature_ro_compat & + if (!(inode->i_sb->u.ext2_sb.s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_RES_FORK)) { - if(!resource->size && !resource->flags) + if (!resource->size && !resource->flags) return 0; return -EINVAL; } @@ -312,6 +313,7 @@ /* Need to know inode is OK (above) before checking resource length? */ + /* XXX: BLOCK_SIZE ->? inode->i_sb->s_blocksize */ if (resource->size > BLOCK_SIZE - ( sizeof(struct ext2_resource_fork_head_struct) + sizeof(struct ext2_resource_head_struct) )) { @@ -321,6 +323,8 @@ return -EINVAL; } + before = 0; /* there is no block before this one */ + #define JUST_DELETE 01 #define ALL_DONE 02 #define DIRTY_BUFFER 04 @@ -414,8 +418,8 @@ /* Found an old version of this resource */ if (!(flags & JUST_DELETE) && - le16_to_cpu(res.rf_res_head->size) == - resource->size) { + le16_to_cpu(res.rf_res_head->size) + == resource->size) { /* Overwrite old with new */ ext2_copy_resource(resource, res); @@ -445,26 +449,68 @@ /* Else, search from same place */ } - /* XXX - if we make an empty block, it * - * might be wise to remove it from chain? */ + /* XXX - a completely empty block? */ + if (res.rf_res_head->id == 0 + && (void *) (-1+res.rf_block_head) + == (void *) bh->b_data) { + + res_debug("deleting resource %u\n", block); + /* We can delete this fork. */ + brelse(bh); + bh = NULL; + ext2_free_blocks(inode, block, 1); + block = before; + + /* we link the predecessor + ('before') block to the + 'next' one */ + + if (before) { + /* XXX - load 'before' block */ + bh = bread(inode->i_dev, block, + inode->i_sb->s_blocksize); + /* XXX - point it at 'next' */ + if (bh == NULL || err) { + ext2_panic(inode->i_sb, "ext2_put_resource", + "failed to reload fork %u", + block); + if (bh) + brelse(bh); + return -EIO; + } + res.rf_data = (__u8 *) bh->b_data; + res.rf_block_head->next_fork_block + = cpu_to_le32(next); + flags |= DIRTY_BUFFER; + } else { /* first block off inode */ + inode->u.ext2_i.i_resource_fork = next; + /* mark inode changed */ + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + inode->i_dirt = 1; + } + + /* load next block */ + break; + } flags |= DIRTY_BUFFER; } else { /* Some other resource - ignore it */ - res.rf_data += - le16_to_cpu(res.rf_res_head->length); + res.rf_data += le16_to_cpu(res.rf_res_head->length); } } - if (flags & DIRTY_BUFFER) - /* This buffer has been changed */ - mark_buffer_dirty(bh, 1); - - brelse(bh); + if (bh) { + if (flags & DIRTY_BUFFER) + /* This buffer has been changed */ + mark_buffer_dirty(bh, 1); + brelse(bh); + } if (flags & ALL_DONE) return 0; + before = block; block = next; }