1 /* 2 * mkdir.c --- make a directory in the filesystem 3 * 4 * Copyright (C) 1994, 1995 Theodore Ts'o. 5 * 6 * %Begin-Header% 7 * This file may be redistributed under the terms of the GNU Library 8 * General Public License, version 2. 9 * %End-Header% 10 */ 11 12 #include "config.h" 13 #include <stdio.h> 14 #include <string.h> 15 #if HAVE_UNISTD_H 16 #include <unistd.h> 17 #endif 18 #include <fcntl.h> 19 #include <time.h> 20 #if HAVE_SYS_STAT_H 21 #include <sys/stat.h> 22 #endif 23 #if HAVE_SYS_TYPES_H 24 #include <sys/types.h> 25 #endif 26 27 #include "ext2_fs.h" 28 #include "ext2fs.h" 29 #include "ext2fsP.h" 30 31 #ifndef EXT2_FT_DIR 32 #define EXT2_FT_DIR 2 33 #endif 34 35 errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, 36 const char *name) 37 { 38 ext2_extent_handle_t handle; 39 errcode_t retval; 40 struct ext2_inode parent_inode, inode; 41 ext2_ino_t ino = inum; 42 ext2_ino_t scratch_ino; 43 blk64_t blk; 44 char *block = 0; 45 int inline_data = 0; 46 47 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 48 49 /* 50 * Create a new dir with inline data iff this feature is enabled 51 * and ino >= EXT2_FIRST_INO. 52 */ 53 if ((!ino || ino >= EXT2_FIRST_INO(fs->super)) && 54 ext2fs_has_feature_inline_data(fs->super)) 55 inline_data = 1; 56 57 /* 58 * Allocate an inode, if necessary 59 */ 60 if (!ino) { 61 retval = ext2fs_new_inode(fs, parent, LINUX_S_IFDIR | 0755, 62 0, &ino); 63 if (retval) 64 goto cleanup; 65 } 66 67 /* 68 * Allocate a data block for the directory 69 */ 70 memset(&inode, 0, sizeof(struct ext2_inode)); 71 if (!inline_data) { 72 retval = ext2fs_new_block2(fs, ext2fs_find_inode_goal(fs, ino, 73 &inode, 74 0), 75 NULL, &blk); 76 if (retval) 77 goto cleanup; 78 } 79 80 /* 81 * Create a scratch template for the directory 82 */ 83 if (inline_data) 84 retval = ext2fs_new_dir_inline_data(fs, ino, parent, 85 inode.i_block); 86 else 87 retval = ext2fs_new_dir_block(fs, ino, parent, &block); 88 if (retval) 89 goto cleanup; 90 91 /* 92 * Get the parent's inode, if necessary 93 */ 94 if (parent != ino) { 95 retval = ext2fs_read_inode(fs, parent, &parent_inode); 96 if (retval) 97 goto cleanup; 98 } else 99 memset(&parent_inode, 0, sizeof(parent_inode)); 100 101 /* 102 * Create the inode structure.... 103 */ 104 inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask); 105 inode.i_uid = inode.i_gid = 0; 106 if (inline_data) { 107 inode.i_flags |= EXT4_INLINE_DATA_FL; 108 inode.i_size = EXT4_MIN_INLINE_DATA_SIZE; 109 } else { 110 if (ext2fs_has_feature_extents(fs->super)) 111 inode.i_flags |= EXT4_EXTENTS_FL; 112 else 113 inode.i_block[0] = blk; 114 inode.i_size = fs->blocksize; 115 ext2fs_iblk_set(fs, &inode, 1); 116 } 117 inode.i_links_count = 2; 118 119 /* 120 * Write out the inode and inode data block. The inode generation 121 * number is assigned by write_new_inode, which means that the call 122 * to write_dir_block must come after that. 123 */ 124 retval = ext2fs_write_new_inode(fs, ino, &inode); 125 if (retval) 126 goto cleanup; 127 if (inline_data) { 128 /* init "system.data" for new dir */ 129 retval = ext2fs_inline_data_init(fs, ino); 130 } else { 131 retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino); 132 if (retval) 133 goto cleanup; 134 135 if (ext2fs_has_feature_extents(fs->super)) { 136 retval = ext2fs_extent_open2(fs, ino, &inode, &handle); 137 if (retval) 138 goto cleanup; 139 retval = ext2fs_extent_set_bmap(handle, 0, blk, 0); 140 ext2fs_extent_free(handle); 141 if (retval) 142 goto cleanup; 143 } 144 } 145 146 /* 147 * Link the directory into the filesystem hierarchy 148 */ 149 if (name) { 150 retval = ext2fs_lookup(fs, parent, name, strlen(name), 0, 151 &scratch_ino); 152 if (!retval) { 153 retval = EXT2_ET_DIR_EXISTS; 154 name = 0; 155 goto cleanup; 156 } 157 if (retval != EXT2_ET_FILE_NOT_FOUND) 158 goto cleanup; 159 retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_DIR); 160 if (retval) 161 goto cleanup; 162 } 163 164 /* 165 * Update parent inode's counts 166 */ 167 if (parent != ino) { 168 /* reload parent inode due to inline data */ 169 retval = ext2fs_read_inode(fs, parent, &parent_inode); 170 if (retval) 171 goto cleanup; 172 parent_inode.i_links_count++; 173 retval = ext2fs_write_inode(fs, parent, &parent_inode); 174 if (retval) 175 goto cleanup; 176 } 177 178 /* 179 * Update accounting.... 180 */ 181 if (!inline_data) 182 ext2fs_block_alloc_stats2(fs, blk, +1); 183 ext2fs_inode_alloc_stats2(fs, ino, +1, 1); 184 185 cleanup: 186 if (block) 187 ext2fs_free_mem(&block); 188 return retval; 189 190 } 191 192 193