L4Re/departure

Annotated libe2access/host/op_copy_in.c

635:18f77ccd5ea8
8 months ago Paul Boddie Updated dataspace size type usage.
paul@278 1
/*
paul@280 2
 * Copy a file into a filesystem.
paul@278 3
 *
paul@278 4
 * Copyright (C) 2019, 2022 Paul Boddie <paul@boddie.org.uk>
paul@278 5
 *
paul@278 6
 * This program is free software; you can redistribute it and/or
paul@278 7
 * modify it under the terms of the GNU General Public License as
paul@278 8
 * published by the Free Software Foundation; either version 2 of
paul@278 9
 * the License, or (at your option) any later version.
paul@278 10
 *
paul@278 11
 * This program is distributed in the hope that it will be useful,
paul@278 12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@278 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@278 14
 * GNU General Public License for more details.
paul@278 15
 *
paul@278 16
 * You should have received a copy of the GNU General Public License
paul@278 17
 * along with this program; if not, write to the Free Software
paul@278 18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@278 19
 * Boston, MA  02110-1301, USA
paul@278 20
 */
paul@278 21
paul@278 22
#include <stdio.h>
paul@278 23
paul@278 24
#include <sys/stat.h>
paul@278 25
paul@278 26
#include <ext2fs/ext2fs.h>
paul@278 27
paul@278 28
#include "file.h"
paul@278 29
#include "image.h"
paul@278 30
#include "path.h"
paul@278 31
#include "session.h"
paul@278 32
paul@278 33
paul@278 34
paul@278 35
/* Copy buffer size. */
paul@278 36
paul@281 37
static int BUFSIZE = 4096;
paul@278 38
paul@278 39
paul@278 40
paul@278 41
/* Alternative metadata set by options. */
paul@278 42
paul@278 43
extern struct metadata md;
paul@278 44
paul@278 45
paul@278 46
paul@278 47
/* Copy a file into the filesystem image. */
paul@278 48
paul@278 49
static int _copy_file_in(const char *filename, ext2_filsys fs,
paul@278 50
                         ext2_ino_t ino_file, int flags)
paul@278 51
{
paul@278 52
    int retval = 0;
paul@278 53
    ext2_file_t file;
paul@278 54
paul@278 55
    /* Copying details. */
paul@278 56
paul@278 57
    FILE *fp;
paul@278 58
    char buf[BUFSIZE];
paul@278 59
    size_t got;
paul@278 60
    unsigned int written;
paul@278 61
paul@278 62
    /* Open a file in the target directory. */
paul@278 63
paul@278 64
    if (ext2fs_file_open(fs, ino_file, flags, &file))
paul@278 65
        return 1;
paul@278 66
paul@296 67
    /* Truncate the file, if overwriting. */
paul@296 68
paul@296 69
    if (!(flags & EXT2_FILE_CREATE))
paul@296 70
        ext2fs_file_set_size2(file, 0);
paul@296 71
paul@278 72
    /* Open the file in the source directory. */
paul@278 73
paul@278 74
    fp = fopen(filename, "r");
paul@278 75
paul@278 76
    /* Copy the file content. */
paul@278 77
paul@278 78
    if (fp != NULL)
paul@278 79
    {
paul@278 80
        while (got = fread(buf, sizeof(char), BUFSIZE, fp))
paul@278 81
        {
paul@278 82
            while (got)
paul@278 83
            {
paul@278 84
                if (ext2fs_file_write(file, buf, got, &written))
paul@278 85
                {
paul@278 86
                    retval = 1;
paul@278 87
                    goto close_files;
paul@278 88
                }
paul@278 89
                got -= written;
paul@278 90
            }
paul@278 91
        }
paul@278 92
    }
paul@278 93
paul@278 94
close_files:
paul@278 95
    fclose(fp);
paul@278 96
    ext2fs_file_flush(file);
paul@278 97
    ext2fs_file_close(file);
paul@278 98
paul@278 99
    return retval;
paul@278 100
}
paul@278 101
paul@278 102
/* Make a new object using the given function. */
paul@278 103
paul@278 104
static int _make_object(ext2_filsys fs, const char *filename,
paul@278 105
                        ext2_ino_t ino_parent, const char *basename,
paul@278 106
                        ext2_ino_t *ino_target,
paul@278 107
                        errcode_t (*fn)(ext2_filsys, ext2_ino_t, const char *,
paul@278 108
                                        __u16, __u16, __u16, ext2_ino_t *))
paul@278 109
{
paul@278 110
    errcode_t retval;
paul@278 111
    struct stat st;
paul@278 112
paul@278 113
    /* Obtain the metadata. */
paul@278 114
paul@278 115
    if (lstat(filename, &st))
paul@278 116
    {
paul@278 117
        fprintf(stderr, "Failed to read object metadata: %s\n", filename);
paul@278 118
        return 1;
paul@278 119
    }
paul@278 120
paul@278 121
    retval = fn(fs, ino_parent, basename, st.st_mode & ~md.mask,
paul@278 122
                md.have_uid ? md.uid : st.st_uid,
paul@278 123
                md.have_gid ? md.gid : st.st_gid,
paul@278 124
                ino_target);
paul@278 125
paul@278 126
    if (retval)
paul@278 127
    {
paul@278 128
        fprintf(stderr, "Failed to create object: %s\n", filename);
paul@278 129
        return 1;
paul@278 130
    }
paul@278 131
paul@278 132
    return 0;
paul@278 133
}
paul@278 134
paul@278 135
/* Copy a source file from the external environment into the filesystem. */
paul@278 136
paul@278 137
static int _copy_in(ext2_filsys fs, const char *filename, ext2_ino_t ino_target,
paul@278 138
                    const char *basename)
