L4Re/departure

Annotated libe2access/lib/src/image.c

243:fedb83ec8dae
2022-02-14 Paul Boddie Added path existence, removal and unlinking functions.
paul@181 1
/*
paul@181 2
 * Filesystem access functions.
paul@181 3
 *
paul@235 4
 * Copyright (C) 2019, 2021, 2022 Paul Boddie <paul@boddie.org.uk>
paul@181 5
 *
paul@181 6
 * This program is free software; you can redistribute it and/or
paul@181 7
 * modify it under the terms of the GNU General Public License as
paul@181 8
 * published by the Free Software Foundation; either version 2 of
paul@181 9
 * the License, or (at your option) any later version.
paul@181 10
 *
paul@181 11
 * This program is distributed in the hope that it will be useful,
paul@181 12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@181 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@181 14
 * GNU General Public License for more details.
paul@181 15
 *
paul@181 16
 * You should have received a copy of the GNU General Public License
paul@181 17
 * along with this program; if not, write to the Free Software
paul@181 18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@181 19
 * Boston, MA  02110-1301, USA
paul@181 20
 */
paul@181 21
paul@181 22
#include <string.h>
paul@181 23
paul@181 24
#include <ext2fs/ext2fs.h>
paul@181 25
paul@181 26
#include "image.h"
paul@181 27
#include "path.h"
paul@181 28
paul@181 29
paul@181 30
paul@236 31
/* Link an inode within the given target directory having the given basename. */
paul@181 32
paul@236 33
static errcode_t _image_link(ext2_filsys fs, ext2_ino_t ino_target,
paul@236 34
                             const char *basename, ext2_ino_t ino_file,
paul@236 35
                             int flags)
paul@181 36
{
paul@181 37
    errcode_t retval;
paul@227 38
    int retry;
paul@181 39
paul@181 40
    /* Connect the inode to its parent. */
paul@181 41
paul@227 42
    for (retry = 0; retry <= 1; retry++)
paul@181 43
    {
paul@236 44
        retval = ext2fs_link(fs, ino_target, basename, ino_file, flags);
paul@181 45
paul@181 46
        if (!retval)
paul@181 47
            break;
paul@227 48
        else if (retry)
paul@227 49
            return retval;
paul@181 50
paul@181 51
        /* Expand the directory if necessary. */
paul@181 52
paul@181 53
        if (retval == EXT2_ET_DIR_NO_SPACE)
paul@181 54
            retval = ext2fs_expand_dir(fs, ino_target);
paul@181 55
paul@181 56
        if (retval)
paul@181 57
            return retval;
paul@181 58
    }
paul@181 59
paul@236 60
    return 0;
paul@236 61
}
paul@236 62
paul@236 63
/* Update the parent entry of a renamed directory. */
paul@236 64
paul@236 65
struct _image_parent_entry_state
paul@236 66
{
paul@236 67
    ext2_ino_t ino;
paul@236 68
};
paul@236 69
paul@236 70
static int _image_update_parent_entry(struct ext2_dir_entry *dir_entry,
paul@236 71
                                      int offset, int blocksize, char *buf,
paul@236 72
                                      void *priv_data)
paul@236 73
{
paul@236 74
    struct _image_parent_entry_state *state = (struct _image_parent_entry_state *) priv_data;
paul@236 75
paul@236 76
    (void) offset; (void) blocksize; (void) buf;
paul@236 77
paul@236 78
    if (strcmp(dir_entry->name, "..") == 0)
paul@236 79
    {
paul@236 80
        dir_entry->inode = state->ino;
paul@236 81
        return DIRENT_CHANGED | DIRENT_ABORT;
paul@236 82
    }
paul@236 83
    else
paul@236 84
        return 0;
paul@236 85
}
paul@236 86
paul@243 87
paul@243 88
paul@236 89
/* Create an inode for a file. */
paul@236 90
paul@236 91
errcode_t image_create_file(ext2_filsys fs, ext2_ino_t ino_target,
paul@236 92
                            const char *basename, __u16 mode,
paul@236 93
                            __u16 uid, __u16 gid, ext2_ino_t *ino_file)
