# HG changeset patch # User Paul Boddie # Date 1646526632 -3600 # Node ID 1a43c2393e2575b60ea7f235ad0fb822a5fb5709 # Parent ddd3835aeaab147922805f11199e80bf7d19ee05 Moved operations to separate files. diff -r ddd3835aeaab -r 1a43c2393e25 libe2access/host/Makefile --- a/libe2access/host/Makefile Sun Mar 06 01:06:30 2022 +0100 +++ b/libe2access/host/Makefile Sun Mar 06 01:30:32 2022 +0100 @@ -42,7 +42,7 @@ # Sources and objects. -E2ACCESS_SRC = e2access.c file.c input.c +E2ACCESS_SRC = e2access.c file.c input.c session.c $(wildcard op_*.c) E2ACCESS_OBJ = $(E2ACCESS_SRC:.c=.o) TEST_LISTING_SRC = test_listing.c diff -r ddd3835aeaab -r 1a43c2393e25 libe2access/host/e2access.c --- a/libe2access/host/e2access.c Sun Mar 06 01:06:30 2022 +0100 +++ b/libe2access/host/e2access.c Sun Mar 06 01:30:32 2022 +0100 @@ -20,28 +20,20 @@ */ #include -#include #include #include -#include -#include -#include /* major, minor */ - #include -#include "file.h" -#include "format.h" -#include "image.h" #include "input.h" -#include "path.h" -#include "utils.h" +#include "ops.h" +#include "session.h" /* Copy buffer size. */ -const int BUFSIZE = 4096; +extern int BUFSIZE; /* Maximum number of arguments in scripts. */ @@ -49,590 +41,6 @@ -/* Alternative metadata set by options. */ - -struct metadata -{ - uid_t uid; - gid_t gid; - mode_t mask; - int have_uid, have_gid; -}; - -struct metadata md; - -/* Parse program options. */ - -static int parse_options(int argc, char *argv[]) -{ - int opt; - - md.have_uid = 0; - md.have_gid = 0; - md.mask = 0000; - - while ((opt = getopt(argc, argv, "g:m:u:")) != -1) - { - switch (opt) - { - case 'g': - md.gid = atoi(optarg); - md.have_gid = 1; - break; - - case 'm': - md.mask = strtol(optarg, NULL, 0); - break; - - case 'u': - md.uid = atoi(optarg); - md.have_uid = 1; - break; - - default: - fprintf(stderr, "Option not recognised: %s\n", argv[optind]); - return -1; - } - } - - return 0; -} - - - -/* Copy a file into the filesystem image. */ - -int copy_file_in(const char *filename, ext2_filsys fs, ext2_ino_t ino_file, int flags) -{ - int retval = 0; - ext2_file_t file; - - /* Copying details. */ - - FILE *fp; - char buf[BUFSIZE]; - size_t got; - unsigned int written; - - /* Open a file in the target directory. */ - - if (ext2fs_file_open(fs, ino_file, flags, &file)) - return 1; - - /* Open the file in the source directory. */ - - fp = fopen(filename, "r"); - - /* Copy the file content. */ - - if (fp != NULL) - { - while (got = fread(buf, sizeof(char), BUFSIZE, fp)) - { - while (got) - { - if (ext2fs_file_write(file, buf, got, &written)) - { - retval = 1; - goto close_files; - } - got -= written; - } - } - } - -close_files: - fclose(fp); - ext2fs_file_flush(file); - ext2fs_file_close(file); - - return retval; -} - -/* Copy a file out of the filesystem image. */ - -int copy_file_out(const char *target, const char *filename, int target_is_file, - ext2_filsys fs, ext2_ino_t ino_file) -{ - int retval = 0; - ext2_file_t file; - - /* Copying details. */ - - FILE *fp; - char buf[BUFSIZE]; - unsigned int got; - size_t written; - - /* Open the file in the source directory. */ - - if (ext2fs_file_open(fs, ino_file, 0, &file)) - return 1; - - /* Open a file in the target directory. */ - - if (target_is_file) - fp = fopen(target, "w"); - else - fp = open_file_in_dir(target, path_basename(filename), "w"); - - /* Copy the file content. */ - - if (fp != NULL) - { - do - { - if (ext2fs_file_read(file, buf, BUFSIZE, &got)) - { - retval = 1; - goto close_files; - } - - while (got) - { - written = fwrite(buf, sizeof(char), got, fp); - got -= written; - } - - } while (got); - } - -close_files: - fclose(fp); - ext2fs_file_close(file); - - return retval; -} - - - -/* Make a new directory in the external environment. */ - -static int _make_directory(const char *target, const char *basename, - ext2_filsys fs, ext2_ino_t ino) -{ - errcode_t retval; - struct ext2_inode inode; - char target_path[strlen(target) + strlen(basename) + 2]; - - sprintf(target_path, "%s/%s", target, basename); - - retval = ext2fs_read_inode(fs, ino, &inode); - - if (retval) - return retval; - - return mkdir(target_path, inode.i_mode); -} - -/* Make a new object using the given function. */ - -static int _make_object(ext2_filsys fs, const char *filename, - ext2_ino_t ino_parent, const char *basename, - ext2_ino_t *ino_target, - errcode_t (*fn)(ext2_filsys, ext2_ino_t, const char *, - __u16, __u16, __u16, ext2_ino_t *)) -{ - errcode_t retval; - struct stat st; - - /* Obtain the metadata. */ - - if (lstat(filename, &st)) - { - fprintf(stderr, "Failed to read object metadata: %s\n", filename); - return 1; - } - - retval = fn(fs, ino_parent, basename, st.st_mode & ~md.mask, - md.have_uid ? md.uid : st.st_uid, - md.have_gid ? md.gid : st.st_gid, - ino_target); - - if (retval) - { - fprintf(stderr, "Failed to create object: %s\n", filename); - return 1; - } - - return 0; -} - -/* Copy a source file from the external environment into the filesystem. */ - -static int _copy_in(ext2_filsys fs, const char *filename, ext2_ino_t ino_target, - const char *basename) -{ - errcode_t retval; - int flags; - - /* By default, treat the target as a new object. */ - - ext2_ino_t ino_parent = ino_target; - int target_is_new = 1; - - /* Source file details. */ - - struct stat st; - - /* Without a basename, the target exists and is either a directory, into - which the source file shall be copied, or it is a file that shall be - overwritten. */ - - if (basename == NULL) - { - basename = path_basename(filename); - target_is_new = image_isdir_by_inode(fs, ino_target); - } - - /* Directories are created with the same metadata. */ - - if (isdir(filename)) - { - if (!target_is_new) - { - fprintf(stderr, "Directory cannot be copied as it already exists: %s\n", filename); - return 1; - } - - if (_make_object(fs, filename, ino_parent, basename, &ino_target, - image_make_dir)) - return 1; - } - - /* Files are copied. */ - - else if (isfile(filename)) - { - flags = EXT2_FILE_WRITE; - - /* Obtain the inode for the target file. */ - - if (target_is_new) - { - if (_make_object(fs, filename, ino_parent, basename, &ino_target, - image_create_file)) - return 1; - - flags |= EXT2_FILE_CREATE; - } - - /* NOTE: Overwrite/update metadata where appropriate. */ - - if (copy_file_in(filename, fs, ino_target, flags)) - { - fprintf(stderr, "Failed to copy file: %s\n", filename); - return 1; - } - } -} - -/* Copy source files from the external environment into the filesystem image. */ - -int copy_in(ext2_filsys fs, int argc, char *argv[]) -{ - errcode_t retval; - int i; - - /* Target filename details. */ - - const char *target = argv[argc - 1]; - const char *target_remaining = target; - const char *basename; - - /* Target file and directory details. */ - - int target_is_file; - ext2_ino_t ino_target; - - /* Locate the target and test whether it is a file or a directory. */ - - if (image_resolve_by_path(fs, &target_remaining, &ino_target)) - { - /* Only a non-existent file in an existing directory is permitted. */ - - if (!image_isdir_by_inode(fs, ino_target) || !path_is_leafname(target_remaining)) - { - fprintf(stderr, "Target not found: %s\n", target); - return 1; - } - - /* Any absent target leaves the basename remaining. - The resolved target is the parent directory. */ - - target_is_file = 0; - basename = target_remaining; - } - else - { - /* Any present target can be a file or directory. - The resolved target is the actual target. */ - - target_is_file = image_isfile_by_inode(fs, ino_target); - basename = NULL; - } - - /* Only permit a target file when one source file is given. */ - - if (target_is_file) - { - if (argc > 2) - { - fprintf(stderr, "Target can only be a file when copying a single file: %s\n", target); - return 1; - } - } - else if (!image_isdir_by_inode(fs, ino_target)) - { - fprintf(stderr, "Target is not a directory: %s\n", target); - return 1; - } - - /* Copy each source object to the target directory. */ - - for (i = 0; i < argc - 1; i++) - if (_copy_in(fs, argv[i], ino_target, basename)) - return 1; - - return 0; -} - -/* Copy a file from the filesystem into the external environment. */ - -static int _copy_out(ext2_filsys fs, const char *source, const char *target, - int target_is_file) -{ - ext2_ino_t ino_source; - - if (image_find_by_path(fs, source, &ino_source)) - { - fprintf(stderr, "Failed to find file: %s\n", source); - return 1; - } - - /* Test whether the filename references a file. */ - - if (image_isdir_by_path(fs, source)) - { - if (_make_directory(target, path_basename(source), fs, ino_source)) - { - fprintf(stderr, "Failed to make directory: %s/%s\n", target, - path_basename(source)); - return 1; - } - } - else if (image_isfile_by_path(fs, source)) - { - if (copy_file_out(target, source, target_is_file, fs, ino_source)) - { - fprintf(stderr, "Failed to read from file: %s\n", source); - return 1; - } - } - else - { - fprintf(stderr, "Object type not supported: %s\n", source); - return 1; - } - - /* NOTE: Overwrite/update metadata where appropriate. */ - - return 0; -} - -/* Copy source files out of the filesystem image into the external environment. */ - -int copy_out(ext2_filsys fs, int argc, char *argv[]) -{ - int i; - - /* Target filename details. */ - - char *target = argv[argc - 1]; - int target_is_file; - - /* Locate the target and test whether it is a directory. */ - - if (!isdir(target)) - { - /* Only a new or existing file in an existing directory is permitted. */ - - if (isfile(target) || isdir_dirname(target)) - target_is_file = 1; - else - { - fprintf(stderr, "Target is not a directory: %s\n", target); - return 1; - } - - /* Only permit a target file when one source file is given. */ - - if (argc > 2) - { - fprintf(stderr, "Target can only be a file when copying a single file: %s\n", target); - return 1; - } - } - else - target_is_file = 0; - - /* Copy each source file to the target directory. */ - - for (i = 0; i < argc - 1; i++) - if (_copy_out(fs, argv[i], target, target_is_file)) - return 1; - - return 0; -} - -/* List objects in the filesystem image. */ - -int list(ext2_filsys fs, int argc, char *argv[]) -{ - int i; - char *path; - - for (i = 0; i < argc; i++) - { - path = argv[i]; - - /* Emit each object. */ - - puts(path); - - /* List individual files or directories. */ - - if (utils_list_dir(fs, path)) - { - fprintf(stderr, "Failed to list object: %s\n", path); - return 1; - } - } - - return 0; -} - -/* Make directories in the filesystem image. */ - -int make_dirs(ext2_filsys fs, int argc, char *argv[]) -{ - int i; - const char *path; - ext2_ino_t ino; - - /* Make each directory component in the given pathname. */ - - for (i = 0; i < argc; i++) - { - path = argv[i]; - - /* Search for the remaining components. */ - - if ((!*path) || !image_resolve_by_path(fs, &path, &ino)) - { - fprintf(stderr, "Path exists: %s\n", argv[i]); - return 1; - } - - /* From the first unrecognised component, make the remaining - directories. */ - - if (image_make_dirs(fs, &path, ino, - 0777 & ~md.mask, - md.have_uid ? md.uid : 0, - md.have_gid ? md.gid : 0)) - { - fprintf(stderr, "Failed to make directory: %s\n", argv[i]); - return 1; - } - } - - return 0; -} - -/* Remove objects from the filesystem image. */ - -int _remove(ext2_filsys fs, int argc, char *argv[], int dir_only) -{ - int i; - const char *path; - ext2_ino_t ino; - - /* Remove each directory with the given pathname. */ - - for (i = 0; i < argc; i++) - { - path = argv[i]; - - /* Detect missing objects. */ - - if ((!*path) || image_find_by_path(fs, path, &ino)) - { - fprintf(stderr, "Not found: %s\n", path); - return 1; - } - - /* Insist on a directory if specified. */ - - if (dir_only) - { - if (!image_isdir_by_inode(fs, ino)) - { - fprintf(stderr, "Not a directory: %s\n", path); - return 1; - } - - /* Test for an empty directory. */ - - if (image_dir_empty_by_inode(fs, ino)) - { - fprintf(stderr, "Directory not empty: %s\n", path); - return 1; - } - } - - /* Otherwise, insist on a non-directory. */ - - else if (image_isdir_by_inode(fs, ino)) - { - fprintf(stderr, "Cannot remove a directory: %s\n", path); - return 1; - } - - /* Unlink the object. */ - - if (image_unlink_by_path(fs, path)) - { - fprintf(stderr, "Could not unlink object: %s\n", path); - return 1; - } - - /* Remove the object. */ - - if (image_remove_by_inode(fs, ino)) - { - fprintf(stderr, "Could not remove object: %s\n", path); - return 1; - } - } - - return 0; -} - -/* Remove directories from the filesystem image. */ - -int remove_dirs(ext2_filsys fs, int argc, char *argv[]) -{ - return _remove(fs, argc, argv, 1); -} - -/* Remove non-directories from the filesystem image. */ - -int remove_non_dirs(ext2_filsys fs, int argc, char *argv[]) -{ - return _remove(fs, argc, argv, 0); -} - /* Read operations from a script file. */ enum op_results @@ -701,61 +109,6 @@ return 0; } -/* Show statistics for files and directories. */ - -int stat_objects(ext2_filsys fs, int argc, char *argv[]) -{ - int i; - const char *path; - ext2_ino_t ino; - struct stat st; - - for (i = 0; i < argc; i++) - { - path = argv[i]; - - /* Detect missing objects. */ - - if (image_find_by_path(fs, path, &ino)) - { - fprintf(stderr, "Not found: %s\n", path); - return 1; - } - - /* Even though the statistics could be read directly out of ext2 data - structures, it is convenient to use the standard stat structure. */ - - if (image_stat_inode(fs, ino, &st)) - { - fprintf(stderr, "Cannot stat object: %s\n", path); - return 1; - } - - /* Terse stat output: - %n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %W %o %C */ - - printf("%s %ld %ld %x %d %d ", - path, st.st_size, st.st_blocks, st.st_mode, st.st_uid, st.st_gid); - - printf("%d %d %d %x %x ", - st.st_dev, st.st_ino, st.st_nlink, - major(st.st_rdev), minor(st.st_rdev)); - - printf("%d %d %d ", - st.st_atim, st.st_mtim, st.st_ctim); - - /* NOTE: Arbitrary values: - %W (creation time) given as 0 - %o (I/O transfer size hint) given as 0 - %C (SELinux security context) given as empty string */ - - printf("%d %d %s\n", - 0, 0, ""); - } - - return 0; -} - /* Help message. */ diff -r ddd3835aeaab -r 1a43c2393e25 libe2access/host/file.c --- a/libe2access/host/file.c Sun Mar 06 01:06:30 2022 +0100 +++ b/libe2access/host/file.c Sun Mar 06 01:30:32 2022 +0100 @@ -1,7 +1,7 @@ /* - * File access functions. + * Generic file access functions. * - * Copyright (C) 2019 Paul Boddie + * Copyright (C) 2019, 2022 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -21,8 +21,8 @@ #include #include +#include #include -#include @@ -75,3 +75,6 @@ return fopen(pathname, mode); } + +/* vim: tabstop=4 expandtab shiftwidth=4 +*/ diff -r ddd3835aeaab -r 1a43c2393e25 libe2access/host/file.h --- a/libe2access/host/file.h Sun Mar 06 01:06:30 2022 +0100 +++ b/libe2access/host/file.h Sun Mar 06 01:30:32 2022 +0100 @@ -19,8 +19,7 @@ * Boston, MA 02110-1301, USA */ -#ifndef __FILE_H__ -#define __FILE_H__ +#pragma once #include @@ -31,4 +30,5 @@ FILE *open_file_in_dir(const char *dirname, const char *basename, const char *mode); -#endif /* __FILE_H__ */ +/* vim: tabstop=4 expandtab shiftwidth=4 +*/ diff -r ddd3835aeaab -r 1a43c2393e25 libe2access/host/input.h --- a/libe2access/host/input.h Sun Mar 06 01:06:30 2022 +0100 +++ b/libe2access/host/input.h Sun Mar 06 01:30:32 2022 +0100 @@ -19,9 +19,7 @@ * Boston, MA 02110-1301, USA */ -#ifndef __INPUT_H__ - - +#pragma once #include @@ -31,22 +29,10 @@ size_t buffer_size, remaining; }; -#ifdef __cplusplus -extern "C" { -#endif - void parse_line(char *start, char *end, int *num_args, char *args[], const int max_args); char *read_line(FILE *fp, struct read_line_state *state); -#ifdef __cplusplus -} -#endif - - - -#endif /* __INPUT_H__ */ - /* vim: tabstop=4 expandtab shiftwidth=4 */ diff -r ddd3835aeaab -r 1a43c2393e25 libe2access/host/op_copy_in.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/host/op_copy_in.c Sun Mar 06 01:30:32 2022 +0100 @@ -0,0 +1,270 @@ +/* + * Access a filesystem. + * + * Copyright (C) 2019, 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include + +#include + +#include "file.h" +#include "image.h" +#include "path.h" +#include "session.h" + + + +/* Copy buffer size. */ + +extern int BUFSIZE; + + + +/* Alternative metadata set by options. */ + +extern struct metadata md; + + + +/* Copy a file into the filesystem image. */ + +static int _copy_file_in(const char *filename, ext2_filsys fs, + ext2_ino_t ino_file, int flags) +{ + int retval = 0; + ext2_file_t file; + + /* Copying details. */ + + FILE *fp; + char buf[BUFSIZE]; + size_t got; + unsigned int written; + + /* Open a file in the target directory. */ + + if (ext2fs_file_open(fs, ino_file, flags, &file)) + return 1; + + /* Open the file in the source directory. */ + + fp = fopen(filename, "r"); + + /* Copy the file content. */ + + if (fp != NULL) + { + while (got = fread(buf, sizeof(char), BUFSIZE, fp)) + { + while (got) + { + if (ext2fs_file_write(file, buf, got, &written)) + { + retval = 1; + goto close_files; + } + got -= written; + } + } + } + +close_files: + fclose(fp); + ext2fs_file_flush(file); + ext2fs_file_close(file); + + return retval; +} + +/* Make a new object using the given function. */ + +static int _make_object(ext2_filsys fs, const char *filename, + ext2_ino_t ino_parent, const char *basename, + ext2_ino_t *ino_target, + errcode_t (*fn)(ext2_filsys, ext2_ino_t, const char *, + __u16, __u16, __u16, ext2_ino_t *)) +{ + errcode_t retval; + struct stat st; + + /* Obtain the metadata. */ + + if (lstat(filename, &st)) + { + fprintf(stderr, "Failed to read object metadata: %s\n", filename); + return 1; + } + + retval = fn(fs, ino_parent, basename, st.st_mode & ~md.mask, + md.have_uid ? md.uid : st.st_uid, + md.have_gid ? md.gid : st.st_gid, + ino_target); + + if (retval) + { + fprintf(stderr, "Failed to create object: %s\n", filename); + return 1; + } + + return 0; +} + +/* Copy a source file from the external environment into the filesystem. */ + +static int _copy_in(ext2_filsys fs, const char *filename, ext2_ino_t ino_target, + const char *basename) +{ + errcode_t retval; + int flags; + + /* By default, treat the target as a new object. */ + + ext2_ino_t ino_parent = ino_target; + int target_is_new = 1; + + /* Source file details. */ + + struct stat st; + + /* Without a basename, the target exists and is either a directory, into + which the source file shall be copied, or it is a file that shall be + overwritten. */ + + if (basename == NULL) + { + basename = path_basename(filename); + target_is_new = image_isdir_by_inode(fs, ino_target); + } + + /* Directories are created with the same metadata. */ + + if (isdir(filename)) + { + if (!target_is_new) + { + fprintf(stderr, "Directory cannot be copied as it already exists: %s\n", filename); + return 1; + } + + if (_make_object(fs, filename, ino_parent, basename, &ino_target, + image_make_dir)) + return 1; + } + + /* Files are copied. */ + + else if (isfile(filename)) + { + flags = EXT2_FILE_WRITE; + + /* Obtain the inode for the target file. */ + + if (target_is_new) + { + if (_make_object(fs, filename, ino_parent, basename, &ino_target, + image_create_file)) + return 1; + + flags |= EXT2_FILE_CREATE; + } + + /* NOTE: Overwrite/update metadata where appropriate. */ + + if (_copy_file_in(filename, fs, ino_target, flags)) + { + fprintf(stderr, "Failed to copy file: %s\n", filename); + return 1; + } + } +} + +/* Copy source files from the external environment into the filesystem image. */ + +int copy_in(ext2_filsys fs, int argc, char *argv[]) +{ + errcode_t retval; + int i; + + /* Target filename details. */ + + const char *target = argv[argc - 1]; + const char *target_remaining = target; + const char *basename; + + /* Target file and directory details. */ + + int target_is_file; + ext2_ino_t ino_target; + + /* Locate the target and test whether it is a file or a directory. */ + + if (image_resolve_by_path(fs, &target_remaining, &ino_target)) + { + /* Only a non-existent file in an existing directory is permitted. */ + + if (!image_isdir_by_inode(fs, ino_target) || !path_is_leafname(target_remaining)) + { + fprintf(stderr, "Target not found: %s\n", target); + return 1; + } + + /* Any absent target leaves the basename remaining. + The resolved target is the parent directory. */ + + target_is_file = 0; + basename = target_remaining; + } + else + { + /* Any present target can be a file or directory. + The resolved target is the actual target. */ + + target_is_file = image_isfile_by_inode(fs, ino_target); + basename = NULL; + } + + /* Only permit a target file when one source file is given. */ + + if (target_is_file) + { + if (argc > 2) + { + fprintf(stderr, "Target can only be a file when copying a single file: %s\n", target); + return 1; + } + } + else if (!image_isdir_by_inode(fs, ino_target)) + { + fprintf(stderr, "Target is not a directory: %s\n", target); + return 1; + } + + /* Copy each source object to the target directory. */ + + for (i = 0; i < argc - 1; i++) + if (_copy_in(fs, argv[i], ino_target, basename)) + return 1; + + return 0; +} + +/* vim: tabstop=4 expandtab shiftwidth=4 +*/ diff -r ddd3835aeaab -r 1a43c2393e25 libe2access/host/op_copy_out.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/host/op_copy_out.c Sun Mar 06 01:30:32 2022 +0100 @@ -0,0 +1,214 @@ +/* + * Access a filesystem. + * + * Copyright (C) 2019, 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include + +#include + +#include + +#include "file.h" +#include "image.h" +#include "path.h" +#include "session.h" + + + +/* Copy buffer size. */ + +extern int BUFSIZE; + + + +/* Alternative metadata set by options. */ + +extern struct metadata md; + + + +/* Copy a file out of the filesystem image. */ + +static int _copy_file_out(const char *target, const char *filename, + int target_is_file, ext2_filsys fs, + ext2_ino_t ino_file) +{ + int retval = 0; + ext2_file_t file; + + /* Copying details. */ + + FILE *fp; + char buf[BUFSIZE]; + unsigned int got; + size_t written; + + /* Open the file in the source directory. */ + + if (ext2fs_file_open(fs, ino_file, 0, &file)) + return 1; + + /* Open a file in the target directory. */ + + if (target_is_file) + fp = fopen(target, "w"); + else + fp = open_file_in_dir(target, path_basename(filename), "w"); + + /* Copy the file content. */ + + if (fp != NULL) + { + do + { + if (ext2fs_file_read(file, buf, BUFSIZE, &got)) + { + retval = 1; + goto close_files; + } + + while (got) + { + written = fwrite(buf, sizeof(char), got, fp); + got -= written; + } + + } while (got); + } + +close_files: + fclose(fp); + ext2fs_file_close(file); + + return retval; +} + + + +/* Make a new directory in the external environment. */ + +static int _make_directory(const char *target, const char *basename, + ext2_filsys fs, ext2_ino_t ino) +{ + errcode_t retval; + struct ext2_inode inode; + char target_path[strlen(target) + strlen(basename) + 2]; + + sprintf(target_path, "%s/%s", target, basename); + + retval = ext2fs_read_inode(fs, ino, &inode); + + if (retval) + return retval; + + return mkdir(target_path, inode.i_mode); +} + +/* Copy a file from the filesystem into the external environment. */ + +static int _copy_out(ext2_filsys fs, const char *source, const char *target, + int target_is_file) +{ + ext2_ino_t ino_source; + + if (image_find_by_path(fs, source, &ino_source)) + { + fprintf(stderr, "Failed to find file: %s\n", source); + return 1; + } + + /* Test whether the filename references a file. */ + + if (image_isdir_by_path(fs, source)) + { + if (_make_directory(target, path_basename(source), fs, ino_source)) + { + fprintf(stderr, "Failed to make directory: %s/%s\n", target, + path_basename(source)); + return 1; + } + } + else if (image_isfile_by_path(fs, source)) + { + if (_copy_file_out(target, source, target_is_file, fs, ino_source)) + { + fprintf(stderr, "Failed to read from file: %s\n", source); + return 1; + } + } + else + { + fprintf(stderr, "Object type not supported: %s\n", source); + return 1; + } + + /* NOTE: Overwrite/update metadata where appropriate. */ + + return 0; +} + +/* Copy source files out of the filesystem image into the external environment. */ + +int copy_out(ext2_filsys fs, int argc, char *argv[]) +{ + int i; + + /* Target filename details. */ + + char *target = argv[argc - 1]; + int target_is_file; + + /* Locate the target and test whether it is a directory. */ + + if (!isdir(target)) + { + /* Only a new or existing file in an existing directory is permitted. */ + + if (isfile(target) || isdir_dirname(target)) + target_is_file = 1; + else + { + fprintf(stderr, "Target is not a directory: %s\n", target); + return 1; + } + + /* Only permit a target file when one source file is given. */ + + if (argc > 2) + { + fprintf(stderr, "Target can only be a file when copying a single file: %s\n", target); + return 1; + } + } + else + target_is_file = 0; + + /* Copy each source file to the target directory. */ + + for (i = 0; i < argc - 1; i++) + if (_copy_out(fs, argv[i], target, target_is_file)) + return 1; + + return 0; +} + +/* vim: tabstop=4 expandtab shiftwidth=4 +*/ diff -r ddd3835aeaab -r 1a43c2393e25 libe2access/host/op_list_objects.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/host/op_list_objects.c Sun Mar 06 01:30:32 2022 +0100 @@ -0,0 +1,67 @@ +/* + * List objects in a filesystem. + * + * Copyright (C) 2019, 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include + +#include "format.h" +#include "image.h" +#include "session.h" +#include "utils.h" + + + +/* Alternative metadata set by options. */ + +extern struct metadata md; + + + +/* List objects in the filesystem image. */ + +int list(ext2_filsys fs, int argc, char *argv[]) +{ + int i; + char *path; + + for (i = 0; i < argc; i++) + { + path = argv[i]; + + /* Emit each object. */ + + puts(path); + + /* List individual files or directories. */ + + if (utils_list_dir(fs, path)) + { + fprintf(stderr, "Failed to list object: %s\n", path); + return 1; + } + } + + return 0; +} + +/* vim: tabstop=4 expandtab shiftwidth=4 +*/ diff -r ddd3835aeaab -r 1a43c2393e25 libe2access/host/op_make_dirs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/host/op_make_dirs.c Sun Mar 06 01:30:32 2022 +0100 @@ -0,0 +1,76 @@ +/* + * Make directories in a filesystem. + * + * Copyright (C) 2019, 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include + +#include "image.h" +#include "session.h" + + + +/* Alternative metadata set by options. */ + +extern struct metadata md; + + + +/* Make directories in the filesystem image. */ + +int make_dirs(ext2_filsys fs, int argc, char *argv[]) +{ + int i; + const char *path; + ext2_ino_t ino; + + /* Make each directory component in the given pathname. */ + + for (i = 0; i < argc; i++) + { + path = argv[i]; + + /* Search for the remaining components. */ + + if ((!*path) || !image_resolve_by_path(fs, &path, &ino)) + { + fprintf(stderr, "Path exists: %s\n", argv[i]); + return 1; + } + + /* From the first unrecognised component, make the remaining + directories. */ + + if (image_make_dirs(fs, &path, ino, + 0777 & ~md.mask, + md.have_uid ? md.uid : 0, + md.have_gid ? md.gid : 0)) + { + fprintf(stderr, "Failed to make directory: %s\n", argv[i]); + return 1; + } + } + + return 0; +} + +/* vim: tabstop=4 expandtab shiftwidth=4 +*/ diff -r ddd3835aeaab -r 1a43c2393e25 libe2access/host/op_remove.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/host/op_remove.c Sun Mar 06 01:30:32 2022 +0100 @@ -0,0 +1,121 @@ +/* + * Remove objects from a filesystem. + * + * Copyright (C) 2019, 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include + +#include "image.h" +#include "session.h" + + + +/* Alternative metadata set by options. */ + +extern struct metadata md; + + + +/* Remove objects from the filesystem image. */ + +int _remove(ext2_filsys fs, int argc, char *argv[], int dir_only) +{ + int i; + const char *path; + ext2_ino_t ino; + + /* Remove each directory with the given pathname. */ + + for (i = 0; i < argc; i++) + { + path = argv[i]; + + /* Detect missing objects. */ + + if ((!*path) || image_find_by_path(fs, path, &ino)) + { + fprintf(stderr, "Not found: %s\n", path); + return 1; + } + + /* Insist on a directory if specified. */ + + if (dir_only) + { + if (!image_isdir_by_inode(fs, ino)) + { + fprintf(stderr, "Not a directory: %s\n", path); + return 1; + } + + /* Test for an empty directory. */ + + if (image_dir_empty_by_inode(fs, ino)) + { + fprintf(stderr, "Directory not empty: %s\n", path); + return 1; + } + } + + /* Otherwise, insist on a non-directory. */ + + else if (image_isdir_by_inode(fs, ino)) + { + fprintf(stderr, "Cannot remove a directory: %s\n", path); + return 1; + } + + /* Unlink the object. */ + + if (image_unlink_by_path(fs, path)) + { + fprintf(stderr, "Could not unlink object: %s\n", path); + return 1; + } + + /* Remove the object. */ + + if (image_remove_by_inode(fs, ino)) + { + fprintf(stderr, "Could not remove object: %s\n", path); + return 1; + } + } + + return 0; +} + +/* Remove directories from the filesystem image. */ + +int remove_dirs(ext2_filsys fs, int argc, char *argv[]) +{ + return _remove(fs, argc, argv, 1); +} + +/* Remove non-directories from the filesystem image. */ + +int remove_non_dirs(ext2_filsys fs, int argc, char *argv[]) +{ + return _remove(fs, argc, argv, 0); +} + +/* vim: tabstop=4 expandtab shiftwidth=4 +*/ diff -r ddd3835aeaab -r 1a43c2393e25 libe2access/host/op_stat_objects.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/host/op_stat_objects.c Sun Mar 06 01:30:32 2022 +0100 @@ -0,0 +1,90 @@ +/* + * Obtain object statistics from a filesystem. + * + * Copyright (C) 2019, 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include +#include /* major, minor */ +#include + +#include + +#include "image.h" + + + +/* Show statistics for files and directories. */ + +int stat_objects(ext2_filsys fs, int argc, char *argv[]) +{ + int i; + const char *path; + ext2_ino_t ino; + struct stat st; + + for (i = 0; i < argc; i++) + { + path = argv[i]; + + /* Detect missing objects. */ + + if (image_find_by_path(fs, path, &ino)) + { + fprintf(stderr, "Not found: %s\n", path); + return 1; + } + + /* Even though the statistics could be read directly out of ext2 data + structures, it is convenient to use the standard stat structure. */ + + if (image_stat_inode(fs, ino, &st)) + { + fprintf(stderr, "Cannot stat object: %s\n", path); + return 1; + } + + /* Terse stat output: + %n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %W %o %C */ + + printf("%s %ld %ld %x %d %d ", + path, st.st_size, st.st_blocks, st.st_mode, st.st_uid, st.st_gid); + + printf("%d %d %d %x %x ", + st.st_dev, st.st_ino, st.st_nlink, + major(st.st_rdev), minor(st.st_rdev)); + + printf("%d %d %d ", + st.st_atim, st.st_mtim, st.st_ctim); + + /* NOTE: Arbitrary values: + %W (creation time) given as 0 + %o (I/O transfer size hint) given as 0 + %C (SELinux security context) given as empty string */ + + printf("%d %d %s\n", + 0, 0, ""); + } + + return 0; +} + +/* vim: tabstop=4 expandtab shiftwidth=4 +*/ diff -r ddd3835aeaab -r 1a43c2393e25 libe2access/host/ops.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/host/ops.h Sun Mar 06 01:30:32 2022 +0100 @@ -0,0 +1,33 @@ +/* + * Operations. + * + * Copyright (C) 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +int copy_in(ext2_filsys fs, int argc, char *argv[]); +int copy_out(ext2_filsys fs, int argc, char *argv[]); +int list(ext2_filsys fs, int argc, char *argv[]); +int make_dirs(ext2_filsys fs, int argc, char *argv[]); +int remove_dirs(ext2_filsys fs, int argc, char *argv[]); +int remove_non_dirs(ext2_filsys fs, int argc, char *argv[]); +int stat_objects(ext2_filsys fs, int argc, char *argv[]); + +/* vim: tabstop=4 expandtab shiftwidth=4 +*/ diff -r ddd3835aeaab -r 1a43c2393e25 libe2access/host/session.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/host/session.c Sun Mar 06 01:30:32 2022 +0100 @@ -0,0 +1,79 @@ +/* + * Session utilities. + * + * Copyright (C) 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + +#include "session.h" + + + +/* Alternative metadata set by options. */ + +struct metadata md; + +/* Common buffer properties. */ + +const int BUFSIZE = 4096; + + + +/* Parse program options. */ + +int parse_options(int argc, char *argv[]) +{ + int opt; + + md.have_uid = 0; + md.have_gid = 0; + md.mask = 0000; + + while ((opt = getopt(argc, argv, "g:m:u:")) != -1) + { + switch (opt) + { + case 'g': + md.gid = atoi(optarg); + md.have_gid = 1; + break; + + case 'm': + md.mask = strtol(optarg, NULL, 0); + break; + + case 'u': + md.uid = atoi(optarg); + md.have_uid = 1; + break; + + default: + fprintf(stderr, "Option not recognised: %s\n", argv[optind]); + return -1; + } + } + + return 0; +} + +/* vim: tabstop=4 expandtab shiftwidth=4 +*/ diff -r ddd3835aeaab -r 1a43c2393e25 libe2access/host/session.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/host/session.h Sun Mar 06 01:30:32 2022 +0100 @@ -0,0 +1,39 @@ +/* + * Common session details. + * + * Copyright (C) 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include + +/* Alternative metadata set by options. */ + +struct metadata +{ + uid_t uid; + gid_t gid; + mode_t mask; + int have_uid, have_gid; +}; + +int parse_options(int argc, char *argv[]); + +/* vim: tabstop=4 expandtab shiftwidth=4 +*/