1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/libe2access/lib/src/image.c Wed Aug 25 01:28:08 2021 +0200
1.3 @@ -0,0 +1,343 @@
1.4 +/*
1.5 + * Filesystem access functions.
1.6 + *
1.7 + * Copyright (C) 2019 Paul Boddie <paul@boddie.org.uk>
1.8 + *
1.9 + * This program is free software; you can redistribute it and/or
1.10 + * modify it under the terms of the GNU General Public License as
1.11 + * published by the Free Software Foundation; either version 2 of
1.12 + * the License, or (at your option) any later version.
1.13 + *
1.14 + * This program is distributed in the hope that it will be useful,
1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.17 + * GNU General Public License for more details.
1.18 + *
1.19 + * You should have received a copy of the GNU General Public License
1.20 + * along with this program; if not, write to the Free Software
1.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
1.22 + * Boston, MA 02110-1301, USA
1.23 + */
1.24 +
1.25 +#include <string.h>
1.26 +#include <sys/stat.h>
1.27 +
1.28 +#include <ext2fs/ext2fs.h>
1.29 +
1.30 +#include "image.h"
1.31 +#include "path.h"
1.32 +
1.33 +
1.34 +
1.35 +/* Create an inode for a file. */
1.36 +
1.37 +errcode_t image_create_file(ext2_filsys fs, ext2_ino_t ino_target,
1.38 + const char *basename, __u16 mode,
1.39 + __u16 uid, __u16 gid, ext2_ino_t *ino_file)
1.40 +{
1.41 + struct ext2_inode inode_file;
1.42 + errcode_t retval;
1.43 +
1.44 + /* Without an inode, create a new one. */
1.45 +
1.46 + retval = ext2fs_new_inode(fs, ino_target, LINUX_S_IFREG | mode, 0, ino_file);
1.47 + if (retval)
1.48 + return retval;
1.49 +
1.50 + /* Connect the inode to its parent. */
1.51 +
1.52 + while (1)
1.53 + {
1.54 + retval = ext2fs_link(fs, ino_target, basename, *ino_file,
1.55 + EXT2_FT_REG_FILE);
1.56 +
1.57 + if (!retval)
1.58 + break;
1.59 +
1.60 + /* Expand the directory if necessary. */
1.61 +
1.62 + if (retval == EXT2_ET_DIR_NO_SPACE)
1.63 + retval = ext2fs_expand_dir(fs, ino_target);
1.64 +
1.65 + if (retval)
1.66 + return retval;
1.67 + }
1.68 +
1.69 + /* Make sure that subsequent files employ different inodes. */
1.70 +
1.71 + ext2fs_inode_alloc_stats2(fs, *ino_file, 1, 0);
1.72 +
1.73 + /* Populate the inode details. */
1.74 +
1.75 + image_set_metadata(&inode_file, 1, LINUX_S_IFREG | mode, uid, gid);
1.76 +
1.77 + return ext2fs_write_new_inode(fs, *ino_file, &inode_file);
1.78 +}
1.79 +
1.80 +/* Set the mode, user and group metadata for a file. */
1.81 +
1.82 +void image_set_metadata(struct ext2_inode *inode, int clean, __u16 mode,
1.83 + __u16 uid, __u16 gid)
1.84 +{
1.85 + if (clean)
1.86 + memset(inode, 0, sizeof(*inode));
1.87 +
1.88 + inode->i_mode = mode;
1.89 + inode->i_uid = uid;
1.90 + inode->i_gid = gid;
1.91 +}
1.92 +
1.93 +/* Find an object in the given directory with the given name in the filesystem
1.94 + image, updating the name reference to refer to the next component. */
1.95 +
1.96 +errcode_t image_find_next(ext2_filsys fs, ext2_ino_t ino_dir,
1.97 + const char **basename, char *buf, ext2_ino_t *ino)
1.98 +{
1.99 + const char *end = path_component_end(*basename);
1.100 + errcode_t retval;
1.101 +
1.102 + /* Find the basename in the directory. */
1.103 +
1.104 + retval = ext2fs_lookup(fs, ino_dir, *basename, end - *basename, buf, ino);
1.105 +
1.106 + /* Update the current component. */
1.107 +
1.108 + if (!retval)
1.109 + *basename = path_component_next(end);
1.110 +
1.111 + return retval;
1.112 +}
1.113 +
1.114 +/* Find an object with the given pathname in the filesystem image. */
1.115 +
1.116 +errcode_t image_find_path(ext2_filsys fs, const char **pathname, ext2_ino_t *ino)
1.117 +{
1.118 + char *buf;
1.119 + ext2_ino_t ino_dir;
1.120 + errcode_t retval;
1.121 +
1.122 + retval = ext2fs_get_mem(fs->blocksize, &buf);
1.123 + if (retval)
1.124 + return retval;
1.125 +
1.126 + /* Skip any leading root marker. */
1.127 +
1.128 + if (**pathname == '/')
1.129 + (*pathname)++;
1.130 +
1.131 + if (!**pathname)
1.132 + *ino = EXT2_ROOT_INO;
1.133 +
1.134 + /* Start at the root. */
1.135 +
1.136 + ino_dir = EXT2_ROOT_INO;
1.137 +
1.138 + /* With any remaining path, find the next component. */
1.139 +
1.140 + while (**pathname)
1.141 + {
1.142 + retval = image_find_next(fs, ino_dir, pathname, buf, ino);
1.143 + if (retval)
1.144 + {
1.145 + *ino = ino_dir;
1.146 + break;
1.147 + }
1.148 +
1.149 + /* Move into the found object for searching the next component. */
1.150 +
1.151 + ino_dir = *ino;
1.152 + }
1.153 +
1.154 + ext2fs_free_mem(&buf);
1.155 +
1.156 + return retval;
1.157 +}
1.158 +
1.159 +/* Find an object in the given directory with the given name in the filesystem
1.160 + image. */
1.161 +
1.162 +errcode_t image_find_file(ext2_filsys fs, const char *dirname,
1.163 + const char *basename, ext2_ino_t *ino)
1.164 +{
1.165 + char pathname[strlen(dirname) + strlen(basename) + 2];
1.166 + const char *s = pathname;
1.167 +
1.168 + strcpy(pathname, dirname);
1.169 + strcat(pathname, "/");
1.170 + strcat(pathname, basename);
1.171 +
1.172 + return image_find_path(fs, &s, ino);
1.173 +}
1.174 +
1.175 +/* Obtain the inode for the object with the given pathname in the filesystem
1.176 + image. */
1.177 +
1.178 +errcode_t image_inode(ext2_filsys fs, const char *pathname,
1.179 + struct ext2_inode *inode)
1.180 +{
1.181 + ext2_ino_t ino;
1.182 + errcode_t retval;
1.183 +
1.184 + retval = image_find_path(fs, &pathname, &ino);
1.185 + if (retval)
1.186 + return retval;
1.187 +
1.188 + return ext2fs_read_inode(fs, ino, inode);
1.189 +}
1.190 +
1.191 +/* Make a directory in the given directory in the filesystem image having the
1.192 + given name and metadata. */
1.193 +
1.194 +errcode_t image_make_dir(ext2_filsys fs, ext2_ino_t ino_dir,
1.195 + const char *basename, __u16 mode,
1.196 + __u16 uid, __u16 gid, ext2_ino_t *ino)
1.197 +{
1.198 + struct ext2_inode inode_dir;
1.199 + errcode_t retval = 0;
1.200 +
1.201 + /* Create an inode in the directory. */
1.202 +
1.203 + retval = ext2fs_new_inode(fs, ino_dir, LINUX_S_IFDIR | mode, 0, ino);
1.204 + if (retval)
1.205 + return retval;
1.206 +
1.207 + /* Make the directory and update the metadata (due to ext2fs_mkdir
1.208 + limitation). */
1.209 +
1.210 + retval = ext2fs_mkdir(fs, ino_dir, *ino, basename);
1.211 + if (retval)
1.212 + return retval;
1.213 +
1.214 + retval = ext2fs_read_inode(fs, *ino, &inode_dir);
1.215 + if (retval)
1.216 + return retval;
1.217 +
1.218 + image_set_metadata(&inode_dir, 0, LINUX_S_IFDIR | mode, uid, gid);
1.219 + return ext2fs_write_inode(fs, *ino, &inode_dir);
1.220 +}
1.221 +
1.222 +/* Make a directory in the given directory in the filesystem image, updating
1.223 + the name reference to refer to the next component. */
1.224 +
1.225 +errcode_t image_make_next_dir(ext2_filsys fs, ext2_ino_t ino_dir,
1.226 + const char **basename, __u16 mode, __u16 uid,
1.227 + __u16 gid, ext2_ino_t *ino)
1.228 +{
1.229 + char *end = (char *) path_component_end(*basename);
1.230 + char endchar = *end;
1.231 + errcode_t retval = 0;
1.232 +
1.233 + /* Delimit the basename and make a directory using the inode. */
1.234 +
1.235 + if (endchar)
1.236 + *end = '\0';
1.237 +
1.238 + /* Do not create directories for empty components. */
1.239 +
1.240 + if (**basename)
1.241 + retval = image_make_dir(fs, ino_dir, *basename, mode, uid, gid, ino);
1.242 +
1.243 + /* Restore the path separator and update the current component. */
1.244 +
1.245 + if (endchar)
1.246 + *end = '/';
1.247 +
1.248 + if (!retval)
1.249 + *basename = path_component_next(end);
1.250 +
1.251 + return retval;
1.252 +}
1.253 +
1.254 +/* Make directories descending to the given path in the filesystem image. */
1.255 +
1.256 +errcode_t image_make_dirs(ext2_filsys fs, const char **pathname,
1.257 + ext2_ino_t ino_dir, __u16 mode, __u16 uid, __u16 gid)
1.258 +{
1.259 + ext2_ino_t ino;
1.260 + errcode_t retval;
1.261 +
1.262 + while (**pathname)
1.263 + {
1.264 + retval = image_make_next_dir(fs, ino_dir, pathname, mode, uid, gid, &ino);
1.265 + if (retval)
1.266 + return retval;
1.267 +
1.268 + /* Move into the created object for handling the next component. */
1.269 +
1.270 + ino_dir = ino;
1.271 + }
1.272 +
1.273 + return 0;
1.274 +}
1.275 +
1.276 +/* Copy file metadata into a stat structure. */
1.277 +
1.278 +errcode_t image_stat_inode(ext2_filsys fs, ext2_ino_t ino, struct stat *st)
1.279 +{
1.280 + struct ext2_inode inode;
1.281 + errcode_t retval = ext2fs_read_inode(fs, ino, &inode);
1.282 +
1.283 + if (retval)
1.284 + return retval;
1.285 +
1.286 + st->st_dev = 0; /* device identifier */
1.287 + st->st_ino = ino;
1.288 + st->st_mode = inode.i_mode;
1.289 + st->st_nlink = inode.i_links_count;
1.290 + st->st_uid = inode_uid(inode);
1.291 + st->st_gid = inode_gid(inode);
1.292 + st->st_rdev = 0; /* special file device identifier */
1.293 + st->st_size = EXT2_I_SIZE(&inode);
1.294 + st->st_blksize = fs->blocksize;
1.295 + st->st_blocks = 0; /* number of 512 byte blocks allocated */
1.296 + st->st_atim.tv_sec = inode.i_atime;
1.297 + st->st_atim.tv_nsec = 0; /* nanosecond resolution */
1.298 + st->st_mtim.tv_sec = inode.i_mtime;
1.299 + st->st_mtim.tv_nsec = 0;
1.300 + st->st_ctim.tv_sec = inode.i_ctime;
1.301 + st->st_ctim.tv_nsec = 0;
1.302 +
1.303 + return 0;
1.304 +}
1.305 +
1.306 +/* Test object types in the filesystem image. */
1.307 +
1.308 +int _image_isdir(ext2_filsys fs, ext2_ino_t ino)
1.309 +{
1.310 + struct ext2_inode inode;
1.311 +
1.312 + if (ext2fs_read_inode(fs, ino, &inode))
1.313 + return 0;
1.314 +
1.315 + return LINUX_S_ISDIR(inode.i_mode);
1.316 +}
1.317 +
1.318 +int image_isdir(ext2_filsys fs, const char *name)
1.319 +{
1.320 + ext2_ino_t ino;
1.321 +
1.322 + if (image_find_path(fs, &name, &ino))
1.323 + return 0;
1.324 +
1.325 + return _image_isdir(fs, ino);
1.326 +}
1.327 +
1.328 +int _image_isfile(ext2_filsys fs, ext2_ino_t ino)
1.329 +{
1.330 + struct ext2_inode inode;
1.331 +
1.332 + if (ext2fs_read_inode(fs, ino, &inode))
1.333 + return 0;
1.334 +
1.335 + return LINUX_S_ISREG(inode.i_mode);
1.336 +}
1.337 +
1.338 +int image_isfile(ext2_filsys fs, const char *name)
1.339 +{
1.340 + ext2_ino_t ino;
1.341 +
1.342 + if (image_find_path(fs, &name, &ino))
1.343 + return 0;
1.344 +
1.345 + return _image_isfile(fs, ino);
1.346 +}