1.1 --- a/libe2access/lib/src/image.c Fri Jan 14 01:10:35 2022 +0100
1.2 +++ b/libe2access/lib/src/image.c Thu Jan 27 23:45:17 2022 +0100
1.3 @@ -28,28 +28,20 @@
1.4
1.5
1.6
1.7 -/* Create an inode for a file. */
1.8 +/* Link an inode within the given target directory having the given basename. */
1.9
1.10 -errcode_t image_create_file(ext2_filsys fs, ext2_ino_t ino_target,
1.11 - const char *basename, __u16 mode,
1.12 - __u16 uid, __u16 gid, ext2_ino_t *ino_file)
1.13 +static errcode_t _image_link(ext2_filsys fs, ext2_ino_t ino_target,
1.14 + const char *basename, ext2_ino_t ino_file,
1.15 + int flags)
1.16 {
1.17 - struct ext2_inode inode_file;
1.18 errcode_t retval;
1.19 int retry;
1.20
1.21 - /* Without an inode, create a new one. */
1.22 -
1.23 - retval = ext2fs_new_inode(fs, ino_target, LINUX_S_IFREG | mode, 0, ino_file);
1.24 - if (retval)
1.25 - return retval;
1.26 -
1.27 /* Connect the inode to its parent. */
1.28
1.29 for (retry = 0; retry <= 1; retry++)
1.30 {
1.31 - retval = ext2fs_link(fs, ino_target, basename, *ino_file,
1.32 - EXT2_FT_REG_FILE);
1.33 + retval = ext2fs_link(fs, ino_target, basename, ino_file, flags);
1.34
1.35 if (!retval)
1.36 break;
1.37 @@ -65,6 +57,50 @@
1.38 return retval;
1.39 }
1.40
1.41 + return 0;
1.42 +}
1.43 +
1.44 +/* Update the parent entry of a renamed directory. */
1.45 +
1.46 +struct _image_parent_entry_state
1.47 +{
1.48 + ext2_ino_t ino;
1.49 +};
1.50 +
1.51 +static int _image_update_parent_entry(struct ext2_dir_entry *dir_entry,
1.52 + int offset, int blocksize, char *buf,
1.53 + void *priv_data)
1.54 +{
1.55 + struct _image_parent_entry_state *state = (struct _image_parent_entry_state *) priv_data;
1.56 +
1.57 + (void) offset; (void) blocksize; (void) buf;
1.58 +
1.59 + if (strcmp(dir_entry->name, "..") == 0)
1.60 + {
1.61 + dir_entry->inode = state->ino;
1.62 + return DIRENT_CHANGED | DIRENT_ABORT;
1.63 + }
1.64 + else
1.65 + return 0;
1.66 +}
1.67 +
1.68 +/* Create an inode for a file. */
1.69 +
1.70 +errcode_t image_create_file(ext2_filsys fs, ext2_ino_t ino_target,
1.71 + const char *basename, __u16 mode,
1.72 + __u16 uid, __u16 gid, ext2_ino_t *ino_file)
1.73 +{
1.74 + struct ext2_inode inode_file;
1.75 + errcode_t retval;
1.76 +
1.77 + /* Without an inode, create a new one. */
1.78 +
1.79 + retval = ext2fs_new_inode(fs, ino_target, LINUX_S_IFREG | mode, 0, ino_file);
1.80 + if (retval)
1.81 + return retval;
1.82 +
1.83 + _image_link(fs, ino_target, basename, *ino_file, EXT2_FT_REG_FILE);
1.84 +
1.85 /* Make sure that subsequent files employ different inodes. */
1.86
1.87 ext2fs_inode_alloc_stats2(fs, *ino_file, 1, 0);
1.88 @@ -77,6 +113,26 @@
1.89 return ext2fs_write_new_inode(fs, *ino_file, &inode_file);
1.90 }
1.91
1.92 +/* Return the appropriate ext2 file type value for the given mode value. */
1.93 +
1.94 +int image_file_type(int mode)
1.95 +{
1.96 + switch (mode & LINUX_S_IFMT)
1.97 + {
1.98 + case LINUX_S_IFSOCK: return EXT2_FT_SOCK;
1.99 + case LINUX_S_IFLNK: return EXT2_FT_SYMLINK;
1.100 + case LINUX_S_IFREG: return EXT2_FT_REG_FILE;
1.101 + case LINUX_S_IFBLK: return EXT2_FT_BLKDEV;
1.102 + case LINUX_S_IFDIR: return EXT2_FT_DIR;
1.103 + case LINUX_S_IFCHR: return EXT2_FT_CHRDEV;
1.104 + case LINUX_S_IFIFO: return EXT2_FT_FIFO;
1.105 +
1.106 + /* NOTE: Perhaps signal an error. */
1.107 +
1.108 + default: return EXT2_FT_REG_FILE;
1.109 + }
1.110 +}
1.111 +
1.112 /* Find an object in the given directory with the given name in the filesystem
1.113 image, updating the name reference to refer to the next component. */
1.114
1.115 @@ -348,6 +404,83 @@
1.116 sizeof(inode));
1.117 }
1.118
1.119 +/* Rename a file. */
1.120 +
1.121 +errcode_t image_rename(ext2_filsys fs, ext2_ino_t source,
1.122 + ext2_ino_t source_parent, const char *source_basename,
1.123 + ext2_ino_t target_parent, const char *target_basename)
1.124 +{
1.125 + errcode_t retval;
1.126 + struct ext2_inode source_inode, source_parent_inode, target_parent_inode;
1.127 + struct _image_parent_entry_state state = {target_parent};
1.128 +
1.129 + /* NOTE: Should check for space. */
1.130 +
1.131 + /* Obtain the source object. */
1.132 +
1.133 + retval = ext2fs_read_inode(fs, source, &source_inode);
1.134 +
1.135 + if (retval)
1.136 + return retval;
1.137 +
1.138 + /* Link from the target parent. */
1.139 +
1.140 + retval = _image_link(fs, target_parent, target_basename, source,
1.141 + image_file_type(source_inode.i_mode));
1.142 +
1.143 + if (retval)
1.144 + return retval;
1.145 +
1.146 + if (_image_isdir(fs, source))
1.147 + {
1.148 + /* Update the link count for the target. */
1.149 +
1.150 + retval = ext2fs_read_inode(fs, target_parent, &target_parent_inode);
1.151 +
1.152 + if (retval)
1.153 + return retval;
1.154 +
1.155 + target_parent_inode.i_links_count++;
1.156 +
1.157 + retval = ext2fs_write_inode(fs, target_parent, &target_parent_inode);
1.158 +
1.159 + if (retval)
1.160 + return retval;
1.161 +
1.162 + /* A directory needs its .. entry updating to refer to its new
1.163 + parent. */
1.164 +
1.165 + retval = ext2fs_dir_iterate(fs, source, 0, NULL,
1.166 + _image_update_parent_entry, &state);
1.167 +
1.168 + /* Update the link count for the source. */
1.169 +
1.170 + retval = ext2fs_read_inode(fs, source_parent, &source_parent_inode);
1.171 +
1.172 + if (retval)
1.173 + return retval;
1.174 +
1.175 + source_parent_inode.i_links_count--;
1.176 +
1.177 + retval = ext2fs_write_inode(fs, source_parent, &source_parent_inode);
1.178 +
1.179 + if (retval)
1.180 + return retval;
1.181 + }
1.182 +
1.183 + /* Unlink from the source parent, doing so by name because the file is now
1.184 + already linked from the target parent, and when the parents are the same,
1.185 + unlinking by inode could just cause the file to disappear from the
1.186 + catalogue. */
1.187 +
1.188 + retval = image_unlink_by_name(fs, source_parent, source_basename);
1.189 +
1.190 + if (retval)
1.191 + return retval;
1.192 +
1.193 + return ext2fs_flush2(fs, 0);
1.194 +}
1.195 +
1.196 /* Set the mode, user and group metadata for a file. */
1.197
1.198 void image_set_metadata(struct ext2_inode *inode, int clean, __u16 mode,
1.199 @@ -396,6 +529,8 @@
1.200 errcode_t image_unlink_by_name(ext2_filsys fs, ext2_ino_t ino_parent,
1.201 const char *basename)
1.202 {
1.203 + /* NOTE: This might do more work for a directory. */
1.204 +
1.205 return ext2fs_unlink(fs, ino_parent, basename, 0, 0);
1.206 }
1.207
1.208 @@ -404,6 +539,8 @@
1.209 errcode_t image_unlink_by_inode(ext2_filsys fs, ext2_ino_t ino_parent,
1.210 ext2_ino_t ino)
1.211 {
1.212 + /* NOTE: This might do more work for a directory. */
1.213 +
1.214 return ext2fs_unlink(fs, ino_parent, 0, ino, 0);
1.215 }
1.216
1.217 @@ -448,3 +585,6 @@
1.218
1.219 return _image_isfile(fs, ino);
1.220 }
1.221 +
1.222 +/* vim: tabstop=4 expandtab shiftwidth=4
1.223 +*/