L4Re/departure

Annotated libe2access/host/e2access.c

263:9edfe5795697
2022-02-19 Paul Boddie Moved input-related functions into a separate module.
paul@226 1
/*
paul@226 2
 * Access a filesystem.
paul@226 3
 *
paul@246 4
 * Copyright (C) 2019, 2022 Paul Boddie <paul@boddie.org.uk>
paul@226 5
 *
paul@226 6
 * This program is free software; you can redistribute it and/or
paul@226 7
 * modify it under the terms of the GNU General Public License as
paul@226 8
 * published by the Free Software Foundation; either version 2 of
paul@226 9
 * the License, or (at your option) any later version.
paul@226 10
 *
paul@226 11
 * This program is distributed in the hope that it will be useful,
paul@226 12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@226 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@226 14
 * GNU General Public License for more details.
paul@226 15
 *
paul@226 16
 * You should have received a copy of the GNU General Public License
paul@226 17
 * along with this program; if not, write to the Free Software
paul@226 18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@226 19
 * Boston, MA  02110-1301, USA
paul@226 20
 */
paul@226 21
paul@226 22
#include <stdio.h>
paul@226 23
#include <stdlib.h>
paul@226 24
#include <string.h>
paul@241 25
#include <unistd.h>
paul@226 26
paul@226 27
#include <sys/types.h>
paul@226 28
#include <sys/stat.h>
paul@226 29
paul@226 30
#include <ext2fs/ext2fs.h>
paul@226 31
paul@226 32
#include "file.h"
paul@226 33
#include "format.h"
paul@226 34
#include "image.h"
paul@263 35
#include "input.h"
paul@226 36
#include "path.h"
paul@250 37
#include "utils.h"
paul@226 38
paul@226 39
paul@226 40
paul@226 41
/* Copy buffer size. */
paul@226 42
paul@226 43
const int BUFSIZE = 4096;
paul@226 44
paul@262 45
/* Maximum number of arguments in scripts. */
paul@262 46
paul@262 47
const int MAX_ARGS = 32;
paul@262 48
paul@226 49
paul@226 50
paul@241 51
/* Alternative metadata set by options. */
paul@241 52
paul@241 53
struct metadata
paul@241 54
{
paul@241 55
    uid_t uid;
paul@241 56
    gid_t gid;
paul@241 57
    mode_t mask;
paul@241 58
    int have_uid, have_gid;
paul@241 59
};
paul@241 60
paul@241 61
struct metadata md;
paul@241 62
paul@246 63
/* Parse program options. */
paul@246 64
paul@241 65
static int parse_options(int argc, char *argv[])
paul@241 66
{
paul@241 67
    int opt;
paul@241 68
paul@241 69
    md.have_uid = 0;
paul@241 70
    md.have_gid = 0;
paul@241 71
    md.mask = 0000;
paul@241 72
paul@241 73
    while ((opt = getopt(argc, argv, "g:m:u:")) != -1)
paul@241 74
    {
paul@241 75
        switch (opt)
paul@241 76
        {
paul@241 77
            case 'g':
paul@241 78
            md.gid = atoi(optarg);
paul@241 79
            md.have_gid = 1;
paul@241 80
            break;
paul@241 81
paul@241 82
            case 'm':
paul@241 83
            md.mask = strtol(optarg, NULL, 0);
paul@241 84
            break;
paul@241 85
paul@241 86
            case 'u':
paul@241 87
            md.uid = atoi(optarg);
paul@241 88
            md.have_uid = 1;
paul@241 89
            break;
paul@241 90
paul@241 91
            default:
paul@246 92
            fprintf(stderr, "Option not recognised: %s\n", argv[optind]);
paul@241 93
            return -1;
paul@241 94
        }
paul@241 95
    }
paul@241 96
paul@241 97
    return 0;
paul@241 98
}
paul@241 99
paul@241 100
paul@241 101
paul@226 102
/* Copy a file into the filesystem image. */
paul@226 103
paul@226 104
int copy_file_in(const char *filename, ext2_filsys fs, ext2_ino_t ino_file, int flags)
paul@226 105
{
paul@226 106
    int retval = 0;
paul@226 107
    ext2_file_t file;
paul@226 108
paul@226 109
    /* Copying details. */
paul@226 110
paul@226 111
    FILE *fp;
paul@226 112
    char buf[BUFSIZE];
paul@226 113
    size_t got;
paul@226 114
    unsigned int written;
paul@226 115
paul@226 116
    /* Open a file in the target directory. */
paul@226 117
paul@226 118
    if (ext2fs_file_open(fs, ino_file, flags, &file))
paul@226 119
        return 1;
paul@226 120
paul@226 121
    /* Open the file in the source directory. */
paul@226 122
paul@226 123
    fp = fopen(filename, "r");
paul@226 124
paul@226 125
    /* Copy the file content. */
paul@226 126
paul@226 127
    if (fp != NULL)
paul@226 128
    {
paul@226 129
        while (got = fread(buf, sizeof(char), BUFSIZE, fp))
paul@226 130
        {
paul@226 131
            while (got)
paul@226 132
            {
paul@226 133
                if (ext2fs_file_write(file, buf, got, &written))
paul@226 134
                {
paul@226 135
                    retval = 1;
paul@226 136
                    goto close_files;
paul@226 137
                }
paul@226 138
                got -= written;
paul@226 139
            }
paul@226 140
        }
paul@226 141
    }
paul@226 142
paul@226 143
close_files:
paul@226 144
    fclose(fp);
paul@226 145
    ext2fs_file_flush(file);
paul@226 146
    ext2fs_file_close(file);
paul@226 147
paul@226 148
    return retval;
paul@226 149
}
paul@226 150
paul@226 151
/* Copy a file out of the filesystem image. */
paul@226 152
paul@226 153
int copy_file_out(const char *target, const char *filename, int target_is_file,
paul@226 154
                  ext2_filsys fs, ext2_ino_t ino_file)
