Changeset 9b9d37bb in mainline for uspace/lib/ext4


Ignore:
Timestamp:
2011-10-06T09:48:53Z (14 years ago)
Author:
Frantisek Princ <frantisek.princ@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
1114173
Parents:
3712434
Message:

mounting + list of mounted directory (ported from ext2) - many TODO remaining

Location:
uspace/lib/ext4
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/ext4/libext4.h

    r3712434 r9b9d37bb  
    4040#include "libext4_superblock.h"
    4141
     42#include <stdio.h>
     43#define EXT4FS_DBG(format, ...) {if (true) printf("ext4fs: %s: " format "\n", __FUNCTION__, ##__VA_ARGS__);}
     44
    4245#endif
    4346
  • uspace/lib/ext4/libext4_directory.c

    r3712434 r9b9d37bb  
    3636 */
    3737
     38#include <byteorder.h>
     39#include <errno.h>
    3840#include "libext4.h"
     41
     42static int ext4_directory_iterator_set(ext4_directory_iterator_t *,
     43    uint32_t);
     44
     45
     46uint32_t ext4_directory_entry_ll_get_inode(ext4_directory_entry_ll_t *de)
     47{
     48        return uint32_t_le2host(de->inode);
     49}
     50
     51uint16_t ext4_directory_entry_ll_get_entry_length(
     52    ext4_directory_entry_ll_t *de)
     53{
     54        return uint16_t_le2host(de->entry_length);
     55}
     56
     57uint16_t ext4_directory_entry_ll_get_name_length(
     58    ext4_superblock_t *sb, ext4_directory_entry_ll_t *de)
     59{
     60        if (ext4_superblock_get_rev_level(sb) == 0 &&
     61            ext4_superblock_get_minor_rev_level(sb) < 5) {
     62                return ((uint16_t)de->name_length_high) << 8 |
     63                    ((uint16_t)de->name_length);
     64        }
     65        return de->name_length;
     66}
     67
     68int ext4_directory_iterator_init(ext4_directory_iterator_t *it,
     69    ext4_filesystem_t *fs, ext4_inode_ref_t *inode_ref, aoff64_t pos)
     70{
     71        it->inode_ref = inode_ref;
     72        it->fs = fs;
     73        it->current = NULL;
     74        it->current_offset = 0;
     75        it->current_block = NULL;
     76
     77        return ext4_directory_iterator_seek(it, pos);
     78}
     79
     80
     81int ext4_directory_iterator_next(ext4_directory_iterator_t *it)
     82{
     83        uint16_t skip;
     84
     85        assert(it->current != NULL);
     86
     87        skip = ext4_directory_entry_ll_get_entry_length(it->current);
     88
     89        return ext4_directory_iterator_seek(it, it->current_offset + skip);
     90}
     91
     92
     93int ext4_directory_iterator_seek(ext4_directory_iterator_t *it, aoff64_t pos)
     94{
     95        int rc;
     96
     97        uint64_t size;
     98        aoff64_t current_block_idx;
     99        aoff64_t next_block_idx;
     100        uint32_t next_block_phys_idx;
     101        uint32_t block_size;
     102
     103        size = ext4_inode_get_size(it->fs->superblock, it->inode_ref->inode);
     104
     105        /* The iterator is not valid until we seek to the desired position */
     106        it->current = NULL;
     107
     108        /* Are we at the end? */
     109        if (pos >= size) {
     110                if (it->current_block) {
     111                        rc = block_put(it->current_block);
     112                        it->current_block = NULL;
     113                        if (rc != EOK) {
     114                                return rc;
     115                        }
     116                }
     117
     118                it->current_offset = pos;
     119                return EOK;
     120        }
     121
     122        block_size = ext4_superblock_get_block_size(it->fs->superblock);
     123        current_block_idx = it->current_offset / block_size;
     124        next_block_idx = pos / block_size;
     125
     126        /* If we don't have a block or are moving accross block boundary,
     127         * we need to get another block
     128         */
     129        if (it->current_block == NULL || current_block_idx != next_block_idx) {
     130                if (it->current_block) {
     131                        rc = block_put(it->current_block);
     132                        it->current_block = NULL;
     133                        if (rc != EOK) {
     134                                return rc;
     135                        }
     136                }
     137
     138                rc = ext4_filesystem_get_inode_data_block_index(it->fs,
     139                    it->inode_ref->inode, next_block_idx, &next_block_phys_idx);
     140                if (rc != EOK) {
     141                        return rc;
     142                }
     143
     144                rc = block_get(&it->current_block, it->fs->device, next_block_phys_idx,
     145                    BLOCK_FLAGS_NONE);
     146                if (rc != EOK) {
     147                        it->current_block = NULL;
     148                        return rc;
     149                }
     150        }
     151
     152        it->current_offset = pos;
     153        return ext4_directory_iterator_set(it, block_size);
     154}
     155
     156static int ext4_directory_iterator_set(ext4_directory_iterator_t *it,
     157    uint32_t block_size)
     158{
     159        uint32_t offset_in_block = it->current_offset % block_size;
     160
     161        it->current = NULL;
     162
     163        /* Ensure proper alignment */
     164        if ((offset_in_block % 4) != 0) {
     165                return EIO;
     166        }
     167
     168        /* Ensure that the core of the entry does not overflow the block */
     169        if (offset_in_block > block_size - 8) {
     170                return EIO;
     171        }
     172
     173        ext4_directory_entry_ll_t *entry = it->current_block->data + offset_in_block;
     174
     175        /* Ensure that the whole entry does not overflow the block */
     176        uint16_t length = ext4_directory_entry_ll_get_entry_length(entry);
     177        if (offset_in_block + length > block_size) {
     178                return EIO;
     179        }
     180
     181        /* Ensure the name length is not too large */
     182        if (ext4_directory_entry_ll_get_name_length(it->fs->superblock,
     183            entry) > length-8) {
     184                return EIO;
     185        }
     186
     187        it->current = entry;
     188        return EOK;
     189}
     190
     191
     192int ext4_directory_iterator_fini(ext4_directory_iterator_t *it)
     193{
     194        int rc;
     195
     196        it->fs = NULL;
     197        it->inode_ref = NULL;
     198        it->current = NULL;
     199
     200        if (it->current_block) {
     201                rc = block_put(it->current_block);
     202                if (rc != EOK) {
     203                        return rc;
     204                }
     205        }
     206
     207        return EOK;
     208}
    39209
    40210
  • uspace/lib/ext4/libext4_directory.h

    r3712434 r9b9d37bb  
    3434#define LIBEXT4_LIBEXT4_DIRECTORY_H_
    3535
     36#include "libext4_filesystem.h"
     37#include "libext4_inode.h"
     38
     39/**
     40 * Linked list directory entry structure
     41 */
     42typedef struct ext4_directory_entry_ll {
     43        uint32_t inode; // Inode for the entry
     44        uint16_t entry_length; // Distance to the next directory entry
     45        uint8_t name_length; // Lower 8 bits of name length
     46        union {
     47                uint8_t name_length_high; // Higher 8 bits of name length
     48                uint8_t inode_type; // Type of referenced inode (in rev >= 0.5)
     49        } __attribute__ ((packed));
     50        uint8_t name; // First byte of name, if present
     51} __attribute__ ((packed)) ext4_directory_entry_ll_t;
     52
     53typedef struct ext4_directory_iterator {
     54        ext4_filesystem_t *fs;
     55        ext4_inode_ref_t *inode_ref;
     56        block_t *current_block;
     57        aoff64_t current_offset;
     58        ext4_directory_entry_ll_t *current;
     59} ext4_directory_iterator_t;
     60
     61extern uint32_t ext4_directory_entry_ll_get_inode(ext4_directory_entry_ll_t *);
     62extern uint16_t ext4_directory_entry_ll_get_entry_length(
     63    ext4_directory_entry_ll_t *);
     64extern uint16_t ext4_directory_entry_ll_get_name_length(
     65    ext4_superblock_t *, ext4_directory_entry_ll_t *);
     66
     67extern int ext4_directory_iterator_init(ext4_directory_iterator_t *,
     68                ext4_filesystem_t *, ext4_inode_ref_t *, aoff64_t);
     69extern int ext4_directory_iterator_next(ext4_directory_iterator_t *);
     70extern int ext4_directory_iterator_seek(ext4_directory_iterator_t *, aoff64_t pos);
     71extern int ext4_directory_iterator_fini(ext4_directory_iterator_t *);
    3672
    3773#endif
  • uspace/lib/ext4/libext4_filesystem.c

    r3712434 r9b9d37bb  
    3636 */
    3737
     38#include <byteorder.h>
    3839#include <errno.h>
    3940#include <malloc.h>
     
    144145    ext4_block_group_ref_t **ref)
    145146{
     147        EXT4FS_DBG("");
     148
    146149        int rc;
    147150        aoff64_t block_id;
     
    161164        block_id = ext4_superblock_get_first_data_block(fs->superblock) + 1;
    162165
     166        EXT4FS_DBG("block_size = \%d", ext4_superblock_get_block_size(fs->superblock));
     167        EXT4FS_DBG("descriptors_per_block = \%d", descriptors_per_block);
     168        EXT4FS_DBG("bgid = \%d", bgid);
     169        EXT4FS_DBG("first_data_block: \%d", (uint32_t)block_id);
     170
    163171        /* Find the block containing the descriptor we are looking for */
    164172        block_id += bgid / descriptors_per_block;
    165173        offset = (bgid % descriptors_per_block) * EXT4_BLOCK_GROUP_DESCRIPTOR_SIZE;
    166174
     175        EXT4FS_DBG("updated block_id: \%d", (uint32_t)block_id);
     176
    167177        rc = block_get(&newref->block, fs->device, block_id, 0);
    168178        if (rc != EOK) {
     179
     180                EXT4FS_DBG("block_get error: \%d", rc);
     181
    169182                free(newref);
    170183                return rc;
    171184        }
    172185
     186        EXT4FS_DBG("block read");
     187
    173188        newref->block_group = newref->block->data + offset;
    174189
    175190        *ref = newref;
     191
     192        EXT4FS_DBG("finished");
    176193
    177194        return EOK;
     
    184201    ext4_inode_ref_t **ref)
    185202{
     203        EXT4FS_DBG("");
     204
    186205        int rc;
    187206        aoff64_t block_id;
     
    202221        }
    203222
     223        EXT4FS_DBG("allocated");
     224
    204225        inodes_per_group = ext4_superblock_get_inodes_per_group(fs->superblock);
     226
     227        EXT4FS_DBG("inodes_per_group_loaded");
    205228
    206229        /* inode numbers are 1-based, but it is simpler to work with 0-based
     
    211234        offset_in_group = index % inodes_per_group;
    212235
     236        EXT4FS_DBG("index: \%d", index);
     237        EXT4FS_DBG("inodes_per_group: \%d", inodes_per_group);
     238        EXT4FS_DBG("bg_id: \%d", block_group);
     239
    213240        rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref);
    214241        if (rc != EOK) {
     
    216243                return rc;
    217244        }
     245
     246        EXT4FS_DBG("block_group_ref loaded");
    218247
    219248        inode_table_start = ext4_block_group_get_inode_table_first_block(
    220249            bg_ref->block_group);
    221250
     251        EXT4FS_DBG("inode_table block loaded");
     252
    222253        inode_size = ext4_superblock_get_inode_size(fs->superblock);
    223254        block_size = ext4_superblock_get_block_size(fs->superblock);
     
    228259        offset_in_block = byte_offset_in_group % block_size;
    229260
     261        EXT4FS_DBG("superblock info loaded");
     262
    230263        rc = block_get(&newref->block, fs->device, block_id, 0);
    231264        if (rc != EOK) {
     
    233266                return rc;
    234267        }
     268
     269        EXT4FS_DBG("block got");
    235270
    236271        newref->inode = newref->block->data + offset_in_block;
     
    242277        *ref = newref;
    243278
     279        EXT4FS_DBG("finished");
     280
     281        return EOK;
     282}
     283
     284int ext4_filesystem_put_inode_ref(ext4_inode_ref_t *ref)
     285{
     286        int rc;
     287
     288        rc = block_put(ref->block);
     289        free(ref);
     290
     291        return rc;
     292}
     293
     294int ext4_filesystem_get_inode_data_block_index(ext4_filesystem_t *fs, ext4_inode_t* inode,
     295    aoff64_t iblock, uint32_t* fblock)
     296{
     297        int rc;
     298        aoff64_t limits[4];
     299        uint32_t block_ids_per_block;
     300        aoff64_t blocks_per_level[4];
     301        uint32_t offset_in_block;
     302        uint32_t current_block;
     303        aoff64_t block_offset_in_level;
     304        int i;
     305        int level;
     306        block_t *block;
     307
     308        /* Handle simple case when we are dealing with direct reference */
     309        if (iblock < EXT4_INODE_DIRECT_BLOCKS) {
     310                current_block = ext4_inode_get_direct_block(inode, (uint32_t)iblock);
     311                *fblock = current_block;
     312                return EOK;
     313        }
     314
     315        /* Compute limits for indirect block levels
     316         * TODO: compute this once when loading filesystem and store in ext2_filesystem_t
     317         */
     318        block_ids_per_block = ext4_superblock_get_block_size(fs->superblock) / sizeof(uint32_t);
     319        limits[0] = EXT4_INODE_DIRECT_BLOCKS;
     320        blocks_per_level[0] = 1;
     321        for (i = 1; i < 4; i++) {
     322                blocks_per_level[i]  = blocks_per_level[i-1] *
     323                    block_ids_per_block;
     324                limits[i] = limits[i-1] + blocks_per_level[i];
     325        }
     326
     327        /* Determine the indirection level needed to get the desired block */
     328        level = -1;
     329        for (i = 1; i < 4; i++) {
     330                if (iblock < limits[i]) {
     331                        level = i;
     332                        break;
     333                }
     334        }
     335
     336        if (level == -1) {
     337                return EIO;
     338        }
     339
     340        /* Compute offsets for the topmost level */
     341        block_offset_in_level = iblock - limits[level-1];
     342        current_block = ext4_inode_get_indirect_block(inode, level-1);
     343        offset_in_block = block_offset_in_level / blocks_per_level[level-1];
     344
     345        /* Navigate through other levels, until we find the block number
     346         * or find null reference meaning we are dealing with sparse file
     347         */
     348        while (level > 0) {
     349                rc = block_get(&block, fs->device, current_block, 0);
     350                if (rc != EOK) {
     351                        return rc;
     352                }
     353
     354                assert(offset_in_block < block_ids_per_block);
     355                current_block = uint32_t_le2host(((uint32_t*)block->data)[offset_in_block]);
     356
     357                rc = block_put(block);
     358                if (rc != EOK) {
     359                        return rc;
     360                }
     361
     362                if (current_block == 0) {
     363                        /* This is a sparse file */
     364                        *fblock = 0;
     365                        return EOK;
     366                }
     367
     368                level -= 1;
     369
     370                /* If we are on the last level, break here as
     371                 * there is no next level to visit
     372                 */
     373                if (level == 0) {
     374                        break;
     375                }
     376
     377                /* Visit the next level */
     378                block_offset_in_level %= blocks_per_level[level];
     379                offset_in_block = block_offset_in_level / blocks_per_level[level-1];
     380        }
     381
     382        *fblock = current_block;
     383
    244384        return EOK;
    245385}
  • uspace/lib/ext4/libext4_filesystem.h

    r3712434 r9b9d37bb  
    108108extern int ext4_filesystem_get_inode_ref(ext4_filesystem_t *, uint32_t,
    109109                ext4_inode_ref_t **);
    110 
     110extern int ext4_filesystem_put_inode_ref(ext4_inode_ref_t *);
     111extern int ext4_filesystem_get_inode_data_block_index(ext4_filesystem_t *,
     112        ext4_inode_t *, aoff64_t iblock, uint32_t *);
    111113
    112114#endif
  • uspace/lib/ext4/libext4_inode.c

    r3712434 r9b9d37bb  
    3939#include "libext4.h"
    4040
     41uint32_t ext4_inode_get_mode(ext4_superblock_t *sb, ext4_inode_t *inode)
     42{
     43        if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_HURD) {
     44                return ((uint32_t)uint16_t_le2host(inode->osd2.hurd2.mode_high)) << 16 |
     45                    ((uint32_t)uint16_t_le2host(inode->mode));
     46        }
     47        return uint16_t_le2host(inode->mode);
     48}
     49
     50bool ext4_inode_is_type(ext4_superblock_t *sb, ext4_inode_t *inode, uint32_t type)
     51{
     52        uint32_t mode = ext4_inode_get_mode(sb, inode);
     53        return (mode & EXT4_INODE_MODE_TYPE_MASK) == type;
     54}
     55
    4156/*
    42 uint32_t ext4_inode_get_mode(ext4_inode_t *inode)
    4357uint32_t ext4_inode_get_uid(ext4_inode_t *inode)
    4458*/
    4559
    46 uint64_t ext4_inode_get_size(ext4_inode_t *inode)
     60uint64_t ext4_inode_get_size(ext4_superblock_t *sb, ext4_inode_t *inode)
    4761{
    48         return ((uint64_t)uint32_t_le2host(inode->size_hi)) << 32 |
    49                         ((uint64_t)uint32_t_le2host(inode->size_lo));
     62        uint32_t major_rev = ext4_superblock_get_rev_level(sb);
     63
     64        if (major_rev > 0 && ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)) {
     65                return ((uint64_t)uint32_t_le2host(inode->size_hi)) << 32 |
     66                            ((uint64_t)uint32_t_le2host(inode->size_lo));
     67                }
     68        return uint32_t_le2host(inode->size_lo);
    5069}
    5170
     
    6887*/
    6988
     89uint32_t ext4_inode_get_direct_block(ext4_inode_t *inode, uint8_t idx)
     90{
     91        assert(idx < EXT4_INODE_DIRECT_BLOCK_COUNT);
     92        return uint32_t_le2host(inode->blocks[idx]);
     93}
     94
     95uint32_t ext4_inode_get_indirect_block(ext4_inode_t *inode, uint8_t idx)
     96{
     97        assert(idx < EXT4_INODE_INDIRECT_BLOCK_COUNT);
     98        return uint32_t_le2host(inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK]);
     99}
     100
    70101/**
    71102 * @}
  • uspace/lib/ext4/libext4_inode.h

    r3712434 r9b9d37bb  
    3636#include <libblock.h>
    3737#include <sys/types.h>
     38#include "libext4_superblock.h"
    3839
    39 #define EXT4_DIRECT_BLOCK_COUNT         12
    40 #define EXT4_INDIRECT_BLOCK             EXT4_DIRECT_BLOCK_COUNT
    41 #define EXT4_DOUBLE_INDIRECT_BLOCK      (EXT4_INDIRECT_BLOCK + 1)
    42 #define EXT4_TRIPPLE_INDIRECT_BLOCK     (EXT4_DOUBLE_INDIRECT_BLOCK + 1)
    43 #define EXT4_INODE_BLOCKS                       (EXT4_TRIPPLE_INDIRECT_BLOCK + 1)
     40
     41#define EXT4_INODE_DIRECT_BLOCK_COUNT           12
     42#define EXT4_INODE_INDIRECT_BLOCK                       EXT4_INODE_DIRECT_BLOCK_COUNT
     43#define EXT4_INODE_DOUBLE_INDIRECT_BLOCK        (EXT4_INODE_INDIRECT_BLOCK + 1)
     44#define EXT4_INODE_TRIPPLE_INDIRECT_BLOCK       (EXT4_INODE_DOUBLE_INDIRECT_BLOCK + 1)
     45#define EXT4_INODE_BLOCKS                                       (EXT4_INODE_TRIPPLE_INDIRECT_BLOCK + 1)
     46#define EXT4_INODE_INDIRECT_BLOCK_COUNT         (EXT4_INODE_BLOCKS - EXT4_INODE_DIRECT_BLOCK_COUNT)
    4447
    4548/*
     
    6467    uint32_t size_hi;
    6568    uint32_t obso_faddr; // Obsoleted fragment address
    66     uint32_t unused_osd2[3]; // OS dependent - not used in HelenOS
     69    union {
     70        struct {
     71                uint16_t blocks_high; /* were l_i_reserved1 */
     72                uint16_t file_acl_high;
     73                uint16_t uid_high;   /* these 2 fields */
     74                uint16_t gid_high;   /* were reserved2[0] */
     75                uint32_t reserved2;
     76        } linux2;
     77        struct {
     78                uint16_t reserved1;  /* Obsoleted fragment number/size which are removed in ext4 */
     79                uint16_t mode_high;
     80                uint16_t uid_high;
     81                uint16_t gid_high;
     82                uint32_t author;
     83        } hurd2;
     84        struct {
     85                uint16_t reserved1;  /* Obsoleted fragment number/size which are removed in ext4 */
     86                uint16_t file_acl_high;
     87                uint32_t reserved2[2];
     88        } masix2;
     89    } __attribute__ ((packed)) osd2;
     90
    6791    uint16_t extra_isize;
    6892    uint16_t pad1;
     
    7599} __attribute__ ((packed)) ext4_inode_t;
    76100
     101#define EXT4_INODE_MODE_FIFO            0x1000
     102#define EXT4_INODE_MODE_CHARDEV         0x2000
     103#define EXT4_INODE_MODE_DIRECTORY       0x4000
     104#define EXT4_INODE_MODE_BLOCKDEV        0x6000
     105#define EXT4_INODE_MODE_FILE            0x8000
     106#define EXT4_INODE_MODE_SOFTLINK        0xA000
     107#define EXT4_INODE_MODE_SOCKET          0xC000
     108#define EXT4_INODE_MODE_TYPE_MASK       0xF000
    77109
    78110#define EXT4_INODE_ROOT_INDEX   2
     
    84116} ext4_inode_ref_t;
    85117
     118
     119extern uint32_t ext4_inode_get_mode(ext4_superblock_t *, ext4_inode_t *);
     120extern bool ext4_inode_is_type(ext4_superblock_t *, ext4_inode_t *, uint32_t);
    86121/*
    87 extern uint16_t ext4_inode_get_mode(ext4_inode_t *);
    88122extern uint32_t ext4_inode_get_uid(ext4_inode_t *);
    89123*/
    90 extern uint64_t ext4_inode_get_size(ext4_inode_t *);
     124extern uint64_t ext4_inode_get_size(ext4_superblock_t *, ext4_inode_t *);
    91125/*
    92126extern uint32_t ext4_inode_get_access_time(ext4_inode_t *);
     
    101135extern uint32_t ext4_inode_get_flags(ext4_inode_t *);
    102136*/
     137
     138uint32_t ext4_inode_get_direct_block(ext4_inode_t *, uint8_t);
     139uint32_t ext4_inode_get_indirect_block(ext4_inode_t *, uint8_t);
    103140
    104141/*
  • uspace/lib/ext4/libext4_superblock.h

    r3712434 r9b9d37bb  
    140140#define EXT4_SUPERBLOCK_SIZE            1024
    141141#define EXT4_SUPERBLOCK_OFFSET          1024
     142
     143#define EXT4_SUPERBLOCK_OS_LINUX        0
     144#define EXT4_SUPERBLOCK_OS_HURD         1
    142145
    143146extern uint32_t ext4_superblock_get_inodes_count(ext4_superblock_t *);
Note: See TracChangeset for help on using the changeset viewer.