# HG changeset patch # User Paul Boddie # Date 1646347220 -3600 # Node ID a7c302c50e9008b8f5eaa858bb867157e24f706f # Parent e9156da534d0d652721df053060a922e36059be3 Reorganised the copy-in operation. diff -r e9156da534d0 -r a7c302c50e90 libe2access/host/e2access.c --- a/libe2access/host/e2access.c Thu Mar 03 22:42:55 2022 +0100 +++ b/libe2access/host/e2access.c Thu Mar 03 23:40:20 2022 +0100 @@ -206,28 +206,123 @@ +/* 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; + } + + /* Obtain the metadata. */ + + if (lstat(filename, &st)) + { + fprintf(stderr, "Failed to read object metadata: %s\n", filename); + return 1; + } + + retval = image_make_dir(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 directory: %s\n", filename); + return 1; + } + } + + /* Files are copied. */ + + else if (isfile(filename)) + { + flags = EXT2_FILE_WRITE; + + /* Obtain the inode for the target file. */ + + if (target_is_new) + { + /* Populate the inode details. */ + + if (lstat(filename, &st)) + { + fprintf(stderr, "Failed to read object metadata: %s\n", filename); + return 1; + } + + retval = image_create_file(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 file: %s\n", filename); + 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 = argv[argc - 1]; + const char *target_remaining = target; const char *basename; /* Target file and directory details. */ - int target_is_file, target_is_new; - ext2_ino_t ino_file, ino_target; - int flags; - - /* Source file details. */ - - struct stat st; - int i; + int target_is_file; + ext2_ino_t ino_target; /* Locate the target and test whether it is a file or a directory. */ @@ -241,13 +336,19 @@ return 1; } - target_is_file = 1; - target_is_new = 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); - target_is_new = 0; + basename = NULL; } /* Only permit a target file when one source file is given. */ @@ -269,87 +370,8 @@ /* 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) - { - fprintf(stderr, "Target cannot be created since it already exists: %s\n", target); - return 1; - } - - /* Obtain the metadata. */ - - if (lstat(argv[i], &st)) - { - fprintf(stderr, "Failed to read object metadata: %s\n", argv[i]); - return 1; - } - - retval = image_make_dir(fs, ino_target, basename, - st.st_mode & ~md.mask, - md.have_uid ? md.uid : st.st_uid, - md.have_gid ? md.gid : st.st_gid, - &ino_file); - - if (retval) - { - fprintf(stderr, "Failed to create directory: %s\n", argv[i]); - 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)) - { - fprintf(stderr, "Failed to read object metadata: %s\n", argv[i]); - return 1; - } - - retval = image_create_file(fs, ino_target, basename, - st.st_mode & ~md.mask, - md.have_uid ? md.uid : st.st_uid, - md.have_gid ? md.gid : st.st_gid, - &ino_file); - if (retval) - { - fprintf(stderr, "Failed to create file: %s\n", argv[i]); - return 1; - } - - flags |= EXT2_FILE_CREATE; - } - - /* NOTE: Overwrite/update metadata where appropriate. */ - - if (copy_file_in(argv[i], fs, ino_file, flags)) - { - fprintf(stderr, "Failed to write to file: %s\n", argv[i]); - return 1; - } - } - } + if (_copy_in(fs, argv[i], ino_target, basename)) + return 1; return 0; }