L4Re/departure

Annotated libe2access/host/e2access.c

244:77b98aed9da8
2022-02-14 Paul Boddie Reorganised e2access, adding directory removal and single file listing support, also permitting the membership of new directories to be specified.
paul@226 1
/*
paul@226 2
 * Access a filesystem.
paul@226 3
 *
paul@226 4
 * Copyright (C) 2019 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@226 35
#include "path.h"
paul@226 36
paul@226 37
paul@226 38
paul@226 39
/* Copy buffer size. */
paul@226 40
paul@226 41
const int BUFSIZE = 4096;
paul@226 42
paul@226 43
paul@226 44
paul@241 45
/* Alternative metadata set by options. */
paul@241 46
paul@241 47
struct metadata
paul@241 48
{
paul@241 49
    uid_t uid;
paul@241 50
    gid_t gid;
paul@241 51
    mode_t mask;
paul@241 52
    int have_uid, have_gid;
paul@241 53
};
paul@241 54
paul@241 55
struct metadata md;
paul@241 56
paul@241 57
static int parse_options(int argc, char *argv[])
paul@241 58
{
paul@241 59
    int opt;
paul@241 60
paul@241 61
    md.have_uid = 0;
paul@241 62
    md.have_gid = 0;
paul@241 63
    md.mask = 0000;
paul@241 64
paul@241 65
    while ((opt = getopt(argc, argv, "g:m:u:")) != -1)
paul@241 66
    {
paul@241 67
        switch (opt)
paul@241 68
        {
paul@241 69
            case 'g':
paul@241 70
            md.gid = atoi(optarg);
paul@241 71
            md.have_gid = 1;
paul@241 72
            break;
paul@241 73
paul@241 74
            case 'm':
paul@241 75
            md.mask = strtol(optarg, NULL, 0);
paul@241 76
            break;
paul@241 77
paul@241 78
            case 'u':
paul@241 79
            md.uid = atoi(optarg);
paul@241 80
            md.have_uid = 1;
paul@241 81
            break;
paul@241 82
paul@241 83
            default:
paul@241 84
            fprintf(stderr, "Option %s not recognised.\n", argv[optind]);
paul@241 85
            return -1;
paul@241 86
        }
paul@241 87
    }
paul@241 88
paul@241 89
    return 0;
paul@241 90
}
paul@241 91
paul@241 92
paul@241 93
paul@226 94
/* Show directory entries when iterating. */
paul@226 95
paul@244 96
struct _list_dir_data
paul@244 97
{
paul@244 98
    ext2_filsys fs;
paul@244 99
    char *filename;
paul@244 100
};
paul@244 101
paul@244 102
static int _list_dir_proc(struct ext2_dir_entry *dirent, int offset,
paul@244 103
                          int blocksize, char *buf, void *priv_data)
