Changeset 9b9d37bb in mainline


Ignore:
Timestamp:
2011-10-06T09:48:53Z (12 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

Files:
10 edited

Legend:

Unmodified
Added
Removed
  • boot/Makefile.common

    r3712434 r9b9d37bb  
    7575        $(USPACE_PATH)/srv/loc/loc \
    7676        $(USPACE_PATH)/srv/bd/rd/rd \
    77         $(USPACE_PATH)/srv/vfs/vfs
     77        $(USPACE_PATH)/srv/vfs/vfs \
     78       
     79# TODO: For comfort ext4fs debugging - delete before merge     
     80INIT_TASKS += $(USPACE_PATH)/srv/bd/ata_bd/ata_bd
    7881
    7982ifeq ($(RDFMT),tmpfs)
  • 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 *);
  • uspace/srv/fs/ext4fs/ext4fs_ops.c

    r3712434 r9b9d37bb  
    4040#include <libext4.h>
    4141#include <libfs.h>
     42#include <macros.h>
    4243#include <malloc.h>
    43 #include <stdio.h>
    4444#include <adt/hash_table.h>
    4545#include <ipc/loc.h>
     
    4848
    4949#define EXT4FS_NODE(node)       ((node) ? (ext4fs_node_t *) (node)->data : NULL)
    50 #define EXT4FS_DBG(format, ...) {if (true) printf("ext4fs: %s: " format "\n", __FUNCTION__, ##__VA_ARGS__);}
    5150
    5251#define OPEN_NODES_KEYS 2
     
    7372 * Forward declarations of auxiliary functions
    7473 */
     74
     75static int ext4fs_read_directory(ipc_callid_t, aoff64_t, size_t,
     76    ext4fs_instance_t *, ext4_inode_ref_t *, size_t *);
     77static int ext4fs_read_file(ipc_callid_t, aoff64_t, size_t, ext4fs_instance_t *,
     78    ext4_inode_ref_t *, size_t *);
     79static bool ext4fs_is_dots(const uint8_t *, size_t);
    7580static int ext4fs_instance_get(service_id_t, ext4fs_instance_t **);
    7681static int ext4fs_node_get_core(fs_node_t **, ext4fs_instance_t *, fs_index_t);
     
    142147int ext4fs_global_init(void)
    143148{
     149        EXT4FS_DBG("");
     150
    144151        if (!hash_table_create(&open_nodes, OPEN_NODES_BUCKETS,
    145152            OPEN_NODES_KEYS, &open_nodes_ops)) {
     
    152159int ext4fs_global_fini(void)
    153160{
     161        EXT4FS_DBG("");
     162
    154163        hash_table_destroy(&open_nodes);
    155164        return EOK;
     
    169178        fibril_mutex_lock(&instance_list_mutex);
    170179
    171         EXT4FS_DBG("Checking lists");
    172 
    173180        if (list_empty(&instance_list)) {
    174181                fibril_mutex_unlock(&instance_list_mutex);
    175182                return EINVAL;
    176183        }
    177 
    178         EXT4FS_DBG("checked");
    179184
    180185        list_foreach(instance_list, link) {
     
    188193        }
    189194
    190         EXT4FS_DBG("Not found");
    191 
    192195        fibril_mutex_unlock(&instance_list_mutex);
    193196        return EINVAL;
     
    197200int ext4fs_root_get(fs_node_t **rfn, service_id_t service_id)
    198201{
     202        EXT4FS_DBG("");
     203
    199204        return ext4fs_node_get(rfn, service_id, EXT4_INODE_ROOT_INDEX);
    200205}
     
    203208int ext4fs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
    204209{
    205         // TODO
     210        EXT4FS_DBG("");
     211
     212        ext4fs_node_t *eparent = EXT4FS_NODE(pfn);
     213        ext4_filesystem_t *fs;
     214        ext4_directory_iterator_t it;
     215        int rc;
     216        size_t name_size;
     217        size_t component_size;
     218        bool found = false;
     219        uint32_t inode;
     220
     221        fs = eparent->instance->filesystem;
     222
     223        if (!ext4_inode_is_type(fs->superblock, eparent->inode_ref->inode,
     224            EXT4_INODE_MODE_DIRECTORY)) {
     225                return ENOTDIR;
     226        }
     227
     228        rc = ext4_directory_iterator_init(&it, fs, eparent->inode_ref, 0);
     229        if (rc != EOK) {
     230                return rc;
     231        }
     232
     233        /* Find length of component in bytes
     234         * TODO: check for library function call that does this
     235         */
     236        component_size = 0;
     237        while (*(component+component_size) != 0) {
     238                component_size++;
     239        }
     240
     241        while (it.current != NULL) {
     242                inode = ext4_directory_entry_ll_get_inode(it.current);
     243
     244                /* ignore empty directory entries */
     245                if (inode != 0) {
     246                        name_size = ext4_directory_entry_ll_get_name_length(fs->superblock,
     247                                it.current);
     248
     249                        if (name_size == component_size && bcmp(component, &it.current->name,
     250                                    name_size) == 0) {
     251                                rc = ext4fs_node_get_core(rfn, eparent->instance,
     252                                        inode);
     253                                if (rc != EOK) {
     254                                        ext4_directory_iterator_fini(&it);
     255                                        return rc;
     256                                }
     257                                found = true;
     258                                break;
     259                        }
     260                }
     261
     262                rc = ext4_directory_iterator_next(&it);
     263                if (rc != EOK) {
     264                        ext4_directory_iterator_fini(&it);
     265                        return rc;
     266                }
     267        }
     268
     269        ext4_directory_iterator_fini(&it);
     270
     271        if (!found) {
     272                return ENOENT;
     273        }
     274
    206275        return EOK;
    207276}
     
    225294                fs_index_t index)
    226295{
    227 
    228296        int rc;
    229297        fs_node_t *node = NULL;
     
    290358
    291359
    292 int ext4fs_node_put_core(ext4fs_node_t *enode) {
    293         // TODO
     360int ext4fs_node_put_core(ext4fs_node_t *enode)
     361{
     362        int rc;
     363        unsigned long key[] = {
     364                [OPEN_NODES_DEV_HANDLE_KEY] = enode->instance->service_id,
     365                [OPEN_NODES_INODE_KEY] = enode->inode_ref->index,
     366        };
     367
     368        hash_table_remove(&open_nodes, key, OPEN_NODES_KEYS);
     369        assert(enode->instance->open_nodes_count > 0);
     370        enode->instance->open_nodes_count--;
     371
     372        rc = ext4_filesystem_put_inode_ref(enode->inode_ref);
     373        if (rc != EOK) {
     374                return rc;
     375        }
     376
     377        free(enode->fs_node);
     378        free(enode);
     379
    294380        return EOK;
    295381}
     
    304390int ext4fs_node_put(fs_node_t *fn)
    305391{
    306         EXT4FS_DBG("");
    307392        int rc;
    308393        ext4fs_node_t *enode = EXT4FS_NODE(fn);
     
    328413int ext4fs_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
    329414{
     415        EXT4FS_DBG("");
     416
    330417        // TODO
    331418        return ENOTSUP;
     
    335422int ext4fs_destroy_node(fs_node_t *fn)
    336423{
     424        EXT4FS_DBG("");
     425
    337426        // TODO
    338427        return ENOTSUP;
     
    342431int ext4fs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
    343432{
     433        EXT4FS_DBG("");
     434
    344435        // TODO
    345436        return ENOTSUP;
     
    349440int ext4fs_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
    350441{
     442        EXT4FS_DBG("");
     443
    351444        // TODO
    352445        return ENOTSUP;
     
    356449int ext4fs_has_children(bool *has_children, fs_node_t *fn)
    357450{
     451        EXT4FS_DBG("");
     452
    358453        // TODO
    359454        return EOK;
     
    363458fs_index_t ext4fs_index_get(fs_node_t *fn)
    364459{
    365         // TODO
    366         return 0;
     460        ext4fs_node_t *enode = EXT4FS_NODE(fn);
     461        return enode->inode_ref->index;
    367462}
    368463
     
    370465aoff64_t ext4fs_size_get(fs_node_t *fn)
    371466{
    372         // TODO
    373         return 0;
     467        ext4fs_node_t *enode = EXT4FS_NODE(fn);
     468        aoff64_t size = ext4_inode_get_size(enode->instance->filesystem->superblock,
     469            enode->inode_ref->inode);
     470        return size;
    374471}
    375472
     
    377474unsigned ext4fs_lnkcnt_get(fs_node_t *fn)
    378475{
    379         // TODO
    380         return 0;
     476        ext4fs_node_t *enode = EXT4FS_NODE(fn);
     477        unsigned count = ext4_inode_get_links_count(enode->inode_ref->inode);
     478        return count;
    381479}
    382480
     
    384482bool ext4fs_is_directory(fs_node_t *fn)
    385483{
     484        EXT4FS_DBG("");
     485
    386486        // TODO
    387487        return false;
     
    391491bool ext4fs_is_file(fs_node_t *fn)
    392492{
    393         // TODO
    394         return false;
     493        ext4fs_node_t *enode = EXT4FS_NODE(fn);
     494        bool is_file = ext4_inode_is_type(enode->instance->filesystem->superblock,
     495            enode->inode_ref->inode, EXT4_INODE_MODE_FILE);
     496        return is_file;
    395497}
    396498
     
    398500service_id_t ext4fs_service_get(fs_node_t *fn)
    399501{
     502        EXT4FS_DBG("");
     503
    400504        // TODO
    401505        return 0;
     
    432536   fs_index_t *index, aoff64_t *size, unsigned *lnkcnt)
    433537{
     538        EXT4FS_DBG("");
    434539
    435540        int rc;
     
    511616static int ext4fs_unmounted(service_id_t service_id)
    512617{
     618        EXT4FS_DBG("");
    513619
    514620        int rc;
     
    545651    size_t *rbytes)
    546652{
    547         // TODO
    548         return 0;
    549 }
    550 
     653        EXT4FS_DBG("");
     654
     655        ext4fs_instance_t *inst;
     656        ext4_inode_ref_t *inode_ref;
     657        int rc;
     658
     659        /*
     660         * Receive the read request.
     661         */
     662        ipc_callid_t callid;
     663        size_t size;
     664        if (!async_data_read_receive(&callid, &size)) {
     665                async_answer_0(callid, EINVAL);
     666                return EINVAL;
     667        }
     668
     669        rc = ext4fs_instance_get(service_id, &inst);
     670        if (rc != EOK) {
     671                async_answer_0(callid, rc);
     672                return rc;
     673        }
     674
     675        rc = ext4_filesystem_get_inode_ref(inst->filesystem, index, &inode_ref);
     676        if (rc != EOK) {
     677                async_answer_0(callid, rc);
     678                return rc;
     679        }
     680
     681        if (ext4_inode_is_type(inst->filesystem->superblock, inode_ref->inode,
     682                        EXT4_INODE_MODE_FILE)) {
     683                rc = ext4fs_read_file(callid, pos, size, inst, inode_ref,
     684                                rbytes);
     685        } else if (ext4_inode_is_type(inst->filesystem->superblock,
     686                        inode_ref->inode, EXT4_INODE_MODE_DIRECTORY)) {
     687                rc = ext4fs_read_directory(callid, pos, size, inst, inode_ref,
     688                                rbytes);
     689        } else {
     690                /* Other inode types not supported */
     691                async_answer_0(callid, ENOTSUP);
     692                rc = ENOTSUP;
     693        }
     694
     695        ext4_filesystem_put_inode_ref(inode_ref);
     696        return rc;
     697}
     698
     699bool ext4fs_is_dots(const uint8_t *name, size_t name_size) {
     700        if (name_size == 1 && name[0] == '.') {
     701                return true;
     702        }
     703
     704        if (name_size == 2 && name[0] == '.' && name[1] == '.') {
     705                return true;
     706        }
     707
     708        return false;
     709}
     710
     711int ext4fs_read_directory(ipc_callid_t callid, aoff64_t pos, size_t size,
     712    ext4fs_instance_t *inst, ext4_inode_ref_t *inode_ref, size_t *rbytes)
     713{
     714        EXT4FS_DBG("");
     715
     716        ext4_directory_iterator_t it;
     717        aoff64_t next;
     718        uint8_t *buf;
     719        size_t name_size;
     720        int rc;
     721        bool found = false;
     722
     723        rc = ext4_directory_iterator_init(&it, inst->filesystem, inode_ref, pos);
     724        if (rc != EOK) {
     725                async_answer_0(callid, rc);
     726                return rc;
     727        }
     728
     729        /* Find next interesting directory entry.
     730         * We want to skip . and .. entries
     731         * as these are not used in HelenOS
     732         */
     733        while (it.current != NULL) {
     734                if (it.current->inode == 0) {
     735                        goto skip;
     736                }
     737
     738                name_size = ext4_directory_entry_ll_get_name_length(
     739                    inst->filesystem->superblock, it.current);
     740
     741                /* skip . and .. */
     742                if (ext4fs_is_dots(&it.current->name, name_size)) {
     743                        goto skip;
     744                }
     745
     746                /* The on-disk entry does not contain \0 at the end
     747                 * end of entry name, so we copy it to new buffer
     748                 * and add the \0 at the end
     749                 */
     750                buf = malloc(name_size+1);
     751                if (buf == NULL) {
     752                        ext4_directory_iterator_fini(&it);
     753                        async_answer_0(callid, ENOMEM);
     754                        return ENOMEM;
     755                }
     756                memcpy(buf, &it.current->name, name_size);
     757                *(buf + name_size) = 0;
     758                found = true;
     759                (void) async_data_read_finalize(callid, buf, name_size + 1);
     760                free(buf);
     761                break;
     762
     763skip:
     764                rc = ext4_directory_iterator_next(&it);
     765                if (rc != EOK) {
     766                        ext4_directory_iterator_fini(&it);
     767                        async_answer_0(callid, rc);
     768                        return rc;
     769                }
     770        }
     771
     772        if (found) {
     773                rc = ext4_directory_iterator_next(&it);
     774                if (rc != EOK)
     775                        return rc;
     776                next = it.current_offset;
     777        }
     778
     779        rc = ext4_directory_iterator_fini(&it);
     780        if (rc != EOK)
     781                return rc;
     782
     783        if (found) {
     784                *rbytes = next - pos;
     785                return EOK;
     786        } else {
     787                async_answer_0(callid, ENOENT);
     788                return ENOENT;
     789        }
     790}
     791
     792int ext4fs_read_file(ipc_callid_t callid, aoff64_t pos, size_t size,
     793    ext4fs_instance_t *inst, ext4_inode_ref_t *inode_ref, size_t *rbytes)
     794{
     795        EXT4FS_DBG("");
     796
     797        int rc;
     798        uint32_t block_size;
     799        aoff64_t file_block;
     800        uint64_t file_size;
     801        uint32_t fs_block;
     802        size_t offset_in_block;
     803        size_t bytes;
     804        block_t *block;
     805        uint8_t *buffer;
     806
     807        file_size = ext4_inode_get_size(inst->filesystem->superblock,
     808                inode_ref->inode);
     809
     810        if (pos >= file_size) {
     811                /* Read 0 bytes successfully */
     812                async_data_read_finalize(callid, NULL, 0);
     813                *rbytes = 0;
     814                return EOK;
     815        }
     816
     817        /* For now, we only read data from one block at a time */
     818        block_size = ext4_superblock_get_block_size(inst->filesystem->superblock);
     819        file_block = pos / block_size;
     820        offset_in_block = pos % block_size;
     821        bytes = min(block_size - offset_in_block, size);
     822
     823        /* Handle end of file */
     824        if (pos + bytes > file_size) {
     825                bytes = file_size - pos;
     826        }
     827
     828        /* Get the real block number */
     829        rc = ext4_filesystem_get_inode_data_block_index(inst->filesystem,
     830                inode_ref->inode, file_block, &fs_block);
     831        if (rc != EOK) {
     832                async_answer_0(callid, rc);
     833                return rc;
     834        }
     835
     836        /* Check for sparse file
     837         * If ext2_filesystem_get_inode_data_block_index returned
     838         * fs_block == 0, it means that the given block is not allocated for the
     839         * file and we need to return a buffer of zeros
     840         */
     841        if (fs_block == 0) {
     842                buffer = malloc(bytes);
     843                if (buffer == NULL) {
     844                        async_answer_0(callid, ENOMEM);
     845                        return ENOMEM;
     846                }
     847
     848                memset(buffer, 0, bytes);
     849
     850                async_data_read_finalize(callid, buffer, bytes);
     851                *rbytes = bytes;
     852
     853                free(buffer);
     854
     855                return EOK;
     856        }
     857
     858        /* Usual case - we need to read a block from device */
     859        rc = block_get(&block, inst->service_id, fs_block, BLOCK_FLAGS_NONE);
     860        if (rc != EOK) {
     861                async_answer_0(callid, rc);
     862                return rc;
     863        }
     864
     865        assert(offset_in_block + bytes <= block_size);
     866        async_data_read_finalize(callid, block->data + offset_in_block, bytes);
     867
     868        rc = block_put(block);
     869        if (rc != EOK)
     870                return rc;
     871
     872        *rbytes = bytes;
     873        return EOK;
     874}
    551875
    552876static int
Note: See TracChangeset for help on using the changeset viewer.