paul@236 94
{
paul@236 95
    struct ext2_inode inode_file;
paul@236 96
    errcode_t retval;
paul@236 97
paul@236 98
    /* Without an inode, create a new one. */
paul@236 99
paul@236 100
    retval = ext2fs_new_inode(fs, ino_target, LINUX_S_IFREG | mode, 0, ino_file);
paul@236 101
    if (retval)
paul@236 102
        return retval;
paul@236 103
paul@236 104
    _image_link(fs, ino_target, basename, *ino_file, EXT2_FT_REG_FILE);
paul@236 105
paul@181 106
    /* Make sure that subsequent files employ different inodes. */
paul@181 107
paul@181 108
    ext2fs_inode_alloc_stats2(fs, *ino_file, 1, 0);
paul@181 109
paul@181 110
    /* Populate the inode details. */
paul@181 111
paul@181 112
    image_set_metadata(&inode_file, 1, LINUX_S_IFREG | mode, uid, gid);
paul@225 113
    inode_file.i_links_count++;
paul@181 114
paul@181 115
    return ext2fs_write_new_inode(fs, *ino_file, &inode_file);
paul@181 116
}
paul@181 117
paul@236 118
/* Return the appropriate ext2 file type value for the given mode value. */
paul@236 119
paul@236 120
int image_file_type(int mode)
paul@236 121
{
paul@236 122
    switch (mode & LINUX_S_IFMT)
paul@236 123
    {
paul@236 124
        case LINUX_S_IFSOCK: return EXT2_FT_SOCK;
paul@236 125
        case LINUX_S_IFLNK: return EXT2_FT_SYMLINK;
paul@236 126
        case LINUX_S_IFREG: return EXT2_FT_REG_FILE;
paul@236 127
        case LINUX_S_IFBLK: return EXT2_FT_BLKDEV;
paul@236 128
        case LINUX_S_IFDIR: return EXT2_FT_DIR;
paul@236 129
        case LINUX_S_IFCHR: return EXT2_FT_CHRDEV;
paul@236 130
        case LINUX_S_IFIFO: return EXT2_FT_FIFO;
paul@236 131
paul@236 132
        /* NOTE: Perhaps signal an error. */
paul@236 133
paul@236 134
        default: return EXT2_FT_REG_FILE;
paul@236 135
    }
paul@236 136
}
paul@236 137
paul@181 138
/* Find an object in the given directory with the given name in the filesystem
paul@181 139
   image, updating the name reference to refer to the next component. */
paul@181 140
paul@181 141
errcode_t image_find_next(ext2_filsys fs, ext2_ino_t ino_dir,
paul@181 142
                          const char **basename, char *buf, ext2_ino_t *ino)
paul@181 143
{
paul@181 144
    const char *end = path_component_end(*basename);
paul@181 145
    errcode_t retval;
paul@181 146
paul@181 147
    /* Find the basename in the directory. */
paul@181 148
paul@181 149
    retval = ext2fs_lookup(fs, ino_dir, *basename, end - *basename, buf, ino);
paul@181 150
paul@181 151
    /* Update the current component. */
paul@181 152
paul@181 153
    if (!retval)
paul@181 154
        *basename = path_component_next(end);
paul@181 155
paul@181 156
    return retval;
paul@181 157
}
paul@181 158
paul@181 159
/* Find an object with the given pathname in the filesystem image. */
paul@181 160
paul@181 161
errcode_t image_find_path(ext2_filsys fs, const char **pathname, ext2_ino_t *ino)
paul@181 162
{
paul@181 163
    char *buf;
paul@181 164
    ext2_ino_t ino_dir;
paul@181 165
    errcode_t retval;
paul@181 166
paul@181 167
    retval = ext2fs_get_mem(fs->blocksize, &buf);
paul@181 168
    if (retval)
paul@181 169
        return retval;
paul@181 170
paul@181 171
    /* Skip any leading root marker. */
paul@181 172
paul@181 173
    if (**pathname == '/')
paul@181 174
        (*pathname)++;
paul@181 175
paul@181 176
    if (!**pathname)
paul@181 177
        *ino = EXT2_ROOT_INO;
paul@181 178
paul@181 179
    /* Start at the root. */
paul@181 180
paul@181 181
    ino_dir = EXT2_ROOT_INO;
paul@181 182
paul@181 183
    /* With any remaining path, find the next component. */
paul@181 184
paul@181 185
    while (**pathname)
paul@181 186
    {
paul@181 187
        retval = image_find_next(fs, ino_dir, pathname, buf, ino);
paul@181 188
        if (retval)
paul@181 189
        {
paul@181 190
            *ino = ino_dir;
paul@181 191
            break;
paul@181 192
        }
paul@181 193
paul@181 194
        /* Move into the found object for searching the next component. */
paul@181 195
paul@181 196
        ino_dir = *ino;
paul@181 197
    }
paul@181 198
paul@181 199
    ext2fs_free_mem(&buf);
paul@181 200
paul@181 201
    return retval;
paul@181 202
}
paul@181 203
paul@181 204
/* Find an object in the given directory with the given name in the filesystem
paul@181 205
   image. */