paul@226 104
{
paul@244 105
    struct _list_dir_data *data = (struct _list_dir_data *) priv_data;
paul@244 106
    ext2_filsys fs = data->fs;
paul@226 107
    struct ext2_inode inode;
paul@226 108
paul@244 109
    /* Select any indicated filename. */
paul@244 110
paul@244 111
    if ((data->filename != NULL) && (strcmp(dirent->name, data->filename)))
paul@244 112
        return 0;
paul@244 113
paul@226 114
    /* Obtain the inode details for metadata. */
paul@226 115
paul@226 116
    if (ext2fs_read_inode(fs, dirent->inode, &inode))
paul@226 117
        return DIRENT_ABORT;
paul@226 118
paul@226 119
    /* Output details in the style of "ls -l" showing directory, permissions,
paul@226 120
       owner, group and size information. */
paul@226 121
paul@226 122
    printf("%s%s   %5d %5d      %6d ",
paul@226 123
        _image_isdir(fs, dirent->inode) ? "d" : "-",
paul@226 124
        get_permission_string(inode.i_mode),
paul@226 125
        inode.i_uid,
paul@226 126
        inode.i_gid,
paul@226 127
        EXT2_I_SIZE(&inode));
paul@226 128
paul@226 129
    /* Output the name which is presumably not necessarily null-terminated. */
paul@226 130
paul@226 131
    fwrite(dirent->name, sizeof(char), ext2fs_dirent_name_len(dirent), stdout);
paul@226 132
    fputc((int) '\n', stdout);
paul@226 133
    return 0;
paul@226 134
}
paul@226 135
paul@226 136
paul@226 137
paul@226 138
/* Copy a file into the filesystem image. */
paul@226 139
paul@226 140
int copy_file_in(const char *filename, ext2_filsys fs, ext2_ino_t ino_file, int flags)
paul@226 141
{
paul@226 142
    int retval = 0;
paul@226 143
    ext2_file_t file;
paul@226 144
paul@226 145
    /* Copying details. */
paul@226 146
paul@226 147
    FILE *fp;
paul@226 148
    char buf[BUFSIZE];
paul@226 149
    size_t got;
paul@226 150
    unsigned int written;
paul@226 151
paul@226 152
    /* Open a file in the target directory. */
paul@226 153
paul@226 154
    if (ext2fs_file_open(fs, ino_file, flags, &file))
paul@226 155
        return 1;
paul@226 156
paul@226 157
    /* Open the file in the source directory. */
paul@226 158
paul@226 159
    fp = fopen(filename, "r");
paul@226 160
paul@226 161
    /* Copy the file content. */
paul@226 162
paul@226 163
    if (fp != NULL)
paul@226 164
    {
paul@226 165
        while (got = fread(buf, sizeof(char), BUFSIZE, fp))
paul@226 166
        {
paul@226 167
            while (got)
paul@226 168
            {
paul@226 169
                if (ext2fs_file_write(file, buf, got, &written))
paul@226 170
                {
paul@226 171
                    retval = 1;
paul@226 172
                    goto close_files;
paul@226 173
                }
paul@226 174
                got -= written;
paul@226 175
            }
paul@226 176
        }
paul@226 177
    }
paul@226 178
paul@226 179
close_files:
paul@226 180
    fclose(fp);
paul@226 181
    ext2fs_file_flush(file);
paul@226 182
    ext2fs_file_close(file);
paul@226 183
paul@226 184
    return retval;
paul@226 185
}
paul@226 186
paul@226 187
/* Copy a file out of the filesystem image. */
paul@226 188
paul@226 189
int copy_file_out(const char *target, const char *filename, int target_is_file,
paul@226 190
                  ext2_filsys fs, ext2_ino_t ino_file)
