1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/libe2access/host/e2access.c Tue Dec 28 01:37:59 2021 +0100
1.3 @@ -0,0 +1,527 @@
1.4 +/*
1.5 + * Access a filesystem.
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 <stdio.h>
1.26 +#include <stdlib.h>
1.27 +#include <string.h>
1.28 +
1.29 +#include <sys/types.h>
1.30 +#include <sys/stat.h>
1.31 +
1.32 +#include <ext2fs/ext2fs.h>
1.33 +
1.34 +#include "file.h"
1.35 +#include "format.h"
1.36 +#include "image.h"
1.37 +#include "path.h"
1.38 +
1.39 +
1.40 +
1.41 +/* Copy buffer size. */
1.42 +
1.43 +const int BUFSIZE = 4096;
1.44 +
1.45 +
1.46 +
1.47 +/* Show directory entries when iterating. */
1.48 +
1.49 +static int image_list_dir_proc(struct ext2_dir_entry *dirent, int offset,
1.50 + int blocksize, char *buf, void *priv_data)
1.51 +{
1.52 + ext2_filsys fs = (ext2_filsys) priv_data;
1.53 + struct ext2_inode inode;
1.54 +
1.55 + /* Obtain the inode details for metadata. */
1.56 +
1.57 + if (ext2fs_read_inode(fs, dirent->inode, &inode))
1.58 + return DIRENT_ABORT;
1.59 +
1.60 + /* Output details in the style of "ls -l" showing directory, permissions,
1.61 + owner, group and size information. */
1.62 +
1.63 + printf("%s%s %5d %5d %6d ",
1.64 + _image_isdir(fs, dirent->inode) ? "d" : "-",
1.65 + get_permission_string(inode.i_mode),
1.66 + inode.i_uid,
1.67 + inode.i_gid,
1.68 + EXT2_I_SIZE(&inode));
1.69 +
1.70 + /* Output the name which is presumably not necessarily null-terminated. */
1.71 +
1.72 + fwrite(dirent->name, sizeof(char), ext2fs_dirent_name_len(dirent), stdout);
1.73 + fputc((int) '\n', stdout);
1.74 + return 0;
1.75 +}
1.76 +
1.77 +
1.78 +
1.79 +/* Copy a file into the filesystem image. */
1.80 +
1.81 +int copy_file_in(const char *filename, ext2_filsys fs, ext2_ino_t ino_file, int flags)
1.82 +{
1.83 + int retval = 0;
1.84 + ext2_file_t file;
1.85 +
1.86 + /* Copying details. */
1.87 +
1.88 + FILE *fp;
1.89 + char buf[BUFSIZE];
1.90 + size_t got;
1.91 + unsigned int written;
1.92 +
1.93 + /* Open a file in the target directory. */
1.94 +
1.95 + if (ext2fs_file_open(fs, ino_file, flags, &file))
1.96 + return 1;
1.97 +
1.98 + /* Open the file in the source directory. */
1.99 +
1.100 + fp = fopen(filename, "r");
1.101 +
1.102 + /* Copy the file content. */
1.103 +
1.104 + if (fp != NULL)
1.105 + {
1.106 + while (got = fread(buf, sizeof(char), BUFSIZE, fp))
1.107 + {
1.108 + while (got)
1.109 + {
1.110 + if (ext2fs_file_write(file, buf, got, &written))
1.111 + {
1.112 + retval = 1;
1.113 + goto close_files;
1.114 + }
1.115 + got -= written;
1.116 + }
1.117 + }
1.118 + }
1.119 +
1.120 +close_files:
1.121 + fclose(fp);
1.122 + ext2fs_file_flush(file);
1.123 + ext2fs_file_close(file);
1.124 +
1.125 + return retval;
1.126 +}
1.127 +
1.128 +/* Copy a file out of the filesystem image. */
1.129 +
1.130 +int copy_file_out(const char *target, const char *filename, int target_is_file,
1.131 + ext2_filsys fs, ext2_ino_t ino_file)
1.132 +{
1.133 + int retval = 0;
1.134 + ext2_file_t file;
1.135 +
1.136 + /* Copying details. */
1.137 +
1.138 + FILE *fp;
1.139 + char buf[BUFSIZE];
1.140 + unsigned int got;
1.141 + size_t written;
1.142 +
1.143 + /* Open the file in the source directory. */
1.144 +
1.145 + if (ext2fs_file_open(fs, ino_file, 0, &file))
1.146 + return 1;
1.147 +
1.148 + /* Open a file in the target directory. */
1.149 +
1.150 + if (target_is_file)
1.151 + fp = fopen(target, "w");
1.152 + else
1.153 + fp = open_file_in_dir(target, path_basename(filename), "w");
1.154 +
1.155 + /* Copy the file content. */
1.156 +
1.157 + if (fp != NULL)
1.158 + {
1.159 + do
1.160 + {
1.161 + if (ext2fs_file_read(file, buf, BUFSIZE, &got))
1.162 + {
1.163 + retval = 1;
1.164 + goto close_files;
1.165 + }
1.166 +
1.167 + while (got)
1.168 + {
1.169 + written = fwrite(buf, sizeof(char), got, fp);
1.170 + got -= written;
1.171 + }
1.172 +
1.173 + } while (got);
1.174 + }
1.175 +
1.176 +close_files:
1.177 + fclose(fp);
1.178 + ext2fs_file_close(file);
1.179 +
1.180 + return retval;
1.181 +}
1.182 +
1.183 +
1.184 +
1.185 +/* Copy source files from the external environment into the filesystem image. */
1.186 +
1.187 +int copy_in(ext2_filsys fs, int argc, char *argv[])
1.188 +{
1.189 + errcode_t retval;
1.190 +
1.191 + /* Target filename details. */
1.192 +
1.193 + const char *target = argv[argc - 1];
1.194 + const char *target_remaining = argv[argc - 1];
1.195 + const char *basename;
1.196 + int target_is_file;
1.197 +
1.198 + /* Target file and directory details. */
1.199 +
1.200 + int target_is_new;
1.201 + ext2_ino_t ino_file, ino_target;
1.202 + int flags;
1.203 +
1.204 + /* Source file details. */
1.205 +
1.206 + struct stat st;
1.207 + int i;
1.208 +
1.209 + /* Locate the target and test whether it is a file or a directory. */
1.210 +
1.211 + if (image_find_path(fs, &target_remaining, &ino_target))
1.212 + {
1.213 + /* Only a non-existent file in an existing directory is permitted. */
1.214 +
1.215 + if (!_image_isdir(fs, ino_target) || !path_is_leafname(target_remaining))
1.216 + {
1.217 + printf("Target %s not found.\n", target);
1.218 + return 1;
1.219 + }
1.220 +
1.221 + target_is_file = 1;
1.222 + target_is_new = 1;
1.223 + }
1.224 + else
1.225 + {
1.226 + target_is_file = _image_isfile(fs, ino_target);
1.227 + target_is_new = 0;
1.228 + }
1.229 +
1.230 + /* Only permit a target file when one source file is given. */
1.231 +
1.232 + if (target_is_file)
1.233 + {
1.234 + if (argc > 2)
1.235 + {
1.236 + printf("Target %s can only be a file when copying a single file.\n", target);
1.237 + return 1;
1.238 + }
1.239 + }
1.240 + else if (!_image_isdir(fs, ino_target))
1.241 + {
1.242 + printf("Target %s is not a directory.\n", target);
1.243 + return 1;
1.244 + }
1.245 +
1.246 + /* Copy each source object to the target directory. */
1.247 +
1.248 + for (i = 0; i < argc - 1; i++)
1.249 + {
1.250 + if (target_is_file)
1.251 + basename = target_remaining;
1.252 + else
1.253 + {
1.254 + basename = path_basename(argv[i]);
1.255 + target_is_new = image_find_file(fs, target, basename, &ino_file);
1.256 + }
1.257 +
1.258 + /* Directories are created with the same metadata. */
1.259 +
1.260 + if (isdir(argv[i]))
1.261 + {
1.262 + if (!target_is_new)
1.263 + {
1.264 + printf("Target %s cannot be created since it already exists.\n", target);
1.265 + return 1;
1.266 + }
1.267 +
1.268 + /* Obtain the metadata. */
1.269 +
1.270 + if (lstat(argv[i], &st))
1.271 + return 1;
1.272 +
1.273 + retval = image_make_dir(fs, ino_target, basename, st.st_mode,
1.274 + st.st_uid, st.st_gid, &ino_file);
1.275 +
1.276 + if (retval)
1.277 + {
1.278 + printf("Failed to create directory %s (%d).\n", argv[i], retval);
1.279 + return 1;
1.280 + }
1.281 + }
1.282 +
1.283 + /* Files are copied. */
1.284 +
1.285 + else if (isfile(argv[i]))
1.286 + {
1.287 + flags = EXT2_FILE_WRITE;
1.288 +
1.289 + /* Obtain the inode for the target file. */
1.290 +
1.291 + if (target_is_new)
1.292 + {
1.293 + /* Populate the inode details. */
1.294 +
1.295 + if (lstat(argv[i], &st))
1.296 + return 1;
1.297 +
1.298 + retval = image_create_file(fs, ino_target, basename, st.st_mode,
1.299 + st.st_uid, st.st_gid, &ino_file);
1.300 + if (retval)
1.301 + {
1.302 + printf("Failed to create file %s (%d).\n", argv[i], retval);
1.303 + return 1;
1.304 + }
1.305 +
1.306 + flags |= EXT2_FILE_CREATE;
1.307 + }
1.308 +
1.309 + /* NOTE: Overwrite/update metadata where appropriate. */
1.310 +
1.311 + if (copy_file_in(argv[i], fs, ino_file, flags))
1.312 + {
1.313 + printf("Failed to write to %s.\n", argv[i]);
1.314 + return 1;
1.315 + }
1.316 + }
1.317 + }
1.318 +
1.319 + return 0;
1.320 +}
1.321 +
1.322 +/* Copy source files out of the filesystem image into the external environment. */
1.323 +
1.324 +int copy_out(ext2_filsys fs, int argc, char *argv[])
1.325 +{
1.326 + /* Target filename details. */
1.327 +
1.328 + char *target = argv[argc - 1];
1.329 + int target_is_file;
1.330 +
1.331 + /* Target file and directory details. */
1.332 +
1.333 + ext2_file_t file;
1.334 + ext2_ino_t ino_file;
1.335 +
1.336 + /* Source file details. */
1.337 +
1.338 + const char *path;
1.339 + int i;
1.340 +
1.341 + /* Locate the target and test whether it is a directory. */
1.342 +
1.343 + if (!isdir(target))
1.344 + {
1.345 + /* Only a new or existing file in an existing directory is permitted. */
1.346 +
1.347 + if (isfile(target) || isdir_dirname(target))
1.348 + target_is_file = 1;
1.349 + else
1.350 + {
1.351 + printf("Target %s is not a directory.\n", target);
1.352 + return 1;
1.353 + }
1.354 +
1.355 + /* Only permit a target file when one source file is given. */
1.356 +
1.357 + if (argc > 2)
1.358 + {
1.359 + printf("Target %s can only be a file when copying a single file.\n", target);
1.360 + return 1;
1.361 + }
1.362 + }
1.363 + else
1.364 + target_is_file = 0;
1.365 +
1.366 + /* For each source filename, test whether it references a file. */
1.367 +
1.368 + for (i = 0; i < argc - 1; i++)
1.369 + {
1.370 + if (!image_isfile(fs, argv[i]))
1.371 + {
1.372 + printf("Source %s is not a file.\n", argv[i]);
1.373 + return 1;
1.374 + }
1.375 + }
1.376 +
1.377 + /* Copy each source file to the target directory. */
1.378 +
1.379 + for (i = 0; i < argc - 1; i++)
1.380 + {
1.381 + path = argv[i];
1.382 +
1.383 + if (image_find_path(fs, &path, &ino_file))
1.384 + return 1;
1.385 +
1.386 + if (copy_file_out(target, argv[i], target_is_file, fs, ino_file))
1.387 + {
1.388 + printf("Failed to read from %s.\n", argv[i]);
1.389 + return 1;
1.390 + }
1.391 +
1.392 + /* NOTE: Overwrite/update metadata where appropriate. */
1.393 + }
1.394 +
1.395 + return 0;
1.396 +}
1.397 +
1.398 +/* List directories in the filesystem image. */
1.399 +
1.400 +int list_dirs(ext2_filsys fs, int argc, char *argv[])
1.401 +{
1.402 + int i;
1.403 + const char *path;
1.404 +
1.405 + for (i = 0; i < argc; i++)
1.406 + {
1.407 + path = argv[i];
1.408 +
1.409 + /* List the directory contents. */
1.410 +
1.411 + puts(path);
1.412 +
1.413 + if (image_list_dir(fs, path, image_list_dir_proc, fs))
1.414 + return 1;
1.415 + }
1.416 +
1.417 + return 0;
1.418 +}
1.419 +
1.420 +/* Make directories in the filesystem image. */
1.421 +
1.422 +int make_dirs(ext2_filsys fs, int argc, char *argv[])
1.423 +{
1.424 + int i;
1.425 + char *path_end;
1.426 + const char *path;
1.427 + ext2_ino_t ino;
1.428 +
1.429 + /* Make each directory component in the given pathname. */
1.430 +
1.431 + for (i = 0; i < argc; i++)
1.432 + {
1.433 + path = argv[i];
1.434 + if (!*path)
1.435 + continue;
1.436 +
1.437 + /* Search for the remaining components. */
1.438 +
1.439 + if (!image_find_path(fs, &path, &ino))
1.440 + continue;
1.441 +
1.442 + /* From the first unrecognised component, make the remaining
1.443 + directories. */
1.444 +
1.445 + if (image_make_dirs(fs, &path, ino, 0777, 0, 0))
1.446 + return 1;
1.447 + }
1.448 +
1.449 + return 0;
1.450 +}
1.451 +
1.452 +int main(int argc, char *argv[])
1.453 +{
1.454 + int flags = EXT2_FLAG_RW; // | EXT2_FLAG_SOFTSUPP_FEATURES | EXT2_FLAG_64BITS;
1.455 + char *fsname, *operation, *filename;
1.456 + ext2_filsys fs = NULL;
1.457 + errcode_t retval;
1.458 + int exitcode = 0;
1.459 +
1.460 + if (argc < 4)
1.461 + {
1.462 + printf("Usage: %s <device or image file> <operation> <filename>...\n", argv[0]);
1.463 + return 1;
1.464 + }
1.465 +
1.466 + fsname = argv[1];
1.467 +
1.468 + /* Open the filesystem image using the POSIX file access mechanism. */
1.469 +
1.470 + retval = ext2fs_open(fsname, flags, 0, 0, unix_io_manager, &fs);
1.471 + if (retval)
1.472 + {
1.473 + printf("Could not open filesystem using %s\n", fsname);
1.474 + return 1;
1.475 + }
1.476 +
1.477 + //fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE;
1.478 +
1.479 + retval = ext2fs_read_bitmaps(fs);
1.480 + if (retval)
1.481 + {
1.482 + printf("Could not read bitmaps from %s\n", fsname);
1.483 + return 1;
1.484 + }
1.485 +
1.486 + /* Perform the requested operation. */
1.487 +
1.488 + operation = argv[2];
1.489 +
1.490 + if (!strcmp(operation, "--copy-out"))
1.491 + {
1.492 + exitcode = copy_out(fs, argc - 3, &argv[3]);
1.493 + }
1.494 + else if (!strcmp(operation, "--copy-in"))
1.495 + {
1.496 + exitcode = copy_in(fs, argc - 3, &argv[3]);
1.497 + }
1.498 + else if (!strcmp(operation, "--list-dirs"))
1.499 + {
1.500 + exitcode = list_dirs(fs, argc - 3, &argv[3]);
1.501 + }
1.502 + else if (!strcmp(operation, "--make-dirs"))
1.503 + {
1.504 + exitcode = make_dirs(fs, argc - 3, &argv[3]);
1.505 + }
1.506 + else
1.507 + {
1.508 + printf("Operation %s is not recognised.\n", operation);
1.509 + exitcode = 1;
1.510 + }
1.511 +
1.512 + /* Close the filesystem image. */
1.513 +
1.514 + retval = ext2fs_flush(fs);
1.515 + if (retval)
1.516 + {
1.517 + printf("Error flushing filesystem in %s\n", fsname);
1.518 + exitcode = 1;
1.519 + }
1.520 +
1.521 + retval = ext2fs_close(fs);
1.522 + if (retval)
1.523 + {
1.524 + printf("Error closing filesystem in %s\n", fsname);
1.525 + exitcode = 1;
1.526 + }
1.527 +
1.528 + ext2fs_free(fs);
1.529 + return exitcode;
1.530 +}