paul@181 206
paul@181 207
errcode_t image_find_file(ext2_filsys fs, const char *dirname,
paul@181 208
                          const char *basename, ext2_ino_t *ino)
paul@181 209
{
paul@181 210
    char pathname[strlen(dirname) + strlen(basename) + 2];
paul@181 211
    const char *s = pathname;
paul@181 212
paul@181 213
    strcpy(pathname, dirname);
paul@181 214
    strcat(pathname, "/");
paul@181 215
    strcat(pathname, basename);
paul@181 216
paul@181 217
    return image_find_path(fs, &s, ino);
paul@181 218
}
paul@181 219
paul@181 220
/* Obtain the inode for the object with the given pathname in the filesystem
paul@181 221
   image. */
paul@181 222
paul@181 223
errcode_t image_inode(ext2_filsys fs, const char *pathname,
paul@181 224
                      struct ext2_inode *inode)
paul@181 225
{
paul@181 226
    ext2_ino_t ino;
paul@181 227
    errcode_t retval;
paul@181 228
paul@181 229
    retval = image_find_path(fs, &pathname, &ino);
paul@181 230
    if (retval)
paul@181 231
        return retval;
paul@181 232
paul@181 233
    return ext2fs_read_inode(fs, ino, inode);
paul@181 234
}
paul@181 235
paul@226 236
/* List a directory in the filesystem image. */
paul@226 237
paul@226 238
errcode_t image_list_dir(ext2_filsys fs, const char *path,
paul@226 239
                         int (*proc)(struct ext2_dir_entry *, int, int, char *,
paul@226 240
                                     void *),
paul@226 241
                         void *data)
paul@226 242
{
paul@226 243
    char *buf;
paul@226 244
    ext2_ino_t ino;
paul@226 245
    errcode_t retval;
paul@226 246
paul@226 247
    retval = ext2fs_get_mem(fs->blocksize, &buf);
paul@226 248
    if (retval)
paul@226 249
        return retval;
paul@226 250
paul@226 251
    /* Locate the object and test whether it is a directory. */
paul@226 252
paul@226 253
    retval = image_find_path(fs, &path, &ino);
paul@226 254
    if (retval)
paul@226 255
    {
paul@226 256
        ext2fs_free_mem(&buf);
paul@226 257
        return retval;
paul@226 258
    }
paul@226 259
paul@226 260
    if (!_image_isdir(fs, ino))
paul@226 261
        return 1;
paul@226 262
paul@226 263
    /* List the directory contents. */
paul@226 264
paul@226 265
    retval = ext2fs_dir_iterate(fs, ino, 0, buf, proc, data);
paul@226 266
    if (retval)
paul@226 267
    {
paul@226 268
        ext2fs_free_mem(&buf);
paul@226 269
        return retval;
paul@226 270
    }
paul@226 271
paul@226 272
    ext2fs_free_mem(&buf);
paul@226 273
    return 0;
paul@226 274
}
paul@226 275
paul@181 276
/* Make a directory in the given directory in the filesystem image having the
paul@181 277
   given name and metadata. */