paul@226 191
{
paul@226 192
    int retval = 0;
paul@226 193
    ext2_file_t file;
paul@226 194
paul@226 195
    /* Copying details. */
paul@226 196
paul@226 197
    FILE *fp;
paul@226 198
    char buf[BUFSIZE];
paul@226 199
    unsigned int got;
paul@226 200
    size_t written;
paul@226 201
paul@226 202
    /* Open the file in the source directory. */
paul@226 203
paul@226 204
    if (ext2fs_file_open(fs, ino_file, 0, &file))
paul@226 205
        return 1;
paul@226 206
paul@226 207
    /* Open a file in the target directory. */
paul@226 208
paul@226 209
    if (target_is_file)
paul@226 210
        fp = fopen(target, "w");
paul@226 211
    else
paul@226 212
        fp = open_file_in_dir(target, path_basename(filename), "w");
paul@226 213
paul@226 214
    /* Copy the file content. */
paul@226 215
paul@226 216
    if (fp != NULL)
paul@226 217
    {
paul@226 218
        do
paul@226 219
        {
paul@226 220
            if (ext2fs_file_read(file, buf, BUFSIZE, &got))
paul@226 221
            {
paul@226 222
                retval = 1;
paul@226 223
                goto close_files;
paul@226 224
            }
paul@226 225
paul@226 226
            while (got)
paul@226 227
            {
paul@226 228
                written = fwrite(buf, sizeof(char), got, fp);
paul@226 229
                got -= written;
paul@226 230
            }
paul@226 231
paul@226 232
        } while (got);
paul@226 233
    }
paul@226 234
paul@226 235
close_files:
paul@226 236
    fclose(fp);
paul@226 237
    ext2fs_file_close(file);
paul@226 238
paul@226 239
    return retval;
paul@226 240
}
paul@226 241
paul@226 242
paul@226 243
paul@226 244
/* Copy source files from the external environment into the filesystem image. */
paul@226 245
paul@226 246
int copy_in(ext2_filsys fs, int argc, char *argv[])
paul@226 247
{
paul@226 248
    errcode_t retval;
paul@226 249
paul@226 250
    /* Target filename details. */
paul@226 251
paul@226 252
    const char *target = argv[argc - 1];
paul@226 253
    const char *target_remaining = argv[argc - 1];
paul@226 254
    const char *basename;
paul@226 255
    int target_is_file;
paul@226 256
paul@226 257
    /* Target file and directory details. */
paul@226 258
paul@226 259
    int target_is_new;
paul@226 260
    ext2_ino_t ino_file, ino_target;
paul@226 261
    int flags;
paul@226 262
paul@226 263
    /* Source file details. */
paul@226 264
paul@226 265
    struct stat st;
paul@226 266
    int i;
paul@226 267
paul@226 268
    /* Locate the target and test whether it is a file or a directory. */
paul@226 269
paul@226 270
    if (image_find_path(fs, &target_remaining, &ino_target))
paul@226 271
    {
paul@226 272
        /* Only a non-existent file in an existing directory is permitted. */
paul@226 273
paul@226 274
        if (!_image_isdir(fs, ino_target) || !path_is_leafname(target_remaining))
paul@226 275
        {
paul@226 276
            printf("Target %s not found.\n", target);
paul@226 277
            return 1;
paul@226 278
        }
paul@226 279
paul@226 280
        target_is_file = 1;
paul@226 281
        target_is_new = 1;
paul@226 282
    }
paul@226 283
    else
paul@226 284
    {
paul@226 285
        target_is_file = _image_isfile(fs, ino_target);
paul@226 286
        target_is_new = 0;
paul@226 287
    }
paul@226 288
paul@226 289
    /* Only permit a target file when one source file is given. */
paul@226 290
paul@226 291
    if (target_is_file)
paul@226 292
    {
paul@226 293
        if (argc > 2)
paul@226 294
        {
paul@226 295
            printf("Target %s can only be a file when copying a single file.\n", target);
paul@226 296
            return 1;
paul@226 297
        }
paul@226 298
    }
paul@226 299
    else if (!_image_isdir(fs, ino_target))
paul@226 300
    {
paul@226 301
        printf("Target %s is not a directory.\n", target);
paul@226 302
        return 1;
paul@226 303
    }
paul@226 304
paul@226 305
    /* Copy each source object to the target directory. */
paul@226 306
paul@226 307
    for (i = 0; i < argc - 1; i++)
paul@226 308
    {
paul@226 309
        if (target_is_file)
paul@226 310
            basename = target_remaining;
paul@226 311
        else
paul@226 312
        {
paul@226 313
            basename = path_basename(argv[i]);
paul@226 314
            target_is_new = image_find_file(fs, target, basename, &ino_file);
paul@226 315
        }
paul@226 316
paul@226 317
        /* Directories are created with the same metadata. */
paul@226 318
paul@226 319
        if (isdir(argv[i]))
paul@226 320
        {
paul@226 321
            if (!target_is_new)
paul@226 322
            {
paul@226 323
                printf("Target %s cannot be created since it already exists.\n", target);
paul@226 324
                return 1;
paul@226 325
            }
paul@226 326
paul@226 327
            /* Obtain the metadata. */
paul@226 328
paul@226 329
            if (lstat(argv[i], &st))
paul@226 330
                return 1;
paul@226 331
paul@241 332
            retval = image_make_dir(fs, ino_target, basename,
paul@241 333
                                    st.st_mode & ~md.mask,
paul@241 334
                                    md.have_uid ? md.uid : st.st_uid,
paul@241 335
                                    md.have_gid ? md.gid : st.st_gid,
paul@241 336
                                    &ino_file);
paul@226 337
paul@226 338
            if (retval)
paul@226 339
            {
paul@226 340
                printf("Failed to create directory %s (%d).\n", argv[i], retval);
paul@226 341
                return 1;
paul@226 342
            }
paul@226 343
        }
paul@226 344
paul@226 345
        /* Files are copied. */
paul@226 346
paul@226 347
        else if (isfile(argv[i]))
paul@226 348
        {
paul@226 349
            flags = EXT2_FILE_WRITE;
paul@226 350
paul@226 351
            /* Obtain the inode for the target file. */
paul@226 352
paul@226 353
            if (target_is_new)
paul@226 354
            {
paul@226 355
                /* Populate the inode details. */
paul@226 356
paul@226 357
                if (lstat(argv[i], &st))
paul@226 358
                    return 1;
paul@226 359
paul@241 360
                retval = image_create_file(fs, ino_target, basename,
paul@241 361
                                           st.st_mode & ~md.mask,
paul@241 362
                                           md.have_uid ? md.uid : st.st_uid,
paul@241 363
                                           md.have_gid ? md.gid : st.st_gid,
paul@241 364
                                           &ino_file);
paul@226 365
                if (retval)
paul@226 366
                {
paul@226 367
                    printf("Failed to create file %s (%d).\n", argv[i], retval);
paul@226 368
                    return 1;
paul@226 369
                }
paul@226 370
paul@226 371
                flags |= EXT2_FILE_CREATE;
paul@226 372
            }
paul@226 373
paul@226 374
            /* NOTE: Overwrite/update metadata where appropriate. */
paul@226 375
paul@226 376
            if (copy_file_in(argv[i], fs, ino_file, flags))
paul@226 377
            {
paul@226 378
                printf("Failed to write to %s.\n", argv[i]);
paul@226 379
                return 1;
paul@226 380
            }
paul@226 381
        }
paul@226 382
    }
paul@226 383
paul@226 384
    return 0;
paul@226 385
}
paul@226 386
paul@226 387
/* Copy source files out of the filesystem image into the external environment. */
paul@226 388
paul@226 389
int copy_out(ext2_filsys fs, int argc, char *argv[])
paul@226 390
{
paul@226 391
    /* Target filename details. */
paul@226 392
paul@226 393
    char *target = argv[argc - 1];
paul@226 394
    int target_is_file;
paul@226 395
paul@226 396
    /* Target file and directory details. */
paul@226 397
paul@226 398
    ext2_file_t file;
paul@226 399
    ext2_ino_t ino_file;
paul@226 400
paul@226 401
    /* Source file details. */
paul@226 402
paul@226 403
    const char *path;
paul@226 404
    int i;
paul@226 405
paul@226 406
    /* Locate the target and test whether it is a directory. */
paul@226 407
paul@226 408
    if (!isdir(target))
paul@226 409
    {
paul@226 410
        /* Only a new or existing file in an existing directory is permitted. */
paul@226 411
paul@226 412
        if (isfile(target) || isdir_dirname(target))
paul@226 413
            target_is_file = 1;
paul@226 414
        else
paul@226 415
        {
paul@226 416
            printf("Target %s is not a directory.\n", target);
paul@226 417
            return 1;
paul@226 418
        }
paul@226 419
paul@226 420
        /* Only permit a target file when one source file is given. */
paul@226 421
paul@226 422
        if (argc > 2)
paul@226 423
        {
paul@226 424
            printf("Target %s can only be a file when copying a single file.\n", target);
paul@226 425
            return 1;
paul@226 426
        }
paul@226 427
    }
paul@226 428
    else
paul@226 429
        target_is_file = 0;
paul@226 430
paul@226 431
    /* For each source filename, test whether it references a file. */
paul@226 432
paul@226 433
    for (i = 0; i < argc - 1; i++)
paul@226 434
    {
paul@226 435
        if (!image_isfile(fs, argv[i]))
paul@226 436
        {
paul@226 437
            printf("Source %s is not a file.\n", argv[i]);
paul@226 438
            return 1;
paul@226 439
        }
paul@226 440
    }
paul@226 441
paul@226 442
    /* Copy each source file to the target directory. */
paul@226 443
paul@226 444
    for (i = 0; i < argc - 1; i++)
paul@226 445
    {
paul@226 446
        path = argv[i];
paul@226 447
paul@226 448
        if (image_find_path(fs, &path, &ino_file))
paul@226 449
            return 1;
paul@226 450
paul@226 451
        if (copy_file_out(target, argv[i], target_is_file, fs, ino_file))
paul@226 452
        {
paul@226 453
            printf("Failed to read from %s.\n", argv[i]);
paul@226 454
            return 1;
paul@226 455
        }
paul@226 456
paul@226 457
        /* NOTE: Overwrite/update metadata where appropriate. */
paul@226 458
    }
paul@226 459
paul@226 460
    return 0;
paul@226 461
}
paul@226 462
paul@244 463
/* List objects in the filesystem image. */
paul@226 464
paul@244 465
int list(ext2_filsys fs, int argc, char *argv[])
paul@226 466
{
paul@226 467
    int i;
paul@244 468
    char *path;
paul@244 469
    struct _list_dir_data data;
paul@226 470
paul@226 471
    for (i = 0; i < argc; i++)
paul@226 472
    {
paul@226 473
        path = argv[i];
paul@226 474
paul@244 475
        /* Emit each object. */
paul@226 476
paul@226 477
        puts(path);
paul@226 478
paul@244 479
        /* List individual files or directories. */
paul@244 480
paul@244 481
        if (image_isfile(fs, path))
paul@244 482
            data.filename = path_split(path);
paul@244 483
        else
paul@244 484
            data.filename = NULL;
paul@244 485
paul@244 486
        data.fs = fs;
paul@244 487
paul@244 488
        if (image_list_dir(fs, path, _list_dir_proc, &data))
paul@226 489
            return 1;
paul@226 490
    }
paul@226 491
paul@226 492
    return 0;
paul@226 493
}
paul@226 494
paul@226 495
/* Make directories in the filesystem image. */
paul@226 496
paul@226 497
int make_dirs(ext2_filsys fs, int argc, char *argv[])
paul@226 498
{
paul@226 499
    int i;
paul@226 500
    const char *path;
paul@226 501
    ext2_ino_t ino;
paul@226 502
paul@226 503
    /* Make each directory component in the given pathname. */
paul@226 504
paul@226 505
    for (i = 0; i < argc; i++)
paul@226 506
    {
paul@226 507
        path = argv[i];
paul@226 508
        if (!*path)
paul@226 509
            continue;
paul@226 510
paul@226 511
        /* Search for the remaining components. */
paul@226 512
paul@226 513
        if (!image_find_path(fs, &path, &ino))
paul@226 514
            continue;
paul@226 515
paul@226 516
        /* From the first unrecognised component, make the remaining
paul@226 517
           directories. */
paul@226 518
paul@244 519
        if (image_make_dirs(fs, &path, ino,
paul@244 520
                            0777 & ~md.mask,
paul@244 521
                            md.have_uid ? md.uid : 0,
paul@244 522
                            md.have_gid ? md.gid : 0))
paul@226 523
            return 1;
paul@226 524
    }
paul@226 525
paul@226 526
    return 0;
paul@226 527
}
paul@226 528
paul@244 529
/* Remove directories from the filesystem image. */
paul@244 530
paul@244 531
int remove_dirs(ext2_filsys fs, int argc, char *argv[])
paul@244 532
{
paul@244 533
    int i;
paul@244 534
    const char *path;
paul@244 535
    ext2_ino_t ino;
paul@244 536
paul@244 537
    /* Remove each directory with the given pathname. */
paul@244 538
paul@244 539
    for (i = 0; i < argc; i++)
paul@244 540
    {
paul@244 541
        path = argv[i];
paul@244 542
        if (!*path)
paul@244 543
            continue;
paul@244 544
paul@244 545
        /* Ignore missing objects. */
paul@244 546
paul@244 547
        if (!image_exists(fs, path))
paul@244 548
            continue;
paul@244 549
paul@244 550
        /* Insist on a directory. */
paul@244 551
paul@244 552
        if (!image_isdir(fs, path))
paul@244 553
            return 1;
paul@244 554
paul@244 555
        /* Remove the directory. */
paul@244 556
paul@244 557
        if (image_remove_by_path(fs, path))
paul@244 558
            return 1;
paul@244 559
paul@244 560
        /* Unlink the directory. */
paul@244 561
paul@244 562
        if (image_unlink_by_path(fs, path))
paul@244 563
            return 1;
paul@244 564
    }
paul@244 565
paul@244 566
    return 0;
paul@244 567
}
paul@244 568
paul@244 569
paul@244 570
paul@244 571
/* Help message. */
paul@241 572
paul@241 573
char help_text[] = "\
paul@241 574
Usage: %s [ <options> ] <image file> <operation> <filename>...\n\
paul@241 575
\n\
paul@241 576
File ownership options:\n\
paul@241 577
\n\
paul@241 578
  -g GID        Set group identifier for new files\n\
