1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/libe2access/host/op_copy_out.c Sun Mar 06 01:30:32 2022 +0100
1.3 @@ -0,0 +1,214 @@
1.4 +/*
1.5 + * Access a filesystem.
1.6 + *
1.7 + * Copyright (C) 2019, 2022 Paul Boddie <paul@boddie.org.uk>
1.8 + *
1.9 + * This program is free software; you can redistribute it and/or
1.10 + * modify it under the terms of the GNU General Public License as
1.11 + * published by the Free Software Foundation; either version 2 of
1.12 + * the License, or (at your option) any later version.
1.13 + *
1.14 + * This program is distributed in the hope that it will be useful,
1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.17 + * GNU General Public License for more details.
1.18 + *
1.19 + * You should have received a copy of the GNU General Public License
1.20 + * along with this program; if not, write to the Free Software
1.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
1.22 + * Boston, MA 02110-1301, USA
1.23 + */
1.24 +
1.25 +#include <stdio.h>
1.26 +#include <string.h>
1.27 +
1.28 +#include <sys/stat.h>
1.29 +
1.30 +#include <ext2fs/ext2fs.h>
1.31 +
1.32 +#include "file.h"
1.33 +#include "image.h"
1.34 +#include "path.h"
1.35 +#include "session.h"
1.36 +
1.37 +
1.38 +
1.39 +/* Copy buffer size. */
1.40 +
1.41 +extern int BUFSIZE;
1.42 +
1.43 +
1.44 +
1.45 +/* Alternative metadata set by options. */
1.46 +
1.47 +extern struct metadata md;
1.48 +
1.49 +
1.50 +
1.51 +/* Copy a file out of the filesystem image. */
1.52 +
1.53 +static int _copy_file_out(const char *target, const char *filename,
1.54 + int target_is_file, ext2_filsys fs,
1.55 + ext2_ino_t ino_file)
1.56 +{
1.57 + int retval = 0;
1.58 + ext2_file_t file;
1.59 +
1.60 + /* Copying details. */
1.61 +
1.62 + FILE *fp;
1.63 + char buf[BUFSIZE];
1.64 + unsigned int got;
1.65 + size_t written;
1.66 +
1.67 + /* Open the file in the source directory. */
1.68 +
1.69 + if (ext2fs_file_open(fs, ino_file, 0, &file))
1.70 + return 1;
1.71 +
1.72 + /* Open a file in the target directory. */
1.73 +
1.74 + if (target_is_file)
1.75 + fp = fopen(target, "w");
1.76 + else
1.77 + fp = open_file_in_dir(target, path_basename(filename), "w");
1.78 +
1.79 + /* Copy the file content. */
1.80 +
1.81 + if (fp != NULL)
1.82 + {
1.83 + do
1.84 + {
1.85 + if (ext2fs_file_read(file, buf, BUFSIZE, &got))
1.86 + {
1.87 + retval = 1;
1.88 + goto close_files;
1.89 + }
1.90 +
1.91 + while (got)
1.92 + {
1.93 + written = fwrite(buf, sizeof(char), got, fp);
1.94 + got -= written;
1.95 + }
1.96 +
1.97 + } while (got);
1.98 + }
1.99 +
1.100 +close_files:
1.101 + fclose(fp);
1.102 + ext2fs_file_close(file);
1.103 +
1.104 + return retval;
1.105 +}
1.106 +
1.107 +
1.108 +
1.109 +/* Make a new directory in the external environment. */
1.110 +
1.111 +static int _make_directory(const char *target, const char *basename,
1.112 + ext2_filsys fs, ext2_ino_t ino)
1.113 +{
1.114 + errcode_t retval;
1.115 + struct ext2_inode inode;
1.116 + char target_path[strlen(target) + strlen(basename) + 2];
1.117 +
1.118 + sprintf(target_path, "%s/%s", target, basename);
1.119 +
1.120 + retval = ext2fs_read_inode(fs, ino, &inode);
1.121 +
1.122 + if (retval)
1.123 + return retval;
1.124 +
1.125 + return mkdir(target_path, inode.i_mode);
1.126 +}
1.127 +
1.128 +/* Copy a file from the filesystem into the external environment. */
1.129 +
1.130 +static int _copy_out(ext2_filsys fs, const char *source, const char *target,
1.131 + int target_is_file)
1.132 +{
1.133 + ext2_ino_t ino_source;
1.134 +
1.135 + if (image_find_by_path(fs, source, &ino_source))
1.136 + {
1.137 + fprintf(stderr, "Failed to find file: %s\n", source);
1.138 + return 1;
1.139 + }
1.140 +
1.141 + /* Test whether the filename references a file. */
1.142 +
1.143 + if (image_isdir_by_path(fs, source))
1.144 + {
1.145 + if (_make_directory(target, path_basename(source), fs, ino_source))
1.146 + {
1.147 + fprintf(stderr, "Failed to make directory: %s/%s\n", target,
1.148 + path_basename(source));
1.149 + return 1;
1.150 + }
1.151 + }
1.152 + else if (image_isfile_by_path(fs, source))
1.153 + {
1.154 + if (_copy_file_out(target, source, target_is_file, fs, ino_source))
1.155 + {
1.156 + fprintf(stderr, "Failed to read from file: %s\n", source);
1.157 + return 1;
1.158 + }
1.159 + }
1.160 + else
1.161 + {
1.162 + fprintf(stderr, "Object type not supported: %s\n", source);
1.163 + return 1;
1.164 + }
1.165 +
1.166 + /* NOTE: Overwrite/update metadata where appropriate. */
1.167 +
1.168 + return 0;
1.169 +}
1.170 +
1.171 +/* Copy source files out of the filesystem image into the external environment. */
1.172 +
1.173 +int copy_out(ext2_filsys fs, int argc, char *argv[])
1.174 +{
1.175 + int i;
1.176 +
1.177 + /* Target filename details. */
1.178 +
1.179 + char *target = argv[argc - 1];
1.180 + int target_is_file;
1.181 +
1.182 + /* Locate the target and test whether it is a directory. */
1.183 +
1.184 + if (!isdir(target))
1.185 + {
1.186 + /* Only a new or existing file in an existing directory is permitted. */
1.187 +
1.188 + if (isfile(target) || isdir_dirname(target))
1.189 + target_is_file = 1;
1.190 + else
1.191 + {
1.192 + fprintf(stderr, "Target is not a directory: %s\n", target);
1.193 + return 1;
1.194 + }
1.195 +
1.196 + /* Only permit a target file when one source file is given. */
1.197 +
1.198 + if (argc > 2)
1.199 + {
1.200 + fprintf(stderr, "Target can only be a file when copying a single file: %s\n", target);
1.201 + return 1;
1.202 + }
1.203 + }
1.204 + else
1.205 + target_is_file = 0;
1.206 +
1.207 + /* Copy each source file to the target directory. */
1.208 +
1.209 + for (i = 0; i < argc - 1; i++)
1.210 + if (_copy_out(fs, argv[i], target, target_is_file))
1.211 + return 1;
1.212 +
1.213 + return 0;
1.214 +}
1.215 +
1.216 +/* vim: tabstop=4 expandtab shiftwidth=4
1.217 +*/