paul@181 278
paul@181 279
errcode_t image_make_dir(ext2_filsys fs, ext2_ino_t ino_dir,
paul@181 280
                         const char *basename, __u16 mode,
paul@181 281
                         __u16 uid, __u16 gid, ext2_ino_t *ino)
paul@181 282
{
paul@181 283
    struct ext2_inode inode_dir;
paul@181 284
    errcode_t retval = 0;
paul@181 285
paul@181 286
    /* Create an inode in the directory. */
paul@181 287
paul@181 288
    retval = ext2fs_new_inode(fs, ino_dir, LINUX_S_IFDIR | mode, 0, ino);
paul@181 289
    if (retval)
paul@181 290
        return retval;
paul@181 291
paul@181 292
    /* Make the directory and update the metadata (due to ext2fs_mkdir
paul@181 293
       limitation). */
paul@181 294
paul@181 295
    retval = ext2fs_mkdir(fs, ino_dir, *ino, basename);
paul@181 296
    if (retval)
paul@181 297
        return retval;
paul@181 298
paul@181 299
    retval = ext2fs_read_inode(fs, *ino, &inode_dir);
paul@181 300
    if (retval)
paul@181 301
        return retval;
paul@181 302
paul@181 303
    image_set_metadata(&inode_dir, 0, LINUX_S_IFDIR | mode, uid, gid);
paul@181 304
    return ext2fs_write_inode(fs, *ino, &inode_dir);
paul@181 305
}
paul@181 306
paul@181 307
/* Make a directory in the given directory in the filesystem image, updating
paul@181 308
   the name reference to refer to the next component. */
paul@181 309
paul@181 310
errcode_t image_make_next_dir(ext2_filsys fs, ext2_ino_t ino_dir,
paul@181 311
                              const char **basename, __u16 mode, __u16 uid,
paul@181 312
                              __u16 gid, ext2_ino_t *ino)
paul@181 313
{
paul@181 314
    char *end = (char *) path_component_end(*basename);
paul@181 315
    char endchar = *end;
paul@181 316
    errcode_t retval = 0;
paul@181 317
paul@181 318
    /* Delimit the basename and make a directory using the inode. */
paul@181 319
paul@181 320
    if (endchar)
paul@181 321
        *end = '\0';
paul@181 322
paul@181 323
    /* Do not create directories for empty components. */
paul@181 324
paul@181 325
    if (**basename)
paul@181 326
        retval = image_make_dir(fs, ino_dir, *basename, mode, uid, gid, ino);
paul@181 327
paul@181 328
    /* Restore the path separator and update the current component. */
paul@181 329
paul@181 330
    if (endchar)
paul@181 331
        *end = '/';
paul@181 332
paul@181 333
    if (!retval)
paul@181 334
        *basename = path_component_next(end);
paul@181 335
paul@181 336
    return retval;
paul@181 337
}
paul@181 338
paul@181 339
/* Make directories descending to the given path in the filesystem image. */
paul@181 340
paul@181 341
errcode_t image_make_dirs(ext2_filsys fs, const char **pathname,
paul@181 342
                          ext2_ino_t ino_dir, __u16 mode, __u16 uid, __u16 gid)
paul@181 343
{
paul@181 344
    ext2_ino_t ino;
paul@181 345
    errcode_t retval;
paul@181 346
paul@181 347
    while (**pathname)
paul@181 348
    {
paul@181 349
        retval = image_make_next_dir(fs, ino_dir, pathname, mode, uid, gid, &ino);
paul@181 350
        if (retval)
paul@181 351
            return retval;
paul@181 352
paul@181 353
        /* Move into the created object for handling the next component. */
paul@181 354
paul@181 355
        ino_dir = ino;
paul@181 356
    }
paul@181 357
paul@181 358
    return 0;
paul@181 359
}
paul@181 360
paul@231 361
/* Remove an inode. */
paul@231 362
paul@231 363
errcode_t image_remove_by_inode(ext2_filsys fs, ext2_ino_t ino)
paul@231 364
{
paul@231 365
    struct ext2_inode_large inode;
paul@231 366
    errcode_t err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *) &inode,
