From: Lawrence S. <ljs...@us...> - 2013-04-18 02:00:41
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "A pseudo Operating System for the Dreamcast.". The branch, master has been updated via 5989a9630505b63b3b167b5609b0d30a0c58e532 (commit) from d6bd897b816bd5efc6525b3618b1ddbb008c1a1a (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 5989a9630505b63b3b167b5609b0d30a0c58e532 Author: Lawrence Sebald <ljs...@us...> Date: Wed Apr 17 21:59:02 2013 -0400 Continuing with write support in libkosext2fs: 1. Allow creating new blank files with open (and O_CREAT). 2. Allow truncation of existing files with open (and O_TRUNC). 3. Allow opening files for writing (although write isn't implemented, so it is still a bit silly to do except to create blank files or truncate existing ones). ----------------------------------------------------------------------- Summary of changes: addons/libkosext2fs/fs_ext2.c | 122 +++++++++++++++++++++++++++++++++++++--- addons/libkosext2fs/inode.c | 73 ++++++++++++++++--------- addons/libkosext2fs/inode.h | 4 + 3 files changed, 163 insertions(+), 36 deletions(-) diff --git a/addons/libkosext2fs/fs_ext2.c b/addons/libkosext2fs/fs_ext2.c index b87b56f..e936d67 100644 --- a/addons/libkosext2fs/fs_ext2.c +++ b/addons/libkosext2fs/fs_ext2.c @@ -47,16 +47,84 @@ static struct { fs_ext2_fs_t *fs; } fh[MAX_EXT2_FILES]; +static int create_empty_file(fs_ext2_fs_t *fs, const char *fn, + ext2_inode_t **rinode, uint32_t *rinode_num) { + int irv; + ext2_inode_t *inode, *ninode; + uint32_t inode_num, ninode_num; + char *cp, *nd; + time_t now = time(NULL); + + if(!(fs->mount_flags & FS_EXT2_MOUNT_READWRITE)) + return -EROFS; + + /* Make a writable copy of the filename */ + if(!(cp = strdup(fn))) + return -ENOMEM; + + /* Separate our copy into the parent and the directory we want to create */ + if(!(nd = strrchr(cp, '/'))) { + free(cp); + return -ENOENT; + } + + /* Split the string. */ + *nd++ = 0; + + /* Find the parent of the directory we want to create. */ + if((irv = ext2_inode_by_path(fs->fs, cp, &inode, &inode_num, 1, NULL))) { + free(cp); + return -irv; + } + + /* Allocate a new inode for the new directory. */ + if(!(ninode = ext2_inode_alloc(fs->fs, inode_num, &irv, &ninode_num))) { + ext2_inode_put(inode); + free(cp); + return -irv; + } + + /* Fill in the inode. Copy most of the interesting parts from the parent. */ + ninode->i_mode = (inode->i_mode & ~EXT2_S_IFDIR) | EXT2_S_IFREG; + ninode->i_uid = inode->i_uid; + ninode->i_atime = ninode->i_ctime = ninode->i_mtime = now; + ninode->i_gid = inode->i_gid; + ninode->i_osd2.l_i_uid_high = inode->i_osd2.l_i_uid_high; + ninode->i_osd2.l_i_gid_high = inode->i_osd2.l_i_gid_high; + ninode->i_links_count = 1; + + /* Add an entry to the parent directory. */ + if((irv = ext2_dir_add_entry(fs->fs, inode, nd, ninode_num, ninode, + NULL))) { + ext2_inode_put(inode); + ext2_inode_deref(fs->fs, ninode_num, 1); + free(cp); + return -irv; + } + + /* Update the parent directory's times. */ + inode->i_mtime = inode->i_ctime = now; + ext2_inode_mark_dirty(inode); + + ext2_inode_put(inode); + free(cp); + *rinode = ninode; + *rinode_num = ninode_num; + return 0; +} + static void *fs_ext2_open(vfs_handler_t *vfs, const char *fn, int mode) { file_t fd; fs_ext2_fs_t *mnt = (fs_ext2_fs_t *)vfs->privdata; int rv; - /* We don't support writing for now... */ - if((mode & (O_WRONLY | O_TRUNC))) { - errno = EROFS; - return NULL; - } + /* Make sure if we're going to be writing to the file that the fs is mounted + read/write. */ + if((mode & (O_TRUNC | O_WRONLY)) && + !(mnt->mount_flags & FS_EXT2_MOUNT_READWRITE)) { + errno = EROFS; + return NULL; + } /* Find a free file handle */ mutex_lock(&ext2_mutex); @@ -78,19 +146,28 @@ static void *fs_ext2_open(vfs_handler_t *vfs, const char *fn, int mode) { if((rv = ext2_inode_by_path(mnt->fs, fn, &fh[fd].inode, &fh[fd].inode_num, 1, NULL))) { fh[fd].inode_num = 0; - ext2_inode_put(fh[fd].inode); - mutex_unlock(&ext2_mutex); if(rv == -ENOENT) { - if(mode & O_CREAT) - errno = EROFS; - else + if(mode & O_CREAT) { + if((rv = create_empty_file(mnt, fn, &fh[fd].inode, + &fh[fd].inode_num))) { + fh[fd].inode_num = 0; + mutex_unlock(&ext2_mutex); + errno = -rv; + return NULL; + } + + goto created; + } + else { errno = ENOENT; + } } else { errno = -rv; } + mutex_unlock(&ext2_mutex); return NULL; } @@ -113,10 +190,35 @@ static void *fs_ext2_open(vfs_handler_t *vfs, const char *fn, int mode) { return NULL; } +created: + /* Do we need to truncate the file? */ + if((mode & O_WRONLY) && (mode & O_TRUNC)) { + if((rv = ext2_inode_free_all(mnt->fs, fh[fd].inode, fh[fd].inode_num, + 0))) { + errno = -rv; + fh[fd].inode_num = 0; + ext2_inode_put(fh[fd].inode); + mutex_unlock(&ext2_mutex); + return NULL; + } + + /* Fix the times/sizes up. */ + fh[fd].inode->i_size = 0; + fh[fd].inode->i_dtime = 0; + fh[fd].inode->i_mtime = time(NULL); + ext2_inode_mark_dirty(fh[fd].inode); + } + /* Fill in the rest of the handle */ fh[fd].mode = mode; fh[fd].ptr = 0; fh[fd].fs = mnt; + + /* Are we appending (and writing, of course... appending without writing is + kinda silly, after all)? */ + if((mode & O_WRONLY) && (mode & O_APPEND)) + fh[fd].ptr = fh[fd].inode->i_size; + mutex_unlock(&ext2_mutex); return (void *)(fd + 1); diff --git a/addons/libkosext2fs/inode.c b/addons/libkosext2fs/inode.c index 7a3fca5..885cb27 100644 --- a/addons/libkosext2fs/inode.c +++ b/addons/libkosext2fs/inode.c @@ -524,8 +524,8 @@ static int free_tind_block(ext2_fs_t *fs, ext2_inode_t *inode, uint32_t iblk) { return rv; } -static int ext2_inode_free_all(ext2_fs_t *fs, ext2_inode_t *inode, - uint32_t inode_num) { +int ext2_inode_free_all(ext2_fs_t *fs, ext2_inode_t *inode, + uint32_t inode_num, int for_del) { uint32_t bg, index, blk; uint8_t *buf; uint32_t i; @@ -537,32 +537,34 @@ static int ext2_inode_free_all(ext2_fs_t *fs, ext2_inode_t *inode, if((rv = ext2_block_cache_wb(fs))) return rv; - /* Figure out what block group and index within that group the inode in - question is. */ - bg = (inode_num - 1) / fs->sb.s_inodes_per_group; - index = (inode_num - 1) % fs->sb.s_inodes_per_group; + if(for_del) { + /* Figure out what block group and index within that group the inode in + question is. */ + bg = (inode_num - 1) / fs->sb.s_inodes_per_group; + index = (inode_num - 1) % fs->sb.s_inodes_per_group; - if(!(buf = ext2_block_read(fs, fs->bg[bg].bg_inode_bitmap, &rv))) - return -EIO; + if(!(buf = ext2_block_read(fs, fs->bg[bg].bg_inode_bitmap, &rv))) + return -EIO; - /* Mark the inode as free in the bitmap and increase the counters. */ - ext2_bit_clear((uint32_t *)buf, index); - ext2_block_mark_dirty(fs, fs->bg[bg].bg_inode_bitmap); + /* Mark the inode as free in the bitmap and increase the counters. */ + ext2_bit_clear((uint32_t *)buf, index); + ext2_block_mark_dirty(fs, fs->bg[bg].bg_inode_bitmap); - ++fs->bg[bg].bg_free_inodes_count; - ++fs->sb.s_free_inodes_count; - fs->flags |= EXT2_FS_FLAG_SB_DIRTY; + ++fs->bg[bg].bg_free_inodes_count; + ++fs->sb.s_free_inodes_count; + fs->flags |= EXT2_FS_FLAG_SB_DIRTY; - /* Set the deletion time of the inode */ - inode->i_dtime = (uint32_t)time(NULL); - iinode->flags |= INODE_FLAG_DIRTY; + /* Set the deletion time of the inode */ + inode->i_dtime = (uint32_t)time(NULL); + iinode->flags |= INODE_FLAG_DIRTY; + } /* First look to see if there's any extended attributes... If so, free them up first. TODO: Should this only be checked for files, or can directories have extended attributes too? For now, assume that both can until we find some reason that assumption fails. */ - if(inode->i_file_acl) { + if(inode->i_file_acl && for_del) { if(!(buf = ext2_block_read(fs, inode->i_file_acl, &rv))) return -EIO; @@ -579,6 +581,10 @@ static int ext2_inode_free_all(ext2_fs_t *fs, ext2_inode_t *inode, ext2_block_mark_dirty(fs, inode->i_file_acl); inode->i_blocks -= sub; } + else if(inode->i_file_acl) { + /* We need to do this for now... We will reverse it later. */ + inode->i_blocks -= sub; + } /* Free the direct data blocks. Note that since fast symlinks have the i_blocks field in their inodes set to 0, we don't have to do anything @@ -592,34 +598,49 @@ static int ext2_inode_free_all(ext2_fs_t *fs, ext2_inode_t *inode, } if((rv = mark_block_free(fs, blk))) - return rv; + goto done; inode->i_blocks -= sub; + inode->i_block[i] = 0; + fs->flags |= EXT2_FS_FLAG_SB_DIRTY; } /* See if we're done already... */ if(!inode->i_blocks) - return 0; + goto done; /* Handle the singly-indirect block */ if((rv = free_ind_block(fs, inode, inode->i_block[12]))) - return rv; + goto done; + + inode->i_block[12] = 0; /* See if we're done now... */ if(!inode->i_blocks) - return 0; + goto done; /* Time to go through the doubly-indirect block... */ if((rv = free_dind_block(fs, inode, inode->i_block[13]))) - return rv; + goto done; + + inode->i_block[13] = 0; /* See if we're done now... */ if(!inode->i_blocks) - return 0; + goto done; /* Ugh... Really... A trebly-indirect block? At least we know we're done at this point... */ - return free_tind_block(fs, inode, inode->i_block[14]); + rv = free_tind_block(fs, inode, inode->i_block[14]); + + inode->i_block[14] = 0; + +done: + /* Restore the xattr block to the block count if needed. */ + if(inode->i_file_acl && !for_del) + inode->i_blocks = sub; + + return rv; } int ext2_inode_deref(ext2_fs_t *fs, uint32_t inode_num, int isdir) { @@ -658,7 +679,7 @@ int ext2_inode_deref(ext2_fs_t *fs, uint32_t inode_num, int isdir) { /* If the inode is not referenced anywhere anymore, free it */ if(!inode->i_links_count) - rv = ext2_inode_free_all(fs, inode, inode_num); + rv = ext2_inode_free_all(fs, inode, inode_num, 1); /* Release our reference to the inode, putting it in the free pool */ ext2_inode_put(inode); diff --git a/addons/libkosext2fs/inode.h b/addons/libkosext2fs/inode.h index 78787b7..e6eac29 100644 --- a/addons/libkosext2fs/inode.h +++ b/addons/libkosext2fs/inode.h @@ -125,6 +125,10 @@ int ext2_inode_cache_wb(ext2_fs_t *fs); ext2_inode_t *ext2_inode_alloc(ext2_fs_t *fs, uint32_t parent, int *err, uint32_t *ninode); +/* Free all data blocks associated with an inode. */ +int ext2_inode_free_all(ext2_fs_t *fs, ext2_inode_t *inode, + uint32_t inode_num, int fxattr); + /* Decrease the reference count on an inode. If the reference count reaches zero, deallocate the inode and all of its blocks. */ int ext2_inode_deref(ext2_fs_t *fs, uint32_t inode_num, int isdir); hooks/post-receive -- A pseudo Operating System for the Dreamcast. |