paul@278 139
{
paul@278 140
    errcode_t retval;
paul@278 141
    int flags;
paul@278 142
paul@278 143
    /* By default, treat the target as a new object. */
paul@278 144
paul@278 145
    ext2_ino_t ino_parent = ino_target;
paul@278 146
    int target_is_new = 1;
paul@278 147
paul@278 148
    /* Source file details. */
paul@278 149
paul@278 150
    struct stat st;
paul@278 151
paul@278 152
    /* Without a basename, the target exists and is either a directory, into
paul@278 153
       which the source file shall be copied, or it is a file that shall be
paul@296 154
       overwritten (for which the basename is irrelevant). */
paul@278 155
paul@278 156
    if (basename == NULL)
paul@278 157
    {
paul@278 158
        basename = path_basename(filename);
paul@278 159
        target_is_new = image_isdir_by_inode(fs, ino_target);
paul@278 160
    }
paul@278 161
paul@278 162
    /* Directories are created with the same metadata. */
paul@278 163
paul@278 164
    if (isdir(filename))
paul@278 165
    {
paul@278 166
        if (!target_is_new)
paul@278 167
        {
paul@278 168
            fprintf(stderr, "Directory cannot be copied as it already exists: %s\n", filename);
paul@278 169
            return 1;
paul@278 170
        }
paul@278 171
paul@278 172
        if (_make_object(fs, filename, ino_parent, basename, &ino_target,
paul@278 173
                         image_make_dir))
paul@278 174
            return 1;
paul@278 175
    }
paul@278 176
paul@278 177
    /* Files are copied. */
paul@278 178
paul@278 179
    else if (isfile(filename))
paul@278 180
    {
paul@278 181
        flags = EXT2_FILE_WRITE;
paul@278 182
paul@278 183
        /* Obtain the inode for the target file. */
paul@278 184
paul@278 185
        if (target_is_new)
paul@278 186
        {
paul@278 187
            if (_make_object(fs, filename, ino_parent, basename, &ino_target,
paul@278 188
                             image_create_file))
paul@278 189
                return 1;
paul@278 190
paul@278 191
            flags |= EXT2_FILE_CREATE;
paul@278 192
        }
paul@278 193
paul@278 194
        /* NOTE: Overwrite/update metadata where appropriate. */
paul@278 195
paul@278 196
        if (_copy_file_in(filename, fs, ino_target, flags))
paul@278 197
        {
paul@278 198
            fprintf(stderr, "Failed to copy file: %s\n", filename);
paul@278 199
            return 1;
paul@278 200
        }
paul@278 201
    }
paul@278 202
}
paul@278 203
paul@278 204
/* Copy source files from the external environment into the filesystem image. */
paul@278 205
paul@278 206
int copy_in(ext2_filsys fs, int argc, char *argv[])
paul@278 207
{
paul@278 208
    errcode_t retval;
paul@278 209
    int i;
paul@278 210
paul@278 211
    /* Target filename details. */
paul@278 212
paul@278 213
    const char *target = argv[argc - 1];
paul@278 214
    const char *target_remaining = target;
paul@278 215
    const char *basename;
paul@278 216
paul@278 217
    /* Target file and directory details. */
paul@278 218
paul@278 219
    int target_is_file;
paul@278 220
    ext2_ino_t ino_target;
paul@278 221
paul@278 222
    /* Locate the target and test whether it is a file or a directory. */
paul@278 223
paul@278 224
    if (image_resolve_by_path(fs, &target_remaining, &ino_target))
paul@278 225
    {
paul@278 226
        /* Only a non-existent file in an existing directory is permitted. */
paul@278 227
paul@278 228
        if (!image_isdir_by_inode(fs, ino_target) || !path_is_leafname(target_remaining))
paul@278 229
        {
paul@278 230
            fprintf(stderr, "Target not found: %s\n", target);
paul@278 231
            return 1;
paul@278 232
        }
paul@278 233
paul@278 234
        /* Any absent target leaves the basename remaining.
paul@278 235
           The resolved target is the parent directory. */
paul@278 236
paul@278 237
        target_is_file = 0;
paul@278 238
        basename = target_remaining;
paul@278 239
    }
paul@278 240
    else
paul@278 241
    {
paul@278 242
        /* Any present target can be a file or directory.
paul@278 243
           The resolved target is the actual target. */
paul@278 244
paul@278 245
        target_is_file = image_isfile_by_inode(fs, ino_target);
paul@278 246
        basename = NULL;
paul@278 247
    }
paul@278 248
paul@278 249
    /* Only permit a target file when one source file is given. */
paul@278 250
paul@278 251
    if (target_is_file)
paul@278 252
    {
paul@278 253
        if (argc > 2)
paul@278 254
        {
paul@278 255
            fprintf(stderr, "Target can only be a file when copying a single file: %s\n", target);
paul@278 256
            return 1;
paul@278 257
        }
paul@278 258
    }
paul@278 259
    else if (!image_isdir_by_inode(fs, ino_target))
paul@278 260
    {
paul@278 261
        fprintf(stderr, "Target is not a directory: %s\n", target);
paul@278 262
        return 1;
paul@278 263
    }
paul@278 264
paul@278 265
    /* Copy each source object to the target directory. */
paul@278 266
paul@278 267
    for (i = 0; i < argc - 1; i++)
paul@278 268
        if (_copy_in(fs, argv[i], ino_target, basename))
paul@278 269
            return 1;
paul@278 270
paul@278 271
    return 0;
paul@278 272
}
paul@278 273
paul@278 274
/* vim: tabstop=4 expandtab shiftwidth=4
paul@278 275
*/