paul@231 367
                                           sizeof(inode));
paul@231 368
paul@231 369
    /* Handle invalid inodes, ignore unreferenced inodes. */
paul@231 370
paul@231 371
    if (err)
paul@231 372
        return err;
paul@231 373
paul@231 374
    if (!inode.i_links_count)
paul@231 375
        return 0;
paul@231 376
paul@231 377
    /* Decrement the reference count. With no more references to the inode,
paul@231 378
       remove its resources. */
paul@231 379
paul@231 380
    inode.i_links_count--;
paul@231 381
paul@231 382
    if (!inode.i_links_count)
paul@231 383
    {
paul@231 384
        err = ext2fs_free_ext_attr(fs, ino, &inode);
paul@231 385
paul@231 386
        if (!err)
paul@231 387
        {
paul@231 388
            /* Deallocate blocks, if appropriate. ~0ULL as the end represents
paul@231 389
               truncation. */
paul@231 390
paul@231 391
            if (ext2fs_inode_has_valid_blocks2(fs, (struct ext2_inode *) &inode))
paul@231 392
            {
paul@231 393
                err = ext2fs_punch(fs, ino, (struct ext2_inode *) &inode, NULL,
paul@231 394
                                   0, ~0ULL);
paul@231 395
paul@231 396
                /* Update allocation statistics. */
paul@231 397
paul@231 398
                if (!err)
paul@231 399
                    ext2fs_inode_alloc_stats2(fs, ino, -1,
paul@231 400
                                  LINUX_S_ISDIR(inode.i_mode));
paul@231 401
            }
paul@231 402
        }
paul@231 403
    }
paul@231 404
paul@231 405
    return ext2fs_write_inode_full(fs, ino, (struct ext2_inode *) &inode,
paul@231 406
                                   sizeof(inode));
paul@231 407
}
paul@231 408
paul@243 409
/* Remove a directory entry using its full path. */
paul@243 410
paul@243 411
errcode_t image_remove_by_path(ext2_filsys fs, const char *path)
paul@243 412
{
paul@243 413
    const char *remaining = path;
paul@243 414
    ext2_ino_t ino;
paul@243 415
    errcode_t retval = image_find_path(fs, &remaining, &ino);
paul@243 416
paul@243 417
    if (retval)
paul@243 418
        return retval;
paul@243 419
paul@243 420
    return image_remove_by_inode(fs, ino);
paul@243 421
}
paul@243 422
paul@236 423
/* Rename a file. */
paul@236 424
paul@236 425
errcode_t image_rename(ext2_filsys fs, ext2_ino_t source,
paul@236 426
                       ext2_ino_t source_parent, const char *source_basename,
paul@236 427
                       ext2_ino_t target_parent, const char *target_basename)
