X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lib%2Fext2fs%2Fmkdir.c;h=2a63aad167158297967c65fea75d6adc7e0d2d60;hb=a935b93dcac8473864587c2e305c2d19b8fcd591;hp=af3b9b7b6583516fc1109a0073aba9a202fc1496;hpb=50e1e10fa0ac12a3e2a9d20a75ee9041873cda96;p=tools%2Fe2fsprogs.git diff --git a/lib/ext2fs/mkdir.c b/lib/ext2fs/mkdir.c index af3b9b7..2a63aad 100644 --- a/lib/ext2fs/mkdir.c +++ b/lib/ext2fs/mkdir.c @@ -1,40 +1,60 @@ /* * mkdir.c --- make a directory in the filesystem - * - * Copyright (C) 1994 Theodore Ts'o. This file may be redistributed - * under the terms of the GNU Public License. + * + * Copyright (C) 1994, 1995 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% */ +#include "config.h" #include #include +#if HAVE_UNISTD_H #include -#include +#endif #include #include +#if HAVE_SYS_STAT_H #include +#endif +#if HAVE_SYS_TYPES_H #include -#if HAVE_ERRNO_H -#include #endif -#include - +#include "ext2_fs.h" #include "ext2fs.h" +#include "ext2fsP.h" -errcode_t ext2fs_mkdir(ext2_filsys fs, ino_t parent, ino_t inum, +#ifndef EXT2_FT_DIR +#define EXT2_FT_DIR 2 +#endif + +errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, const char *name) { + ext2_extent_handle_t handle; errcode_t retval; - struct ext2_inode inode; - ino_t ino = inum; - ino_t scratch_ino; - blk_t blk; + struct ext2_inode parent_inode, inode; + ext2_ino_t ino = inum; + ext2_ino_t scratch_ino; + blk64_t blk; char *block = 0; - int group; + int inline_data = 0; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); /* + * Create a new dir with inline data iff this feature is enabled + * and ino >= EXT2_FIRST_INO. + */ + if ((!ino || ino >= EXT2_FIRST_INO(fs->super)) && + ext2fs_has_feature_inline_data(fs->super)) + inline_data = 1; + + /* * Allocate an inode, if necessary */ if (!ino) { @@ -47,52 +67,82 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ino_t parent, ino_t inum, /* * Allocate a data block for the directory */ - retval = ext2fs_new_block(fs, 0, 0, &blk); - if (retval) - goto cleanup; + memset(&inode, 0, sizeof(struct ext2_inode)); + if (!inline_data) { + retval = ext2fs_new_block2(fs, ext2fs_find_inode_goal(fs, ino, + &inode, + 0), + NULL, &blk); + if (retval) + goto cleanup; + } /* * Create a scratch template for the directory */ - retval = ext2fs_new_dir_block(fs, ino, parent, &block); + if (inline_data) + retval = ext2fs_new_dir_inline_data(fs, ino, parent, + inode.i_block); + else + retval = ext2fs_new_dir_block(fs, ino, parent, &block); if (retval) goto cleanup; /* + * Get the parent's inode, if necessary + */ + if (parent != ino) { + retval = ext2fs_read_inode(fs, parent, &parent_inode); + if (retval) + goto cleanup; + } else + memset(&parent_inode, 0, sizeof(parent_inode)); + + /* * Create the inode structure.... */ - memset(&inode, 0, sizeof(struct ext2_inode)); - inode.i_mode = LINUX_S_IFDIR | 0755; + inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask); inode.i_uid = inode.i_gid = 0; - inode.i_blocks = fs->blocksize / 512; - inode.i_block[0] = blk; + if (inline_data) { + inode.i_flags |= EXT4_INLINE_DATA_FL; + inode.i_size = EXT4_MIN_INLINE_DATA_SIZE; + } else { + if (ext2fs_has_feature_extents(fs->super)) + inode.i_flags |= EXT4_EXTENTS_FL; + else + inode.i_block[0] = blk; + inode.i_size = fs->blocksize; + ext2fs_iblk_set(fs, &inode, 1); + } inode.i_links_count = 2; - inode.i_ctime = inode.i_atime = inode.i_mtime = time(NULL); - inode.i_size = fs->blocksize; /* - * Write out the inode and inode data block + * Write out the inode and inode data block. The inode generation + * number is assigned by write_new_inode, which means that the call + * to write_dir_block must come after that. */ - retval = ext2fs_write_dir_block(fs, blk, block); + retval = ext2fs_write_new_inode(fs, ino, &inode); if (retval) goto cleanup; - retval = ext2fs_write_inode(fs, ino, &inode); - if (retval) - goto cleanup; - - /* - * Update parent inode's counts - */ - if (parent != ino) { - retval = ext2fs_read_inode(fs, parent, &inode); - if (retval) - goto cleanup; - inode.i_links_count++; - retval = ext2fs_write_inode(fs, parent, &inode); + if (inline_data) { + /* init "system.data" for new dir */ + retval = ext2fs_inline_data_init(fs, ino); + } else { + retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino); if (retval) goto cleanup; + + if (ext2fs_has_feature_extents(fs->super)) { + retval = ext2fs_extent_open2(fs, ino, &inode, &handle); + if (retval) + goto cleanup; + retval = ext2fs_extent_set_bmap(handle, 0, blk, 0); + ext2fs_extent_free(handle); + if (retval) + goto cleanup; + } } - + /* * Link the directory into the filesystem hierarchy */ @@ -100,13 +150,27 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ino_t parent, ino_t inum, retval = ext2fs_lookup(fs, parent, name, strlen(name), 0, &scratch_ino); if (!retval) { - retval = EEXIST; + retval = EXT2_ET_DIR_EXISTS; name = 0; goto cleanup; } - if (retval != ENOENT) + if (retval != EXT2_ET_FILE_NOT_FOUND) goto cleanup; - retval = ext2fs_link(fs, parent, name, ino, 0); + retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_DIR); + if (retval) + goto cleanup; + } + + /* + * Update parent inode's counts + */ + if (parent != ino) { + /* reload parent inode due to inline data */ + retval = ext2fs_read_inode(fs, parent, &parent_inode); + if (retval) + goto cleanup; + parent_inode.i_links_count++; + retval = ext2fs_write_inode(fs, parent, &parent_inode); if (retval) goto cleanup; } @@ -114,23 +178,13 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ino_t parent, ino_t inum, /* * Update accounting.... */ - ext2fs_mark_block_bitmap(fs->block_map, blk); - ext2fs_mark_bb_dirty(fs); - ext2fs_mark_inode_bitmap(fs->inode_map, ino); - ext2fs_mark_ib_dirty(fs); - - group = ext2fs_group_of_blk(fs, blk); - fs->group_desc[group].bg_free_blocks_count--; - group = ext2fs_group_of_ino(fs, ino); - fs->group_desc[group].bg_free_inodes_count--; - fs->group_desc[group].bg_used_dirs_count++; - fs->super->s_free_blocks_count--; - fs->super->s_free_inodes_count--; - ext2fs_mark_super_dirty(fs); - + if (!inline_data) + ext2fs_block_alloc_stats2(fs, blk, +1); + ext2fs_inode_alloc_stats2(fs, ino, +1, 1); + cleanup: if (block) - free(block); + ext2fs_free_mem(&block); return retval; }