paul@241 579
  -u UID        Set user identifier for new files\n\
paul@241 580
\n\
paul@241 581
File permission options:\n\
paul@241 582
\n\
paul@241 583
  -m MASK       Set mode/permissions mask for new directories\n\
paul@244 584
\n\
paul@244 585
Operations:\n\
paul@244 586
\n\
paul@244 587
  copy-in       Copy files into a directory within the image\n\
paul@244 588
  copy-out      Copy files from the image into a directory\n\
paul@244 589
  ls            List files and directories within the image\n\
paul@244 590
  mkdir         Make directories within the image\n\
paul@244 591
  rmdir         Remove directories from the image\n\
paul@241 592
";
paul@241 593
paul@244 594
/* Operations exposed by the program. */
paul@244 595
paul@244 596
struct operation
paul@244 597
{
paul@244 598
    const char *name;
paul@244 599
    int (*fn)(ext2_filsys, int, char *[]);
paul@244 600
};
paul@244 601
paul@244 602
static struct operation operations[] = {
paul@244 603
    {"copy-in", copy_in},
paul@244 604
    {"copy-out", copy_out},
paul@244 605
    {"ls", list},
paul@244 606
    {"mkdir", make_dirs},
paul@244 607
    {"rmdir", remove_dirs},
paul@244 608
    {NULL, NULL},
paul@244 609
    };
