From ae51f41d14f548d494ac41e0d21137c5a4c3f59c Mon Sep 17 00:00:00 2001 From: Iru Cai Date: Wed, 30 Oct 2019 14:21:52 +0800 Subject: import the U-Boot code and make it compile --- ext4fs.c | 300 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 300 insertions(+) create mode 100644 ext4fs.c (limited to 'ext4fs.c') diff --git a/ext4fs.c b/ext4fs.c new file mode 100644 index 0000000..37b31d9 --- /dev/null +++ b/ext4fs.c @@ -0,0 +1,300 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2011 - 2012 Samsung Electronics + * EXT4 filesystem implementation in Uboot by + * Uma Shankar + * Manjunatha C Achar + * + * ext4ls and ext4load : Based on ext2 ls and load support in Uboot. + * Ext4 read optimization taken from Open-Moko + * Qi bootloader + * + * (C) Copyright 2004 + * esd gmbh + * Reinhard Arlt + * + * based on code from grub2 fs/ext2.c and fs/fshelp.c by + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003, 2004 Free Software Foundation, Inc. + * + * ext4write : Based on generic ext4 protocol. + */ + +#include +#include +#include +#include "ext4_common.h" +#include + +int ext4fs_symlinknest; +struct ext_filesystem ext_fs; + +struct ext_filesystem *get_fs(void) +{ + return &ext_fs; +} + +void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot) +{ + if ((node != &ext4fs_root->diropen) && (node != currroot)) + free(node); +} + +/* + * Taken from openmoko-kernel mailing list: By Andy green + * Optimized read file API : collects and defers contiguous sector + * reads into one potentially more efficient larger sequential read action + */ +int ext4fs_read_file(struct ext2fs_node *node, loff_t pos, + loff_t len, char *buf, loff_t *actread) +{ + struct ext_filesystem *fs = get_fs(); + int i; + lbaint_t blockcnt; + int log2blksz = fs->dev_desc->log2blksz; + int log2_fs_blocksize = LOG2_BLOCK_SIZE(node->data) - log2blksz; + int blocksize = (1 << (log2_fs_blocksize + log2blksz)); + unsigned int filesize = le32_to_cpu(node->inode.size); + lbaint_t previous_block_number = -1; + lbaint_t delayed_start = 0; + lbaint_t delayed_extent = 0; + lbaint_t delayed_skipfirst = 0; + lbaint_t delayed_next = 0; + char *delayed_buf = NULL; + char *start_buf = buf; + short status; + struct ext_block_cache cache; + + ext_cache_init(&cache); + + /* Adjust len so it we can't read past the end of the file. */ + if (len + pos > filesize) + len = (filesize - pos); + + if (blocksize <= 0 || len <= 0) { + ext_cache_fini(&cache); + return -1; + } + + blockcnt = lldiv(((len + pos) + blocksize - 1), blocksize); + + for (i = lldiv(pos, blocksize); i < blockcnt; i++) { + long int blknr; + int blockoff = pos - (blocksize * i); + int blockend = blocksize; + int skipfirst = 0; + blknr = read_allocated_block(&node->inode, i, &cache); + if (blknr < 0) { + ext_cache_fini(&cache); + return -1; + } + + blknr = blknr << log2_fs_blocksize; + + /* Last block. */ + if (i == blockcnt - 1) { + blockend = (len + pos) - (blocksize * i); + + /* The last portion is exactly blocksize. */ + if (!blockend) + blockend = blocksize; + } + + /* First block. */ + if (i == lldiv(pos, blocksize)) { + skipfirst = blockoff; + blockend -= skipfirst; + } + if (blknr) { + int status; + + if (previous_block_number != -1) { + if (delayed_next == blknr) { + delayed_extent += blockend; + delayed_next += blockend >> log2blksz; + } else { /* spill */ + status = ext4fs_devread(delayed_start, + delayed_skipfirst, + delayed_extent, + delayed_buf); + if (status == 0) { + ext_cache_fini(&cache); + return -1; + } + previous_block_number = blknr; + delayed_start = blknr; + delayed_extent = blockend; + delayed_skipfirst = skipfirst; + delayed_buf = buf; + delayed_next = blknr + + (blockend >> log2blksz); + } + } else { + previous_block_number = blknr; + delayed_start = blknr; + delayed_extent = blockend; + delayed_skipfirst = skipfirst; + delayed_buf = buf; + delayed_next = blknr + + (blockend >> log2blksz); + } + } else { + int n; + int n_left; + if (previous_block_number != -1) { + /* spill */ + status = ext4fs_devread(delayed_start, + delayed_skipfirst, + delayed_extent, + delayed_buf); + if (status == 0) { + ext_cache_fini(&cache); + return -1; + } + previous_block_number = -1; + } + /* Zero no more than `len' bytes. */ + n = blocksize - skipfirst; + n_left = len - ( buf - start_buf ); + if (n > n_left) + n = n_left; + memset(buf, 0, n); + } + buf += blocksize - skipfirst; + } + if (previous_block_number != -1) { + /* spill */ + status = ext4fs_devread(delayed_start, + delayed_skipfirst, delayed_extent, + delayed_buf); + if (status == 0) { + ext_cache_fini(&cache); + return -1; + } + previous_block_number = -1; + } + + *actread = len; + ext_cache_fini(&cache); + return 0; +} + +int ext4fs_ls(const char *dirname) +{ + struct ext2fs_node *dirnode = NULL; + int status; + + if (dirname == NULL) + return 0; + + status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode, + FILETYPE_DIRECTORY); + if (status != 1) { + printf("** Can not find directory. **\n"); + if (dirnode) + ext4fs_free_node(dirnode, &ext4fs_root->diropen); + return 1; + } + + ext4fs_iterate_dir(dirnode, NULL, NULL, NULL); + ext4fs_free_node(dirnode, &ext4fs_root->diropen); + + return 0; +} + +int ext4fs_exists(const char *filename) +{ + loff_t file_len; + int ret; + + ret = ext4fs_open(filename, &file_len); + return ret == 0; +} + +int ext4fs_size(const char *filename, loff_t *size) +{ + return ext4fs_open(filename, size); +} + +int ext4fs_read(char *buf, loff_t offset, loff_t len, loff_t *actread) +{ + if (ext4fs_root == NULL || ext4fs_file == NULL) + return -1; + + return ext4fs_read_file(ext4fs_file, offset, len, buf, actread); +} + +int ext4fs_probe(struct blk_desc *fs_dev_desc, + disk_partition_t *fs_partition) +{ + ext4fs_set_blk_dev(fs_dev_desc, fs_partition); + + if (!ext4fs_mount(fs_partition->size)) { + ext4fs_close(); + return -1; + } + + return 0; +} + +int ext4_read_file(const char *filename, void *buf, loff_t offset, loff_t len, + loff_t *len_read) +{ + loff_t file_len; + int ret; + + ret = ext4fs_open(filename, &file_len); + if (ret < 0) { + printf("** File not found %s **\n", filename); + return -1; + } + + if (len == 0) + len = file_len; + + return ext4fs_read(buf, offset, len, len_read); +} + +int ext4fs_uuid(char *uuid_str) +{ + if (ext4fs_root == NULL) + return -1; + +#ifdef CONFIG_LIB_UUID + uuid_bin_to_str((unsigned char *)ext4fs_root->sblock.unique_id, + uuid_str, UUID_STR_FORMAT_STD); + + return 0; +#else + return -ENOSYS; +#endif +} + +void ext_cache_init(struct ext_block_cache *cache) +{ + memset(cache, 0, sizeof(*cache)); +} + +void ext_cache_fini(struct ext_block_cache *cache) +{ + free(cache->buf); + ext_cache_init(cache); +} + +int ext_cache_read(struct ext_block_cache *cache, lbaint_t block, int size) +{ + /* This could be more lenient, but this is simple and enough for now */ + if (cache->buf && cache->block == block && cache->size == size) + return 1; + ext_cache_fini(cache); + cache->buf = malloc(size); + if (!cache->buf) + return 0; + if (!ext4fs_devread(block, 0, size, cache->buf)) { + ext_cache_fini(cache); + return 0; + } + cache->block = block; + cache->size = size; + return 1; +} -- cgit v1.2.3