paul@226 155
{
paul@226 156
    int retval = 0;
paul@226 157
    ext2_file_t file;
paul@226 158
paul@226 159
    /* Copying details. */
paul@226 160
paul@226 161
    FILE *fp;
paul@226 162
    char buf[BUFSIZE];
paul@226 163
    unsigned int got;
paul@226 164
    size_t written;
paul@226 165
paul@226 166
    /* Open the file in the source directory. */
paul@226 167
paul@226 168
    if (ext2fs_file_open(fs, ino_file, 0, &file))
paul@226 169
        return 1;
paul@226 170
paul@226 171
    /* Open a file in the target directory. */
paul@226 172
paul@226 173
    if (target_is_file)
paul@226 174
        fp = fopen(target, "w");
paul@226 175
    else
paul@226 176
        fp = open_file_in_dir(target, path_basename(filename), "w");
paul@226 177
paul@226 178
    /* Copy the file content. */
paul@226 179
paul@226 180
    if (fp != NULL)
paul@226 181
    {
paul@226 182
        do
paul@226 183
        {
paul@226 184
            if (ext2fs_file_read(file, buf, BUFSIZE, &got))
paul@226 185
            {
paul@226 186
                retval = 1;
paul@226 187
                goto close_files;
paul@226 188
            }
paul@226 189
paul@226 190
            while (got)
paul@226 191
            {
paul@226 192
                written = fwrite(buf, sizeof(char), got, fp);
paul@226 193
                got -= written;
paul@226 194
            }
paul@226 195
paul@226 196
        } while (got);
paul@226 197
    }
paul@226 198
paul@226 199
close_files:
paul@226 200
    fclose(fp);
paul@226 201
    ext2fs_file_close(file);
paul@226 202
paul@226 203
    return retval;
paul@226 204
}
paul@226 205
paul@226 206
paul@226 207
paul@226 208
/* Copy source files from the external environment into the filesystem image. */
paul@226 209
paul@226 210
int copy_in(ext2_filsys fs, int argc, char *argv[])
paul@226 211
{
paul@226 212
    errcode_t retval;
paul@226 213
paul@226 214
    /* Target filename details. */
paul@226 215
paul@226 216
    const char *target = argv[argc - 1];
paul@226 217
    const char *target_remaining = argv[argc - 1];
paul@226 218
    const char *basename;
paul@226 219
    int target_is_file;
paul@226 220
paul@226 221
    /* Target file and directory details. */
paul@226 222
paul@226 223
    int target_is_new;
paul@226 224
    ext2_ino_t ino_file, ino_target;
paul@226 225
    int flags;
paul@226 226
paul@226 227
    /* Source file details. */
paul@226 228
paul@226 229
    struct stat st;
paul@226 230
    int i;
paul@226 231
paul@226 232
    /* Locate the target and test whether it is a file or a directory. */
paul@226 233
paul@257 234
    if (image_resolve_by_path(fs, &target_remaining, &ino_target))
paul@226 235
    {
paul@226 236
        /* Only a non-existent file in an existing directory is permitted. */
paul@226 237
paul@258 238
        if (!image_isdir_by_inode(fs, ino_target) || !path_is_leafname(target_remaining))
paul@226 239
        {
paul@246 240
            fprintf(stderr, "Target not found: %s\n", target);
paul@226 241
            return 1;
paul@226 242
        }
paul@226 243
paul@226 244
        target_is_file = 1;
paul@226 245
        target_is_new = 1;
paul@226 246
    }
paul@226 247
    else
paul@226 248
    {
paul@258 249
        target_is_file = image_isfile_by_inode(fs, ino_target);
paul@226 250
        target_is_new = 0;
paul@226 251
    }
paul@226 252
paul@226 253
    /* Only permit a target file when one source file is given. */
paul@226 254
paul@226 255
    if (target_is_file)
paul@226 256
    {
paul@226 257
        if (argc > 2)
paul@226 258
        {
paul@246 259
            fprintf(stderr, "Target can only be a file when copying a single file: %s\n", target);
paul@226 260
            return 1;
paul@226 261
        }
paul@226 262
    }
paul@258 263
    else if (!image_isdir_by_inode(fs, ino_target))
paul@226 264
    {
paul@246 265
        fprintf(stderr, "Target is not a directory: %s\n", target);
paul@226 266
        return 1;
paul@226 267
    }
paul@226 268
paul@226 269
    /* Copy each source object to the target directory. */
paul@226 270
paul@226 271
    for (i = 0; i < argc - 1; i++)
paul@226 272
    {
paul@226 273
        if (target_is_file)
paul@226 274
            basename = target_remaining;
paul@226 275
        else
paul@226 276
        {
paul@226 277
            basename = path_basename(argv[i]);
paul@226 278
            target_is_new = image_find_file(fs, target, basename, &ino_file);
paul@226 279
        }
paul@226 280
paul@226 281
        /* Directories are created with the same metadata. */
paul@226 282
paul@226 283
        if (isdir(argv[i]))
paul@226 284
        {
paul@226 285
            if (!target_is_new)
paul@226 286
            {
paul@246 287
                fprintf(stderr, "Target cannot be created since it already exists: %s\n", target);
paul@226 288
                return 1;
paul@226 289
            }
paul@226 290
paul@226 291
            /* Obtain the metadata. */
paul@226 292
paul@226 293
            if (lstat(argv[i], &st))
paul@246 294
            {
paul@246 295
                fprintf(stderr, "Failed to read object metadata: %s\n", argv[i]);
paul@226 296
                return 1;
paul@246 297
            }
paul@226 298
paul@241 299
            retval = image_make_dir(fs, ino_target, basename,
paul@241 300
                                    st.st_mode & ~md.mask,
paul@241 301
                                    md.have_uid ? md.uid : st.st_uid,
paul@241 302
                                    md.have_gid ? md.gid : st.st_gid,
paul@241 303
                                    &ino_file);
paul@226 304
paul@226 305
            if (retval)
paul@226 306
            {
paul@246 307
                fprintf(stderr, "Failed to create directory: %s\n", argv[i]);
paul@226 308
                return 1;
paul@226 309
            }
paul@226 310
        }
paul@226 311
paul@226 312
        /* Files are copied. */
paul@226 313
paul@226 314
        else if (isfile(argv[i]))
paul@226 315
        {
paul@226 316
            flags = EXT2_FILE_WRITE;
paul@226 317
paul@226 318
            /* Obtain the inode for the target file. */
paul@226 319
paul@226 320
            if (target_is_new)
paul@226 321
            {
paul@226 322
                /* Populate the inode details. */
paul@226 323
paul@226 324
                if (lstat(argv[i], &st))
paul@246 325
                {
paul@246 326
                    fprintf(stderr, "Failed to read object metadata: %s\n", argv[i]);
paul@226 327
                    return 1;
paul@246 328
                }
paul@226 329
paul@241 330
                retval = image_create_file(fs, ino_target, basename,
paul@241 331
                                           st.st_mode & ~md.mask,
paul@241 332
                                           md.have_uid ? md.uid : st.st_uid,
paul@241 333
                                           md.have_gid ? md.gid : st.st_gid,
paul@241 334
                                           &ino_file);
paul@226 335
                if (retval)
paul@226 336
                {
paul@246 337
                    fprintf(stderr, "Failed to create file: %s\n", argv[i]);
paul@226 338
                    return 1;
paul@226 339
                }
paul@226 340
paul@226 341
                flags |= EXT2_FILE_CREATE;
paul@226 342
            }
paul@226 343
paul@226 344
            /* NOTE: Overwrite/update metadata where appropriate. */
paul@226 345
paul@226 346
            if (copy_file_in(argv[i], fs, ino_file, flags))
paul@226 347
            {
paul@246 348
                fprintf(stderr, "Failed to write to file: %s\n", argv[i]);
paul@226 349
                return 1;
paul@226 350
            }
paul@226 351
        }
paul@226 352
    }
paul@226 353
paul@226 354
    return 0;
paul@226 355
}
paul@226 356
paul@226 357
/* Copy source files out of the filesystem image into the external environment. */
paul@226 358
paul@226 359
int copy_out(ext2_filsys fs, int argc, char *argv[])
paul@226 360
{
paul@226 361
    /* Target filename details. */
paul@226 362
paul@226 363
    char *target = argv[argc - 1];
paul@226 364
    int target_is_file;
paul@226 365
paul@226 366
    /* Target file and directory details. */
paul@226 367
paul@226 368
    ext2_file_t file;
paul@226 369
    ext2_ino_t ino_file;
paul@226 370
paul@226 371
    /* Source file details. */
paul@226 372
paul@226 373
    const char *path;
paul@226 374
    int i;
paul@226 375
paul@226 376
    /* Locate the target and test whether it is a directory. */
paul@226 377
paul@226 378
    if (!isdir(target))
paul@226 379
    {
paul@226 380
        /* Only a new or existing file in an existing directory is permitted. */
paul@226 381
paul@226 382
        if (isfile(target) || isdir_dirname(target))
paul@226 383
            target_is_file = 1;
paul@226 384
        else
paul@226 385
        {
paul@246 386
            fprintf(stderr, "Target is not a directory: %s\n", target);
paul@226 387
            return 1;
paul@226 388
        }
paul@226 389
paul@226 390
        /* Only permit a target file when one source file is given. */
paul@226 391
paul@226 392
        if (argc > 2)
paul@226 393
        {
paul@246 394
            fprintf(stderr, "Target can only be a file when copying a single file: %s\n", target);
paul@226 395
            return 1;
paul@226 396
        }
paul@226 397
    }
paul@226 398
    else
paul@226 399
        target_is_file = 0;
paul@226 400
paul@226 401
    /* For each source filename, test whether it references a file. */
paul@226 402
paul@226 403
    for (i = 0; i < argc - 1; i++)
paul@226 404
    {
paul@258 405
        if (!image_isfile_by_path(fs, argv[i]))
paul@226 406
        {
paul@246 407
            fprintf(stderr, "Source is not a file: %s\n", argv[i]);
paul@226 408
            return 1;
paul@226 409
        }
paul@226 410
    }
paul@226 411
paul@226 412
    /* Copy each source file to the target directory. */
paul@226 413
paul@226 414
    for (i = 0; i < argc - 1; i++)
paul@226 415
    {
paul@226 416
        path = argv[i];
paul@226 417
paul@257 418
        if (image_find_by_path(fs, path, &ino_file))
paul@246 419
        {
paul@246 420
            fprintf(stderr, "Failed to find file: %s\n", argv[i]);
paul@226 421
            return 1;
paul@246 422
        }
paul@226 423
paul@226 424
        if (copy_file_out(target, argv[i], target_is_file, fs, ino_file))
paul@226 425
        {
paul@246 426
            fprintf(stderr, "Failed to read from file: %s\n", argv[i]);
paul@226 427
            return 1;
paul@226 428
        }
paul@226 429
paul@226 430
        /* NOTE: Overwrite/update metadata where appropriate. */
paul@226 431
    }
paul@226 432
paul@226 433
    return 0;
paul@226 434
}
paul@226 435
paul@244 436
/* List objects in the filesystem image. */
paul@226 437
paul@244 438
int list(ext2_filsys fs, int argc, char *argv[])
paul@226 439
{
paul@226 440
    int i;
paul@244 441
    char *path;
paul@226 442
paul@226 443
    for (i = 0; i < argc; i++)
paul@226 444
    {
paul@226 445
        path = argv[i];
paul@226 446
paul@244 447
        /* Emit each object. */
paul@226 448
paul@226 449
        puts(path);
paul@226 450
paul@244 451
        /* List individual files or directories. */
paul@244 452
paul@250 453
        if (utils_list_dir(fs, path))
paul@246 454
        {
paul@262 455
            fprintf(stderr, "Failed to list object: %s\n", path);
paul@226 456
            return 1;
paul@246 457
        }
paul@226 458
    }
paul@226 459
paul@226 460
    return 0;
paul@226 461
}
paul@226 462
paul@226 463
/* Make directories in the filesystem image. */
paul@226 464
paul@226 465
int make_dirs(ext2_filsys fs, int argc, char *argv[])
paul@226 466
{
paul@226 467
    int i;
paul@226 468
    const char *path;
paul@226 469
    ext2_ino_t ino;
paul@226 470
paul@226 471
    /* Make each directory component in the given pathname. */
paul@226 472
paul@226 473
    for (i = 0; i < argc; i++)
paul@226 474
    {
paul@226 475
        path = argv[i];
paul@226 476
paul@226 477
        /* Search for the remaining components. */
paul@226 478
paul@257 479
        if ((!*path) || !image_resolve_by_path(fs, &path, &ino))
paul@246 480
        {
paul@246 481
            fprintf(stderr, "Path exists: %s\n", argv[i]);
paul@246 482
            return 1;
paul@246 483
        }
paul@226 484
paul@226 485
        /* From the first unrecognised component, make the remaining
paul@226 486
           directories. */
paul@226 487
paul@244 488
        if (image_make_dirs(fs, &path, ino,
paul@244 489
                            0777 & ~md.mask,
paul@244 490
                            md.have_uid ? md.uid : 0,
paul@244 491
                            md.have_gid ? md.gid : 0))
paul@246 492
        {
paul@246 493
            fprintf(stderr, "Failed to make directory: %s\n", argv[i]);
paul@226 494
            return 1;
paul@246 495
        }
paul@226 496
    }
paul@226 497
paul@226 498
    return 0;
paul@226 499
}
paul@226 500
paul@255 501
/* Remove objects from the filesystem image. */
paul@244 502
paul@255 503
int _remove(ext2_filsys fs, int argc, char *argv[], int dir_only)
paul@244 504
{
paul@244 505
    int i;
paul@244 506
    const char *path;
paul@244 507
    ext2_ino_t ino;
paul@244 508
paul@244 509
    /* Remove each directory with the given pathname. */
paul@244 510
paul@244 511
    for (i = 0; i < argc; i++)
paul@244 512
    {
paul@244 513
        path = argv[i];
paul@246 514
paul@246 515
        /* Detect missing objects. */
paul@244 516
paul@258 517
        if ((!*path) || image_find_by_path(fs, path, &ino))
paul@246 518
        {
paul@246 519
            fprintf(stderr, "Not found: %s\n", path);
paul@246 520
            return 1;
paul@246 521
        }
paul@244 522
paul@255 523
        /* Insist on a directory if specified. */
paul@255 524
paul@255 525
        if (dir_only)
paul@255 526
        {
paul@258 527
            if (!image_isdir_by_inode(fs, ino))
paul@255 528
            {
paul@255 529
                fprintf(stderr, "Not a directory: %s\n", path);
paul@255 530
                return 1;
paul@255 531
            }
paul@255 532
paul@255 533
            /* Test for an empty directory. */
paul@244 534
paul@258 535
            if (image_dir_empty_by_inode(fs, ino))
paul@255 536
            {
paul@255 537
                fprintf(stderr, "Directory not empty: %s\n", path);
paul@255 538
                return 1;
paul@255 539
            }
paul@255 540
        }
paul@255 541
paul@255 542
        /* Otherwise, insist on a non-directory. */
paul@255 543
paul@258 544
        else if (image_isdir_by_inode(fs, ino))
paul@246 545
        {
paul@255 546
            fprintf(stderr, "Cannot remove a directory: %s\n", path);
paul@244 547
            return 1;
paul@246 548
        }
paul@244 549
paul@255 550
        /* Unlink the object. */
paul@244 551
paul@255 552
        if (image_unlink_by_path(fs, path))
paul@246 553
        {
paul@255 554
            fprintf(stderr, "Could not unlink object: %s\n", path);
paul@244 555
            return 1;
paul@246 556
        }
paul@244 557
paul@255 558
        /* Remove the object. */
paul@249 559
paul@249 560
        if (image_remove_by_inode(fs, ino))
paul@249 561
        {
paul@255 562
            fprintf(stderr, "Could not remove object: %s\n", path);
paul@249 563
            return 1;
paul@249 564
        }
paul@244 565
    }
paul@244 566
paul@244 567
    return 0;
paul@244 568
}
paul@244 569
paul@255 570
/* Remove directories from the filesystem image. */
paul@255 571
paul@255 572
int remove_dirs(ext2_filsys fs, int argc, char *argv[])
paul@255 573
{
paul@255 574
    return _remove(fs, argc, argv, 1);
paul@255 575
}
paul@255 576
paul@255 577
/* Remove non-directories from the filesystem image. */
paul@255 578
paul@255 579
int remove_non_dirs(ext2_filsys fs, int argc, char *argv[])
paul@255 580
{
paul@255 581
    return _remove(fs, argc, argv, 0);
paul@255 582
}
paul@255 583
paul@262 584
/* Read operations from a script file. */
paul@262 585
paul@262 586
enum op_results
paul@262 587
{
paul@262 588
    OP_SUCCESS = 0,
paul@262 589
    OP_FAILED = 1,
paul@262 590
    OP_UNKNOWN = 2,
paul@262 591
};
paul@262 592
paul@262 593
int handle_op_result(const char *operation, enum op_results op_result)
paul@262 594
{
paul@262 595
    if (op_result == OP_UNKNOWN)
paul@262 596
    {
paul@262 597
        fprintf(stderr, "Operation not recognised: %s\n", operation);
paul@262 598
        return 1;
paul@262 599
    }
paul@262 600
    else if (op_result == OP_FAILED)
paul@262 601
    {
paul@262 602
        fprintf(stderr, "Operation failed: %s\n", operation);
paul@262 603
        return 1;
paul@262 604
    }
paul@262 605
    else
paul@262 606
        return 0;
paul@262 607
}
paul@262 608
paul@262 609
enum op_results run_operation(ext2_filsys fs, const char *operation, int argc, char *argv[]);
paul@262 610
paul@262 611
int run_script(ext2_filsys fs, int argc, char *argv[])
paul@262 612
{
paul@262 613
    FILE *fp;
paul@262 614
    char buffer[BUFSIZE];
paul@262 615
    struct read_line_state state;
paul@262 616
    enum op_results op_result;
paul@262 617
    int num_args;
paul@262 618
    char *args[MAX_ARGS];
paul@262 619
    int i;
paul@262 620
paul@262 621
    for (i = 0; i < argc; i++)
paul@262 622
    {
paul@262 623
        fp = fopen(argv[i], "r");
paul@262 624
paul@262 625
        state.buffer = buffer;
paul@262 626
        state.start = buffer;
paul@262 627
        state.end = buffer;
paul@263 628
        state.buffer_size = BUFSIZE;
paul@262 629
        state.remaining = BUFSIZE - 1;
paul@262 630
paul@262 631
        while (read_line(fp, &state) != NULL)
paul@262 632
        {
paul@262 633
            parse_line(state.start, state.eolp, &num_args, args, MAX_ARGS);
paul@262 634
paul@262 635
            if (num_args > 1)
paul@262 636
            {
paul@262 637
                op_result = run_operation(fs, args[0], num_args - 1, &args[1]);
paul@262 638
paul@262 639
                if (handle_op_result(args[0], op_result))
paul@262 640
                    return 1;
paul@262 641
            }
paul@262 642
paul@262 643
            state.start = state.eolp + 1;
paul@262 644
        }
paul@262 645
paul@262 646
        fclose(fp);
paul@262 647
    }
paul@262 648
paul@262 649
    return 0;
paul@262 650
}
paul@262 651
paul@262 652
paul@244 653
paul@244 654
paul@244 655
/* Help message. */
paul@241 656
paul@241 657
char help_text[] = "\
paul@241 658
Usage: %s [ <options> ] <image file> <operation> <filename>...\n\
paul@241 659
\n\
paul@241 660
File ownership options:\n\
paul@241 661
\n\
paul@241 662
  -g GID        Set group identifier for new files\n\
