# HG changeset patch # User Paul Boddie # Date 1647818262 -3600 # Node ID 5c3d7f228d1f716a0d1f27da4e349c2998820b9b # Parent 1afd6b4b1fd6f25b4bbe2cfefecc2e3da4349646 Added copy-in support to fsaccess. diff -r 1afd6b4b1fd6 -r 5c3d7f228d1f conf/fsaccess.txt --- a/conf/fsaccess.txt Mon Mar 21 00:15:43 2022 +0100 +++ b/conf/fsaccess.txt Mon Mar 21 00:17:42 2022 +0100 @@ -1,7 +1,13 @@ ls home/paulb/many ls home/paulb -mkdir home/paulb/newdir +mkdir home/paulb/fsaccess ls home/paulb -ls home/paulb/newdir +ls home/paulb/fsaccess stat home/paulb -stat home/paulb/newdir +stat home/paulb/fsaccess +copy-in rom/fsaccess.txt home/paulb/fsaccess +ls home/paulb/fsaccess +stat home/paulb/fsaccess/fsaccess.txt +copy-in rom/fsaccess.txt home/paulb/fsaccess/script.txt +ls home/paulb/fsaccess +stat home/paulb/fsaccess/script.txt diff -r 1afd6b4b1fd6 -r 5c3d7f228d1f fsaccess/Makefile --- a/fsaccess/Makefile Mon Mar 21 00:15:43 2022 +0100 +++ b/fsaccess/Makefile Mon Mar 21 00:17:42 2022 +0100 @@ -6,10 +6,10 @@ MODE = static SRC_C = \ - fsaccess.c input.c session.c \ - ops.c op_list_objects.c op_make_dirs.c op_script.c \ + file.c fsaccess.c input.c session.c ops.c \ + op_copy_in.c op_list_objects.c op_make_dirs.c op_script.c \ op_stat_objects.c -REQUIRES_LIBS = l4re_c-util libfsclient libmem libipc libsystypes libe2access_blockserver +REQUIRES_LIBS = l4re_c-util libfsclient libmem libipc libsystypes libe2access libe2access_blockserver include $(L4DIR)/mk/prog.mk diff -r 1afd6b4b1fd6 -r 5c3d7f228d1f fsaccess/file.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fsaccess/file.c Mon Mar 21 00:17:42 2022 +0100 @@ -0,0 +1,82 @@ +/* + * Generic file access functions. + * + * 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" + + + +/* 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); +} + +/* vim: tabstop=4 expandtab shiftwidth=4 +*/ diff -r 1afd6b4b1fd6 -r 5c3d7f228d1f fsaccess/file.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fsaccess/file.h Mon Mar 21 00:17:42 2022 +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 + */ + +#pragma once + +#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); + +/* vim: tabstop=4 expandtab shiftwidth=4 +*/ diff -r 1afd6b4b1fd6 -r 5c3d7f228d1f fsaccess/fsaccess.c --- a/fsaccess/fsaccess.c Mon Mar 21 00:15:43 2022 +0100 +++ b/fsaccess/fsaccess.c Mon Mar 21 00:17:42 2022 +0100 @@ -57,8 +57,8 @@ /* Operations exposed by the program. */ struct operation operations[] = { + {"copy-in", copy_in}, #if 0 - {"copy-in", copy_in}, {"copy-out", copy_out}, #endif {"ls", list_objects}, diff -r 1afd6b4b1fd6 -r 5c3d7f228d1f fsaccess/op_copy_in.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fsaccess/op_copy_in.c Mon Mar 21 00:17:42 2022 +0100 @@ -0,0 +1,267 @@ +/* + * Copy a file into 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 +#include + +#include "file.h" +#include "ops.h" +#include "session.h" + + + +/* Copy buffer size. */ + +static int BUFSIZE = 4096; + + + +/* Alternative metadata set by options. */ + +extern struct metadata md; + + + +/* Copy a file into the filesystem image. */ + +static int _copy_file_in(const char *source, const char *target, flags_t flags) +{ + int retval = 0; + + /* Copying details. */ + + FILE *fp; + file_t *target_fp; + char buf[BUFSIZE]; + size_t got; + offset_t written; + + /* Open a file in the target directory. */ + + target_fp = client_open(target, flags); + + if (target_fp == NULL) + return 1; + + /* Open the file in the source directory. */ + + fp = fopen(source, "r"); + + /* Copy the file content. */ + + if (fp != NULL) + { + while ((got = fread(buf, sizeof(char), BUFSIZE, fp))) + { + while (got) + { + written = client_write(target_fp, buf, got); + + if (!written) + { + retval = 1; + goto close_files; + } + got -= written; + } + } + } + +close_files: + fclose(fp); + client_close(target_fp); + + return retval; +} + +/* Copy a source file from the external environment into the filesystem. */ + +static int _copy_in(const char *source, const char *target, + const char *basename) +{ + /* Obtain basename and eventual target path. */ + + const char *source_basename = path_basename(source); + char target_plus_basename[strlen(target) + 1 + + (basename != NULL ? strlen(basename) + : strlen(source_basename)) + 1]; + const char *target_path; + + /* Target file properties. */ + + flags_t flags; + struct stat st; + long err; + + /* By default, treat the target as a new object. */ + + int target_is_new = 1; + + /* 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) + { + err = client_stat(target, &st); + + if (err) + { + fprintf(stderr, "Could not stat target: %s\n", target); + return 1; + } + + target_is_new = S_ISDIR(st.st_mode); + + if (target_is_new) + basename = path_basename(source); + } + + /* Obtain the target path. */ + + if (basename != NULL) + { + sprintf(target_plus_basename, "%s/%s", target, basename); + target_path = target_plus_basename; + } + else + target_path = target; + + /* Directories are created with the same metadata. */ + + if (isdir(source)) + { + if (!target_is_new) + { + fprintf(stderr, "Directory cannot be copied as it already exists: %s\n", target_path); + return 1; + } + + err = client_stat(source, &st); + + if (err) + { + fprintf(stderr, "Could not stat source: %s\n", source); + return 1; + } + + if (client_mkdir(target_path, st.st_mode & ~md.mask)) + return 1; + } + + /* Files are copied. */ + + else if (isfile(source)) + { + flags = O_WRONLY; + + /* Obtain the inode for the target file. */ + + if (target_is_new) + flags |= O_CREAT; + + /* NOTE: Overwrite/update metadata where appropriate. */ + + if (_copy_file_in(source, target_path, flags)) + { + fprintf(stderr, "Failed to copy file: %s\n", source); + return 1; + } + } + + return 0; +} + +/* Copy source files from the external environment into the filesystem image. */ + +int copy_in(int argc, char *argv[]) +{ + int i; + + /* Target filename details. */ + + char *target = argv[argc - 1]; + const char *basename; + struct stat st; + + /* Locate the target and test whether it is a file or a directory. */ + + long err = client_stat(target, &st); + + /* Only a non-existent file in an existing directory is permitted. */ + + if (err == -L4_ENOENT) + { + /* Split the path, making target the parent directory. */ + + basename = path_split(target); + err = client_stat(target, &st); + + if (err) + { + fprintf(stderr, "Could not stat target parent: %s\n", target); + return 1; + } + + if (!S_ISDIR(st.st_mode)) + { + fprintf(stderr, "Target parent is not directory: %s\n", target); + return 1; + } + } + else if (err) + { + fprintf(stderr, "Could not stat target: %s\n", target); + return 1; + } + + /* An existing object can be a file or directory. */ + + else + { + basename = NULL; + + /* Only permit a target file when one source file is given. */ + + if (!S_ISDIR(st.st_mode) && (argc > 2)) + { + fprintf(stderr, "Target can only be a file when copying a single file: %s\n", target); + return 1; + } + } + + /* Copy each source object to the target directory. */ + + for (i = 0; i < argc - 1; i++) + if (_copy_in(argv[i], target, basename)) + return 1; + + return 0; +} + +/* vim: tabstop=4 expandtab shiftwidth=4 +*/