paul@236 428
{
paul@236 429
    errcode_t retval;
paul@236 430
    struct ext2_inode source_inode, source_parent_inode, target_parent_inode;
paul@236 431
    struct _image_parent_entry_state state = {target_parent};
paul@236 432
paul@236 433
    /* NOTE: Should check for space. */
paul@236 434
paul@236 435
    /* Obtain the source object. */
paul@236 436
paul@236 437
    retval = ext2fs_read_inode(fs, source, &source_inode);
paul@236 438
paul@236 439
    if (retval)
paul@236 440
        return retval;
paul@236 441
paul@236 442
    /* Link from the target parent. */
paul@236 443
paul@236 444
    retval = _image_link(fs, target_parent, target_basename, source,
paul@236 445
                         image_file_type(source_inode.i_mode));
paul@236 446
paul@236 447
    if (retval)
paul@236 448
        return retval;
paul@236 449
paul@236 450
    if (_image_isdir(fs, source))
paul@236 451
    {
paul@236 452
        /* Update the link count for the target. */
paul@236 453
paul@236 454
        retval = ext2fs_read_inode(fs, target_parent, &target_parent_inode);
paul@236 455
paul@236 456
        if (retval)
paul@236 457
            return retval;
paul@236 458
paul@236 459
        target_parent_inode.i_links_count++;
paul@236 460
paul@236 461
        retval = ext2fs_write_inode(fs, target_parent, &target_parent_inode);
paul@236 462
paul@236 463
        if (retval)
paul@236 464
            return retval;
paul@236 465
paul@236 466
        /* A directory needs its .. entry updating to refer to its new
paul@236 467
           parent. */
paul@236 468
paul@236 469
        retval = ext2fs_dir_iterate(fs, source, 0, NULL,
paul@236 470
                                    _image_update_parent_entry, &state);
paul@236 471
paul@236 472
        /* Update the link count for the source. */
paul@236 473
paul@236 474
        retval = ext2fs_read_inode(fs, source_parent, &source_parent_inode);
paul@236 475
paul@236 476
        if (retval)
paul@236 477
            return retval;
paul@236 478
paul@236 479
        source_parent_inode.i_links_count--;
paul@236 480
paul@236 481
        retval = ext2fs_write_inode(fs, source_parent, &source_parent_inode);
paul@236 482
paul@236 483
        if (retval)
paul@236 484
            return retval;
paul@236 485
    }
paul@236 486
paul@236 487
    /* Unlink from the source parent, doing so by name because the file is now
paul@236 488
       already linked from the target parent, and when the parents are the same,
paul@236 489
       unlinking by inode could just cause the file to disappear from the
paul@236 490
       catalogue. */
paul@236 491
paul@236 492
    retval = image_unlink_by_name(fs, source_parent, source_basename);
paul@236 493
paul@236 494
    if (retval)
paul@236 495
        return retval;
paul@236 496
paul@236 497
    return ext2fs_flush2(fs, 0);
paul@236 498
}
paul@236 499
paul@235 500
/* Set the mode, user and group metadata for a file. */
paul@235 501
paul@235 502
void image_set_metadata(struct ext2_inode *inode, int clean, __u16 mode,
paul@235 503
                        __u16 uid, __u16 gid)
paul@235 504
{
paul@235 505
    if (clean)
paul@235 506
        memset(inode, 0, sizeof(*inode));
paul@235 507
paul@235 508
    inode->i_mode = mode;
paul@235 509
    inode->i_uid = uid;
paul@235 510
    inode->i_gid = gid;
paul@235 511
}
paul@235 512
paul@235 513
/* Copy file metadata into a stat structure. */
paul@235 514
paul@235 515
errcode_t image_stat_inode(ext2_filsys fs, ext2_ino_t ino, struct stat *st)
paul@235 516
{
paul@235 517
    struct ext2_inode inode;
paul@235 518
    errcode_t retval = ext2fs_read_inode(fs, ino, &inode);
paul@235 519
paul@235 520
    if (retval)
paul@235 521
        return retval;
paul@235 522
paul@235 523
    st->st_dev = 0;                       /* device identifier */
paul@235 524
    st->st_ino = ino;
paul@235 525
    st->st_mode = inode.i_mode;
paul@235 526
    st->st_nlink = inode.i_links_count;
paul@235 527
    st->st_uid = inode_uid(inode);
paul@235 528
    st->st_gid = inode_gid(inode);
paul@235 529
    st->st_rdev = 0;                      /* special file device identifier */
paul@235 530
    st->st_size = EXT2_I_SIZE(&inode);
paul@235 531
    st->st_blksize = fs->blocksize;
paul@235 532
    st->st_blocks = 0;                    /* number of 512 byte blocks allocated */
paul@235 533
    st->st_atim.tv_sec = inode.i_atime;
paul@235 534
    st->st_atim.tv_nsec = 0;              /* nanosecond resolution */
paul@235 535
    st->st_mtim.tv_sec = inode.i_mtime;
paul@235 536
    st->st_mtim.tv_nsec = 0;
paul@235 537
    st->st_ctim.tv_sec = inode.i_ctime;
paul@235 538
    st->st_ctim.tv_nsec = 0;
paul@235 539
paul@235 540
    return 0;
paul@235 541
}
paul@235 542
paul@231 543
/* Unlink a directory entry by name. */
paul@231 544
paul@231 545
errcode_t image_unlink_by_name(ext2_filsys fs, ext2_ino_t ino_parent,
paul@231 546
                               const char *basename)