paul@244 610
paul@244 611
/* Main program. */
paul@244 612
paul@226 613
int main(int argc, char *argv[])
paul@226 614
{
paul@226 615
    int flags = EXT2_FLAG_RW; // | EXT2_FLAG_SOFTSUPP_FEATURES | EXT2_FLAG_64BITS;
paul@226 616
    ext2_filsys fs = NULL;
paul@226 617
    errcode_t retval;
paul@226 618
    int exitcode = 0;
paul@226 619
paul@241 620
    /* Program argument details. */
paul@241 621
paul@241 622
    char **args;
paul@241 623
    char *fsname, *operation, *filename;
paul@241 624
    int num_args;
paul@244 625
    struct operation *op;
paul@241 626
paul@241 627
    /* Parse program options and initialise the argument details. */
paul@241 628
paul@241 629
    if (parse_options(argc, argv))
paul@241 630
        return 1;
paul@241 631
paul@241 632
    args = &argv[optind];
paul@241 633
    num_args = argc - optind;
paul@241 634
paul@241 635
    if (num_args < 3)
paul@226 636
    {
paul@241 637
        printf(help_text, argv[0]);
paul@226 638
        return 1;
paul@226 639
    }
paul@226 640
paul@241 641
    /* Open the filesystem image using the POSIX file access mechanism. */
paul@226 642
paul@241 643
    fsname = args[0];
paul@226 644
paul@226 645
    retval = ext2fs_open(fsname, flags, 0, 0, unix_io_manager, &fs);
paul@226 646
    if (retval)
paul@226 647
    {
paul@226 648
        printf("Could not open filesystem using %s\n", fsname);
paul@226 649
        return 1;
paul@226 650
    }
paul@226 651
paul@226 652
    //fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE;
paul@226 653
paul@226 654
    retval = ext2fs_read_bitmaps(fs);
paul@226 655
    if (retval)
paul@226 656
    {
paul@226 657
        printf("Could not read bitmaps from %s\n", fsname);
paul@226 658
        return 1;
paul@226 659
    }
paul@226 660
paul@226 661
    /* Perform the requested operation. */
paul@226 662
paul@241 663
    operation = args[1];
paul@241 664
    args = &args[2];
paul@241 665
    num_args -= 2;
paul@226 666
paul@244 667
    for (op = &operations[0]; op->name != NULL; op++)
paul@226 668
    {
paul@244 669
        if (!strcmp(operation, op->name))
paul@244 670
        {
paul@244 671
            exitcode = op->fn(fs, num_args, args);
paul@244 672
            break;
paul@244 673
        }
paul@226 674
    }
paul@244 675
paul@244 676
    if (op->name == NULL)
paul@226 677
    {
paul@226 678
        printf("Operation %s is not recognised.\n", operation);
paul@226 679
        exitcode = 1;
paul@226 680
    }
paul@226 681
paul@226 682
    /* Close the filesystem image. */
paul@226 683
paul@226 684
    retval = ext2fs_flush(fs);
paul@226 685
    if (retval)
paul@226 686
    {
paul@226 687
        printf("Error flushing filesystem in %s\n", fsname);
paul@226 688
        exitcode = 1;
paul@226 689
    }
paul@226 690
paul@226 691
    retval = ext2fs_close(fs);
paul@226 692
    if (retval)
paul@226 693
    {
paul@226 694
        printf("Error closing filesystem in %s\n", fsname);
paul@226 695
        exitcode = 1;
paul@226 696
    }
paul@226 697
paul@226 698
    ext2fs_free(fs);
paul@226 699
    return exitcode;
paul@226 700
}
paul@241 701
paul@241 702
/* vim: tabstop=4 expandtab shiftwidth=4
paul@241 703
*/