paul@241 663
  -u UID        Set user identifier for new files\n\
paul@241 664
\n\
paul@241 665
File permission options:\n\
paul@241 666
\n\
paul@241 667
  -m MASK       Set mode/permissions mask for new directories\n\
paul@244 668
\n\
paul@262 669
Transfer operations:\n\
paul@244 670
\n\
paul@244 671
  copy-in       Copy files into a directory within the image\n\
paul@244 672
  copy-out      Copy files from the image into a directory\n\
paul@262 673
\n\
paul@262 674
Image operations:\n\
paul@262 675
\n\
paul@244 676
  ls            List files and directories within the image\n\
paul@244 677
  mkdir         Make directories within the image\n\
paul@255 678
  rm            Remove non-directory objects from the image\n\
paul@244 679
  rmdir         Remove directories from the image\n\
paul@262 680
\n\
paul@262 681
Script operations:\n\
paul@262 682
\n\
paul@262 683
  script        Read operations from a script file\n\
paul@241 684
";
paul@241 685
paul@244 686
/* Operations exposed by the program. */
paul@244 687
paul@244 688
struct operation
paul@244 689
{
paul@244 690
    const char *name;
paul@244 691
    int (*fn)(ext2_filsys, int, char *[]);
paul@244 692
};
paul@244 693
paul@244 694
static struct operation operations[] = {
paul@244 695
    {"copy-in", copy_in},
paul@244 696
    {"copy-out", copy_out},
paul@244 697
    {"ls", list},
paul@244 698
    {"mkdir", make_dirs},
paul@255 699
    {"rm", remove_non_dirs},
paul@244 700
    {"rmdir", remove_dirs},
paul@262 701
    {"script", run_script},
paul@244 702
    {NULL, NULL},
paul@244 703
    };
