Changeset 9b9d37bb in mainline for uspace/srv/fs/ext4fs/ext4fs_ops.c


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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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.