# HG changeset patch # User Paul Boddie # Date 1644971139 -3600 # Node ID af6019950ebe8985c1a15602ea991193bef41316 # Parent dfd7946310c2f04be7d70f627742da182a3f897f Rearranged removal-related functions, exposing the semantics to e2access and to other users of the library. This reduces the activities performed by some functions, also permitting the reordering of removal operations. An adapter function has also been introduced to provide variants of operations accepting paths instead of inode numbers. diff -r dfd7946310c2 -r af6019950ebe libe2access/host/Makefile --- a/libe2access/host/Makefile Wed Feb 16 00:02:37 2022 +0100 +++ b/libe2access/host/Makefile Wed Feb 16 01:25:39 2022 +0100 @@ -1,6 +1,6 @@ # Makefile - Build the filesystem access programs # -# Copyright (C) 2019, 2021 Paul Boddie +# Copyright (C) 2019, 2021, 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 @@ -26,7 +26,7 @@ # Compilation and linking flags. -CFLAGS = -I$(INC) # -g +CFLAGS = -I$(INC) -fPIC # -g LDFLAGS = -lext2fs -L. -le2access # -lcom_err # Output programs and libraries. diff -r dfd7946310c2 -r af6019950ebe libe2access/host/e2access.c --- a/libe2access/host/e2access.c Wed Feb 16 00:02:37 2022 +0100 +++ b/libe2access/host/e2access.c Wed Feb 16 01:25:39 2022 +0100 @@ -574,11 +574,11 @@ return 1; } - /* Remove the directory. */ + /* Test for an empty directory. */ - if (image_remove_by_path(fs, path)) + if (image_dir_empty_by_path(fs, path, &ino)) { - fprintf(stderr, "Could not remove directory: %s\n", path); + fprintf(stderr, "Directory not empty: %s\n", path); return 1; } @@ -589,6 +589,14 @@ fprintf(stderr, "Could not unlink directory: %s\n", path); return 1; } + + /* Remove the directory. */ + + if (image_remove_by_inode(fs, ino)) + { + fprintf(stderr, "Could not remove directory: %s\n", path); + return 1; + } } return 0; diff -r dfd7946310c2 -r af6019950ebe libe2access/include/e2access/image.h --- a/libe2access/include/e2access/image.h Wed Feb 16 00:02:37 2022 +0100 +++ b/libe2access/include/e2access/image.h Wed Feb 16 01:25:39 2022 +0100 @@ -31,10 +31,22 @@ /* Filesystem operations. */ +errcode_t image_access_by_path(ext2_filsys fs, const char *path, + errcode_t (*op)(ext2_filsys, ext2_ino_t), + ext2_ino_t *ino); + errcode_t image_create_file(ext2_filsys fs, ext2_ino_t ino_target, const char *basename, __u16 mode, __u16 uid, __u16 gid, ext2_ino_t *ino_file); +errcode_t image_dir_empty_by_inode(ext2_filsys fs, ext2_ino_t ino); + +errcode_t image_dir_empty_by_path(ext2_filsys fs, const char *path, + ext2_ino_t *ino); + +errcode_t image_dir_get_parent(ext2_filsys fs, ext2_ino_t ino, + ext2_ino_t *ino_parent); + int image_file_type(int mode); errcode_t image_find_next(ext2_filsys fs, ext2_ino_t ino_dir, @@ -49,6 +61,8 @@ errcode_t image_inode(ext2_filsys fs, const char *pathname, struct ext2_inode *inode); +errcode_t image_inode_decrement(ext2_filsys fs, ext2_ino_t ino); + errcode_t image_list_dir(ext2_filsys fs, const char *path, int (*proc)(struct ext2_dir_entry *, int, int, char *, void *), @@ -68,11 +82,8 @@ errcode_t image_remove_by_inode(ext2_filsys fs, ext2_ino_t ino); -errcode_t image_remove_by_path(ext2_filsys fs, const char *path); - -errcode_t image_remove_directory_test(ext2_filsys fs, ext2_ino_t ino); - -errcode_t image_remove_parent_decrement(ext2_filsys fs, ext2_ino_t ino); +errcode_t image_remove_by_path(ext2_filsys fs, const char *path, + ext2_ino_t *ino); errcode_t image_rename(ext2_filsys fs, ext2_ino_t source, ext2_ino_t source_parent, const char *source_basename, @@ -109,3 +120,6 @@ #endif /* __IMAGE_H__ */ + +/* vim: tabstop=4 expandtab shiftwidth=4 +*/ diff -r dfd7946310c2 -r af6019950ebe libe2access/lib/src/image.c --- a/libe2access/lib/src/image.c Wed Feb 16 00:02:37 2022 +0100 +++ b/libe2access/lib/src/image.c Wed Feb 16 01:25:39 2022 +0100 @@ -126,6 +126,23 @@ +/* Adapter function. */ + +errcode_t image_access_by_path(ext2_filsys fs, const char *path, + errcode_t (*op)(ext2_filsys, ext2_ino_t), + ext2_ino_t *ino) +{ + const char *remaining = path; + errcode_t retval = image_find_path(fs, &remaining, ino); + + if (retval) + return retval; + + return op(fs, *ino); +} + + + /* Create an inode for a file. */ errcode_t image_create_file(ext2_filsys fs, ext2_ino_t ino_target, @@ -155,6 +172,52 @@ return ext2fs_write_new_inode(fs, *ino_file, &inode_file); } +/* Test for an empty directory. */ + +errcode_t image_dir_empty_by_inode(ext2_filsys fs, ext2_ino_t ino) +{ + /* Initialise the directory listing processing state. */ + + struct _image_parent_entry_state state = {.nonempty = 0}; + errcode_t retval = ext2fs_dir_iterate(fs, ino, 0, NULL, + _image_test_directory, &state); + + if (retval) + return retval; + + /* NOTE: Need a proper error here. */ + + return state.nonempty; +} + +/* Test for an empty directory using its path. */ + +errcode_t image_dir_empty_by_path(ext2_filsys fs, const char *path, + ext2_ino_t *ino) +{ + return image_access_by_path(fs, path, image_dir_empty_by_inode, ino); +} + +/* Find any parent reference. */ + +errcode_t image_dir_get_parent(ext2_filsys fs, ext2_ino_t ino, ext2_ino_t *ino_parent) +{ + /* Initialise the directory listing processing state. */ + + struct _image_parent_entry_state state = {.ino = 0}; + + /* A directory needs to be inspected for files and for the .. entry + to be queried to obtain the parent directory. */ + + errcode_t retval = ext2fs_dir_iterate(fs, ino, 0, NULL, + _image_get_parent_entry, &state); + + if (!retval) + *ino_parent = state.ino; + + return retval; +} + /* Return the appropriate ext2 file type value for the given mode value. */ int image_file_type(int mode) @@ -273,6 +336,32 @@ return ext2fs_read_inode(fs, ino, inode); } +/* Decrement the reference count on an inode. */ + +errcode_t image_inode_decrement(ext2_filsys fs, ext2_ino_t ino) +{ + struct ext2_inode_large inode; + errcode_t retval; + + retval = ext2fs_read_inode_full(fs, ino, + (struct ext2_inode *) &inode, + sizeof(inode)); + + if (retval) + return retval; + + /* NOTE: FUSE implementation tests for > 1. */ + + if (inode.i_links_count) + inode.i_links_count--; + + /* NOTE: Update modification time. */ + + return ext2fs_write_inode_full(fs, ino, + (struct ext2_inode *) &inode, + sizeof(inode)); +} + /* List a directory in the filesystem image. */ errcode_t image_list_dir(ext2_filsys fs, const char *path, @@ -403,11 +492,12 @@ errcode_t image_remove_by_inode(ext2_filsys fs, ext2_ino_t ino) { struct ext2_inode_large inode; + ext2_ino_t ino_parent = 0; errcode_t retval; if (_image_isdir(fs, ino)) { - retval = image_remove_directory_test(fs, ino); + retval = image_dir_get_parent(fs, ino, &ino_parent); if (retval) return retval; } @@ -430,11 +520,6 @@ if (!inode.i_links_count) { - retval = image_remove_parent_decrement(fs, ino); - - if (retval) - return retval; - /* NOTE: Update deletion time. */ retval = ext2fs_free_ext_attr(fs, ino, &inode); @@ -446,8 +531,8 @@ if (ext2fs_inode_has_valid_blocks2(fs, (struct ext2_inode *) &inode)) { - retval = ext2fs_punch(fs, ino, (struct ext2_inode *) &inode, NULL, - 0, ~0ULL); + retval = ext2fs_punch(fs, ino, (struct ext2_inode *) &inode, + NULL, 0, ~0ULL); /* Update allocation statistics. */ @@ -458,83 +543,23 @@ } } - return ext2fs_write_inode_full(fs, ino, (struct ext2_inode *) &inode, - sizeof(inode)); + retval = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *) &inode, + sizeof(inode)); + + /* Decrement the parent reference count for directories. */ + + if (!retval && !inode.i_links_count && ino_parent) + retval = image_inode_decrement(fs, ino_parent); + + return retval; } /* Remove a directory entry using its full path. */ -errcode_t image_remove_by_path(ext2_filsys fs, const char *path) -{ - const char *remaining = path; - ext2_ino_t ino; - errcode_t retval = image_find_path(fs, &remaining, &ino); - - if (retval) - return retval; - - return image_remove_by_inode(fs, ino); -} - -/* Test for an empty directory. */ - -errcode_t image_remove_directory_test(ext2_filsys fs, ext2_ino_t ino) -{ - /* Initialise the directory listing processing state. */ - - struct _image_parent_entry_state state = {.nonempty = 0}; - errcode_t retval = ext2fs_dir_iterate(fs, ino, 0, NULL, - _image_test_directory, &state); - - if (retval) - return retval; - - /* NOTE: Need a proper error here. */ - - return state.nonempty; -} - -/* Find any parent reference and decrement the parent reference count. */ - -errcode_t image_remove_parent_decrement(ext2_filsys fs, ext2_ino_t ino) +errcode_t image_remove_by_path(ext2_filsys fs, const char *path, + ext2_ino_t *ino) { - struct ext2_inode_large inode; - - /* Initialise the directory listing processing state. */ - - struct _image_parent_entry_state state = {.ino = 0}; - - /* A directory needs to be inspected for files and for the .. entry - to be queried to obtain the parent directory. */ - - errcode_t retval = ext2fs_dir_iterate(fs, ino, 0, NULL, - _image_get_parent_entry, &state); - - if (retval) - return retval; - - /* Reduce the reference count on the parent directory. */ - - if (state.ino) - { - retval = ext2fs_read_inode_full(fs, state.ino, - (struct ext2_inode *) &inode, - sizeof(inode)); - - if (retval) - return retval; - - if (inode.i_links_count) - inode.i_links_count--; - - /* NOTE: Update modification time. */ - - retval = ext2fs_write_inode_full(fs, state.ino, - (struct ext2_inode *) &inode, - sizeof(inode)); - } - - return retval; + return image_access_by_path(fs, path, image_remove_by_inode, ino); } /* Rename a file. */