paul@244 704
paul@262 705
/* Invocation of operations. */
paul@262 706
paul@262 707
enum op_results run_operation(ext2_filsys fs, const char *operation, int argc, char *argv[])
paul@262 708
{
paul@262 709
    struct operation *op;
paul@262 710
    int exitcode;
paul@262 711
paul@262 712
    for (op = &operations[0]; op->name != NULL; op++)
paul@262 713
    {
paul@262 714
        if (!strcmp(operation, op->name))
paul@262 715
        {
paul@262 716
            exitcode = op->fn(fs, argc, argv);
paul@262 717
            if (exitcode)
paul@262 718
                return OP_FAILED;
paul@262 719
            break;
paul@262 720
        }
paul@262 721
    }
paul@262 722
paul@262 723
    if (op->name == NULL)
paul@262 724
        return OP_UNKNOWN;
paul@262 725
paul@262 726
    return OP_SUCCESS;
paul@262 727
}
paul@262 728
paul@244 729
/* Main program. */
paul@244 730
paul@226 731
int main(int argc, char *argv[])
paul@226 732
{
paul@226 733
    int flags = EXT2_FLAG_RW; // | EXT2_FLAG_SOFTSUPP_FEATURES | EXT2_FLAG_64BITS;
paul@226 734
    ext2_filsys fs = NULL;
paul@226 735
    errcode_t retval;
paul@226 736
    int exitcode = 0;
paul@226 737
paul@241 738
    /* Program argument details. */
paul@241 739
paul@241 740
    char **args;
paul@262 741
    char *fsname, *filename;
paul@241 742
    int num_args;
paul@262 743
    enum op_results op_result;
paul@241 744
paul@241 745
    /* Parse program options and initialise the argument details. */
paul@241 746
paul@241 747
    if (parse_options(argc, argv))
paul@241 748
        return 1;
paul@241 749
paul@241 750
    args = &argv[optind];
paul@241 751
    num_args = argc - optind;
paul@241 752
paul@241 753
    if (num_args < 3)
paul@226 754
    {
paul@246 755
        fprintf(stderr, help_text, argv[0]);
paul@226 756
        return 1;
paul@226 757
    }
paul@226 758
paul@241 759
    /* Open the filesystem image using the POSIX file access mechanism. */
paul@226 760
paul@241 761
    fsname = args[0];
paul@226 762
paul@226 763
    retval = ext2fs_open(fsname, flags, 0, 0, unix_io_manager, &fs);
paul@226 764
    if (retval)
paul@226 765
    {
paul@246 766
        fprintf(stderr, "Could not open filesystem: %s\n", fsname);
paul@226 767
        return 1;
paul@226 768
    }
paul@226 769
paul@226 770
    //fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE;
paul@226 771
paul@226 772
    retval = ext2fs_read_bitmaps(fs);
paul@226 773
    if (retval)
paul@226 774
    {
paul@246 775
        fprintf(stderr, "Could not read bitmaps: %s\n", fsname);
paul@226 776
        return 1;
paul@226 777
    }
paul@226 778
paul@226 779
    /* Perform the requested operation. */
paul@226 780
paul@262 781
    op_result = run_operation(fs, args[1], num_args - 2, &args[2]);
paul@262 782
    exitcode = handle_op_result(args[1], op_result);
paul@226 783
paul@226 784
    /* Close the filesystem image. */
paul@226 785
paul@226 786
    retval = ext2fs_flush(fs);
paul@226 787
    if (retval)
paul@226 788
    {
paul@246 789
        fprintf(stderr, "Error flushing filesystem: %s\n", fsname);
paul@226 790
        exitcode = 1;
paul@226 791
    }
paul@226 792
paul@226 793
    retval = ext2fs_close(fs);
paul@226 794
    if (retval)
paul@226 795
    {
paul@246 796
        fprintf(stderr, "Error closing filesystem: %s\n", fsname);
paul@226 797
        exitcode = 1;
paul@226 798
    }
paul@226 799
paul@226 800
    ext2fs_free(fs);
paul@226 801
    return exitcode;
paul@226 802
}
paul@241 803
paul@241 804
/* vim: tabstop=4 expandtab shiftwidth=4
paul@241 805
*/