paul@231 547
{
paul@243 548
    return ext2fs_unlink(fs, ino_parent, basename, 0, 0);
paul@243 549
}
paul@243 550
paul@243 551
/* Unlink a directory entry by full path. */
paul@243 552
paul@243 553
errcode_t image_unlink_by_path(ext2_filsys fs, const char *path)
paul@243 554
{
paul@243 555
    char _path[strlen(path) + 1];
paul@243 556
    const char *remaining = _path;
paul@243 557
    char *basename;
paul@243 558
    ext2_ino_t ino_parent;
paul@243 559
    errcode_t retval;
paul@243 560
paul@243 561
    strcpy(_path, path);
paul@243 562
    basename = path_split(_path);
paul@243 563
paul@243 564
    retval = image_find_path(fs, &remaining, &ino_parent);
paul@243 565
paul@243 566
    if (retval)
paul@243 567
        return retval;
paul@236 568
paul@231 569
    return ext2fs_unlink(fs, ino_parent, basename, 0, 0);
paul@231 570
}
paul@231 571
paul@231 572
/* Unlink a directory entry by inode number. */
paul@231 573
paul@231 574
errcode_t image_unlink_by_inode(ext2_filsys fs, ext2_ino_t ino_parent,
paul@231 575
                                ext2_ino_t ino)
paul@231 576
{
paul@231 577
    return ext2fs_unlink(fs, ino_parent, 0, ino, 0);
paul@231 578
}
paul@231 579
paul@243 580
paul@243 581
paul@243 582
/* Test object presence and types in the filesystem image. */
paul@243 583
paul@243 584
int image_exists(ext2_filsys fs, const char *name)
paul@243 585
{
paul@243 586
    ext2_ino_t ino;
paul@243 587
paul@243 588
    return !image_find_path(fs, &name, &ino);
paul@243 589
}
paul@181 590
paul@181 591
int _image_isdir(ext2_filsys fs, ext2_ino_t ino)
paul@181 592
{
paul@181 593
    struct ext2_inode inode;
paul@181 594
paul@181 595
    if (ext2fs_read_inode(fs, ino, &inode))
paul@181 596
        return 0;
paul@181 597
paul@181 598
    return LINUX_S_ISDIR(inode.i_mode);
paul@181 599
}
paul@181 600
paul@181 601
int image_isdir(ext2_filsys fs, const char *name)
paul@181 602
{
paul@181 603
    ext2_ino_t ino;
paul@181 604
paul@181 605
    if (image_find_path(fs, &name, &ino))
paul@181 606
        return 0;
paul@181 607
paul@181 608
    return _image_isdir(fs, ino);
paul@181 609
}
paul@181 610
paul@181 611
int _image_isfile(ext2_filsys fs, ext2_ino_t ino)
paul@181 612
{
paul@181 613
    struct ext2_inode inode;
paul@181 614
paul@181 615
    if (ext2fs_read_inode(fs, ino, &inode))
paul@181 616
        return 0;
paul@181 617
paul@181 618
    return LINUX_S_ISREG(inode.i_mode);
paul@181 619
}
paul@181 620
paul@181 621
int image_isfile(ext2_filsys fs, const char *name)
paul@181 622
{
paul@181 623
    ext2_ino_t ino;
paul@181 624
paul@181 625
    if (image_find_path(fs, &name, &ino))
paul@181 626
        return 0;
paul@181 627
paul@181 628
    return _image_isfile(fs, ino);
paul@181 629
}
paul@236 630
paul@236 631
/* vim: tabstop=4 expandtab shiftwidth=4
paul@236 632
*/