# HG changeset patch # User Paul Boddie # Date 1640651879 -3600 # Node ID 8ad94f3addb28f79f271e829b10e19a85ea7b21e # Parent 85fcd5943fa5905f5a9be5d1dec70be46cfbf728 Updated libe2access sources and added host-based programs and tests. diff -r 85fcd5943fa5 -r 8ad94f3addb2 libe2access/host/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/host/Makefile Tue Dec 28 01:37:59 2021 +0100 @@ -0,0 +1,88 @@ +# Makefile - Build the filesystem access programs +# +# Copyright (C) 2019, 2021 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 3 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, see . + +# Paths to library sources. + +INC = ../include/e2access +SRC = ../lib/src + +# Tool definitions. + +RANLIB = ranlib + +# Compilation and linking flags. + +CFLAGS = -I$(INC) # -g +LDFLAGS = -lext2fs -L. -le2access # -lcom_err + +# Output programs and libraries. + +E2ACCESS = e2access +LIBE2ACCESS = libe2access.a +LIBE2ACCESS_SHARED = libe2access.so + +TEST_LISTING = test_listing +TEST_REMOVE = test_remove + +TARGETS = $(E2ACCESS) $(LIBE2ACCESS) $(LIBE2ACCESS_SHARED) $(TEST_LISTING) $(TEST_REMOVE) + +# Sources and objects. + +E2ACCESS_SRC = e2access.c file.c +E2ACCESS_OBJ = $(E2ACCESS_SRC:.c=.o) + +TEST_LISTING_SRC = test_listing.c +TEST_LISTING_OBJ = $(TEST_LISTING_SRC:.c=.o) + +TEST_REMOVE_SRC = test_remove.c +TEST_REMOVE_OBJ = $(TEST_REMOVE_SRC:.c=.o) + +LIBE2ACCESS_SRC = $(foreach FILE,format.c image.c path.c,$(SRC)/$(FILE)) +LIBE2ACCESS_OBJ = $(LIBE2ACCESS_SRC:.c=.o) + +ALL_OBJ = $(E2ACCESS_OBJ) $(LIBE2ACCESS_OBJ) $(TEST_LISTING_OBJ) $(TEST_REMOVE_OBJ) + +# Rules. + +.PHONY: all clean distclean + +all: $(TARGETS) + +clean: + rm -f $(ALL_OBJ) $(TARGETS) + +distclean: clean + echo "Nothing else to clean." + +$(E2ACCESS): $(E2ACCESS_OBJ) $(LIBE2ACCESS_SHARED) + $(CC) $(LDFLAGS) $(E2ACCESS_OBJ) -o $@ + +$(LIBE2ACCESS): $(LIBE2ACCESS_OBJ) + $(AR) rc $@ $(LIBE2ACCESS_OBJ) + $(RANLIB) $@ + +$(LIBE2ACCESS_SHARED): $(LIBE2ACCESS) $(LIBE2ACCESS_OBJ) + $(LD) -shared $(LIBE2ACCESS_OBJ) -o $(LIBE2ACCESS_SHARED) + +$(TEST_LISTING): $(TEST_LISTING_OBJ) $(LIBE2ACCESS_SHARED) + $(CC) $(LDFLAGS) $(TEST_LISTING_OBJ) -o $@ + +$(TEST_REMOVE): $(TEST_REMOVE_OBJ) $(LIBE2ACCESS_SHARED) + $(CC) $(LDFLAGS) $(TEST_REMOVE_OBJ) -o $@ + +.c.o: + $(CC) -c $(CFLAGS) $< -o $@ diff -r 85fcd5943fa5 -r 8ad94f3addb2 libe2access/host/e2access.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/host/e2access.c Tue Dec 28 01:37:59 2021 +0100 @@ -0,0 +1,527 @@ +/* + * Access a filesystem. + * + * Copyright (C) 2019 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 + +#include + +#include "file.h" +#include "format.h" +#include "image.h" +#include "path.h" + + + +/* Copy buffer size. */ + +const int BUFSIZE = 4096; + + + +/* Show directory entries when iterating. */ + +static int image_list_dir_proc(struct ext2_dir_entry *dirent, int offset, + int blocksize, char *buf, void *priv_data) +{ + ext2_filsys fs = (ext2_filsys) priv_data; + struct ext2_inode inode; + + /* Obtain the inode details for metadata. */ + + if (ext2fs_read_inode(fs, dirent->inode, &inode)) + return DIRENT_ABORT; + + /* Output details in the style of "ls -l" showing directory, permissions, + owner, group and size information. */ + + printf("%s%s %5d %5d %6d ", + _image_isdir(fs, dirent->inode) ? "d" : "-", + get_permission_string(inode.i_mode), + inode.i_uid, + inode.i_gid, + EXT2_I_SIZE(&inode)); + + /* Output the name which is presumably not necessarily null-terminated. */ + + fwrite(dirent->name, sizeof(char), ext2fs_dirent_name_len(dirent), stdout); + fputc((int) '\n', stdout); + 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; +} + + + +/* Copy source files from the external environment into the filesystem image. */ + +int copy_in(ext2_filsys fs, int argc, char *argv[]) +{ + errcode_t retval; + + /* Target filename details. */ + + const char *target = argv[argc - 1]; + const char *target_remaining = argv[argc - 1]; + const char *basename; + int target_is_file; + + /* Target file and directory details. */ + + int target_is_new; + ext2_ino_t ino_file, ino_target; + int flags; + + /* Source file details. */ + + struct stat st; + int i; + + /* Locate the target and test whether it is a file or a directory. */ + + if (image_find_path(fs, &target_remaining, &ino_target)) + { + /* Only a non-existent file in an existing directory is permitted. */ + + if (!_image_isdir(fs, ino_target) || !path_is_leafname(target_remaining)) + { + printf("Target %s not found.\n", target); + return 1; + } + + target_is_file = 1; + target_is_new = 1; + } + else + { + target_is_file = _image_isfile(fs, ino_target); + target_is_new = 0; + } + + /* Only permit a target file when one source file is given. */ + + if (target_is_file) + { + if (argc > 2) + { + printf("Target %s can only be a file when copying a single file.\n", target); + return 1; + } + } + else if (!_image_isdir(fs, ino_target)) + { + printf("Target %s is not a directory.\n", target); + return 1; + } + + /* Copy each source object to the target directory. */ + + for (i = 0; i < argc - 1; i++) + { + if (target_is_file) + basename = target_remaining; + else + { + basename = path_basename(argv[i]); + target_is_new = image_find_file(fs, target, basename, &ino_file); + } + + /* Directories are created with the same metadata. */ + + if (isdir(argv[i])) + { + if (!target_is_new) + { + printf("Target %s cannot be created since it already exists.\n", target); + return 1; + } + + /* Obtain the metadata. */ + + if (lstat(argv[i], &st)) + return 1; + + retval = image_make_dir(fs, ino_target, basename, st.st_mode, + st.st_uid, st.st_gid, &ino_file); + + if (retval) + { + printf("Failed to create directory %s (%d).\n", argv[i], retval); + return 1; + } + } + + /* Files are copied. */ + + else if (isfile(argv[i])) + { + flags = EXT2_FILE_WRITE; + + /* Obtain the inode for the target file. */ + + if (target_is_new) + { + /* Populate the inode details. */ + + if (lstat(argv[i], &st)) + return 1; + + retval = image_create_file(fs, ino_target, basename, st.st_mode, + st.st_uid, st.st_gid, &ino_file); + if (retval) + { + printf("Failed to create file %s (%d).\n", argv[i], retval); + return 1; + } + + flags |= EXT2_FILE_CREATE; + } + + /* NOTE: Overwrite/update metadata where appropriate. */ + + if (copy_file_in(argv[i], fs, ino_file, flags)) + { + printf("Failed to write to %s.\n", argv[i]); + return 1; + } + } + } + + return 0; +} + +/* Copy source files out of the filesystem image into the external environment. */ + +int copy_out(ext2_filsys fs, int argc, char *argv[]) +{ + /* Target filename details. */ + + char *target = argv[argc - 1]; + int target_is_file; + + /* Target file and directory details. */ + + ext2_file_t file; + ext2_ino_t ino_file; + + /* Source file details. */ + + const char *path; + int i; + + /* 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 + { + printf("Target %s is not a directory.\n", target); + return 1; + } + + /* Only permit a target file when one source file is given. */ + + if (argc > 2) + { + printf("Target %s can only be a file when copying a single file.\n", target); + return 1; + } + } + else + target_is_file = 0; + + /* For each source filename, test whether it references a file. */ + + for (i = 0; i < argc - 1; i++) + { + if (!image_isfile(fs, argv[i])) + { + printf("Source %s is not a file.\n", argv[i]); + return 1; + } + } + + /* Copy each source file to the target directory. */ + + for (i = 0; i < argc - 1; i++) + { + path = argv[i]; + + if (image_find_path(fs, &path, &ino_file)) + return 1; + + if (copy_file_out(target, argv[i], target_is_file, fs, ino_file)) + { + printf("Failed to read from %s.\n", argv[i]); + return 1; + } + + /* NOTE: Overwrite/update metadata where appropriate. */ + } + + return 0; +} + +/* List directories in the filesystem image. */ + +int list_dirs(ext2_filsys fs, int argc, char *argv[]) +{ + int i; + const char *path; + + for (i = 0; i < argc; i++) + { + path = argv[i]; + + /* List the directory contents. */ + + puts(path); + + if (image_list_dir(fs, path, image_list_dir_proc, fs)) + return 1; + } + + return 0; +} + +/* Make directories in the filesystem image. */ + +int make_dirs(ext2_filsys fs, int argc, char *argv[]) +{ + int i; + char *path_end; + const char *path; + ext2_ino_t ino; + + /* Make each directory component in the given pathname. */ + + for (i = 0; i < argc; i++) + { + path = argv[i]; + if (!*path) + continue; + + /* Search for the remaining components. */ + + if (!image_find_path(fs, &path, &ino)) + continue; + + /* From the first unrecognised component, make the remaining + directories. */ + + if (image_make_dirs(fs, &path, ino, 0777, 0, 0)) + return 1; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + int flags = EXT2_FLAG_RW; // | EXT2_FLAG_SOFTSUPP_FEATURES | EXT2_FLAG_64BITS; + char *fsname, *operation, *filename; + ext2_filsys fs = NULL; + errcode_t retval; + int exitcode = 0; + + if (argc < 4) + { + printf("Usage: %s ...\n", argv[0]); + return 1; + } + + fsname = argv[1]; + + /* Open the filesystem image using the POSIX file access mechanism. */ + + retval = ext2fs_open(fsname, flags, 0, 0, unix_io_manager, &fs); + if (retval) + { + printf("Could not open filesystem using %s\n", fsname); + return 1; + } + + //fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE; + + retval = ext2fs_read_bitmaps(fs); + if (retval) + { + printf("Could not read bitmaps from %s\n", fsname); + return 1; + } + + /* Perform the requested operation. */ + + operation = argv[2]; + + if (!strcmp(operation, "--copy-out")) + { + exitcode = copy_out(fs, argc - 3, &argv[3]); + } + else if (!strcmp(operation, "--copy-in")) + { + exitcode = copy_in(fs, argc - 3, &argv[3]); + } + else if (!strcmp(operation, "--list-dirs")) + { + exitcode = list_dirs(fs, argc - 3, &argv[3]); + } + else if (!strcmp(operation, "--make-dirs")) + { + exitcode = make_dirs(fs, argc - 3, &argv[3]); + } + else + { + printf("Operation %s is not recognised.\n", operation); + exitcode = 1; + } + + /* Close the filesystem image. */ + + retval = ext2fs_flush(fs); + if (retval) + { + printf("Error flushing filesystem in %s\n", fsname); + exitcode = 1; + } + + retval = ext2fs_close(fs); + if (retval) + { + printf("Error closing filesystem in %s\n", fsname); + exitcode = 1; + } + + ext2fs_free(fs); + return exitcode; +} diff -r 85fcd5943fa5 -r 8ad94f3addb2 libe2access/host/file.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/host/file.c Tue Dec 28 01:37:59 2021 +0100 @@ -0,0 +1,77 @@ +/* + * File access functions. + * + * Copyright (C) 2019 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 + + + +/* Test object types in the external environment. */ + +int isdir(const char *name) +{ + struct stat st; + + if (!lstat(name, &st)) + return S_ISDIR(st.st_mode); + else + return 0; +} + +int isdir_dirname(const char *name) +{ + char dirname[strlen(name) + 1]; + char *s; + + strcpy(dirname, name); + s = strrchr(dirname, (int) '/'); + + if (s != NULL) + *s = '\0'; + + return isdir(dirname); +} + +int isfile(const char *name) +{ + struct stat st; + + if (!lstat(name, &st)) + return S_ISREG(st.st_mode); + else + return 0; +} + +/* Open a file in the external environment. */ + +FILE *open_file_in_dir(const char *dirname, const char *basename, + const char *mode) +{ + char pathname[strlen(dirname) + strlen(basename) + 1]; + + strcpy(pathname, dirname); + strcat(pathname, "/"); + strcat(pathname, basename); + + return fopen(pathname, mode); +} diff -r 85fcd5943fa5 -r 8ad94f3addb2 libe2access/host/file.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/host/file.h Tue Dec 28 01:37:59 2021 +0100 @@ -0,0 +1,34 @@ +/* + * File access functions. + * + * Copyright (C) 2019 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 + */ + +#ifndef __FILE_H__ +#define __FILE_H__ + +#include + +int isdir(const char *name); +int isdir_dirname(const char *name); +int isfile(const char *name); + +FILE *open_file_in_dir(const char *dirname, const char *basename, + const char *mode); + +#endif /* __FILE_H__ */ diff -r 85fcd5943fa5 -r 8ad94f3addb2 libe2access/host/mkfs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/host/mkfs Tue Dec 28 01:37:59 2021 +0100 @@ -0,0 +1,47 @@ +#!/bin/sh + +# Make a filesystem image. +# +# Copyright (C) 2019, 2021 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 + +TARGET=$1 + +if [ -e "$TARGET" ] ; then + echo "File already exists: $TARGET" 1>&2 + exit 1 +fi + +if [ ! "$TARGET" ] ; then + echo "Creating temporary file." 1>&2 + TARGET=`mktemp` +fi + +SIZE=${2:-2000} + +# Make a filesystem. + + dd if=/dev/zero of="$TARGET" bs=1024 count=1 seek="$SIZE" \ +> /dev/null 2>&1 + +if ! `/sbin/mkfs.ext2 -q "$TARGET"` ; then + exit 1 +fi + +echo "$TARGET" + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 85fcd5943fa5 -r 8ad94f3addb2 libe2access/host/run_test --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/host/run_test Tue Dec 28 01:37:59 2021 +0100 @@ -0,0 +1,64 @@ +#!/bin/sh + +# Run a test program with its own image. +# +# Copyright (C) 2021 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 + +THISDIR=`dirname "$0"` +PROGNAME=`basename "$0"` + +# Obtain any option. + +if [ "$1" = '-k' ] ; then + KEEP_IMAGE="$1" + shift 1 +else + KEEP_IMAGE= +fi + +# Obtain the test name. + +TEST="$1" +TESTPROG="$THISDIR/$TEST" + +if [ ! "$TEST" ] || [ ! -e "$TESTPROG" ] ; then + echo "Usage: $PROGNAME [ -k ] " 1>&2 + exit 1 +fi + +# Indicate the library location. + +export LD_LIBRARY_PATH="$THISDIR":"$LD_LIBRARY_PATH" + +# Make an image to use for testing. + +IMAGE=`"$THISDIR/mkfs"` + +# Run the test program. + +"$TESTPROG" "$IMAGE" + +# Show the image filename or remove the image. + +if [ "$KEEP_IMAGE" ] ; then + echo "$IMAGE" +else + rm "$IMAGE" +fi + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 85fcd5943fa5 -r 8ad94f3addb2 libe2access/host/test_listing.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/host/test_listing.c Tue Dec 28 01:37:59 2021 +0100 @@ -0,0 +1,169 @@ +/* + * Test filesystem listing concurrency limitations. + * + * Copyright (C) 2019, 2021 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 + +#include + +#include "file.h" +#include "format.h" +#include "image.h" +#include "path.h" + + + +/* Show directory entries when iterating. */ + +static int image_list_dir_proc(struct ext2_dir_entry *dirent, int offset, + int blocksize, char *buf, void *priv_data) +{ + ext2_filsys fs = (ext2_filsys) priv_data; + struct ext2_inode inode; + ext2_file_t file; + __u64 size; + char *to_remove[] = {"file0061", "file0062", "file0063", "file0125", "file0126", "file0127", 0}; + char **f; + + /* Obtain the inode details for metadata. */ + + if (ext2fs_read_inode(fs, dirent->inode, &inode)) + return DIRENT_ABORT; + + /* Output details in the style of "ls -l" showing directory, permissions, + owner, group and size information. */ + + printf("%06d: %s%s %5d %5d %6d ", + offset, + _image_isdir(fs, dirent->inode) ? "d" : "-", + get_permission_string(inode.i_mode), + inode.i_uid, + inode.i_gid, + EXT2_I_SIZE(&inode)); + + /* Output the name which is presumably not necessarily null-terminated. */ + + fwrite(dirent->name, sizeof(char), ext2fs_dirent_name_len(dirent), stdout); + fputc((int) '\n', stdout); + + /* Remove files at an awkward point in time. */ + + if (!strncmp(dirent->name, "file0060", ext2fs_dirent_name_len(dirent))) + { + for (f = to_remove; *f; f++) + if (ext2fs_unlink(fs, EXT2_ROOT_INO, *f, 0, 0)) + printf("%s not removed!\n", *f); + } + + return 0; +} + + + +int main(int argc, char *argv[]) +{ + int flags = EXT2_FLAG_RW; + char *fsname; + ext2_filsys fs = NULL; + errcode_t retval; + int exitcode = 0; + char basename[32]; + ext2_ino_t ino; + ext2_file_t file; + int i; + + if (argc < 2) + { + printf("Usage: %s \n", argv[0]); + return 1; + } + + fsname = argv[1]; + + /* Open the filesystem image using the POSIX file access mechanism. */ + + retval = ext2fs_open(fsname, flags, 0, 0, unix_io_manager, &fs); + if (retval) + { + printf("Could not open filesystem using %s\n", fsname); + return 1; + } + + retval = ext2fs_read_bitmaps(fs); + if (retval) + { + printf("Could not read bitmaps from %s\n", fsname); + return 1; + } + + printf("Filesystem with blocksize %d\n", fs->blocksize); + + /* Create some files. */ + + for (i = 1; i <= 200; i++) + { + sprintf(basename, "file%04d", i); + + retval = image_create_file(fs, EXT2_ROOT_INO, basename, 0644, + 1000, 1000, &ino); + + if (retval) + { + printf("Could not create file %s\n", basename); + return 1; + } + + if (ext2fs_file_open(fs, ino, EXT2_FILE_WRITE | EXT2_FILE_CREATE, &file)) + { + printf("Could not write file %s\n", basename); + return 1; + } + + ext2fs_file_flush(file); + ext2fs_file_close(file); + } + + image_list_dir(fs, "", image_list_dir_proc, fs); + image_list_dir(fs, "", image_list_dir_proc, fs); + + /* Close the filesystem image. */ + + retval = ext2fs_flush(fs); + if (retval) + { + printf("Error flushing filesystem in %s\n", fsname); + exitcode = 1; + } + + retval = ext2fs_close(fs); + if (retval) + { + printf("Error closing filesystem in %s\n", fsname); + exitcode = 1; + } + + ext2fs_free(fs); + return exitcode; +} diff -r 85fcd5943fa5 -r 8ad94f3addb2 libe2access/host/test_remove.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libe2access/host/test_remove.c Tue Dec 28 01:37:59 2021 +0100 @@ -0,0 +1,264 @@ +/* + * Test file removal semantics. + * + * Copyright (C) 2019, 2021 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 + +#include + +#include "file.h" +#include "format.h" +#include "image.h" +#include "path.h" + + + +/* Buffer size for file access. */ + +const int BUFSIZE = 4096; + +/* Number of open files. */ + +const int FILES = 20; + + + +/* Show directory entries when iterating. */ + +static int image_list_dir_proc(struct ext2_dir_entry *dirent, int offset, + int blocksize, char *buf, void *priv_data) +{ + ext2_filsys fs = (ext2_filsys) priv_data; + struct ext2_inode inode; + ext2_file_t file; + __u64 size; + + /* Obtain the inode details for metadata. */ + + if (ext2fs_read_inode(fs, dirent->inode, &inode)) + return DIRENT_ABORT; + + /* Output details in the style of "ls -l" showing directory, permissions, + owner, group and size information. */ + + printf("%06d: %s%s %5d %5d %6d ", + offset, + _image_isdir(fs, dirent->inode) ? "d" : "-", + get_permission_string(inode.i_mode), + inode.i_uid, + inode.i_gid, + EXT2_I_SIZE(&inode)); + + /* Output the name which is presumably not necessarily null-terminated. */ + + fwrite(dirent->name, sizeof(char), ext2fs_dirent_name_len(dirent), stdout); + fputc((int) '\n', stdout); + + return 0; +} + + + +int main(int argc, char *argv[]) +{ + int flags = EXT2_FLAG_RW; + char *fsname; + ext2_filsys fs = NULL; + errcode_t retval; + int exitcode = 0; + char basename[32]; + ext2_ino_t ino, inos[FILES]; + ext2_file_t file, files[FILES]; + char buf[BUFSIZE]; + unsigned int transferred; + int i; + + if (argc < 2) + { + printf("Usage: %s \n", argv[0]); + return 1; + } + + fsname = argv[1]; + + /* Open the filesystem image using the POSIX file access mechanism. */ + + retval = ext2fs_open(fsname, flags, 0, 0, unix_io_manager, &fs); + if (retval) + { + printf("Could not open filesystem using %s\n", fsname); + return 1; + } + + retval = ext2fs_read_bitmaps(fs); + if (retval) + { + printf("Could not read bitmaps from %s\n", fsname); + return 1; + } + + printf("Filesystem with blocksize %d\n", fs->blocksize); + + /* Create some files. */ + + for (i = 1; i <= FILES; i++) + { + sprintf(basename, "file%04d", i); + + retval = image_create_file(fs, EXT2_ROOT_INO, basename, 0644, + 1000, 1000, &ino); + + if (retval) + { + printf("Could not create file %s\n", basename); + return 1; + } + + if (ext2fs_file_open(fs, ino, EXT2_FILE_WRITE | EXT2_FILE_CREATE, &file)) + { + printf("Could not open file %s\n", basename); + return 1; + } + + ext2fs_file_flush(file); + + files[i - 1] = file; + inos[i - 1] = ino; + } + + image_list_dir(fs, "", image_list_dir_proc, fs); + printf("----\n"); + + /* Unlink the files. */ + + for (i = 1; i <= FILES; i++) + { + sprintf(basename, "file%04d", i); + + if (ext2fs_unlink(fs, EXT2_ROOT_INO, basename, 0, 0)) + { + printf("Could not unlink file %s\n", basename); + return 1; + } + } + + image_list_dir(fs, "", image_list_dir_proc, fs); + printf("----\n"); + + /* Access and close unlinked files. */ + + for (i = 1; i <= FILES; i++) + { + sprintf(basename, "file%04d", i); + sprintf(buf, "writing to file%04d", i); + + file = files[i - 1]; + + if (ext2fs_file_write(file, buf, strlen(buf), &transferred)) + { + printf("Could not write to file %s\n", basename); + return 1; + } + + ext2fs_file_flush(file); + ext2fs_file_close(file); + } + + image_list_dir(fs, "", image_list_dir_proc, fs); + printf("----\n"); + + /* Create some more files. */ + + for (i = 1; i <= FILES; i++) + { + sprintf(basename, "file%04d", i + FILES); + + retval = image_create_file(fs, EXT2_ROOT_INO, basename, 0644, + 1000, 1000, &ino); + + if (retval) + { + printf("Could not create file %s\n", basename); + return 1; + } + + if (ext2fs_file_open(fs, ino, EXT2_FILE_WRITE | EXT2_FILE_CREATE, &file)) + { + printf("Could not write file %s\n", basename); + return 1; + } + + ext2fs_file_flush(file); + ext2fs_file_close(file); + } + + image_list_dir(fs, "", image_list_dir_proc, fs); + printf("----\n"); + + /* Re-open the original files and read from them. */ + + for (i = 1; i <= FILES; i++) + { + sprintf(basename, "file%04d", i); + + ino = inos[i - 1]; + + if (ext2fs_file_open(fs, ino, 0, &file)) + { + printf("Could not open file %s\n", basename); + return 1; + } + + if (ext2fs_file_read(file, buf, BUFSIZE, &transferred)) + { + printf("Could not read from file %s\n", basename); + return 1; + } + + buf[transferred] = '\0'; + printf("Read from %s: %s\n", basename, buf); + + ext2fs_file_close(file); + } + + /* Close the filesystem image. */ + + retval = ext2fs_flush(fs); + if (retval) + { + printf("Error flushing filesystem in %s\n", fsname); + exitcode = 1; + } + + retval = ext2fs_close(fs); + if (retval) + { + printf("Error closing filesystem in %s\n", fsname); + exitcode = 1; + } + + ext2fs_free(fs); + return exitcode; +} diff -r 85fcd5943fa5 -r 8ad94f3addb2 libe2access/include/e2access/image.h --- a/libe2access/include/e2access/image.h Sun Nov 28 22:18:33 2021 +0100 +++ b/libe2access/include/e2access/image.h Tue Dec 28 01:37:59 2021 +0100 @@ -1,7 +1,7 @@ /* * Filesystem image access functions. * - * Copyright (C) 2019 Paul Boddie + * Copyright (C) 2019, 2021 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 @@ -23,8 +23,7 @@ #define __IMAGE_H__ #include - - +#include #ifdef __cplusplus extern "C" { @@ -46,6 +45,11 @@ errcode_t image_inode(ext2_filsys fs, const char *pathname, struct ext2_inode *inode); +errcode_t image_list_dir(ext2_filsys fs, const char *path, + int (*proc)(struct ext2_dir_entry *, int, int, char *, + void *), + void *data); + errcode_t image_make_dir(ext2_filsys fs, ext2_ino_t ino_dir, const char *basename, __u16 mode, __u16 uid, __u16 gid, ext2_ino_t *ino); diff -r 85fcd5943fa5 -r 8ad94f3addb2 libe2access/lib/src/format.c --- a/libe2access/lib/src/format.c Sun Nov 28 22:18:33 2021 +0100 +++ b/libe2access/lib/src/format.c Tue Dec 28 01:37:59 2021 +0100 @@ -1,7 +1,7 @@ /* * File metadata formatting. * - * Copyright (C) 2019 Paul Boddie + * Copyright (C) 2019, 2021 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 @@ -27,12 +27,12 @@ char *get_permission_string(uint16_t permissions) { - static char s[9] = "--------\0"; + static char s[11] = "---------\0"; static char letters[] = "rwx"; int i, letter; uint16_t selector = 0400; - for (i = 0, letter = 0; i < 9; i++, letter = (letter + 1) % 3, selector >>= 1) + for (i = 0, letter = 0; i < 10; i++, letter = (letter + 1) % 3, selector >>= 1) s[i] = permissions & selector ? letters[letter] : '-'; return s; diff -r 85fcd5943fa5 -r 8ad94f3addb2 libe2access/lib/src/image.c --- a/libe2access/lib/src/image.c Sun Nov 28 22:18:33 2021 +0100 +++ b/libe2access/lib/src/image.c Tue Dec 28 01:37:59 2021 +0100 @@ -1,7 +1,7 @@ /* * Filesystem access functions. * - * Copyright (C) 2019 Paul Boddie + * Copyright (C) 2019, 2021 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 @@ -20,7 +20,6 @@ */ #include -#include #include @@ -186,6 +185,47 @@ return ext2fs_read_inode(fs, ino, inode); } +/* List a directory in the filesystem image. */ + +errcode_t image_list_dir(ext2_filsys fs, const char *path, + int (*proc)(struct ext2_dir_entry *, int, int, char *, + void *), + void *data) +{ + const char *path_orig = path; + char *buf; + ext2_ino_t ino; + errcode_t retval; + + retval = ext2fs_get_mem(fs->blocksize, &buf); + if (retval) + return retval; + + /* Locate the object and test whether it is a directory. */ + + retval = image_find_path(fs, &path, &ino); + if (retval) + { + ext2fs_free_mem(&buf); + return retval; + } + + if (!_image_isdir(fs, ino)) + return 1; + + /* List the directory contents. */ + + retval = ext2fs_dir_iterate(fs, ino, 0, buf, proc, data); + if (retval) + { + ext2fs_free_mem(&buf); + return retval; + } + + ext2fs_free_mem(&buf); + return 0; +} + /* Make a directory in the given directory in the filesystem image having the given name and metadata. */