ref: d868262d36283441a727e1022414ac706abddb59
parent: 7b3739e7e42e753f9e5b3820b876ff1430243a10
author: gkostka <kostka.grzegorz@gmail.com>
date: Sun Oct 13 13:36:52 EDT 2013
Update directory tree.
--- /dev/null
+++ b/CMakeLists.txt
@@ -1,0 +1,46 @@
+project(lwext4 C)
+cmake_minimum_required(VERSION 2.8)
+
+
+#LIBRARY
+include_directories(. lwext4)
+aux_source_directory(lwext4 LWEXT4_SRC)
+add_library(lwext4 ${LWEXT4_SRC})
+
+
+#EXECUTABLE
+
+if(CMAKE_SYSTEM_PROCESSOR STREQUAL cortex-m3)
+#Library size print
+add_custom_target(size ALL DEPENDS lwext4 COMMAND ${SIZE} -B liblwext4.a)
+
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL cortex-m4)
+#Library size print
+add_custom_target(size ALL DEPENDS lwext4 COMMAND ${SIZE} -B liblwext4.a)
+
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL bf518)
+#Library size print
+add_custom_target(size ALL DEPENDS lwext4 COMMAND ${SIZE} -B liblwext4.a)
+
+else()
+#Generic example target
+include_directories(blockdev/filedev)
+aux_source_directory(blockdev/filedev FILEDEV_SRC)
+aux_source_directory(demos/generic GENERIC_SRC)
+add_executable(fileimage_demo ${GENERIC_SRC} ${FILEDEV_SRC})
+target_link_libraries(fileimage_demo lwext4)
+add_custom_target(size ALL DEPENDS lwext4 COMMAND size -B liblwext4.a)
+endif()
+
+#DISTRIBUTION
+set(CPACK_PACKAGE_VERSION_MAJOR "0")
+set(CPACK_PACKAGE_VERSION_MINOR "1")
+set(CPACK_PACKAGE_VERSION_PATCH "1")
+set(CPACK_SOURCE_GENERATOR "TBZ2")
+set(CPACK_SOURCE_PACKAGE_FILE_NAME
+ "${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
+set(CPACK_SOURCE_IGNORE_FILES
+"/build")
+include(CPack)
+
+add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source)
--- /dev/null
+++ b/Makefile
@@ -1,0 +1,36 @@
+
+all: generic bf518 cortex-m3 cortex-m4 generic
+
+bf518:
+ rm -R -f build_bf518
+ mkdir build_bf518
+ cd build_bf518 && cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../toolchain/bf518.cmake ..
+ cd build_bf518 && make
+
+cortex-m3:
+ rm -R -f build_cortex-m3
+ mkdir build_cortex-m3
+ cd build_cortex-m3 && cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../toolchain/cortex-m3.cmake ..
+ cd build_cortex-m3 && make
+
+cortex-m4:
+ rm -R -f build_cortex-m4
+ mkdir build_cortex-m4
+ cd build_cortex-m4 && cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../toolchain/cortex-m4.cmake ..
+ cd build_cortex-m4 && make
+
+
+generic:
+ rm -R -f build_generic
+ mkdir build_generic
+ cd build_generic && cmake -G"Unix Makefiles" ../
+ cd build_generic && make
+
+
+clean:
+ rm -R -f build_bf518
+ rm -R -f build_cortex-m3
+ rm -R -f build_cortex-m4
+ rm -R -f build_generic
+
+
\ No newline at end of file
--- /dev/null
+++ b/blockdev/filedev/ext4_filedev.c
@@ -1,0 +1,135 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <ext4_config.h>
+#include <ext4_blockdev.h>
+#include <ext4_errno.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+
+/**@brief Default filename.*/
+const char *fname = "ext2";
+
+/**@brief Image block size.*/
+#define EXT4_FILEDEV_BSIZE 512
+
+/**@brief Image file descriptor.*/
+static FILE *dev_file;
+
+
+/**********************BLOCKDEV INTERFACE**************************************/
+static int filedev_open(struct ext4_blockdev *bdev);
+static int filedev_bread(struct ext4_blockdev *bdev, void *buf, uint64_t blk_id,
+ uint32_t blk_cnt);
+static int filedev_bwrite(struct ext4_blockdev *bdev, const void *buf,
+ uint64_t blk_id, uint32_t blk_cnt);
+static int filedev_close(struct ext4_blockdev *bdev);
+
+
+/******************************************************************************/
+EXT4_BLOCKDEV_STATIC_INSTANCE(
+ _filedev,
+ EXT4_FILEDEV_BSIZE,
+ 0,
+ filedev_open,
+ filedev_bread,
+ filedev_bwrite,
+ filedev_close
+);
+
+/******************************************************************************/
+EXT4_BCACHE_STATIC_INSTANCE(__cache, 8, 1024);
+
+/******************************************************************************/
+static int filedev_open(struct ext4_blockdev *bdev)
+{
+ dev_file = fopen(fname, "r+b");
+
+ if(!dev_file)
+ return ENOENT;
+
+ if(fseek(dev_file, 0, SEEK_END))
+ return EFAULT;
+
+ _filedev.ph_bcnt = ftell(dev_file) / _filedev.ph_bsize;
+
+ return EOK;
+}
+
+/******************************************************************************/
+
+static int filedev_bread(struct ext4_blockdev *bdev, void *buf, uint64_t blk_id,
+ uint32_t blk_cnt)
+{
+ if(fseek(dev_file, blk_id * bdev->ph_bsize, SEEK_SET))
+ return EIO;
+
+ if(!fread(buf, bdev->ph_bsize * blk_cnt, 1, dev_file))
+ return EIO;
+
+ return EOK;
+}
+
+/******************************************************************************/
+static int filedev_bwrite(struct ext4_blockdev *bdev, const void *buf,
+ uint64_t blk_id, uint32_t blk_cnt)
+{
+ if(fseek(dev_file, blk_id * bdev->ph_bsize, SEEK_SET))
+ return EIO;
+
+ if(!fwrite(buf, bdev->ph_bsize * blk_cnt, 1, dev_file))
+ return EIO;
+ return EOK;
+}
+
+/******************************************************************************/
+static int filedev_close(struct ext4_blockdev *bdev)
+{
+ fclose(dev_file);
+ return EOK;
+}
+
+
+/******************************************************************************/
+
+struct ext4_bcache* ext4_filecache_get(void)
+{
+ return &__cache;
+}
+/******************************************************************************/
+struct ext4_blockdev* ext4_filedev_get(void)
+{
+ return &_filedev;
+}
+/******************************************************************************/
+void ext4_filedev_filename(const char *n)
+{
+ fname = n;
+}
+
+/******************************************************************************/
--- /dev/null
+++ b/blockdev/filedev/ext4_filedev.h
@@ -1,0 +1,45 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EXT4_FILEDEV_H_
+#define EXT4_FILEDEV_H_
+
+#include <ext4_config.h>
+#include <ext4_blockdev.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/**@brief Filecache get.*/
+struct ext4_bcache* ext4_filecache_get(void);
+
+/**@brief File blockdev get.*/
+struct ext4_blockdev* ext4_filedev_get(void);
+
+void ext4_filedev_filename(const char *n);
+
+#endif /* EXT4_FILEDEV_H_ */
--- /dev/null
+++ b/demos/generic/main.c
@@ -1,0 +1,344 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <stdbool.h>
+
+#include <ext4_filedev.h>
+#include <ext4.h>
+
+
+
+char input_name[128] = "ext2";
+
+/**@brief Read-write size*/
+static int rw_szie = 1024;
+
+/**@brief Read-write size*/
+static int rw_count = 1024;
+
+static bool cache_mode = false;
+
+
+/**@brief File write buffer*/
+static uint8_t *wr_buff;
+
+/**@brief File read buffer.*/
+static uint8_t *rd_buff;
+
+/**@brief Block device handle.*/
+static struct ext4_blockdev *bd;
+
+/**@brief Block cache handle.*/
+static struct ext4_bcache *bc;
+
+static const char *usage = " \n\
+Welcome in ext4 generic demo. \n\
+Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com) \n\
+Usage: \n\
+ -i - input file (default = ext2) \n\
+ -rws - single R/W size (default = 1024) \n\
+ -rwc - R/W count (default = 1024) \n\
+ -cache - 0 static, 1 dynamic (default = 0) \n\
+\n";
+
+static char* entry_to_str(uint8_t type)
+{
+ switch(type){
+ case EXT4_DIRENTRY_UNKNOWN:
+ return "[UNK] ";
+ case EXT4_DIRENTRY_REG_FILE:
+ return "[FIL] ";
+ case EXT4_DIRENTRY_DIR:
+ return "[DIR] ";
+ case EXT4_DIRENTRY_CHRDEV:
+ return "[CHA] ";
+ case EXT4_DIRENTRY_BLKDEV:
+ return "[BLK] ";
+ case EXT4_DIRENTRY_FIFO:
+ return "[FIF] ";
+ case EXT4_DIRENTRY_SOCK:
+ return "[SOC] ";
+ case EXT4_DIRENTRY_SYMLINK:
+ return "[SYM] ";
+ default:
+ break;
+ }
+ return "[???]";
+}
+
+static void dir_ls(const char *path)
+{
+ int j = 0;
+ char sss[255];
+ ext4_dir d;
+ ext4_direntry *de;
+
+ printf("**********************************************\n");
+
+ ext4_dir_open(&d, path);
+ de = ext4_entry_get(&d, j++);
+ printf("ls %s\n", path);
+
+ while(de){
+ memcpy(sss, de->name, de->name_length);
+ sss[de->name_length] = 0;
+ printf(entry_to_str(de->inode_type));
+ printf(sss);
+ printf("\n");
+ de = ext4_entry_get(&d, j++);
+ }
+ printf("**********************************************\n");
+ ext4_dir_close(&d);
+}
+
+static void mp_stats(void)
+{
+ struct ext4_mount_stats stats;
+ ext4_mount_point_stats("/mp/", &stats);
+
+ printf("**********************************************\n");
+ printf("ext4_mount_point_stats\n");
+ printf("inodes_count = %d\n", stats.inodes_count);
+ printf("free_inodes_count = %d\n", stats.free_inodes_count);
+ printf("blocks_count = %d\n", stats.blocks_count);
+ printf("free_blocks_count = %d\n", stats.free_blocks_count);
+ printf("block_size = %d\n", stats.block_size);
+ printf("block_group_count = %d\n", stats.block_group_count);
+ printf("blocks_per_group = %d\n", stats.blocks_per_group);
+ printf("inodes_per_group = %d\n", stats.inodes_per_group);
+ printf("volume_name = %s\n", stats.volume_name);
+
+ printf("**********************************************\n");
+
+}
+
+static void block_stats(void)
+{
+ uint32_t i;
+
+ printf("**********************************************\n");
+ printf("ext4 blockdev stats\n");
+ printf("bdev->bread_ctr = %d\n", bd->bread_ctr);
+ printf("bdev->bwrite_ctr = %d\n", bd->bwrite_ctr);
+
+
+ printf("bcache->ref_blocks = %d\n", bc->ref_blocks);
+ printf("bcache->max_ref_blocks = %d\n", bc->max_ref_blocks);
+ printf("bcache->lru_ctr = %d\n", bc->lru_ctr);
+
+ printf("\n");
+ for (i = 0; i < bc->cnt; ++i) {
+ printf("bcache->refctr[%d] = %d\n", i, bc->refctr[i]);
+ }
+
+ printf("\n");
+ for (i = 0; i < bc->cnt; ++i) {
+ printf("bcache->lru_id[%d] = %d\n", i, bc->lru_id[i]);
+ }
+
+ printf("\n");
+ for (i = 0; i < bc->cnt; ++i) {
+ printf("bcache->free_delay[%d] = %d\n", i, bc->free_delay[i]);
+ }
+
+ printf("\n");
+ for (i = 0; i < bc->cnt; ++i) {
+ printf("bcache->lba[%d] = %d\n", i, bc->lba[i]);
+ }
+
+
+
+ printf("**********************************************\n");
+}
+
+
+int main(int argc, char **argv)
+{
+ int option_index = 0;
+ int c;
+ int r;
+ int i;
+ uint32_t size;
+ ext4_file f;
+
+ static struct option long_options[] =
+ {
+ {"in", required_argument, 0, 'a'},
+ {"rws", required_argument, 0, 'b'},
+ {"rwc", required_argument, 0, 'c'},
+ {"cache", required_argument, 0, 'd'},
+ {0, 0, 0, 0}
+ };
+
+ while(-1 != (c = getopt_long (argc, argv, "a:b:c:d:", long_options, &option_index))) {
+
+ switch(c){
+ case 'a':
+ strcpy(input_name, optarg);
+ break;
+ case 'b':
+ rw_szie = atoi(optarg);
+ break;
+ case 'c':
+ rw_count = atoi(optarg);
+ break;
+ case 'd':
+ cache_mode = atoi(optarg);
+ break;
+ default:
+ printf(usage);
+ return EXIT_FAILURE;
+
+ }
+ }
+
+ printf("Test conditions:\n");
+ printf("Imput name: %s\n", input_name);
+ printf("RW size: %d\n", rw_szie);
+ printf("RW count: %d\n", rw_count);
+ printf("Cache mode: %s\n", cache_mode ? "dynamic" : "static");
+
+
+
+ ext4_filedev_filename(input_name);
+
+ wr_buff = malloc(rw_szie);
+ rd_buff = malloc(rw_szie);
+
+ if(!wr_buff || !rd_buff){
+ printf("Read-Write allocation ERROR\n");
+ return EXIT_FAILURE;
+ }
+
+ bd = ext4_filedev_get();
+ bc = ext4_filecache_get();
+
+ if(!bd || !bc){
+ printf("Block device ERROR\n");
+ return EXIT_FAILURE;
+ }
+
+ ext4_dmask_set(EXT4_DEBUG_ALL);
+
+ r = ext4_device_register(bd, cache_mode ? 0 : bc, "ext4_filesim");
+ if(r != EOK){
+ printf("ext4_device_register ERROR = %d\n", r);
+ return EXIT_FAILURE;
+ }
+
+ r = ext4_mount("ext4_filesim", "/mp/");
+ if(r != EOK){
+ printf("ext4_mount ERROR = %d\n", r);
+ return EXIT_FAILURE;
+ }
+
+
+ ext4_fremove("/mp/hello.txt");
+ ext4_fremove("/mp/test1");
+ mp_stats();
+ dir_ls("/mp/");
+
+ /*Add hello world file.*/
+ r = ext4_fopen(&f, "/mp/hello.txt", "wb");
+ r = ext4_fwrite(&f, "Hello World !\n", strlen("Hello World !\n"), 0);
+ r = ext4_fclose(&f);
+
+
+ printf("ext4_fopen: test1\n");
+
+ r = ext4_fopen(&f, "/mp/test1", "wb");
+ if(r != EOK){
+ printf("ext4_fopen ERROR = %d\n", r);
+ return EXIT_FAILURE;
+ }
+
+ printf("ext4_write: %d * %d ..." , rw_count, rw_szie);
+
+ for (i = 0; i < rw_count; ++i) {
+
+ memset(wr_buff, i & 0xFF, rw_szie);
+
+ r = ext4_fwrite(&f, wr_buff, rw_szie, &size);
+
+ if((r != EOK) || (size != rw_szie))
+ break;
+ }
+
+ if(i != rw_count){
+ printf("ERROR: rw_count = %d\n", i);
+ return EXIT_FAILURE;
+ }
+
+ printf("OK\n");
+ r = ext4_fclose(&f);
+ printf("ext4_fopen: test1\n");
+
+ r = ext4_fopen(&f, "/mp/test1", "r+");
+ if(r != EOK){
+ printf("ext4_fopen ERROR = %d\n", r);
+ return EXIT_FAILURE;
+ }
+
+ printf("ext4_read: %d * %d ..." , rw_count, rw_szie);
+
+ for (i = 0; i < rw_count; ++i) {
+ memset(wr_buff, i & 0xFF, rw_szie);
+ r = ext4_fread(&f, rd_buff, rw_szie, &size);
+
+ if((r != EOK) || (size != rw_szie))
+ break;
+
+ if(memcmp(rd_buff, wr_buff, rw_szie)){
+ break;
+ }
+ }
+ if(i != rw_count){
+ printf("ERROR: rw_count = %d\n", i);
+ return EXIT_FAILURE;
+ }
+
+ printf("OK\n");
+
+ r = ext4_fclose(&f);
+
+
+ mp_stats();
+ dir_ls("/mp/");
+
+ block_stats();
+ r = ext4_umount("/mp/");
+
+ printf("Test finish: OK\n");
+ return EXIT_SUCCESS;
+
+}
--- /dev/null
+++ b/ext4.h
@@ -1,0 +1,267 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4.h
+ * @brief Ext4 high level operations (files, directories, mountpoints...).
+ * Client has to include only this file.
+ */
+
+#ifndef EXT4_H_
+#define EXT4_H_
+
+#include <ext4_config.h>
+#include <ext4_blockdev.h>
+#include <stdint.h>
+
+/********************************FILE OPEN FLAGS********************************/
+
+#ifndef O_RDONLY
+#define O_RDONLY 00
+#endif
+
+#ifndef O_WRONLY
+#define O_WRONLY 01
+#endif
+
+#ifndef O_RDWR
+#define O_RDWR 02
+#endif
+
+#ifndef O_CREAT
+#define O_CREAT 0100
+#endif
+
+#ifndef O_EXCL
+#define O_EXCL 0200
+#endif
+
+#ifndef O_TRUNC
+#define O_TRUNC 01000
+#endif
+
+#ifndef O_APPEND
+#define O_APPEND 02000
+#endif
+
+/********************************FILE SEEK FLAGS*****************************/
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+#ifndef SEEK_CUR
+#define SEEK_CUR 1
+#endif
+
+#ifndef SEEK_END
+#define SEEK_END 2
+#endif
+
+/********************************OS LOCK INFERFACE***************************/
+
+/**@brief OS dependent lock interface.*/
+struct ext4_lock {
+
+ /**@brief Lock access to mountpoint*/
+ void (*lock)(void);
+
+ /**@brief Unlock access to mountpoint*/
+ void (*unlock)(void);
+};
+
+
+/********************************FILE DESCRIPTOR*****************************/
+
+/**@brief File descriptor*/
+typedef struct ext4_file {
+
+ /**@brief Pountpoint handle.*/
+ struct ext4_mountpoint *mp;
+
+ /**@brief File inode id*/
+ uint32_t inode;
+
+ /**@brief Open flags.*/
+ uint32_t flags;
+
+ /**@brief File size.*/
+ uint64_t fsize;
+
+ /**@brief File position*/
+ uint64_t fpos;
+}ext4_file;
+
+/*****************************DIRECTORY DESCRIPTOR***************************/
+/**@brief Directory entry types. Copy from ext4_types.h*/
+enum {
+ EXT4_DIRENTRY_UNKNOWN = 0,
+ EXT4_DIRENTRY_REG_FILE,
+ EXT4_DIRENTRY_DIR,
+ EXT4_DIRENTRY_CHRDEV,
+ EXT4_DIRENTRY_BLKDEV,
+ EXT4_DIRENTRY_FIFO,
+ EXT4_DIRENTRY_SOCK,
+ EXT4_DIRENTRY_SYMLINK
+};
+
+/**@brief Directory entry descriptor. Copy from ext4_types.h*/
+typedef struct {
+ uint32_t inode;
+ uint16_t entry_length;
+ uint8_t name_length;
+ union {
+ uint8_t name_length_high;
+ uint8_t inode_type;
+ };
+ uint8_t name[255];
+}ext4_direntry;
+
+typedef struct {
+ /**@brief File descriptor*/
+ ext4_file f;
+ /**@brief Current direntry.*/
+ ext4_direntry de;
+}ext4_dir;
+
+/********************************MOUNT OPERATIONS****************************/
+
+/**@brief Register a block device to a name.
+ * @warning Block device has to be filled by
+ * @ref EXT4_BLOCKDEV_STATIC_INSTANCE. Block cache may be created
+ * @ref EXT4_BCACHE_STATIC_INSTANCE.
+ * Block cache may by created automaticly when bc parameter is 0.
+ * @param bd block device
+ * @param bd block device cache (0 = automatic cache mode)
+ * @param dev_name register name
+ * @param standard error code*/
+int ext4_device_register(struct ext4_blockdev *bd, struct ext4_bcache *bc,
+ const char *dev_name);
+
+/**@brief Mount a block device with EXT4 partition to the mountpoint.
+ * @param dev_name block device name (@ref ext4_device_register)
+ * @param mount_point pount point, for example
+ * - /
+ * - /my_partition/
+ * - /my_second_partition/
+ *
+ * @return standard error code */
+int ext4_mount(const char * dev_name, char *mount_point);
+
+/**@brief Umount operation.
+ * @param mount_point mount name
+ * @return standard error code */
+int ext4_umount(char *mount_point);
+
+
+/**@brief Some of the filesystem params.*/
+struct ext4_mount_stats {
+ uint32_t inodes_count;
+ uint32_t free_inodes_count;
+ uint64_t blocks_count;
+ uint64_t free_blocks_count;
+
+ uint32_t block_size;
+ uint32_t block_group_count;
+ uint32_t blocks_per_group;
+ uint32_t inodes_per_group;
+
+ char volume_name[16];
+};
+
+int ext4_mount_point_stats(const char *mount_point,
+ struct ext4_mount_stats *stats);
+
+/********************************FILE OPERATIONS*****************************/
+
+/**@brief */
+int ext4_fremove(const char *path);
+
+/**@brief File open function.
+ * @param filename, (has to start from mountpoint)
+ * /my_partition/my_file
+ * @param flags open file flags
+ * |---------------------------------------------------------------|
+ * | r or rb O_RDONLY |
+ * |---------------------------------------------------------------|
+ * | w or wb O_WRONLY|O_CREAT|O_TRUNC |
+ * |---------------------------------------------------------------|
+ * | a or ab O_WRONLY|O_CREAT|O_APPEND |
+ * |---------------------------------------------------------------|
+ * | r+ or rb+ or r+b O_RDWR |
+ * |---------------------------------------------------------------|
+ * | w+ or wb+ or w+b O_RDWR|O_CREAT|O_TRUNC |
+ * |---------------------------------------------------------------|
+ * | a+ or ab+ or a+b O_RDWR|O_CREAT|O_APPEND |
+ * |---------------------------------------------------------------|
+ *
+ * @return standard error code*/
+int ext4_fopen (ext4_file *f, const char *path, const char *flags);
+
+/**@brief */
+int ext4_fclose(ext4_file *f);
+
+/**@brief */
+int ext4_fread (ext4_file *f, void *buf, uint32_t size, uint32_t *rcnt);
+
+/**@brief */
+int ext4_fwrite(ext4_file *f, void *buf, uint32_t size, uint32_t *wcnt);
+
+/**@brief */
+int ext4_fseek (ext4_file *f, uint64_t offset, uint32_t origin);
+
+/**@brief */
+uint64_t ext4_ftell (ext4_file *f);
+
+/**@brief */
+uint64_t ext4_fsize (ext4_file *f);
+
+/*********************************DIRECTORY OPERATION***********************/
+/**@brief */
+int ext4_mkdir(const char *path);
+
+/**@brief */
+int ext4_rmdir(const char *path);
+
+/**@brief */
+int ext4_dir_open (ext4_dir *d, const char *path);
+
+/**@brief */
+int ext4_dir_close(ext4_dir *d);
+
+/**@brief */
+ext4_direntry* ext4_entry_get(ext4_dir *d, uint32_t id);
+
+#endif /* EXT4_H_ */
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/lwext4/ext4.c
@@ -1,0 +1,1205 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4.h
+ * @brief Ext4 high level operations (file, directory, mountpoints...)
+ */
+
+#include <ext4_config.h>
+#include <ext4_blockdev.h>
+#include <ext4_types.h>
+#include <ext4_debug.h>
+#include <ext4_errno.h>
+#include <ext4_fs.h>
+#include <ext4_dir.h>
+#include <ext4_inode.h>
+#include <ext4_super.h>
+#include <ext4_dir_idx.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <ext4.h>
+
+/**@brief Mount point OS dependent lock*/
+#define EXT4_MP_LOCK(_m) \
+ do { (_m)->os_locks ? (_m)->os_locks->lock() : 0; }while(0)
+
+/**@brief Mount point OS dependent unlock*/
+#define EXT4_MP_UNLOCK(_m) \
+ do { (_m)->os_locks ? (_m)->os_locks->unlock() : 0; }while(0)
+
+/**@brief Mount point descrpitor.*/
+struct ext4_mountpoint {
+
+ /**@brief Mount point name (@ref ext4_mount)*/
+ const char *name;
+
+ /**@brief Os dependent lock/unlock functions.*/
+ struct ext4_lock *os_locks;
+
+ /**@brief Ext4 filesystem internals.*/
+ struct ext4_fs fs;
+
+ /**@brief Dynamic alocation cache flag.*/
+ bool cache_dynamic;
+};
+
+/**@brief Block devices descriptor.*/
+struct _ext4_devices {
+
+ /**@brief Block device name (@ref ext4_device_register)*/
+ const char *name;
+
+ /**@brief Block device handle.*/
+ struct ext4_blockdev *bd;
+
+ /**@brief Block cache handle.*/
+ struct ext4_bcache *bc;
+};
+
+/**@brief Block devices.*/
+struct _ext4_devices _bdevices[CONFIG_EXT4_BLOCKDEVS_COUNT];
+
+
+/**@brief Mountpoints.*/
+struct ext4_mountpoint _mp[CONFIG_EXT4_MOUNTPOINTS_COUNT];
+
+
+
+int ext4_device_register(struct ext4_blockdev *bd, struct ext4_bcache *bc,
+ const char *dev_name)
+{
+ uint32_t i;
+ ext4_assert(bd && dev_name);
+
+ for (i = 0; i < CONFIG_EXT4_BLOCKDEVS_COUNT; ++i) {
+ if(!_bdevices[i].name){
+ _bdevices[i].name = dev_name;
+ _bdevices[i].bd = bd;
+ _bdevices[i].bc = bc;
+ return EOK;
+ }
+ }
+ return ENOSPC;
+}
+
+/****************************************************************************/
+
+
+static bool ext4_is_dots(const uint8_t *name, size_t name_size)
+{
+ if ((name_size == 1) && (name[0] == '.'))
+ return true;
+
+ if ((name_size == 2) && (name[0] == '.') && (name[1] == '.'))
+ return true;
+
+ return false;
+}
+
+static int ext4_has_children(bool *has_children, struct ext4_inode_ref *enode)
+{
+
+ struct ext4_fs *fs = enode->fs;
+
+ /* Check if node is directory */
+ if (!ext4_inode_is_type(&fs->sb, enode->inode,
+ EXT4_INODE_MODE_DIRECTORY)) {
+ *has_children = false;
+ return EOK;
+ }
+
+ struct ext4_directory_iterator it;
+ int rc = ext4_dir_iterator_init(&it, enode, 0);
+ if (rc != EOK)
+ return rc;
+
+ /* Find a non-empty directory entry */
+ bool found = false;
+ while (it.current != NULL) {
+ if (it.current->inode != 0) {
+ uint16_t name_size =
+ ext4_dir_entry_ll_get_name_length(&fs->sb,
+ it.current);
+ if (!ext4_is_dots(it.current->name, name_size)) {
+ found = true;
+ break;
+ }
+ }
+
+ rc = ext4_dir_iterator_next(&it);
+ if (rc != EOK) {
+ ext4_dir_iterator_fini(&it);
+ return rc;
+ }
+ }
+
+ rc = ext4_dir_iterator_fini(&it);
+ if (rc != EOK)
+ return rc;
+
+ *has_children = found;
+
+ return EOK;
+}
+
+
+static int ext4_link(struct ext4_mountpoint *mp, struct ext4_inode_ref *parent,
+ struct ext4_inode_ref *child, const char *name, uint32_t name_len)
+{
+ /* Check maximum name length */
+ if(name_len > EXT4_DIRECTORY_FILENAME_LEN)
+ return EINVAL;
+
+ /* Add entry to parent directory */
+ int rc = ext4_dir_add_entry(parent, name, name_len,
+ child);
+ if (rc != EOK)
+ return rc;
+
+ /* Fill new dir -> add '.' and '..' entries */
+ if (ext4_inode_is_type(&mp->fs.sb, child->inode,
+ EXT4_INODE_MODE_DIRECTORY)) {
+ rc = ext4_dir_add_entry(child, ".", strlen("."),
+ child);
+ if (rc != EOK) {
+ ext4_dir_remove_entry(parent, name, strlen(name));
+ return rc;
+ }
+
+ rc = ext4_dir_add_entry(child, "..", strlen(".."),
+ parent);
+ if (rc != EOK) {
+ ext4_dir_remove_entry(parent, name, strlen(name));
+ ext4_dir_remove_entry(child, ".", strlen("."));
+ return rc;
+ }
+
+#if CONFIG_DIR_INDEX_ENABLE
+ /* Initialize directory index if supported */
+ if (ext4_sb_check_feature_compatible(&mp->fs.sb,
+ EXT4_FEATURE_COMPAT_DIR_INDEX)) {
+ rc = ext4_dir_dx_init(child);
+ if (rc != EOK)
+ return rc;
+
+ ext4_inode_set_flag(child->inode,
+ EXT4_INODE_FLAG_INDEX);
+ child->dirty = true;
+ }
+#endif
+
+ uint16_t parent_links =
+ ext4_inode_get_links_count(parent->inode);
+ parent_links++;
+ ext4_inode_set_links_count(parent->inode, parent_links);
+
+ parent->dirty = true;
+ }
+
+ uint16_t child_links =
+ ext4_inode_get_links_count(child->inode);
+ child_links++;
+ ext4_inode_set_links_count(child->inode, child_links);
+
+ child->dirty = true;
+
+ return EOK;
+}
+
+static int ext4_unlink(struct ext4_mountpoint *mp,
+ struct ext4_inode_ref *parent, struct ext4_inode_ref *child_inode_ref,
+ const char *name, uint32_t name_len)
+{
+ bool has_children;
+ int rc = ext4_has_children(&has_children, child_inode_ref);
+ if (rc != EOK)
+ return rc;
+
+ /* Cannot unlink non-empty node */
+ if (has_children)
+ return ENOTSUP;
+
+ /* Remove entry from parent directory */
+
+ rc = ext4_dir_remove_entry(parent, name, name_len);
+ if (rc != EOK)
+ return rc;
+
+
+ uint32_t lnk_count =
+ ext4_inode_get_links_count(child_inode_ref->inode);
+ lnk_count--;
+
+ bool is_dir = ext4_inode_is_type(&mp->fs.sb, child_inode_ref->inode,
+ EXT4_INODE_MODE_DIRECTORY);
+
+ /* If directory - handle links from parent */
+ if ((lnk_count <= 1) && (is_dir)) {
+ ext4_assert(lnk_count == 1);
+
+ lnk_count--;
+
+ uint32_t parent_lnk_count = ext4_inode_get_links_count(
+ parent->inode);
+
+ parent_lnk_count--;
+ ext4_inode_set_links_count(parent->inode, parent_lnk_count);
+
+ parent->dirty = true;
+ }
+
+ /*
+ * TODO: Update timestamps of the parent
+ * (when we have wall-clock time).
+ *
+ * ext4_inode_set_change_inode_time(parent->inode, (uint32_t) now);
+ * ext4_inode_set_modification_time(parent->inode, (uint32_t) now);
+ * parent->dirty = true;
+ */
+
+ /*
+ * TODO: Update timestamp for inode.
+ *
+ * ext4_inode_set_change_inode_time(child_inode_ref->inode,
+ * (uint32_t) now);
+ */
+
+ ext4_inode_set_deletion_time(child_inode_ref->inode, 1);
+ ext4_inode_set_links_count(child_inode_ref->inode, lnk_count);
+ child_inode_ref->dirty = true;
+
+ return EOK;
+}
+
+/****************************************************************************/
+
+int ext4_mount(const char * dev_name, char *mount_point)
+{
+ ext4_assert(mount_point && dev_name);
+ int r = EOK;
+ int i;
+
+ uint32_t bsize;
+ struct ext4_blockdev *bd = 0;
+ struct ext4_bcache *bc = 0;
+ struct ext4_mountpoint *mp = 0;
+
+ if(mount_point[strlen(mount_point) - 1] != '/')
+ return ENOTSUP;
+
+ for (i = 0; i < CONFIG_EXT4_BLOCKDEVS_COUNT; ++i) {
+ if(_bdevices[i].name){
+ if(!strcmp(dev_name, _bdevices[i].name)){
+ bd = _bdevices[i].bd;
+ bc = _bdevices[i].bc;
+ break;
+ }
+ }
+ }
+
+ if(!bd)
+ return ENODEV;
+
+ for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) {
+ if(!_mp[i].name){
+ _mp[i].name = mount_point;
+ mp = &_mp[i];
+ break;
+ }
+ }
+
+ if(!mp)
+ return ENOMEM;
+
+ r = ext4_block_init(bd);
+ if(r != EOK)
+ return r;
+
+ r = ext4_fs_init(&mp->fs, bd);
+ if(r != EOK){
+ ext4_block_fini(bd);
+ return r;
+ }
+
+ bsize = ext4_sb_get_block_size(&mp->fs.sb);
+ ext4_block_set_lb_size(bd, bsize);
+
+
+ mp->cache_dynamic = 0;
+
+ if(!bc){
+ /*Automatic block cache alloc.*/
+ mp->cache_dynamic = 1;
+ bc = malloc(sizeof(struct ext4_bcache));
+
+ r = ext4_bcache_init_dynamic(bc, 8, bsize);
+ if(r != EOK){
+ free(bc);
+ ext4_block_fini(bd);
+ return r;
+ }
+ }
+
+ if(bsize != bc->itemsize)
+ return ENOTSUP;
+
+
+ /*Bind block cache to block device*/
+ r = ext4_block_bind_bcache(bd, bc);
+ if(r != EOK){
+ ext4_block_fini(bd);
+ if(mp->cache_dynamic){
+ ext4_bcache_fini_dynamic(bc);
+ free(bc);
+ }
+ return r;
+ }
+
+ return r;
+}
+
+
+int ext4_umount(char *mount_point)
+{
+ int i;
+ int r = EOK;
+ struct ext4_mountpoint *mp = 0;
+
+ for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) {
+ if(_mp[i].name){
+ if(!strcmp(_mp[i].name, mount_point))
+ mp = &_mp[i];
+ break;
+ }
+ }
+
+ if(!mp)
+ return ENODEV;
+
+ r = ext4_fs_fini(&mp->fs);
+ if(r != EOK)
+ return r;
+
+ mp->name = 0;
+
+ if(mp->cache_dynamic){
+ ext4_bcache_fini_dynamic(mp->fs.bdev->bc);
+ free(mp->fs.bdev->bc);
+ }
+
+ return ext4_block_fini(mp->fs.bdev);
+}
+
+int ext4_mount_point_stats(const char *mount_point,
+ struct ext4_mount_stats *stats)
+{
+ uint32_t i;
+ struct ext4_mountpoint *mp = 0;
+
+ for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) {
+ if(_mp[i].name){
+ if(!strcmp(_mp[i].name, mount_point))
+ mp = &_mp[i];
+ break;
+ }
+ }
+
+ if(!mp)
+ return ENOENT;
+
+
+ EXT4_MP_LOCK(mp);
+ stats->inodes_count = ext4_get32(&mp->fs.sb, inodes_count);
+ stats->free_inodes_count = ext4_get32(&mp->fs.sb, free_inodes_count);
+ stats->blocks_count = ext4_sb_get_blocks_cnt(&mp->fs.sb);
+ stats->free_blocks_count = ext4_sb_get_free_blocks_cnt(&mp->fs.sb);
+ stats->block_size = ext4_sb_get_block_size(&mp->fs.sb);
+
+ stats->block_group_count = ext4_block_group_cnt(&mp->fs.sb);
+ stats->blocks_per_group = ext4_get32(&mp->fs.sb, blocks_per_group);
+ stats->inodes_per_group = ext4_get32(&mp->fs.sb, inodes_per_group);
+
+ memcpy(stats->volume_name, mp->fs.sb.volume_name, 16);
+ EXT4_MP_UNLOCK(mp);
+
+ return EOK;
+}
+
+/********************************FILE OPERATIONS*****************************/
+
+static struct ext4_mountpoint* ext4_get_mount(const char *path)
+{
+ int i;
+ for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) {
+ if(_mp[i].name){
+ if(!strncmp(_mp[i].name, path, strlen(_mp[i].name)))
+ return &_mp[i];
+ }
+ }
+ return 0;
+}
+
+
+static int ext4_path_check(const char *path, bool* is_goal)
+{
+ int i;
+
+ for (i = 0; i < EXT4_DIRECTORY_FILENAME_LEN; ++i) {
+
+ if(path[i] == '/'){
+ *is_goal = false;
+ return i;
+ }
+
+ if(path[i] == 0){
+ *is_goal = true;
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+
+static bool ext4_parse_flags(const char *flags, uint32_t *file_flags)
+{
+ if(!flags)
+ return false;
+
+ if(!strcmp(flags, "r") || !strcmp(flags, "rb")){
+ *file_flags = O_RDONLY;
+ return true;
+ }
+
+ if(!strcmp(flags, "w") || !strcmp(flags, "wb")){
+ *file_flags = O_WRONLY | O_CREAT | O_TRUNC;
+ return true;
+ }
+
+ if(!strcmp(flags, "a") || !strcmp(flags, "ab")){
+ *file_flags = O_WRONLY | O_CREAT | O_APPEND ;
+ return true;
+ }
+
+ if(!strcmp(flags, "r+") || !strcmp(flags, "rb+") || !strcmp(flags, "r+b")){
+ *file_flags = O_RDWR;
+ return true;
+ }
+
+ if(!strcmp(flags, "w+") || !strcmp(flags, "wb+") || !strcmp(flags, "w+b")){
+ *file_flags = O_RDWR | O_CREAT | O_TRUNC;
+ return true;
+ }
+
+ if(!strcmp(flags, "a+") || !strcmp(flags, "ab+") || !strcmp(flags, "a+b")){
+ *file_flags = O_RDWR | O_CREAT | O_APPEND;
+ return true;
+ }
+
+ return false;
+}
+
+/****************************************************************************/
+
+static int ext4_generic_open (ext4_file *f, const char *path,
+ const char *flags, bool file_expect)
+{
+ struct ext4_mountpoint *mp = ext4_get_mount(path);
+ struct ext4_directory_search_result result;
+ struct ext4_inode_ref ref;
+ bool is_goal = false;
+ uint8_t inode_type;
+ int r = ENOENT;
+ uint32_t next_inode;
+
+ f->mp = 0;
+
+ if(!mp)
+ return ENOENT;
+
+ if(ext4_parse_flags(flags, &f->flags) == false)
+ return EINVAL;
+
+ /*Skip mount point*/
+ path += strlen(mp->name);
+
+ EXT4_MP_LOCK(mp);
+
+ /*Load root*/
+ r = ext4_fs_get_inode_ref(&mp->fs, EXT4_INODE_ROOT_INDEX, &ref);
+
+ if(r != EOK)
+ return r;
+
+ int len = ext4_path_check(path, &is_goal);
+
+ /*If root open was request.*/
+ if(!len && is_goal)
+ goto IsGoal;
+
+ while(1){
+
+ len = ext4_path_check(path, &is_goal);
+
+ if(!len){
+ r = ENOENT;
+ break;
+ }
+
+ r = ext4_dir_find_entry(&result, &ref, path, len);
+ if(r != EOK){
+
+ if(r != ENOENT)
+ break;
+
+ if(!(f->flags & O_CREAT))
+ break;
+
+ /*O_CREAT allows to create new entry*/
+ struct ext4_inode_ref child_ref;
+ r = ext4_fs_alloc_inode(&mp->fs, &child_ref, !is_goal);
+ if(r != EOK)
+ break;
+
+ /*Destroy last result*/
+ ext4_dir_destroy_result(&ref, &result);
+
+ /*Link with root dir.*/
+ r = ext4_link(mp, &ref, &child_ref, path, len);
+ if(r != EOK){
+ /*Fali. Free new inode.*/
+ ext4_fs_free_inode(&child_ref);
+ /*We do not want to write new inode.
+ But block has to be released.*/
+ child_ref.dirty = false;
+ ext4_fs_put_inode_ref(&child_ref);
+ break;
+ }
+
+ ext4_fs_put_inode_ref(&child_ref);
+
+ continue;
+ }
+
+ next_inode = result.dentry->inode;
+ inode_type = ext4_dir_entry_ll_get_inode_type(&mp->fs.sb, result.dentry);
+
+ r = ext4_dir_destroy_result(&ref, &result);
+ if(r != EOK)
+ break;
+
+ /*If expected file error*/
+ if((inode_type == EXT4_DIRECTORY_FILETYPE_REG_FILE)
+ && !file_expect && is_goal){
+ r = ENOENT;
+ break;
+ }
+
+ /*If expected directory error*/
+ if((inode_type == EXT4_DIRECTORY_FILETYPE_DIR)
+ && file_expect && is_goal){
+ r = ENOENT;
+ break;
+ }
+
+ r = ext4_fs_put_inode_ref(&ref);
+ if(r != EOK)
+ break;
+
+ r = ext4_fs_get_inode_ref(&mp->fs, next_inode, &ref);
+ if(r != EOK)
+ break;
+
+ if(is_goal)
+ break;
+
+ path += len + 1;
+ };
+
+ if(r != EOK){
+ ext4_fs_put_inode_ref(&ref);
+ EXT4_MP_UNLOCK(mp);
+ return r;
+ }
+
+ IsGoal:
+ if(is_goal){
+
+ if(f->flags & O_TRUNC){
+ /*Turncate.*/
+ ext4_block_delay_cache_flush(mp->fs.bdev, 1);
+ /*Truncate may be IO heavy.
+ Do it with delayed cache flush mode.*/
+ r = ext4_fs_truncate_inode(&ref, 0);
+ ext4_block_delay_cache_flush(mp->fs.bdev, 0);
+
+ if(r != EOK){
+ ext4_fs_put_inode_ref(&ref);
+ EXT4_MP_UNLOCK(mp);
+ return r;
+ }
+ }
+
+ f->mp = mp;
+ f->fsize = ext4_inode_get_size(&f->mp->fs.sb, ref.inode);
+ f->inode = ref.index;
+ f->fpos = 0;
+
+ if(f->flags & O_APPEND)
+ f->fpos = f->fsize;
+
+ }
+
+ r = ext4_fs_put_inode_ref(&ref);
+ EXT4_MP_UNLOCK(mp);
+ return r;
+}
+
+/****************************************************************************/
+
+int ext4_fremove(const char *path)
+{
+ struct ext4_mountpoint *mp = ext4_get_mount(path);
+ struct ext4_directory_search_result result;
+ bool is_goal = false;
+ uint8_t inode_type;
+ int r = ENOENT;
+ uint32_t next_inode;
+
+ struct ext4_inode_ref parent;
+ struct ext4_inode_ref child;
+ int len = 0;
+
+ if(!mp)
+ return ENOENT;
+
+
+ /*Skip mount point*/
+ path += strlen(mp->name);
+
+ /*Lock mountpoint*/
+ EXT4_MP_LOCK(mp);
+
+ /*Load root*/
+ r = ext4_fs_get_inode_ref(&mp->fs, EXT4_INODE_ROOT_INDEX, &parent);
+
+ if(r != EOK){
+ EXT4_MP_UNLOCK(mp);
+ return r;
+ }
+
+ while(1){
+
+ len = ext4_path_check(path, &is_goal);
+
+ if(!len){
+ r = ENOENT;
+ break;
+ }
+
+ r = ext4_dir_find_entry(&result, &parent, path, len);
+ if(r != EOK){
+ ext4_dir_destroy_result(&parent, &result);
+ break;
+ }
+
+ next_inode = result.dentry->inode;
+ inode_type = ext4_dir_entry_ll_get_inode_type(&mp->fs.sb,
+ result.dentry);
+
+ r = ext4_dir_destroy_result(&parent, &result);
+ if(r != EOK)
+ break;
+
+ /*If expected file error*/
+ if((inode_type == EXT4_DIRECTORY_FILETYPE_REG_FILE) && !is_goal){
+ r = ENOENT;
+ break;
+ }
+
+ /*If expected directory error*/
+ if((inode_type == EXT4_DIRECTORY_FILETYPE_DIR) && is_goal){
+ r = ENOENT;
+ break;
+ }
+
+ if(is_goal)
+ break;
+
+ r = ext4_fs_put_inode_ref(&parent);
+ if(r != EOK)
+ break;
+
+
+ r = ext4_fs_get_inode_ref(&mp->fs, next_inode, &parent);
+ if(r != EOK)
+ break;
+
+ path += len + 1;
+ };
+
+ if(r != EOK){
+ /*No entry or other error.*/
+ ext4_fs_put_inode_ref(&parent);
+ EXT4_MP_UNLOCK(mp);
+ return r;
+ }
+
+
+ /*We have file to delete. Load it.*/
+ r = ext4_fs_get_inode_ref(&mp->fs, next_inode, &child);
+ if(r != EOK){
+ /*Parent free*/
+ ext4_fs_put_inode_ref(&parent);
+ EXT4_MP_UNLOCK(mp);
+ return r;
+ }
+
+ /*Turncate.*/
+ ext4_block_delay_cache_flush(mp->fs.bdev, 1);
+
+ /*Truncate may be IO heavy. Do it with delayed cache flush mode.*/
+ r = ext4_fs_truncate_inode(&child, 0);
+
+ ext4_block_delay_cache_flush(mp->fs.bdev, 0);
+ if(r != EOK)
+ goto Finish;
+
+ /*Unlink from parent.*/
+ r = ext4_unlink(mp, &parent, &child, path, len);
+ if(r != EOK)
+ goto Finish;
+
+ r = ext4_fs_free_inode(&child);
+ if(r != EOK)
+ goto Finish;
+
+
+ Finish:
+ ext4_fs_put_inode_ref(&child);
+ ext4_fs_put_inode_ref(&parent);
+ EXT4_MP_UNLOCK(mp);
+ return r;
+}
+
+
+int ext4_fopen (ext4_file *f, const char *path, const char *flags)
+{
+ return ext4_generic_open(f, path, flags, true);
+}
+
+int ext4_fclose(ext4_file *f)
+{
+ ext4_assert(f && f->mp);
+
+ f->mp = 0;
+ f->flags = 0;
+ f->inode = 0;
+ f->fpos = f->fsize = 0;
+
+ return EOK;
+}
+int ext4_fread (ext4_file *f, void *buf, uint32_t size, uint32_t *rcnt)
+{
+ int r = EOK;
+ uint32_t u;
+ uint32_t fblock;
+ struct ext4_block b;
+ uint8_t *u8_buf = buf;
+ struct ext4_inode_ref ref;
+ uint32_t sblock;
+ uint32_t block_size;
+
+ ext4_assert(f && f->mp);
+
+ if(f->flags & O_WRONLY)
+ return EPERM;
+
+ if(!size)
+ return EOK;
+
+ EXT4_MP_LOCK(f->mp);
+
+ if(rcnt)
+ *rcnt = 0;
+
+ r = ext4_fs_get_inode_ref(&f->mp->fs, f->inode, &ref);
+ if(r != EOK){
+ EXT4_MP_UNLOCK(f->mp);
+ return r;
+ }
+
+ /*Sync file size*/
+ f->fsize = ext4_inode_get_size(&f->mp->fs.sb, ref.inode);
+
+
+ block_size = ext4_sb_get_block_size(&f->mp->fs.sb);
+ size = size > (f->fsize - f->fpos) ? (f->fsize - f->fpos) : size;
+
+ sblock = (f->fpos) / block_size;
+
+ u = (f->fpos) % block_size;
+
+
+ if(u){
+
+ uint32_t ll = size > (block_size - u) ? (block_size - u) : size;
+
+ r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
+ if(r != EOK)
+ goto Finish;
+
+ r = ext4_block_get(f->mp->fs.bdev, &b, fblock);
+ if(r != EOK)
+ goto Finish;
+
+ memcpy(u8_buf, b.data + u, ll);
+
+ r = ext4_block_set(f->mp->fs.bdev, &b);
+ if(r != EOK)
+ goto Finish;
+
+ u8_buf += ll;
+ size -= ll;
+ f->fpos += ll;
+
+ if(rcnt)
+ *rcnt += ll;
+
+ sblock++;
+ }
+
+ while(size >= block_size){
+
+ r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
+ if(r != EOK)
+ goto Finish;
+
+ r = ext4_block_get_direct(f->mp->fs.bdev, u8_buf, fblock);
+ if(r != EOK)
+ goto Finish;
+
+
+ u8_buf += block_size;
+ size -= block_size;
+ f->fpos += block_size;
+
+ if(rcnt)
+ *rcnt += block_size;
+
+ sblock++;
+ }
+
+ if(size){
+ r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
+ if(r != EOK)
+ goto Finish;
+
+ r = ext4_block_get(f->mp->fs.bdev, &b, fblock);
+ if(r != EOK)
+ goto Finish;
+
+ memcpy(u8_buf, b.data , size);
+
+ r = ext4_block_set(f->mp->fs.bdev, &b);
+ if(r != EOK)
+ goto Finish;
+
+ f->fpos += size;
+
+ if(rcnt)
+ *rcnt += size;
+ }
+
+ Finish:
+ ext4_fs_put_inode_ref(&ref);
+ EXT4_MP_UNLOCK(f->mp);
+ return r;
+}
+
+int ext4_fwrite(ext4_file *f, void *buf, uint32_t size, uint32_t *wcnt)
+{
+ int r = EOK;
+ uint32_t u;
+ uint32_t fblock;
+ struct ext4_block b;
+ uint8_t *u8_buf = buf;
+ struct ext4_inode_ref ref;
+ uint32_t sblock;
+ uint32_t file_blocks;
+ uint32_t block_size;
+
+ ext4_assert(f && f->mp);
+
+ if(f->flags & O_RDONLY)
+ return EPERM;
+
+ if(!size)
+ return EOK;
+
+ EXT4_MP_LOCK(f->mp);
+
+ if(wcnt)
+ *wcnt = 0;
+
+ r = ext4_fs_get_inode_ref(&f->mp->fs, f->inode, &ref);
+ if(r != EOK){
+ EXT4_MP_UNLOCK(f->mp);
+ return r;
+ }
+
+ /*Sync file size*/
+ f->fsize = ext4_inode_get_size(&f->mp->fs.sb, ref.inode);
+
+ block_size = ext4_sb_get_block_size(&f->mp->fs.sb);
+
+ file_blocks = (f->fsize / block_size);
+
+ if(f->fsize % block_size)
+ file_blocks++;
+
+ sblock = (f->fpos) / block_size;
+
+ u = (f->fpos) % block_size;
+
+
+ if(u){
+ uint32_t ll = size > (block_size - u) ? (block_size - u) : size;
+
+ r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
+ if(r != EOK)
+ goto Finish;
+
+ r = ext4_block_get(f->mp->fs.bdev, &b, fblock);
+ if(r != EOK)
+ goto Finish;
+
+ memcpy(b.data + u, u8_buf, ll);
+ b.dirty = true;
+
+ r = ext4_block_set(f->mp->fs.bdev, &b);
+ if(r != EOK)
+ goto Finish;
+
+ u8_buf += ll;
+ size -= ll;
+ f->fpos += ll;
+
+ if(wcnt)
+ *wcnt += ll;
+
+ sblock++;
+ }
+
+
+ /*Start delay cache flush mode.*/
+ r = ext4_block_delay_cache_flush(f->mp->fs.bdev, 1);
+ if(r != EOK)
+ goto Finish;
+
+ while(size >= block_size){
+
+ if(sblock < file_blocks){
+ r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
+ if(r != EOK)
+ break;
+ }
+ else {
+ r = ext4_fs_append_inode_block(&ref, &fblock, &sblock);
+ if(r != EOK)
+ break;
+ }
+
+ r = ext4_block_set_direct(f->mp->fs.bdev, u8_buf, fblock);
+ if(r != EOK)
+ break;
+
+ u8_buf += block_size;
+ size -= block_size;
+ f->fpos += block_size;
+
+ if(wcnt)
+ *wcnt += block_size;
+
+ sblock++;
+ }
+
+ /*Stop delay cache flush mode*/
+ ext4_block_delay_cache_flush(f->mp->fs.bdev, 0);
+
+ if(r != EOK)
+ goto Finish;
+
+ if(size){
+ if(sblock < file_blocks){
+ r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
+ if(r != EOK)
+ goto Finish;
+ }
+ else {
+ r = ext4_fs_append_inode_block(&ref, &fblock, &sblock);
+ if(r != EOK)
+ goto Finish;
+ }
+
+ r = ext4_block_get(f->mp->fs.bdev, &b, fblock);
+ if(r != EOK)
+ goto Finish;
+
+ memcpy(b.data, u8_buf , size);
+ b.dirty = true;
+
+ r = ext4_block_set(f->mp->fs.bdev, &b);
+ if(r != EOK)
+ goto Finish;
+
+ f->fpos += size;
+
+ if(wcnt)
+ *wcnt += size;
+ }
+
+ if(f->fpos > f->fsize){
+ f->fsize = f->fpos;
+ ext4_inode_set_size(ref.inode, f->fsize);
+ ref.dirty = true;
+ }
+
+ Finish:
+ ext4_fs_put_inode_ref(&ref);
+ EXT4_MP_UNLOCK(f->mp);
+ return r;
+
+}
+
+
+
+int ext4_fseek (ext4_file *f, uint64_t offset, uint32_t origin)
+{
+ switch(origin){
+ case SEEK_SET:
+
+ if(offset > f->fsize)
+ return EINVAL;
+
+ f->fpos = offset;
+ return EOK;
+ case SEEK_CUR:
+ if((offset + f->fpos) > f->fsize)
+ return EINVAL;
+
+ f->fpos += offset;
+ return EOK;
+ case SEEK_END:
+ if(offset > f->fsize)
+ return EINVAL;
+ f->fpos = f->fsize - offset;
+ return EOK;
+
+ }
+
+ return EINVAL;
+}
+
+uint64_t ext4_ftell (ext4_file *f)
+{
+ return f->fpos;
+}
+
+uint64_t ext4_fsize (ext4_file *f)
+{
+ return f->fsize;
+}
+
+/*********************************DIRECTORY OPERATION************************/
+
+int ext4_dir_open (ext4_dir *d, const char *path)
+{
+ return ext4_generic_open(&d->f, path, "r", false);
+}
+
+int ext4_dir_close(ext4_dir *d)
+{
+ return ext4_fclose(&d->f);
+}
+
+ext4_direntry* ext4_entry_get(ext4_dir *d, uint32_t id)
+{
+ int r;
+ uint32_t i;
+ ext4_direntry *de = 0;
+ struct ext4_inode_ref dir;
+ struct ext4_directory_iterator it;
+
+ EXT4_MP_LOCK(d->f.mp);
+
+ r = ext4_fs_get_inode_ref(&d->f.mp->fs, d->f.inode, &dir);
+ if(r != EOK){
+ goto Finish;
+ }
+
+ r = ext4_dir_iterator_init(&it, &dir, 0);
+ if(r != EOK){
+ ext4_fs_put_inode_ref(&dir);
+ goto Finish;
+ }
+
+ i = 0;
+ while(r == EOK){
+
+ if(!it.current)
+ break;
+
+ if(i == id){
+ memcpy(&d->de, it.current, sizeof(ext4_direntry));
+ de = &d->de;
+ break;
+ }
+
+
+ i++;
+ r = ext4_dir_iterator_next(&it);
+ }
+
+ ext4_dir_iterator_fini(&it);
+ ext4_fs_put_inode_ref(&dir);
+
+ Finish:
+ EXT4_MP_UNLOCK(d->f.mp);
+ return de;
+}
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/lwext4/ext4_balloc.c
@@ -1,0 +1,609 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_balloc.c
+ * @brief Physical block allocator.
+ */
+
+#include <ext4_config.h>
+#include <ext4_balloc.h>
+#include <ext4_super.h>
+#include <ext4_block_group.h>
+#include <ext4_fs.h>
+#include <ext4_bitmap.h>
+#include <ext4_inode.h>
+
+
+
+static uint32_t ext4_balloc_get_bgid_of_block(struct ext4_sblock *s,
+ uint32_t baddr)
+{
+ if(ext4_get32(s, first_data_block))
+ baddr--;
+
+ return baddr / ext4_get32(s, blocks_per_group);
+}
+
+
+uint32_t ext4_balloc_get_first_data_block_in_group(struct ext4_sblock *s,
+ struct ext4_block_group_ref * bg_ref)
+{
+ uint32_t block_group_count = ext4_block_group_cnt(s);
+ uint32_t inode_table_first_block =
+ ext4_bg_get_inode_table_first_block(bg_ref->block_group, s);
+ uint32_t block_size = ext4_sb_get_block_size(s);
+
+ uint16_t inode_size = ext4_get16(s, inode_size);
+ uint32_t inodes_per_group = ext4_get32(s, inodes_per_group);
+
+ uint32_t inode_table_bytes;
+
+
+ if (bg_ref->index < block_group_count - 1) {
+ inode_table_bytes = inodes_per_group * inode_size;
+ } else {
+ /* Last block group could be smaller */
+ uint32_t inodes_count_total = ext4_get32(s, inodes_count);
+ inode_table_bytes =
+ (inodes_count_total - ((block_group_count - 1) *
+ inodes_per_group)) * inode_size;
+ }
+
+ uint32_t inode_table_blocks = inode_table_bytes / block_size;
+
+ if (inode_table_bytes % block_size)
+ inode_table_blocks++;
+
+ return inode_table_first_block + inode_table_blocks;
+}
+
+int ext4_balloc_free_block(struct ext4_inode_ref *inode_ref, uint32_t baddr)
+{
+ struct ext4_fs *fs = inode_ref->fs;
+ struct ext4_sblock *sb = &fs->sb;
+
+
+ uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, baddr);
+ uint32_t index_in_group = ext4_fs_baddr2_index_in_group(sb, baddr);
+
+ /* Load block group reference */
+ struct ext4_block_group_ref bg_ref;
+ int rc = ext4_fs_get_block_group_ref(fs, block_group, &bg_ref);
+ if (rc != EOK)
+ return rc;
+
+ /* Load block with bitmap */
+ uint32_t bitmap_block_addr =
+ ext4_bg_get_block_bitmap(bg_ref.block_group, sb);
+
+ struct ext4_block bitmap_block;
+
+ rc = ext4_block_get(fs->bdev, &bitmap_block, bitmap_block_addr);
+ if (rc != EOK)
+ return rc;
+
+ /* Modify bitmap */
+ ext4_bmap_bit_clr(bitmap_block.data, index_in_group);
+ bitmap_block.dirty = true;
+
+ /* Release block with bitmap */
+ rc = ext4_block_set(fs->bdev, &bitmap_block);
+ if (rc != EOK) {
+ /* Error in saving bitmap */
+ ext4_fs_put_block_group_ref(&bg_ref);
+ return rc;
+ }
+
+ uint32_t block_size = ext4_sb_get_block_size(sb);
+
+ /* Update superblock free blocks count */
+ uint64_t sb_free_blocks =
+ ext4_sb_get_free_blocks_cnt(sb);
+ sb_free_blocks++;
+ ext4_sb_set_free_blocks_cnt(sb, sb_free_blocks);
+
+ /* Update inode blocks count */
+ uint64_t ino_blocks =
+ ext4_inode_get_blocks_count(sb, inode_ref->inode);
+ ino_blocks -= block_size / EXT4_INODE_BLOCK_SIZE;
+ ext4_inode_set_blocks_count(sb, inode_ref->inode, ino_blocks);
+ inode_ref->dirty = true;
+
+ /* Update block group free blocks count */
+ uint32_t free_blocks =
+ ext4_bg_get_free_blocks_count(bg_ref.block_group, sb);
+ free_blocks++;
+ ext4_bg_set_free_blocks_count(bg_ref.block_group,
+ sb, free_blocks);
+
+ bg_ref.dirty = true;
+
+ /* Release block group reference */
+ rc = ext4_fs_put_block_group_ref(&bg_ref);
+ if (rc != EOK)
+ return rc;
+
+ return EOK;
+}
+
+int ext4_balloc_free_blocks(struct ext4_inode_ref *inode_ref, uint32_t first,
+ uint32_t count)
+{
+ struct ext4_fs *fs = inode_ref->fs;
+ struct ext4_sblock *sb = &fs->sb;
+
+ /* Compute indexes */
+ uint32_t block_group_first =
+ ext4_balloc_get_bgid_of_block(sb, first);
+ uint32_t block_group_last =
+ ext4_balloc_get_bgid_of_block(sb, first + count - 1);
+
+ ext4_assert(block_group_first == block_group_last);
+
+ /* Load block group reference */
+ struct ext4_block_group_ref bg_ref;
+ int rc = ext4_fs_get_block_group_ref(fs, block_group_first, &bg_ref);
+ if (rc != EOK)
+ return rc;
+
+ uint32_t index_in_group_first =
+ ext4_fs_baddr2_index_in_group(sb, first);
+
+ /* Load block with bitmap */
+ uint32_t bitmap_block_addr =
+ ext4_bg_get_block_bitmap(bg_ref.block_group, sb);
+
+ struct ext4_block bitmap_block;
+
+ rc = ext4_block_get(fs->bdev, &bitmap_block, bitmap_block_addr);
+ if (rc != EOK)
+ return rc;
+
+ /* Modify bitmap */
+ ext4_bmap_bits_free(bitmap_block.data, index_in_group_first, count);
+ bitmap_block.dirty = true;
+
+ /* Release block with bitmap */
+ rc = ext4_block_set(fs->bdev, &bitmap_block);
+ if (rc != EOK) {
+ ext4_fs_put_block_group_ref(&bg_ref);
+ return rc;
+ }
+
+ uint32_t block_size = ext4_sb_get_block_size(sb);
+
+ /* Update superblock free blocks count */
+ uint64_t sb_free_blocks =
+ ext4_sb_get_free_blocks_cnt(sb);
+ sb_free_blocks += count;
+ ext4_sb_set_free_blocks_cnt(sb, sb_free_blocks);
+
+ /* Update inode blocks count */
+ uint64_t ino_blocks =
+ ext4_inode_get_blocks_count(sb, inode_ref->inode);
+ ino_blocks -= count * (block_size / EXT4_INODE_BLOCK_SIZE);
+ ext4_inode_set_blocks_count(sb, inode_ref->inode, ino_blocks);
+ inode_ref->dirty = true;
+
+ /* Update block group free blocks count */
+ uint32_t free_blocks =
+ ext4_bg_get_free_blocks_count(bg_ref.block_group, sb);
+ free_blocks += count;
+ ext4_bg_set_free_blocks_count(bg_ref.block_group,
+ sb, free_blocks);
+ bg_ref.dirty = true;
+
+ /* Release block group reference */
+ rc = ext4_fs_put_block_group_ref(&bg_ref);
+ if (rc != EOK)
+ return rc;
+
+ return EOK;
+}
+
+static uint32_t ext4_balloc_find_goal(struct ext4_inode_ref *inode_ref)
+{
+ uint32_t goal = 0;
+
+ struct ext4_sblock *sb = &inode_ref->fs->sb;
+
+ uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
+ uint32_t block_size = ext4_sb_get_block_size(sb);
+ uint32_t inode_block_count = inode_size / block_size;
+
+ if (inode_size % block_size != 0)
+ inode_block_count++;
+
+ /* If inode has some blocks, get last block address + 1 */
+ if (inode_block_count > 0) {
+ int rc = ext4_fs_get_inode_data_block_index(inode_ref,
+ inode_block_count - 1, &goal);
+ if (rc != EOK)
+ return 0;
+
+ if (goal != 0) {
+ goal++;
+ return goal;
+ }
+
+ /* If goal == 0, sparse file -> continue */
+ }
+
+ /* Identify block group of inode */
+
+ uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
+ uint32_t block_group = (inode_ref->index - 1) / inodes_per_group;
+ block_size = ext4_sb_get_block_size(sb);
+
+ /* Load block group reference */
+ struct ext4_block_group_ref bg_ref;
+ int rc = ext4_fs_get_block_group_ref(inode_ref->fs,
+ block_group, &bg_ref);
+ if (rc != EOK)
+ return 0;
+
+ /* Compute indexes */
+ uint32_t block_group_count = ext4_block_group_cnt(sb);
+ uint32_t inode_table_first_block =
+ ext4_bg_get_inode_table_first_block(bg_ref.block_group, sb);
+ uint16_t inode_table_item_size = ext4_get16(sb, inode_size);
+ uint32_t inode_table_bytes;
+
+ /* Check for last block group */
+ if (block_group < block_group_count - 1) {
+ inode_table_bytes = inodes_per_group * inode_table_item_size;
+ } else {
+ /* Last block group could be smaller */
+ uint32_t inodes_count_total = ext4_get32(sb, inodes_count);
+
+ inode_table_bytes =
+ (inodes_count_total - ((block_group_count - 1) *
+ inodes_per_group)) * inode_table_item_size;
+ }
+
+ uint32_t inode_table_blocks = inode_table_bytes / block_size;
+
+ if (inode_table_bytes % block_size)
+ inode_table_blocks++;
+
+ goal = inode_table_first_block + inode_table_blocks;
+
+ ext4_fs_put_block_group_ref(&bg_ref);
+
+ return goal;
+}
+
+
+int ext4_balloc_alloc_block(struct ext4_inode_ref *inode_ref,
+ uint32_t *fblock)
+{
+ uint32_t allocated_block = 0;
+ uint32_t bitmap_block_addr;
+ uint32_t rel_block_idx = 0;
+
+ struct ext4_block bitmap_block;
+
+ /* Find GOAL */
+ uint32_t goal = ext4_balloc_find_goal(inode_ref);
+ if (goal == 0) {
+ /* no goal found => partition is full */
+ return ENOSPC;
+ }
+
+ struct ext4_sblock *sb = &inode_ref->fs->sb;
+
+ /* Load block group number for goal and relative index */
+ uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, goal);
+ uint32_t index_in_group =
+ ext4_fs_baddr2_index_in_group(sb, goal);
+
+ /* Load block group reference */
+ struct ext4_block_group_ref bg_ref;
+ int rc = ext4_fs_get_block_group_ref(inode_ref->fs,
+ block_group, &bg_ref);
+ if (rc != EOK)
+ return rc;
+
+ /* Compute indexes */
+ uint32_t first_in_group =
+ ext4_balloc_get_first_data_block_in_group(sb, &bg_ref);
+
+ uint32_t first_in_group_index =
+ ext4_fs_baddr2_index_in_group(sb, first_in_group);
+
+ if (index_in_group < first_in_group_index)
+ index_in_group = first_in_group_index;
+
+ /* Load block with bitmap */
+ bitmap_block_addr =
+ ext4_bg_get_block_bitmap(bg_ref.block_group, sb);
+
+ rc = ext4_block_get(inode_ref->fs->bdev, &bitmap_block,
+ bitmap_block_addr);
+ if (rc != EOK) {
+ ext4_fs_put_block_group_ref(&bg_ref);
+ return rc;
+ }
+
+ /* Check if goal is free */
+ if (ext4_bmap_is_bit_clr(bitmap_block.data, index_in_group)) {
+ ext4_bmap_bit_set(bitmap_block.data, index_in_group);
+ bitmap_block.dirty = true;
+ rc = ext4_block_set(inode_ref->fs->bdev, &bitmap_block);
+ if (rc != EOK) {
+ ext4_fs_put_block_group_ref(&bg_ref);
+ return rc;
+ }
+
+ allocated_block =
+ ext4_fs_index_in_group2_baddr(sb, index_in_group,
+ block_group);
+
+ goto success;
+ }
+
+ uint32_t blocks_in_group =
+ ext4_blocks_in_group_cnt(sb, block_group);
+
+ uint32_t end_idx = (index_in_group + 63) & ~63;
+ if (end_idx > blocks_in_group)
+ end_idx = blocks_in_group;
+
+ /* Try to find free block near to goal */
+ uint32_t tmp_idx;
+ for (tmp_idx = index_in_group + 1; tmp_idx < end_idx;
+ ++tmp_idx) {
+ if (ext4_bmap_is_bit_clr(bitmap_block.data, tmp_idx)) {
+ ext4_bmap_bit_set(bitmap_block.data, tmp_idx);
+
+ bitmap_block.dirty = true;
+ rc = ext4_block_set(inode_ref->fs->bdev, &bitmap_block);
+ if (rc != EOK)
+ return rc;
+
+ allocated_block =
+ ext4_fs_index_in_group2_baddr(sb, tmp_idx,
+ block_group);
+
+ goto success;
+ }
+ }
+
+
+
+ /* Find free bit in bitmap */
+ rc = ext4_bmap_bit_find_clr(bitmap_block.data,
+ index_in_group, blocks_in_group, &rel_block_idx);
+ if (rc == EOK) {
+ ext4_bmap_bit_set(bitmap_block.data, rel_block_idx);
+ bitmap_block.dirty = true;
+ rc = ext4_block_set(inode_ref->fs->bdev, &bitmap_block);
+ if (rc != EOK)
+ return rc;
+
+ allocated_block =
+ ext4_fs_index_in_group2_baddr(sb, rel_block_idx,
+ block_group);
+
+ goto success;
+ }
+
+ /* No free block found yet */
+ ext4_block_set(inode_ref->fs->bdev, &bitmap_block);
+ ext4_fs_put_block_group_ref(&bg_ref);
+
+ /* Try other block groups */
+ uint32_t block_group_count = ext4_block_group_cnt(sb);
+
+ uint32_t bgid = (block_group + 1) % block_group_count;
+ uint32_t count = block_group_count;
+
+ while (count > 0) {
+ rc = ext4_fs_get_block_group_ref(inode_ref->fs, bgid,
+ &bg_ref);
+ if (rc != EOK)
+ return rc;
+
+ /* Load block with bitmap */
+ bitmap_block_addr =
+ ext4_bg_get_block_bitmap(bg_ref.block_group, sb);
+
+ rc = ext4_block_get(inode_ref->fs->bdev, &bitmap_block,
+ bitmap_block_addr);
+
+ if (rc != EOK) {
+ ext4_fs_put_block_group_ref(&bg_ref);
+ return rc;
+ }
+
+ /* Compute indexes */
+ first_in_group =
+ ext4_balloc_get_first_data_block_in_group(sb, &bg_ref);
+ index_in_group =
+ ext4_fs_baddr2_index_in_group(sb, first_in_group);
+ blocks_in_group = ext4_blocks_in_group_cnt(sb, bgid);
+
+ first_in_group_index =
+ ext4_fs_baddr2_index_in_group(sb, first_in_group);
+
+ if (index_in_group < first_in_group_index)
+ index_in_group = first_in_group_index;
+
+
+ rc = ext4_bmap_bit_find_clr(bitmap_block.data,
+ index_in_group, blocks_in_group, &rel_block_idx);
+
+ if (rc == EOK) {
+
+ ext4_bmap_bit_set(bitmap_block.data, rel_block_idx);
+
+ bitmap_block.dirty = true;
+ rc = ext4_block_set(inode_ref->fs->bdev, &bitmap_block);
+ if (rc != EOK)
+ return rc;
+
+ allocated_block =
+ ext4_fs_index_in_group2_baddr(sb, rel_block_idx,
+ bgid);
+
+ goto success;
+ }
+
+ ext4_block_set(inode_ref->fs->bdev, &bitmap_block);
+ ext4_fs_put_block_group_ref(&bg_ref);
+
+ /* Goto next group */
+ bgid = (bgid + 1) % block_group_count;
+ count--;
+ }
+
+ return ENOSPC;
+
+ success:
+ /* Empty command - because of syntax */
+ ;
+
+ uint32_t block_size = ext4_sb_get_block_size(sb);
+
+ /* Update superblock free blocks count */
+ uint64_t sb_free_blocks = ext4_sb_get_free_blocks_cnt(sb);
+ sb_free_blocks--;
+ ext4_sb_set_free_blocks_cnt(sb, sb_free_blocks);
+
+ /* Update inode blocks (different block size!) count */
+ uint64_t ino_blocks =
+ ext4_inode_get_blocks_count(sb, inode_ref->inode);
+ ino_blocks += block_size / EXT4_INODE_BLOCK_SIZE;
+ ext4_inode_set_blocks_count(sb, inode_ref->inode, ino_blocks);
+ inode_ref->dirty = true;
+
+ /* Update block group free blocks count */
+ uint32_t bg_free_blocks =
+ ext4_bg_get_free_blocks_count(bg_ref.block_group, sb);
+ bg_free_blocks--;
+ ext4_bg_set_free_blocks_count(bg_ref.block_group, sb,
+ bg_free_blocks);
+
+ bg_ref.dirty = true;
+
+ ext4_fs_put_block_group_ref(&bg_ref);
+
+ *fblock = allocated_block;
+ return EOK;
+}
+
+int ext4_balloc_try_alloc_block(struct ext4_inode_ref *inode_ref,
+ uint32_t baddr, bool *free)
+{
+ int rc = EOK;
+
+ struct ext4_fs *fs = inode_ref->fs;
+ struct ext4_sblock *sb = &fs->sb;
+
+ /* Compute indexes */
+ uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, baddr);
+ uint32_t index_in_group =
+ ext4_fs_baddr2_index_in_group(sb, baddr);
+
+ /* Load block group reference */
+ struct ext4_block_group_ref bg_ref;
+ rc = ext4_fs_get_block_group_ref(fs, block_group, &bg_ref);
+ if (rc != EOK)
+ return rc;
+
+ /* Load block with bitmap */
+ uint32_t bitmap_block_addr =
+ ext4_bg_get_block_bitmap(bg_ref.block_group, sb);
+
+
+ struct ext4_block bitmap_block;
+
+ rc = ext4_block_get(fs->bdev, &bitmap_block, bitmap_block_addr);
+ if (rc != EOK)
+ return rc;
+
+ /* Check if block is free */
+ *free = ext4_bmap_is_bit_clr(bitmap_block.data, index_in_group);
+
+ /* Allocate block if possible */
+ if (*free) {
+ ext4_bmap_bit_set(bitmap_block.data, index_in_group);
+ bitmap_block.dirty = true;
+ }
+
+ /* Release block with bitmap */
+ rc = ext4_block_set(fs->bdev, &bitmap_block);
+ if (rc != EOK) {
+ /* Error in saving bitmap */
+ ext4_fs_put_block_group_ref(&bg_ref);
+ return rc;
+ }
+
+ /* If block is not free, return */
+ if (!(*free))
+ goto terminate;
+
+ uint32_t block_size = ext4_sb_get_block_size(sb);
+
+ /* Update superblock free blocks count */
+ uint64_t sb_free_blocks = ext4_sb_get_free_blocks_cnt(sb);
+ sb_free_blocks--;
+ ext4_sb_set_free_blocks_cnt(sb, sb_free_blocks);
+
+ /* Update inode blocks count */
+ uint64_t ino_blocks =
+ ext4_inode_get_blocks_count(sb, inode_ref->inode);
+ ino_blocks += block_size / EXT4_INODE_BLOCK_SIZE;
+ ext4_inode_set_blocks_count(sb, inode_ref->inode, ino_blocks);
+ inode_ref->dirty = true;
+
+ /* Update block group free blocks count */
+ uint32_t free_blocks =
+ ext4_bg_get_free_blocks_count(bg_ref.block_group, sb);
+ free_blocks--;
+ ext4_bg_set_free_blocks_count(bg_ref.block_group,
+ sb, free_blocks);
+
+ bg_ref.dirty = true;
+
+ terminate:
+ return ext4_fs_put_block_group_ref(&bg_ref);
+}
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/lwext4/ext4_balloc.h
@@ -1,0 +1,93 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_balloc.h
+ * @brief Physical block allocator.
+ */
+
+#ifndef EXT4_BALLOC_H_
+#define EXT4_BALLOC_H_
+
+#include <ext4_config.h>
+#include <ext4_types.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+
+
+/**@brief Get first datablock in block group
+ * @param s superblock descriptor
+ * @param bg_ref block group reference
+ * @return block id of the first datablock in block group*/
+uint32_t ext4_balloc_get_first_data_block_in_group(struct ext4_sblock *s,
+ struct ext4_block_group_ref * bg_ref);
+
+/**@brief Free block from inode.
+ * @param inode_ref inode reference
+ * @param baddr block address
+ * @return standard error code*/
+int ext4_balloc_free_block(struct ext4_inode_ref *inode_ref,
+ uint32_t baddr);
+
+/**@brief Free blocks from inode.
+ * @param inode_ref inode reference
+ * @param baddr block address
+ * @return standard error code*/
+int ext4_balloc_free_blocks(struct ext4_inode_ref *inode_ref,
+ uint32_t first, uint32_t count);
+
+/**@brief Allocate block procedure.
+ * @param inode_ref inode reference
+ * @param baddr allocated block address
+ * @return standard error code*/
+int ext4_balloc_alloc_block(struct ext4_inode_ref *inode_ref,
+ uint32_t *baddr);
+
+/**@brief Try allocate selected block.
+ * @param inode_ref inode reference
+ * @param baddr block address to allocate
+ * @param free if baddr is not allocated
+ * @return standard error code*/
+int ext4_balloc_try_alloc_block(struct ext4_inode_ref *inode_ref,
+ uint32_t baddr, bool *free);
+
+#endif /* EXT4_BALLOC_H_ */
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/lwext4/ext4_bcache.c
@@ -1,0 +1,276 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_bcache.c
+ * @brief Block cache allocator.
+ */
+
+#include <ext4_config.h>
+#include <ext4_bcache.h>
+#include <ext4_debug.h>
+#include <ext4_errno.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+
+int ext4_bcache_init_dynamic(struct ext4_bcache *bc, uint32_t cnt,
+ uint32_t itemsize)
+{
+ ext4_assert(bc && cnt && itemsize);
+
+ bc->lru_ctr= 0;
+
+ bc->refctr = 0;
+ bc->lru_id = 0;
+ bc->free_delay = 0;
+ bc->lba = 0;
+ bc->data = 0;
+
+ bc->refctr = malloc(cnt * sizeof(uint32_t));
+ if(!bc->refctr)
+ goto error;
+
+ bc->lru_id = malloc(cnt * sizeof(uint32_t));
+ if(!bc->lru_id)
+ goto error;
+
+ bc->free_delay = malloc(cnt * sizeof(uint8_t));
+ if(!bc->free_delay)
+ goto error;
+
+ bc->lba = malloc(cnt * sizeof(uint64_t));
+ if(!bc->lba)
+ goto error;
+
+ bc->data = malloc(cnt * itemsize);
+ if(!bc->data)
+ goto error;
+
+ memset(bc->refctr, 0, cnt * sizeof(uint32_t));
+ memset(bc->lru_id, 0, cnt * sizeof(uint32_t));
+ memset(bc->free_delay, 0, cnt * sizeof(uint8_t));
+ memset(bc->lba, 0, cnt * sizeof(uint64_t));
+
+ bc->cnt = cnt;
+ bc->itemsize = itemsize;
+ bc->ref_blocks = 0;
+ bc->max_ref_blocks = 0;
+
+ return EOK;
+
+ error:
+
+ if(bc->refctr)
+ free(bc->refctr);
+
+ if(bc->lru_id)
+ free(bc->lru_id);
+
+ if(bc->free_delay)
+ free(bc->free_delay);
+
+ if(bc->lba)
+ free(bc->lba);
+
+ if(bc->data)
+ free(bc->data);
+
+ return ENOMEM;
+}
+
+int ext4_bcache_fini_dynamic(struct ext4_bcache *bc)
+{
+ if(bc->refctr)
+ free(bc->refctr);
+
+ if(bc->lru_id)
+ free(bc->lru_id);
+
+ if(bc->free_delay)
+ free(bc->free_delay);
+
+ if(bc->lba)
+ free(bc->lba);
+
+ if(bc->data)
+ free(bc->data);
+
+ bc->lru_ctr= 0;
+
+ bc->refctr = 0;
+ bc->lru_id = 0;
+ bc->free_delay = 0;
+ bc->lba = 0;
+ bc->data = 0;
+
+ return EOK;
+}
+
+
+int ext4_bcache_alloc(struct ext4_bcache *bc, struct ext4_block *b,
+ bool *is_new)
+{
+ uint32_t i;
+ ext4_assert(bc && b && is_new);
+
+ /*Check if valid.*/
+ ext4_assert(b->lb_id);
+ if(!b->lb_id){
+ ext4_assert(b->lb_id);
+ }
+
+ uint32_t cache_id = bc->cnt;
+ uint32_t alloc_id;
+
+ *is_new = false;
+
+ /*Find in free blocks (Last Recently Used).*/
+ for (i = 0; i < bc->cnt; ++i) {
+
+ /*Check if block is already in cache*/
+ if(b->lb_id == bc->lba[i]){
+
+ if(!bc->refctr[i] && !bc->free_delay[i])
+ bc->ref_blocks++;
+
+ /*Update reference counter*/
+ bc->refctr[i]++;
+
+ /*Update usage marker*/
+ bc->lru_id[i] = ++bc->lru_ctr;
+
+ /*Set valid cache data and id*/
+ b->data = bc->data + i * bc->itemsize;
+ b->cache_id = i;
+
+ return EOK;
+ }
+
+ /*Best fit calculations.*/
+ if(bc->refctr[i])
+ continue;
+
+ if(bc->free_delay[i])
+ continue;
+
+ /*Block is unreferenced, but it may exist block with
+ * lower usage marker*/
+
+ /*First find.*/
+ if(cache_id == bc->cnt){
+ cache_id = i;
+ alloc_id = bc->lru_id[i];
+ continue;
+ }
+
+ /*Next find*/
+ if(alloc_id <= bc->lru_id[i])
+ continue;
+
+ /*This block has lower alloc id marker*/
+ cache_id = i;
+ alloc_id = bc->lru_id[i];
+ }
+
+
+ if(cache_id != bc->cnt){
+ /*There was unreferenced block*/
+ bc->lba[cache_id] = b->lb_id;
+ bc->refctr[cache_id] = 1;
+ bc->lru_id[cache_id] = ++bc->lru_ctr;
+
+ /*Set valid cache data and id*/
+ b->data = bc->data + cache_id * bc->itemsize;
+ b->cache_id = cache_id;
+
+ /*Statistics*/
+ bc->ref_blocks++;
+ if(bc->ref_blocks > bc->max_ref_blocks)
+ bc->max_ref_blocks = bc->ref_blocks;
+
+
+ /*Block needs to be read.*/
+ *is_new = true;
+
+ return EOK;
+ }
+
+ ext4_dprintf(EXT4_DEBUG_BCACHE,
+ "ext4_bcache_alloc: FAIL, unable to alloc block cache!\n");
+ return ENOMEM;
+}
+
+int ext4_bcache_free (struct ext4_bcache *bc, struct ext4_block *b,
+ uint8_t free_delay)
+{
+ ext4_assert(bc && b);
+
+ /*Check if valid.*/
+ ext4_assert(b->lb_id);
+
+ /*Block should be in cache.*/
+ ext4_assert(b->cache_id < bc->cnt);
+
+ /*Check if someone don't try free unreferenced block cache.*/
+ ext4_assert(bc->refctr[b->cache_id]);
+
+ /*Just decrease reference counter*/
+ if(bc->refctr[b->cache_id])
+ bc->refctr[b->cache_id]--;
+
+ if(free_delay)
+ bc->free_delay[b->cache_id] = free_delay;
+
+ /*Update statistics*/
+ if(!bc->refctr[b->cache_id] && !bc->free_delay[b->cache_id])
+ bc->ref_blocks--;
+
+ b->lb_id = 0;
+ b->data = 0;
+ b->cache_id = 0;
+
+ return EOK;
+}
+
+
+
+bool ext4_bcache_is_full(struct ext4_bcache *bc)
+{
+ return (bc->cnt == bc->ref_blocks);
+}
+
+/**
+ * @}
+ */
+
+
--- /dev/null
+++ b/lwext4/ext4_bcache.h
@@ -1,0 +1,155 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_bcache.h
+ * @brief Block cache allocator.
+ */
+
+#ifndef EXT4_BCACHE_H_
+#define EXT4_BCACHE_H_
+
+#include <ext4_config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/**@brief Single block descriptor.*/
+struct ext4_block {
+ /**@brief Dirty flag.*/
+ bool dirty;
+
+ /**@brief Logical block ID*/
+ uint64_t lb_id;
+
+ /**@brief Cache id*/
+ uint32_t cache_id;
+
+ /**@brief Data buffer.*/
+ uint8_t *data;
+};
+
+
+/**@brief Block cache descriptor.*/
+struct ext4_bcache {
+
+ /**@brief Item count in block cache*/
+ uint32_t cnt;
+
+ /**@brief Item size in block cache*/
+ uint32_t itemsize;
+
+ /**@brief Last recently used counter.*/
+ uint32_t lru_ctr;
+
+ /**@brief Reference count table (cnt).*/
+ uint32_t *refctr;
+
+ /**@brief Last recently used ID table (cnt)*/
+ uint32_t *lru_id;
+
+ /**@brief Free delay mode table (cnt)*/
+ uint8_t *free_delay;
+
+ /**@brief Logical block table (cnt).*/
+ uint64_t *lba;
+
+ /**@brief Cache data buffers (cnt * itemsize)*/
+ uint8_t *data;
+
+ /**@brief Currently referenced datablocks*/
+ uint32_t ref_blocks;
+
+ /**@brief Maximum referenced datablocks*/
+ uint32_t max_ref_blocks;
+
+};
+
+/**@brief Static initializer of block cache structure.*/
+#define EXT4_BCACHE_STATIC_INSTANCE(__name, __cnt, __itemsize) \
+ static uint32_t __name##_refctr[(__cnt)]; \
+ static uint32_t __name##_lru_id[(__cnt)]; \
+ static uint8_t __name##_free_delay[(__cnt)]; \
+ static uint64_t __name##_lba[(__cnt)]; \
+ static uint8_t __name##_data[(__cnt) * (__itemsize)]; \
+ static struct ext4_bcache __name = { \
+ .cnt = __cnt, \
+ .itemsize = __itemsize, \
+ .lru_ctr = 0, \
+ .refctr = __name##_refctr, \
+ .lru_id = __name##_lru_id, \
+ .lba = __name##_lba, \
+ .free_delay= __name##_free_delay, \
+ .data = __name##_data, \
+ }
+
+
+/**@brief Dynamic initialization of block cache.
+ * @param bc block cache descriptor
+ * @param cnt items count in block cache
+ * @param itemsize single item size (in bytes)
+ * @return standard error code*/
+int ext4_bcache_init_dynamic(struct ext4_bcache *bc, uint32_t cnt,
+ uint32_t itemsize);
+
+/**@brief Dynamic de-initialization of block cache.
+ * @param bc block cache descriptor
+ * @return standard error code*/
+int ext4_bcache_fini_dynamic(struct ext4_bcache *bc);
+
+/**@brief Allocate block from block cache memory.
+ * Unreferenced block allocation is based on LRU
+ * (Last Recently Used) algorithm.
+ * @param bc block cache descriptor
+ * @param b block to alloc
+ * @param is_new block is new (needs to be read)
+ * @return standard error code*/
+int ext4_bcache_alloc(struct ext4_bcache *bc, struct ext4_block *b,
+ bool *is_new);
+
+/**@brief Free block from cache memory (decrement reference counter).
+ * @param bc block cache descriptor
+ * @param b block to free
+ * @return standard error code*/
+int ext4_bcache_free (struct ext4_bcache *bc, struct ext4_block *b,
+ uint8_t free_delay);
+
+
+/**@brief Return a full status of block cache.
+ * @param bc block cache descriptor
+ * @return full status*/
+bool ext4_bcache_is_full(struct ext4_bcache *bc);
+
+#endif /* EXT4_BCACHE_H_ */
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/lwext4/ext4_bitmap.c
@@ -1,0 +1,173 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_bitmap.c
+ * @brief Block/inode bitmap allocator.
+ */
+
+#include <ext4_config.h>
+#include <ext4_bitmap.h>
+
+#include <ext4_errno.h>
+
+
+void ext4_bmap_bits_free(uint8_t *bmap, uint32_t sbit, uint32_t bcnt)
+{
+ uint32_t i;
+
+ i = sbit;
+
+ while(i & 7){
+
+ if(!bcnt)
+ return;
+
+ ext4_bmap_bit_clr(bmap, i);
+
+ bcnt--;
+ i++;
+ }
+
+ sbit = i;
+ bmap += (sbit >> 3);
+
+
+
+ while(bcnt >= 32){
+ *(uint32_t *)bmap = 0;
+
+ bmap += 4;
+ bcnt -= 32;
+ sbit += 32;
+ }
+
+ while(bcnt >= 16){
+ *(uint16_t *)bmap = 0;
+
+ bmap += 2;
+ bcnt -= 16;
+ sbit += 16;
+ }
+
+ while(bcnt >= 8){
+ *bmap = 0;
+
+ bmap += 1;
+ bcnt -= 8;
+ sbit += 8;
+ }
+
+ for (i = 0; i < bcnt; ++i) {
+ ext4_bmap_bit_clr(bmap, i);
+ }
+}
+
+
+
+int ext4_bmap_bit_find_clr(uint8_t *bmap, uint32_t sbit, uint32_t ebit,
+ uint32_t *bit_id)
+{
+ uint32_t i;
+ uint32_t bcnt = ebit - sbit;
+
+ i = sbit;
+
+ while(i & 7){
+
+ if(!bcnt)
+ return ENOSPC;
+
+ if(ext4_bmap_is_bit_clr(bmap, i)){
+ *bit_id = sbit;
+ return EOK;
+ }
+
+ i++;
+ bcnt--;
+ }
+
+ sbit = i;
+ bmap += (sbit >> 3);
+
+
+ while(bcnt >= 32){
+ if(*(uint32_t *)bmap != 0xFFFFFFFF)
+ goto finish_it;
+
+
+ bmap += 4;
+ bcnt -= 32;
+ sbit += 32;
+ }
+
+ while(bcnt >= 16){
+ if(*(uint16_t *)bmap != 0xFFFF)
+ goto finish_it;
+
+
+ bmap += 2;
+ bcnt -= 16;
+ sbit += 16;
+ }
+
+ finish_it:
+ while(bcnt >= 8){
+ if(*bmap != 0xFF){
+ for (i = 0; i < 8; ++i) {
+ if(ext4_bmap_is_bit_clr(bmap, i)){
+ *bit_id = sbit + i;
+ return EOK;
+ }
+ }
+ }
+
+ bmap += 1;
+ bcnt -= 8;
+ sbit += 8;
+ }
+
+ for (i = 0; i < bcnt; ++i) {
+ if(ext4_bmap_is_bit_clr(bmap, i)){
+ *bit_id = sbit + i;
+ return EOK;
+ }
+ }
+
+
+ return ENOSPC;
+}
+
+/**
+ * @}
+ */
+
+
--- /dev/null
+++ b/lwext4/ext4_bitmap.h
@@ -1,0 +1,98 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_bitmap.h
+ * @brief Block/inode bitmap allocator.
+ */
+
+
+#ifndef EXT4_BITMAP_H_
+#define EXT4_BITMAP_H_
+
+#include <ext4_config.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+/**@brief Set bitmap bit.
+ * @param bmap bitmap
+ * @param bit bit to set*/
+static inline void ext4_bmap_bit_set(uint8_t *bmap, uint32_t bit)
+{
+ *(bmap + (bit >> 3)) |= (1 << (bit & 7));
+}
+
+/**@brief Clear bitmap bit.
+ * @param bmap bitmap buffer
+ * @param bit bit to clear*/
+static inline void ext4_bmap_bit_clr(uint8_t *bmap, uint32_t bit)
+{
+ *(bmap + (bit >> 3)) &= ~(1 << (bit & 7));
+}
+
+
+/**@brief Check if the bitmap bit is set.
+ * @param bmap bitmap buffer
+ * @param bit bit to check*/
+static inline bool ext4_bmap_is_bit_set(uint8_t *bmap, uint32_t bit)
+{
+ return (*(bmap + (bit >> 3)) & (1 << (bit & 7)));
+}
+
+/**@brief Check if the bitmap bit is clear.
+ * @param bmap bitmap buffer
+ * @param bit bit to check*/
+static inline bool ext4_bmap_is_bit_clr(uint8_t *bmap, uint32_t bit)
+{
+ return !ext4_bmap_is_bit_set(bmap, bit);
+}
+
+/**@brief Free range of bits in bitmap.
+ * @param bmap bitmap buffer
+ * @param sbit start bit
+ * @param bcnt bit count*/
+void ext4_bmap_bits_free(uint8_t *bmap, uint32_t sbit, uint32_t bcnt);
+
+/**@brief Find first clear bit in bitmap.
+ * @param sbit start bit of search
+ * @param ebit end bit of search
+ * @param bit_id output parameter (first free bit)
+ * @return standard error code*/
+int ext4_bmap_bit_find_clr(uint8_t *bmap, uint32_t sbit, uint32_t ebit,
+ uint32_t *bit_id);
+
+
+#endif /* EXT4_BITMAP_H_ */
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/lwext4/ext4_block_group.c
@@ -1,0 +1,55 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_block_group.c
+ * @brief Block group function set.
+ */
+
+#include <ext4_config.h>
+#include <ext4_block_group.h>
+
+
+
+uint16_t ext4_bg_crc16(uint16_t crc, const uint8_t *buffer, size_t len)
+{
+ // TODO
+ return 0;
+}
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/lwext4/ext4_block_group.h
@@ -1,0 +1,199 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_block_group.h
+ * @brief Block group function set.
+ */
+
+#ifndef EXT4_BLOCK_GROUP_H_
+#define EXT4_BLOCK_GROUP_H_
+
+
+#include <ext4_config.h>
+#include <ext4_types.h>
+#include <ext4_super.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+
+static inline uint64_t ext4_bg_get_block_bitmap(struct ext4_bgroup *bg,
+ struct ext4_sblock *s)
+{
+ uint64_t v = to_le32(bg->block_bitmap_lo);
+
+ if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+ v |= (uint64_t) to_le32(bg->block_bitmap_hi) << 32;
+
+ return v;
+}
+
+static inline uint64_t ext4_bg_get_inode_bitmap(struct ext4_bgroup *bg,
+ struct ext4_sblock *s)
+{
+
+ uint64_t v = to_le32(bg->inode_bitmap_lo);
+
+ if (ext4_sb_get_desc_size(s)> EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+ v |= (uint64_t) to_le32(bg->inode_bitmap_hi) << 32;
+
+ return v;
+}
+
+static inline uint64_t ext4_bg_get_inode_table_first_block(
+ struct ext4_bgroup *bg, struct ext4_sblock *s)
+{
+ uint64_t v = to_le32(bg->inode_table_first_block_lo);
+
+ if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+ v |= (uint64_t) to_le32(bg->inode_table_first_block_hi) << 32;
+
+ return v;
+}
+
+static inline uint32_t ext4_bg_get_free_blocks_count(struct ext4_bgroup *bg,
+ struct ext4_sblock *s)
+{
+ uint32_t v = to_le16(bg->free_blocks_count_lo);
+
+ if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+ v |= (uint32_t) to_le16(bg->free_blocks_count_hi) << 16;
+
+ return v;
+}
+
+static inline void ext4_bg_set_free_blocks_count(struct ext4_bgroup *bg,
+ struct ext4_sblock *s, uint32_t cnt)
+{
+ bg->free_blocks_count_lo = to_le16((cnt << 16) >> 16);
+ if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+ bg->free_blocks_count_hi = to_le16(cnt >> 16);
+}
+
+static inline uint32_t ext4_bg_get_free_inodes_count(struct ext4_bgroup *bg,
+ struct ext4_sblock *s)
+{
+ uint32_t v = to_le16(bg->free_inodes_count_lo);
+
+ if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+ v |= (uint32_t) to_le16(bg->free_inodes_count_hi) << 16;
+
+ return v;
+}
+
+static inline void ext4_bg_set_free_inodes_count(struct ext4_bgroup *bg,
+ struct ext4_sblock *s, uint32_t cnt)
+{
+ bg->free_inodes_count_lo = to_le16((cnt << 16) >> 16);
+ if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+ bg->free_inodes_count_hi = to_le16(cnt >> 16);
+}
+
+
+static inline uint32_t ext4_bg_get_used_dirs_count(struct ext4_bgroup *bg,
+ struct ext4_sblock *s)
+{
+ uint32_t v = to_le16(bg->used_dirs_count_lo);
+
+ if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+ v |= (uint32_t) to_le16(bg->used_dirs_count_hi) << 16;
+
+ return v;
+}
+
+static inline void ext4_bg_set_used_dirs_count(struct ext4_bgroup *bg,
+ struct ext4_sblock *s, uint32_t cnt)
+{
+ bg->used_dirs_count_lo = to_le16((cnt << 16) >> 16);
+ if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+ bg->used_dirs_count_hi = to_le16(cnt >> 16);
+}
+
+
+static inline uint32_t ext4_bg_get_itable_unused(struct ext4_bgroup *bg,
+ struct ext4_sblock *s)
+{
+
+ uint32_t v = to_le16(bg->itable_unused_lo);
+
+ if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+ v |= (uint32_t) to_le16(bg->itable_unused_hi) << 16;
+
+ return v;
+}
+
+static inline void ext4_bg_set_itable_unused(struct ext4_bgroup *bg,
+ struct ext4_sblock *s, uint32_t cnt)
+{
+ bg->itable_unused_lo = to_le16((cnt << 16) >> 16);
+ if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+ bg->itable_unused_hi = to_le16(cnt >> 16);
+}
+
+
+static inline void ext4_bg_set_checksum(struct ext4_bgroup *bg,
+ uint16_t crc)
+{
+ bg->checksum = to_le16(crc);
+}
+
+static inline bool ext4_bg_has_flag(struct ext4_bgroup *bg, uint32_t f)
+{
+ return to_le16(bg->flags) & f;
+}
+
+static inline void ext4_bg_set_flag(struct ext4_bgroup *bg, uint32_t f)
+{
+ uint16_t flags = to_le16(bg->flags);
+ flags |= f;
+ bg->flags = to_le16(flags);
+}
+
+static inline void ext4_bg_clear_flag(struct ext4_bgroup *bg, uint32_t f)
+{
+ uint16_t flags = to_le16(bg->flags);
+ flags &= ~f;
+ bg->flags = to_le16(flags);
+}
+
+
+uint16_t ext4_bg_crc16(uint16_t crc, const uint8_t *buffer, size_t len);
+
+#endif /* EXT4_BLOCK_GROUP_H_ */
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/lwext4/ext4_blockdev.c
@@ -1,0 +1,448 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_blockdev.c
+ * @brief Block device module.
+ */
+
+#include <ext4_config.h>
+#include <ext4_blockdev.h>
+#include <ext4_errno.h>
+#include <ext4_debug.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+
+
+int ext4_block_init(struct ext4_blockdev *bdev)
+{
+ int rc;
+ ext4_assert(bdev);
+
+ ext4_assert(bdev->open && bdev->close && bdev->bread && bdev->bwrite);
+
+ /*Low level block init*/
+ rc = bdev->open(bdev);
+ if(EOK != rc)
+ return rc;
+
+ bdev->flags |= EXT4_BDEV_INITIALIZED;
+
+ return EOK;
+}
+
+int ext4_block_bind_bcache(struct ext4_blockdev *bdev, struct ext4_bcache *bc)
+{
+ ext4_assert(bdev && bc);
+ bdev->bc = bc;
+ return EOK;
+}
+
+void ext4_block_set_lb_size(struct ext4_blockdev *bdev, uint64_t lb_bsize)
+{
+ /*Logical block size has to be multiply of physical */
+ ext4_assert(!(lb_bsize % bdev->ph_bsize));
+
+ bdev->lg_bsize = lb_bsize;
+ bdev->lg_bcnt = (bdev->ph_bcnt * bdev->ph_bsize) / lb_bsize;
+
+}
+
+int ext4_block_fini(struct ext4_blockdev *bdev)
+{
+ ext4_assert(bdev);
+
+ bdev->flags &= ~(EXT4_BDEV_INITIALIZED);
+
+ /*Low level block fini*/
+ return bdev->close(bdev);
+}
+
+
+int ext4_block_get(struct ext4_blockdev *bdev, struct ext4_block *b,
+ uint64_t lba)
+{
+ uint64_t pba;
+ uint32_t pb_cnt;
+ bool is_new;
+ int r;
+ ext4_assert(bdev && b);
+
+ if(!(bdev->flags & EXT4_BDEV_INITIALIZED))
+ return EIO;
+
+ if(!(lba < bdev->lg_bcnt))
+ return ERANGE;
+
+ b->dirty = 0;
+ b->lb_id = lba;
+
+ r = ext4_bcache_alloc(bdev->bc, b, &is_new);
+ if(r != EOK)
+ return r;
+
+
+ if(!is_new){
+ /*Block is in cache. Read from physical device is not required*/
+ return EOK;
+ }
+
+ if(!b->data)
+ return ENOMEM;
+
+ pba = (lba * bdev->lg_bsize) / bdev->ph_bsize;
+ pb_cnt = bdev->lg_bsize / bdev->ph_bsize;
+
+
+ r = bdev->bread(bdev, b->data, pba, pb_cnt);
+
+ if(r != EOK){
+ ext4_bcache_free(bdev->bc, b, 0);
+ b->lb_id = 0;
+ return r;
+ }
+
+ bdev->bread_ctr++;
+
+ return EOK;
+}
+
+int ext4_block_set(struct ext4_blockdev *bdev, struct ext4_block *b)
+{
+ uint64_t pba;
+ uint32_t pb_cnt;
+ uint32_t i;
+ int r;
+
+ ext4_assert(bdev && b);
+
+ if(!(bdev->flags & EXT4_BDEV_INITIALIZED))
+ return EIO;
+
+ /*Doesn,t need to write.*/
+ if(b->dirty == false){
+ ext4_bcache_free(bdev->bc, b, 0);
+ return EOK;
+ }
+
+ /*Free cache delay mode*/
+ if(bdev->cache_flush_delay){
+
+ /*Free cahe block and mark as free delayed*/
+ ext4_bcache_free(bdev->bc, b, bdev->cache_flush_delay);
+
+ /*If cache is full we have to flush it anyway :(*/
+ if(ext4_bcache_is_full(bdev->bc)){
+ for (i = 0; i < bdev->bc->cnt; ++i) {
+ /*Check if buffer free was delayed.*/
+ if(!bdev->bc->free_delay[i])
+ continue;
+
+ /*Check reference counter.*/
+ if(bdev->bc->refctr[i])
+ continue;
+
+ /*Buffer free was delayed and have no reference. Flush it.*/
+ r = ext4_block_set_direct(bdev,
+ bdev->bc->data + bdev->bc->itemsize * i,
+ bdev->bc->lba[i]);
+ if(r != EOK)
+ return r;
+
+ /*No delayed anymore*/
+ bdev->bc->free_delay[i] = 0;
+
+ /*Reduce refered block count*/
+ bdev->bc->ref_blocks--;
+ }
+ }
+
+ return EOK;
+ }
+
+ pba = (b->lb_id * bdev->lg_bsize) / bdev->ph_bsize;
+ pb_cnt = bdev->lg_bsize / bdev->ph_bsize;
+
+
+ r = bdev->bwrite(bdev, b->data, pba, pb_cnt);
+
+ if(r != EOK){
+ b->dirty = false;
+ ext4_bcache_free(bdev->bc, b, 0);
+ return r;
+ }
+
+ bdev->bwrite_ctr++;
+ b->dirty = false;
+ ext4_bcache_free(bdev->bc, b, 0);
+ return EOK;
+}
+
+int ext4_block_get_direct(struct ext4_blockdev *bdev, void *buf,
+ uint64_t lba)
+{
+ uint64_t pba;
+ uint32_t pb_cnt;
+
+ ext4_assert(bdev && buf);
+
+ pba = (lba * bdev->lg_bsize) / bdev->ph_bsize;
+ pb_cnt = bdev->lg_bsize / bdev->ph_bsize;
+
+ bdev->bread_ctr++;
+
+ return bdev->bread(bdev, buf, pba, pb_cnt);
+}
+
+
+
+int ext4_block_set_direct(struct ext4_blockdev *bdev, const void *buf,
+ uint64_t lba)
+{
+ uint64_t pba;
+ uint32_t pb_cnt;
+
+ ext4_assert(bdev && buf);
+
+ pba = (lba * bdev->lg_bsize) / bdev->ph_bsize;
+ pb_cnt = bdev->lg_bsize / bdev->ph_bsize;
+
+ bdev->bwrite_ctr++;
+
+ return bdev->bwrite(bdev, buf, pba, pb_cnt);
+}
+
+
+int ext4_block_writebytes(struct ext4_blockdev *bdev, uint64_t off,
+ const void *buf, uint32_t len)
+{
+ uint64_t block_idx;
+ uint64_t block_end;
+
+ uint32_t blen;
+
+ uint32_t unalg;
+ int r = EOK;
+
+ const uint8_t *p = (void *)buf;
+
+ ext4_assert(bdev && buf);
+
+ if(!(bdev->flags & EXT4_BDEV_INITIALIZED))
+ return EIO;
+
+
+ block_idx = off / bdev->ph_bsize;
+ block_end = block_idx + len / bdev->ph_bsize;
+
+ if(!(block_end < bdev->ph_bcnt))
+ return EINVAL; /*Ups. Out of range operation*/
+
+
+ /*OK lets deal with the first possible unaligned block*/
+ unalg = (off & (bdev->ph_bsize - 1));
+ if(unalg){
+
+ uint32_t wlen = (bdev->ph_bsize - unalg) > len ?
+ len : (bdev->ph_bsize - unalg);
+
+ r = bdev->bread(bdev, bdev->ph_bbuf, block_idx, 1);
+
+ if(r != EOK)
+ return r;
+
+ memcpy(bdev->ph_bbuf + unalg, p, wlen);
+
+ r = bdev->bwrite(bdev, bdev->ph_bbuf, block_idx, 1);
+
+ if(r != EOK)
+ return r;
+
+ p += wlen;
+ len -= wlen;
+ block_idx++;
+ }
+
+
+ /*Aligned data*/
+ blen = len / bdev->ph_bsize;
+
+ r = bdev->bwrite(bdev, p, block_idx, blen);
+
+ if(r != EOK)
+ return r;
+
+ p += bdev->ph_bsize * blen;
+ len -= bdev->ph_bsize * blen;
+
+ block_idx += blen;
+
+
+ /*Rest of the data*/
+ if(len){
+
+ r = bdev->bread(bdev, bdev->ph_bbuf, block_idx, 1);
+
+ if(r != EOK)
+ return r;
+
+ memcpy(bdev->ph_bbuf, p, len);
+
+ r = bdev->bwrite(bdev, bdev->ph_bbuf, block_idx, 1);
+
+ if(r != EOK)
+ return r;
+ }
+
+ return r;
+}
+
+
+
+
+int ext4_block_readbytes(struct ext4_blockdev *bdev, uint64_t off, void *buf,
+ uint32_t len)
+{
+
+ uint64_t block_idx;
+ uint64_t block_end;
+ uint32_t blen;
+
+ uint32_t unalg;
+ int r = EOK;
+
+ uint8_t *p = (void *)buf;
+
+ ext4_assert(bdev && buf);
+
+ if(!(bdev->flags & EXT4_BDEV_INITIALIZED))
+ return EIO;
+
+
+ block_idx = off / bdev->ph_bsize;
+ block_end = block_idx + len / bdev->ph_bsize;
+
+ if(!(block_end < bdev->ph_bcnt))
+ return EINVAL; /*Ups. Out of range operation*/
+
+
+ /*OK lets deal with the first possible unaligned block*/
+ unalg = (off & (bdev->ph_bsize - 1));
+ if(unalg){
+
+ uint32_t rlen = (bdev->ph_bsize - unalg) > len ?
+ len : (bdev->ph_bsize - unalg);
+
+ r = bdev->bread(bdev, bdev->ph_bbuf, block_idx, 1);
+
+ if(r != EOK)
+ return r;
+
+ memcpy(p, bdev->ph_bbuf + unalg, rlen);
+
+ p += rlen;
+ len -= rlen;
+ block_idx++;
+ }
+
+
+ /*Aligned data*/
+ blen = len / bdev->ph_bsize;
+
+ r = bdev->bread(bdev, p, block_idx, blen);
+
+ if(r != EOK)
+ return r;
+
+ p += bdev->ph_bsize * blen;
+ len -= bdev->ph_bsize * blen;
+
+ block_idx += blen;
+
+
+ /*Rest of the data*/
+ if(len){
+
+ r = bdev->bread(bdev, bdev->ph_bbuf, block_idx, 1);
+
+ if(r != EOK)
+ return r;
+
+ memcpy(p, bdev->ph_bbuf, len);
+
+ }
+
+ return r;
+}
+
+int ext4_block_delay_cache_flush(struct ext4_blockdev *bdev,
+ uint8_t on_off)
+{
+ int r;
+ uint32_t i;
+ bdev->cache_flush_delay = on_off;
+
+ /*Flush all delayed cache blocks*/
+ if(!on_off){
+ for (i = 0; i < bdev->bc->cnt; ++i) {
+
+ /*Check if buffer free was delayed.*/
+ if(!bdev->bc->free_delay[i])
+ continue;
+
+ /*Check reference counter.*/
+ if(bdev->bc->refctr[i])
+ continue;
+
+ /*Buffer free was delayed and have no reference. Flush it.*/
+ r = ext4_block_set_direct(bdev,
+ bdev->bc->data + bdev->bc->itemsize * i,
+ bdev->bc->lba[i]);
+ if(r != EOK)
+ return r;
+
+ /*No delayed anymore*/
+ bdev->bc->free_delay[i] = 0;
+
+ /*Reduce refered block count*/
+ bdev->bc->ref_blocks--;
+ }
+ }
+
+ return EOK;
+}
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/lwext4/ext4_blockdev.h
@@ -1,0 +1,211 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EXT4_BLOCKDEV_H_
+#define EXT4_BLOCKDEV_H_
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_blockdev.h
+ * @brief Block device module.
+ */
+
+#include <ext4_config.h>
+#include <ext4_bcache.h>
+#include <ext4_debug.h>
+
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/**@brief Initialization status flag*/
+#define EXT4_BDEV_INITIALIZED (1 << 0)
+
+
+/**@brief Definiton of the simple block device.*/
+struct ext4_blockdev {
+
+ /**@brief Open device function
+ * @param bdev block device.*/
+ int (*open)(struct ext4_blockdev *bdev);
+
+ /**@brief Block read function.
+ * @param bdev block device
+ * @param buf output buffer
+ * @param blk_id block id
+ * @param blk_cnt block count*/
+ int (*bread)(struct ext4_blockdev *bdev, void *buf,
+ uint64_t blk_id, uint32_t blk_cnt);
+
+ /**@brief Block write function.
+ * @param buf input buffer
+ * @param blk_id block id
+ * @param blk_cnt block count*/
+ int (*bwrite)(struct ext4_blockdev *bdev, const void *buf,
+ uint64_t blk_id, uint32_t blk_cnt);
+
+ /**@brief Close device function.
+ * @param bdev block device.*/
+ int (*close)(struct ext4_blockdev *bdev);
+
+ /**@brief Block size (bytes): physical*/
+ uint32_t ph_bsize;
+
+ /**@brief Block count: physical.*/
+ uint64_t ph_bcnt;
+
+ /**@brief Block size buffer: physical.*/
+ uint8_t *ph_bbuf;
+
+ /**@brief Block size (bytes) logical*/
+ uint32_t lg_bsize;
+
+ /**@brief Block count: phisical.*/
+ uint64_t lg_bcnt;
+
+ /**@brief Flags of te block device.*/
+ uint8_t flags;
+
+ /**@brief Block cache.*/
+ struct ext4_bcache *bc;
+
+ uint8_t cache_flush_delay;
+
+ uint32_t bread_ctr;
+ uint32_t bwrite_ctr;
+};
+
+
+/**@brief Static initialization fo the block device.*/
+#define EXT4_BLOCKDEV_STATIC_INSTANCE(__name, __bsize, __bcnt, __open, \
+ __bread, __bwrite, __close) \
+ static uint8_t __name##_ph_bbuf[(__bsize)]; \
+ static struct ext4_blockdev __name = { \
+ .open = __open, \
+ .bread = __bread, \
+ .bwrite = __bwrite, \
+ .close = __close, \
+ .ph_bsize = __bsize, \
+ .ph_bcnt = __bcnt, \
+ .ph_bbuf = __name##_ph_bbuf, \
+ }
+
+/**@brief Block device initialization.
+ * @param bdev block device descriptor
+ * @param bg_bsize logical block size
+ * @param bdev block device descriptor
+ * @return standard error code*/
+int ext4_block_init(struct ext4_blockdev *bdev);
+
+
+/**@brief Binds a bcache to block device.
+ * @param bdev block device descriptor
+ * @param bc block cache descriptor
+ * @return standard error code*/
+int ext4_block_bind_bcache(struct ext4_blockdev *bdev,
+ struct ext4_bcache *bc);
+
+/**@brief Close block device
+ * @param bdev block device descriptor
+ * @return standard error code*/
+int ext4_block_fini(struct ext4_blockdev *bdev);
+
+
+/**@brief Set logical block size in block device.
+ * @param bdev block device descriptor
+ * @param lb_size ligical block size (in bytes)
+ * @return standard error code*/
+void ext4_block_set_lb_size(struct ext4_blockdev *bdev,
+ uint64_t lb_bsize);
+
+/**@brief Block get function (through cache).
+ * @param bdev block device descriptor
+ * @param b block descriptor
+ * @param lba logical block address
+ * @return standard error code*/
+int ext4_block_get(struct ext4_blockdev *bdev, struct ext4_block *b,
+ uint64_t lba);
+
+/**@brief Block set procedure (through cache).
+ * @param bdev block device descriptor
+ * @param b block descriptor
+ * @return standard error code*/
+int ext4_block_set(struct ext4_blockdev *bdev, struct ext4_block *b);
+
+
+/**@brief Block read procedure (without cache)
+ * @param bdev block device descriptor
+ * @param buf output buffer
+ * @param lba logical block adderss
+ * @return standard error code*/
+int ext4_block_get_direct(struct ext4_blockdev *bdev, void *buf,
+ uint64_t lba);
+
+
+/**@brief Block write procedure (without cache)
+ * @param bdev block device descriptor
+ * @param buf output buffer
+ * @param lba logical block address
+ * @return standard error code*/
+int ext4_block_set_direct(struct ext4_blockdev *bdev, const void *buf,
+ uint64_t lba);
+
+/**@brief Write to block device (by direct adress).
+ * @param bdev block device descriptor
+ * @param off byte offset in block device
+ * @param buf input buffer
+ * @param len length of the write nuffer
+ * @return EOK when sucess*/
+int ext4_block_writebytes(struct ext4_blockdev *bdev, uint64_t off,
+ const void *buf, uint32_t len);
+
+
+
+/**@brief Read freom block device (by direct adress).
+ * @param bdev block device descriptor
+ * @param off byte offset in block device
+ * @param buf input buffer
+ * @param len length of the write nuffer
+ * @return EOK when sucess*/
+int ext4_block_readbytes(struct ext4_blockdev *bdev, uint64_t off,
+ void *buf, uint32_t len);
+
+/**@brief Enable/disable delayed cache flush mode.
+ * @param bdev block device descriptor
+ * @param on_off
+ * !0 - ENABLE
+ * 0 - DISABLE (all delayed cache buffers will be flushed)
+ * @return standard error code*/
+int ext4_block_delay_cache_flush(struct ext4_blockdev *bdev, uint8_t on_off);
+
+#endif /* EXT4_BLOCKDEV_H_ */
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/lwext4/ext4_config.h
@@ -1,0 +1,99 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_config.h
+ * @brief Configuration file.
+ */
+
+#ifndef EXT4_CONFIG_H_
+#define EXT4_CONFIG_H_
+
+#ifdef CONFIG_HAVE_OWN_CFG
+#include <config.h>
+#endif
+
+
+/**@brief Enable directory indexing feature (EXT3 feature)*/
+#ifndef CONFIG_DIR_INDEX_ENABLE
+#define CONFIG_DIR_INDEX_ENABLE 0
+#endif
+
+/**@brief Enable extents feature (EXT4 feature)*/
+#ifndef CONFIG_EXTENT_ENABLE
+#define CONFIG_EXTENT_ENABLE 0
+#endif
+
+
+
+/**@brief Include error codes from ext4_errno or sandard library.*/
+#ifndef CONFIG_HAVE_OWN_ERRNO
+#define CONFIG_HAVE_OWN_ERRNO 1
+#endif
+
+
+/**@brief Debug printf enable (stdout)*/
+#ifndef CONFIG_DEBUG_PRINTF
+#define CONFIG_DEBUG_PRINTF 1
+#endif
+
+/**@brief Assert printf enable (stdout)*/
+#ifndef CONFIG_DEBUG_ASSERT
+#define CONFIG_DEBUG_ASSERT 1
+#endif
+
+/**@brief Statistics of block device*/
+#ifndef CONFIG_BLOCK_DEV_ENABLE_STATS
+#define CONFIG_BLOCK_DEV_ENABLE_STATS 1
+#endif
+
+/**@brief Cache size of block device.*/
+#ifndef CONFIG_BLOCK_DEV_CACHE_SIZE
+#define CONFIG_BLOCK_DEV_CACHE_SIZE 8
+#endif
+
+
+/**@brief Ilosc urzadzen blokowych.*/
+#ifndef CONFIG_EXT4_BLOCKDEVS_COUNT
+#define CONFIG_EXT4_BLOCKDEVS_COUNT 2
+#endif
+
+/**@brief Ilosc punktow montowania systemu plikow*/
+#ifndef CONFIG_EXT4_MOUNTPOINTS_COUNT
+#define CONFIG_EXT4_MOUNTPOINTS_COUNT 2
+#endif
+
+
+#endif /* EXT4_CONFIG_H_ */
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/lwext4/ext4_debug.c
@@ -1,0 +1,58 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_debug.c
+ * @brief Debug printf and assert macros.
+ */
+
+#include <ext4_config.h>
+#include <ext4_debug.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+
+static uint32_t __dbg_mask__;
+
+
+void ext4_dmask_set(uint32_t m)
+{
+ __dbg_mask__ = m;
+}
+
+uint32_t ext4_dmask_get(void)
+{
+ return __dbg_mask__;
+}
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/lwext4/ext4_debug.h
@@ -1,0 +1,116 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_debug.c
+ * @brief Debug printf and assert macros.
+ */
+
+#ifndef EXT4_DEBUG_H_
+#define EXT4_DEBUG_H_
+
+#include <ext4_config.h>
+#include <ext4_errno.h>
+#include <stdint.h>
+#include <stdio.h>
+
+/**@brief Debug mask: ext4_blockdev.c*/
+#define EXT4_DEBUG_BLOCKDEV (1 << 0)
+
+/**@brief Debug mask: ext4_fs.c*/
+#define EXT4_DEBUG_FS (1 << 1)
+
+/**@brief Debug mask: ext4_balloc.c*/
+#define EXT4_DEBUG_BALLOC (1 << 2)
+
+/**@brief Debug mask: ext4_bitmap.c*/
+#define EXT4_DEBUG_BITMAP (1 << 3)
+
+/**@brief Debug mask: ext4_dir_idx.c*/
+#define EXT4_DEBUG_DIR_IDX (1 << 4)
+
+/**@brief Debug mask: ext4_dir.c*/
+#define EXT4_DEBUG_DIR (1 << 5)
+
+/**@brief Debug mask: ext4_ialloc.c*/
+#define EXT4_DEBUG_IALLOC (1 << 6)
+
+/**@brief Debug mask: ext4_inode.c*/
+#define EXT4_DEBUG_INODE (1 << 7)
+
+/**@brief Debug mask: ext4_super.c*/
+#define EXT4_DEBUG_SUPER (1 << 8)
+
+/**@brief Debug mask: ext4_bcache.c*/
+#define EXT4_DEBUG_BCACHE (1 << 9)
+
+
+/**@brief All debug printf enabled.*/
+#define EXT4_DEBUG_ALL (0xFFFFFFFF)
+
+/**@brief Global mask debug settings.
+ * @brief m new debug mask.*/
+void ext4_dmask_set(uint32_t m);
+
+/**@brief Global debug mask get.
+ * @return debug mask*/
+uint32_t ext4_dmask_get(void);
+
+
+#if CONFIG_DEBUG_PRINTF
+/**@brief Debug printf.*/
+#define ext4_dprintf(m, ...) do { \
+ (m & ext4_dmask_get()) ? printf(__VA_ARGS__) : (void)0; \
+ fflush(stdout); \
+}while(0)
+#else
+#define ext4_dprintf(m, ...)
+#endif
+
+
+
+#if CONFIG_DEBUG_ASSERT
+#define ext4_assert(_v) do { \
+ if(!(_v)){ \
+ printf("Assertion failed:\nModule: %s\nFunc: %s\nLine: %d\n", \
+ __FILE__, __FUNCTION__, __LINE__); \
+ } \
+}while(0)
+#else
+#define ext4_assert(_v)
+#endif
+
+
+#endif /* EXT4_DEBUG_H_ */
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/lwext4/ext4_dir.c
@@ -1,0 +1,618 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_dir.h
+ * @brief Directory handle procedures.
+ */
+
+#include <ext4_config.h>
+#include <ext4_dir.h>
+#include <ext4_dir_idx.h>
+#include <ext4_inode.h>
+#include <ext4_fs.h>
+
+#include <string.h>
+
+uint32_t ext4_dir_entry_ll_get_inode(struct ext4_directory_entry_ll *de)
+{
+ return to_le32(de->inode);
+}
+
+void ext4_dir_entry_ll_set_inode(struct ext4_directory_entry_ll *de,
+ uint32_t inode)
+{
+ de->inode = to_le32(inode);
+}
+
+
+uint16_t ext4_dir_entry_ll_get_entry_length(struct ext4_directory_entry_ll *de)
+{
+ return to_le16(de->entry_length);
+}
+
+void ext4_dir_entry_ll_set_entry_length(struct ext4_directory_entry_ll *de,
+ uint16_t len)
+{
+ de->entry_length = to_le16(len);
+}
+
+
+uint16_t ext4_dir_entry_ll_get_name_length(struct ext4_sblock *sb,
+ struct ext4_directory_entry_ll *de)
+{
+ uint16_t v = de->name_length;
+
+ if ((ext4_get32(sb, rev_level) == 0) &&
+ (ext4_get32(sb, minor_rev_level) < 5))
+ v |= ((uint16_t)de->name_length_high) << 8;
+
+ return v;
+}
+void ext4_dir_entry_ll_set_name_length(struct ext4_sblock *sb,
+ struct ext4_directory_entry_ll *de, uint16_t len)
+{
+ de->name_length = (len << 8) >> 8;
+
+ if ((ext4_get32(sb, rev_level) == 0) &&
+ (ext4_get32(sb, minor_rev_level) < 5))
+ de->name_length_high = len >> 8;
+}
+
+
+
+uint8_t ext4_dir_entry_ll_get_inode_type(struct ext4_sblock *sb,
+ struct ext4_directory_entry_ll *de)
+{
+ if ((ext4_get32(sb, rev_level) > 0) ||
+ (ext4_get32(sb, minor_rev_level) >= 5))
+ return de->inode_type;
+
+ return EXT4_DIRECTORY_FILETYPE_UNKNOWN;
+}
+
+
+void ext4_dir_entry_ll_set_inode_type(struct ext4_sblock *sb,
+ struct ext4_directory_entry_ll *de, uint8_t type)
+{
+ if ((ext4_get32(sb, rev_level) > 0) ||
+ (ext4_get32(sb, minor_rev_level) >= 5))
+ de->inode_type = type;
+}
+
+/****************************************************************************/
+
+
+static int ext4_dir_iterator_set(struct ext4_directory_iterator *it,
+ uint32_t block_size)
+{
+ it->current = NULL;
+
+ uint32_t offset_in_block = it->current_offset % block_size;
+
+ /* Ensure proper alignment */
+ if ((offset_in_block % 4) != 0)
+ return EIO;
+
+ /* Ensure that the core of the entry does not overflow the block */
+ if (offset_in_block > block_size - 8)
+ return EIO;
+
+ struct ext4_directory_entry_ll *entry =
+ (void *)(it->current_block.data + offset_in_block);
+
+ /* Ensure that the whole entry does not overflow the block */
+ uint16_t length = ext4_dir_entry_ll_get_entry_length(entry);
+ if (offset_in_block + length > block_size)
+ return EIO;
+
+ /* Ensure the name length is not too large */
+ if (ext4_dir_entry_ll_get_name_length(
+ &it->inode_ref->fs->sb, entry) > length-8)
+ return EIO;
+
+ /* Everything OK - "publish" the entry */
+ it->current = entry;
+ return EOK;
+}
+
+static int ext4_dir_iterator_seek(struct ext4_directory_iterator *it,
+ uint64_t pos)
+{
+ uint64_t size = ext4_inode_get_size(&it->inode_ref->fs->sb,
+ it->inode_ref->inode);
+
+ /* The iterator is not valid until we seek to the desired position */
+ it->current = NULL;
+
+ /* Are we at the end? */
+ if (pos >= size) {
+ if (it->current_block.lb_id) {
+
+ int rc = ext4_block_set(it->inode_ref->fs->bdev,
+ &it->current_block);
+ it->current_block.lb_id = 0;
+
+ if (rc != EOK)
+ return rc;
+ }
+
+ it->current_offset = pos;
+ return EOK;
+ }
+
+ /* Compute next block address */
+ uint32_t block_size =
+ ext4_sb_get_block_size(&it->inode_ref->fs->sb);
+ uint64_t current_block_idx = it->current_offset / block_size;
+ uint64_t next_block_idx = pos / block_size;
+
+ /*
+ * If we don't have a block or are moving accross block boundary,
+ * we need to get another block
+ */
+ if ((it->current_block.lb_id == 0) ||
+ (current_block_idx != next_block_idx)) {
+ if (it->current_block.lb_id) {
+ int rc = ext4_block_set(it->inode_ref->fs->bdev, &it->current_block);
+ it->current_block.lb_id = 0;
+
+ if (rc != EOK)
+ return rc;
+ }
+
+ uint32_t next_block_phys_idx;
+ int rc = ext4_fs_get_inode_data_block_index(it->inode_ref,
+ next_block_idx, &next_block_phys_idx);
+ if (rc != EOK)
+ return rc;
+
+
+ rc = ext4_block_get(it->inode_ref->fs->bdev, &it->current_block,
+ next_block_phys_idx);
+ if (rc != EOK) {
+ it->current_block.lb_id = 0;
+ return rc;
+ }
+ }
+
+ it->current_offset = pos;
+
+ return ext4_dir_iterator_set(it, block_size);
+}
+
+
+int ext4_dir_iterator_init(struct ext4_directory_iterator *it,
+ struct ext4_inode_ref *inode_ref, uint64_t pos)
+{
+ it->inode_ref = inode_ref;
+ it->current = 0;
+ it->current_offset = 0;
+ it->current_block.lb_id = 0;
+
+ return ext4_dir_iterator_seek(it, pos);
+}
+
+int ext4_dir_iterator_next(struct ext4_directory_iterator *it)
+{
+ uint16_t skip = ext4_dir_entry_ll_get_entry_length(it->current);
+
+ return ext4_dir_iterator_seek(it, it->current_offset + skip);
+}
+
+int ext4_dir_iterator_fini(struct ext4_directory_iterator *it)
+{
+ it->current = 0;
+
+ if (it->current_block.lb_id)
+ return ext4_block_set(it->inode_ref->fs->bdev, &it->current_block);
+
+ return EOK;
+}
+
+void ext4_dir_write_entry(struct ext4_sblock *sb,
+ struct ext4_directory_entry_ll *entry, uint16_t entry_len,
+ struct ext4_inode_ref *child, const char *name, size_t name_len)
+{
+ /* Check maximum entry length */
+ uint32_t block_size = ext4_sb_get_block_size(sb);
+ ext4_assert(entry_len <= block_size);
+
+ /* Set basic attributes */
+ ext4_dir_entry_ll_set_inode(entry, child->index);
+ ext4_dir_entry_ll_set_entry_length(entry, entry_len);
+ ext4_dir_entry_ll_set_name_length(sb, entry, name_len);
+
+ /* Write name */
+ memcpy(entry->name, name, name_len);
+
+ /* Set type of entry */
+ if (ext4_inode_is_type(sb, child->inode, EXT4_INODE_MODE_DIRECTORY))
+ ext4_dir_entry_ll_set_inode_type(sb, entry,
+ EXT4_DIRECTORY_FILETYPE_DIR);
+ else
+ ext4_dir_entry_ll_set_inode_type(sb, entry,
+ EXT4_DIRECTORY_FILETYPE_REG_FILE);
+}
+
+int ext4_dir_add_entry(struct ext4_inode_ref *parent, const char *name,
+ uint32_t name_len, struct ext4_inode_ref *child)
+{
+ struct ext4_fs *fs = parent->fs;
+
+#if CONFIG_DIR_INDEX_ENABLE
+ /* Index adding (if allowed) */
+ if ((ext4_sb_check_feature_compatible(&fs->sb,
+ EXT4_FEATURE_COMPAT_DIR_INDEX)) &&
+ (ext4_inode_has_flag(parent->inode, EXT4_INODE_FLAG_INDEX))) {
+ int rc = ext4_dir_dx_add_entry(parent, child, name);
+
+ /* Check if index is not corrupted */
+ if (rc != EXT4_ERR_BAD_DX_DIR) {
+ if (rc != EOK)
+ return rc;
+
+ return EOK;
+ }
+
+ /* Needed to clear dir index flag if corrupted */
+ ext4_inode_clear_flag(parent->inode, EXT4_INODE_FLAG_INDEX);
+ parent->dirty = true;
+ }
+#endif
+
+ /* Linear algorithm */
+ uint32_t iblock = 0;
+ uint32_t fblock = 0;
+ uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
+ uint32_t inode_size = ext4_inode_get_size(&fs->sb, parent->inode);
+ uint32_t total_blocks = inode_size / block_size;
+
+
+ /* Find block, where is space for new entry and try to add */
+ bool success = false;
+ for (iblock = 0; iblock < total_blocks; ++iblock) {
+ int rc = ext4_fs_get_inode_data_block_index(parent,
+ iblock, &fblock);
+ if (rc != EOK)
+ return rc;
+
+
+ struct ext4_block block;
+ rc = ext4_block_get(fs->bdev, &block, fblock);
+ if (rc != EOK)
+ return rc;
+
+ /* If adding is successful, function can finish */
+ rc = ext4_dir_try_insert_entry(&fs->sb, &block,
+ child, name, name_len);
+ if (rc == EOK)
+ success = true;
+
+ rc = ext4_block_set(fs->bdev, &block);
+ if (rc != EOK)
+ return rc;
+
+ if (success)
+ return EOK;
+ }
+
+ /* No free block found - needed to allocate next data block */
+
+ iblock = 0;
+ fblock = 0;
+ int rc = ext4_fs_append_inode_block(parent, &fblock, &iblock);
+ if (rc != EOK)
+ return rc;
+
+ /* Load new block */
+ struct ext4_block new_block;
+
+ rc = ext4_block_get(fs->bdev, &new_block, fblock);
+ if (rc != EOK)
+ return rc;
+
+ /* Fill block with zeroes */
+ memset(new_block.data, 0, block_size);
+ struct ext4_directory_entry_ll *block_entry = (void *)new_block.data;
+ ext4_dir_write_entry(&fs->sb, block_entry, block_size,
+ child, name, name_len);
+
+ /* Save new block */
+ new_block.dirty = true;
+ rc = ext4_block_set(fs->bdev, &new_block);
+
+ return rc;
+}
+
+int ext4_dir_find_entry(struct ext4_directory_search_result *result,
+ struct ext4_inode_ref *parent, const char *name, uint32_t name_len)
+{
+ struct ext4_sblock *sb = &parent->fs->sb;
+
+
+#if CONFIG_DIR_INDEX_ENABLE
+ /* Index search */
+ if ((ext4_sb_check_feature_compatible(sb,
+ EXT4_FEATURE_COMPAT_DIR_INDEX)) &&
+ (ext4_inode_has_flag(parent->inode, EXT4_INODE_FLAG_INDEX))) {
+ int rc = ext4_dir_dx_find_entry(result, parent, name_len,
+ name);
+
+ /* Check if index is not corrupted */
+ if (rc != EXT4_ERR_BAD_DX_DIR) {
+ if (rc != EOK)
+ return rc;
+
+ return EOK;
+ }
+
+ /* Needed to clear dir index flag if corrupted */
+ ext4_inode_clear_flag(parent->inode, EXT4_INODE_FLAG_INDEX);
+ parent->dirty = true;
+ }
+#endif
+
+ /* Linear algorithm */
+
+ uint32_t iblock;
+ uint32_t fblock;
+ uint32_t block_size = ext4_sb_get_block_size(sb);
+ uint32_t inode_size = ext4_inode_get_size(sb, parent->inode);
+ uint32_t total_blocks = inode_size / block_size;
+
+ /* Walk through all data blocks */
+ for (iblock = 0; iblock < total_blocks; ++iblock) {
+ /* Load block address */
+ int rc = ext4_fs_get_inode_data_block_index(parent, iblock,
+ &fblock);
+ if (rc != EOK)
+ return rc;
+
+ /* Load data block */
+ struct ext4_block block;
+ rc = ext4_block_get( parent->fs->bdev, &block, fblock);
+ if (rc != EOK)
+ return rc;
+
+ /* Try to find entry in block */
+ struct ext4_directory_entry_ll *res_entry;
+ rc = ext4_dir_find_in_block(&block, sb, name_len, name,
+ &res_entry);
+ if (rc == EOK) {
+ result->block = block;
+ result->dentry = res_entry;
+ return EOK;
+ }
+
+ /* Entry not found - put block and continue to the next block */
+
+ rc = ext4_block_set(parent->fs->bdev, &block);
+ if (rc != EOK)
+ return rc;
+ }
+
+ /* Entry was not found */
+
+ result->block.lb_id = 0;
+ result->dentry = NULL;
+
+ return ENOENT;
+}
+
+int ext4_dir_remove_entry(struct ext4_inode_ref *parent, const char *name,
+ uint32_t name_len)
+{
+ /* Check if removing from directory */
+ if (!ext4_inode_is_type(&parent->fs->sb, parent->inode,
+ EXT4_INODE_MODE_DIRECTORY))
+ return ENOTDIR;
+
+ /* Try to find entry */
+ struct ext4_directory_search_result result;
+ int rc = ext4_dir_find_entry(&result, parent, name, name_len);
+ if (rc != EOK)
+ return rc;
+
+ /* Invalidate entry */
+ ext4_dir_entry_ll_set_inode(result.dentry, 0);
+
+ /* Store entry position in block */
+ uint32_t pos = (uint8_t *) result.dentry - result.block.data;
+
+ /*
+ * If entry is not the first in block, it must be merged
+ * with previous entry
+ */
+ if (pos != 0) {
+ uint32_t offset = 0;
+
+ /* Start from the first entry in block */
+ struct ext4_directory_entry_ll *tmp_dentry = (void *)result.block.data;
+ uint16_t tmp_dentry_length =
+ ext4_dir_entry_ll_get_entry_length(tmp_dentry);
+
+ /* Find direct predecessor of removed entry */
+ while ((offset + tmp_dentry_length) < pos) {
+ offset +=
+ ext4_dir_entry_ll_get_entry_length(tmp_dentry);
+ tmp_dentry = (void *)(result.block.data + offset);
+ tmp_dentry_length =
+ ext4_dir_entry_ll_get_entry_length(tmp_dentry);
+ }
+
+ ext4_assert(tmp_dentry_length + offset == pos);
+
+ /* Add to removed entry length to predecessor's length */
+ uint16_t del_entry_length =
+ ext4_dir_entry_ll_get_entry_length(result.dentry);
+ ext4_dir_entry_ll_set_entry_length(tmp_dentry,
+ tmp_dentry_length + del_entry_length);
+ }
+
+ result.block.dirty = true;
+
+ return ext4_dir_destroy_result(parent, &result);
+}
+
+int ext4_dir_try_insert_entry(struct ext4_sblock *sb,
+ struct ext4_block *target_block, struct ext4_inode_ref *child,
+ const char *name, uint32_t name_len)
+{
+ /* Compute required length entry and align it to 4 bytes */
+ uint32_t block_size = ext4_sb_get_block_size(sb);
+ uint16_t required_len = sizeof(struct ext4_fake_directory_entry) + name_len;
+
+ if ((required_len % 4) != 0)
+ required_len += 4 - (required_len % 4);
+
+ /* Initialize pointers, stop means to upper bound */
+ struct ext4_directory_entry_ll *dentry = (void *)target_block->data;
+ struct ext4_directory_entry_ll *stop =
+ (void *)(target_block->data + block_size);
+
+ /*
+ * Walk through the block and check for invalid entries
+ * or entries with free space for new entry
+ */
+ while (dentry < stop) {
+ uint32_t inode = ext4_dir_entry_ll_get_inode(dentry);
+ uint16_t rec_len = ext4_dir_entry_ll_get_entry_length(dentry);
+
+ /* If invalid and large enough entry, use it */
+ if ((inode == 0) && (rec_len >= required_len)) {
+ ext4_dir_write_entry(sb, dentry, rec_len, child,
+ name, name_len);
+ target_block->dirty = true;
+
+ return EOK;
+ }
+
+ /* Valid entry, try to split it */
+ if (inode != 0) {
+ uint16_t used_name_len =
+ ext4_dir_entry_ll_get_name_length(sb, dentry);
+
+ uint16_t used_space =
+ sizeof(struct ext4_fake_directory_entry) + used_name_len;
+
+ if ((used_name_len % 4) != 0)
+ used_space += 4 - (used_name_len % 4);
+
+ uint16_t free_space = rec_len - used_space;
+
+ /* There is free space for new entry */
+ if (free_space >= required_len) {
+ /* Cut tail of current entry */
+ ext4_dir_entry_ll_set_entry_length(dentry, used_space);
+ struct ext4_directory_entry_ll *new_entry =
+ (void *) dentry + used_space;
+ ext4_dir_write_entry(sb, new_entry,
+ free_space, child, name, name_len);
+
+ target_block->dirty = true;
+
+ return EOK;
+ }
+ }
+
+ /* Jump to the next entry */
+ dentry = (void *) dentry + rec_len;
+ }
+
+ /* No free space found for new entry */
+ return ENOSPC;
+}
+
+
+int ext4_dir_find_in_block(struct ext4_block *block, struct ext4_sblock *sb,
+ size_t name_len, const char *name,
+ struct ext4_directory_entry_ll **res_entry)
+{
+ /* Start from the first entry in block */
+ struct ext4_directory_entry_ll *dentry =
+ (struct ext4_directory_entry_ll *) block->data;
+
+ /* Set upper bound for cycling */
+ uint8_t *addr_limit = block->data + ext4_sb_get_block_size(sb);
+
+ /* Walk through the block and check entries */
+ while ((uint8_t *) dentry < addr_limit) {
+ /* Termination condition */
+ if ((uint8_t *) dentry + name_len > addr_limit)
+ break;
+
+ /* Valid entry - check it */
+ if (dentry->inode != 0) {
+ /* For more effectivity compare firstly only lengths */
+ if (ext4_dir_entry_ll_get_name_length(sb, dentry) ==
+ name_len) {
+ /* Compare names */
+ if (memcmp((uint8_t *) name, dentry->name, name_len) == 0) {
+ *res_entry = dentry;
+ return EOK;
+ }
+ }
+ }
+
+ uint16_t dentry_len =
+ ext4_dir_entry_ll_get_entry_length(dentry);
+
+ /* Corrupted entry */
+ if (dentry_len == 0)
+ return EINVAL;
+
+ /* Jump to next entry */
+ dentry = (struct ext4_directory_entry_ll *)
+ ((uint8_t *) dentry + dentry_len);
+ }
+
+ /* Entry not found */
+ return ENOENT;
+}
+
+int ext4_dir_destroy_result(struct ext4_inode_ref *parent,
+ struct ext4_directory_search_result *result)
+{
+ if (result->block.lb_id)
+ return ext4_block_set(parent->fs->bdev, &result->block);
+
+ return EOK;
+}
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/lwext4/ext4_dir.h
@@ -1,0 +1,114 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_dir.h
+ * @brief Directory handle procedures.
+ */
+
+#ifndef EXT4_DIR_H_
+#define EXT4_DIR_H_
+
+#include <ext4_config.h>
+#include <ext4_types.h>
+#include <ext4_blockdev.h>
+#include <ext4_super.h>
+
+
+#include <stdint.h>
+
+uint32_t ext4_dir_entry_ll_get_inode(struct ext4_directory_entry_ll *de);
+
+void ext4_dir_entry_ll_set_inode(struct ext4_directory_entry_ll *de,
+ uint32_t inode);
+
+
+uint16_t ext4_dir_entry_ll_get_entry_length(struct ext4_directory_entry_ll *de);
+void ext4_dir_entry_ll_set_entry_length(struct ext4_directory_entry_ll *de,
+ uint16_t len);
+
+
+uint16_t ext4_dir_entry_ll_get_name_length(struct ext4_sblock *sb,
+ struct ext4_directory_entry_ll *de);
+void ext4_dir_entry_ll_set_name_length(struct ext4_sblock *sb,
+ struct ext4_directory_entry_ll *de, uint16_t len);
+
+
+
+uint8_t ext4_dir_entry_ll_get_inode_type(struct ext4_sblock *sb,
+ struct ext4_directory_entry_ll *de);
+void ext4_dir_entry_ll_set_inode_type(struct ext4_sblock *sb,
+ struct ext4_directory_entry_ll *de, uint8_t type);
+
+
+int ext4_dir_iterator_init(struct ext4_directory_iterator *it,
+ struct ext4_inode_ref *inode_ref, uint64_t pos);
+
+int ext4_dir_iterator_next(struct ext4_directory_iterator *it);
+int ext4_dir_iterator_fini(struct ext4_directory_iterator *it);
+
+void ext4_dir_write_entry(struct ext4_sblock *sb,
+ struct ext4_directory_entry_ll *entry, uint16_t entry_len,
+ struct ext4_inode_ref *child, const char *name, size_t name_len);
+
+int ext4_dir_add_entry(struct ext4_inode_ref *parent, const char *name,
+ uint32_t name_len, struct ext4_inode_ref *child);
+
+int ext4_dir_find_entry(struct ext4_directory_search_result *result,
+ struct ext4_inode_ref *parent, const char *name, uint32_t name_len);
+
+int ext4_dir_remove_entry(struct ext4_inode_ref *parent, const char *name,
+ uint32_t name_len);
+
+int ext4_dir_try_insert_entry(struct ext4_sblock *sb,
+ struct ext4_block *target_block, struct ext4_inode_ref *child,
+ const char *name, uint32_t name_len);
+
+int ext4_dir_find_in_block(struct ext4_block *block, struct ext4_sblock *sb,
+ size_t name_len, const char *name,
+ struct ext4_directory_entry_ll **res_entry);
+
+int ext4_dir_destroy_result(struct ext4_inode_ref *parent,
+ struct ext4_directory_search_result *result);
+
+
+#endif /* EXT4_DIR_H_ */
+
+/**
+ * @}
+ */
+
+
--- /dev/null
+++ b/lwext4/ext4_dir_idx.c
@@ -1,0 +1,1016 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_dir_idx.c
+ * @brief Directory indexing procedures.
+ */
+
+#include <ext4_config.h>
+#include <ext4_dir_idx.h>
+#include <ext4_dir.h>
+#include <ext4_blockdev.h>
+#include <ext4_fs.h>
+#include <ext4_super.h>
+#include <ext4_hash.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+struct ext4_dx_sort_entry {
+ uint32_t hash;
+ uint32_t rec_len;
+ void *dentry;
+};
+
+static int ext4_dir_dx_hash_string(struct ext4_hash_info *hinfo, int len,
+ const char *name)
+{
+ return ext2_htree_hash(name, len, hinfo->seed, hinfo->hash_version,
+ &hinfo->hash, &hinfo->minor_hash);
+}
+
+
+uint8_t ext4_dir_dx_root_info_get_hash_version(
+ struct ext4_directory_dx_root_info *root_info)
+{
+ return root_info->hash_version;
+}
+
+
+void ext4_dir_dx_root_info_set_hash_version(
+ struct ext4_directory_dx_root_info *root_info, uint8_t v)
+{
+ root_info->hash_version = v;
+}
+
+uint8_t ext4_dir_dx_root_info_get_info_length(
+ struct ext4_directory_dx_root_info *root_info)
+{
+ return root_info->info_length;
+}
+void ext4_dir_dx_root_info_set_info_length(
+ struct ext4_directory_dx_root_info *root_info, uint8_t len)
+{
+ root_info->info_length = len;
+}
+
+uint8_t ext4_dir_dx_root_info_get_indirect_levels(
+ struct ext4_directory_dx_root_info *root_info)
+{
+ return root_info->indirect_levels;
+}
+
+void ext4_dir_dx_root_info_set_indirect_levels(
+ struct ext4_directory_dx_root_info *root_info, uint8_t lvl)
+{
+ root_info->indirect_levels = lvl;
+}
+
+
+
+uint16_t ext4_dir_dx_countlimit_get_limit(
+ struct ext4_directory_dx_countlimit *climit)
+{
+ return to_le16(climit->limit);
+}
+void ext4_dir_dx_countlimit_set_limit(
+ struct ext4_directory_dx_countlimit *climit, uint16_t limit)
+{
+ climit->limit = to_le16(limit);
+}
+
+uint16_t ext4_dir_dx_countlimit_get_count(
+ struct ext4_directory_dx_countlimit *climit)
+{
+ return to_le16(climit->count);
+}
+
+void ext4_dir_dx_countlimit_set_count(
+ struct ext4_directory_dx_countlimit *climit, uint16_t count)
+{
+ climit->count = to_le16(count);
+}
+
+
+uint32_t ext4_dir_dx_entry_get_hash(
+ struct ext4_directory_dx_entry *entry)
+{
+ return to_le32(entry->hash);
+}
+void ext4_dir_dx_entry_set_hash(
+ struct ext4_directory_dx_entry *entry, uint32_t hash)
+{
+ entry->hash = to_le32(hash);
+}
+
+uint32_t ext4_dir_dx_entry_get_block(
+ struct ext4_directory_dx_entry *entry)
+{
+ return to_le32(entry->block);
+}
+void ext4_dir_dx_entry_set_block(
+ struct ext4_directory_dx_entry *entry, uint32_t block)
+{
+ entry->block = to_le32(block);
+}
+/****************************************************************************/
+
+int ext4_dir_dx_init(struct ext4_inode_ref *dir)
+{
+ /* Load block 0, where will be index root located */
+ uint32_t fblock;
+ int rc = ext4_fs_get_inode_data_block_index(dir, 0,
+ &fblock);
+ if (rc != EOK)
+ return rc;
+
+ struct ext4_block block;
+ rc = ext4_block_get(dir->fs->bdev, &block, fblock);
+ if (rc != EOK)
+ return rc;
+
+ /* Initialize pointers to data structures */
+ struct ext4_directory_dx_root *root = (void *)block.data;
+ struct ext4_directory_dx_root_info *info = &(root->info);
+
+ /* Initialize root info structure */
+ uint8_t hash_version = ext4_get8(&dir->fs->sb, default_hash_version);
+
+
+ ext4_dir_dx_root_info_set_hash_version(info, hash_version);
+ ext4_dir_dx_root_info_set_indirect_levels(info, 0);
+ ext4_dir_dx_root_info_set_info_length(info, 8);
+
+ /* Set limit and current number of entries */
+ struct ext4_directory_dx_countlimit *countlimit =
+ (struct ext4_directory_dx_countlimit *) &root->entries;
+
+ ext4_dir_dx_countlimit_set_count(countlimit, 1);
+
+ uint32_t block_size =
+ ext4_sb_get_block_size(&dir->fs->sb);
+ uint32_t entry_space =
+ block_size - 2 * sizeof(struct ext4_directory_dx_dot_entry) -
+ sizeof(struct ext4_directory_dx_root_info);
+ uint16_t root_limit = entry_space / sizeof(struct ext4_directory_dx_entry);
+ ext4_dir_dx_countlimit_set_limit(countlimit, root_limit);
+
+ /* Append new block, where will be new entries inserted in the future */
+ uint32_t iblock;
+ rc = ext4_fs_append_inode_block(dir, &fblock, &iblock);
+ if (rc != EOK) {
+ ext4_block_set(dir->fs->bdev, &block);
+ return rc;
+ }
+
+ struct ext4_block new_block;
+
+ rc = ext4_block_get(dir->fs->bdev, &new_block, fblock);
+ if (rc != EOK) {
+ ext4_block_set(dir->fs->bdev, &block);
+ return rc;
+ }
+
+ /* Fill the whole block with empty entry */
+ struct ext4_directory_entry_ll *block_entry = (void *)new_block.data;
+
+ ext4_dir_entry_ll_set_entry_length(block_entry, block_size);
+ ext4_dir_entry_ll_set_inode(block_entry, 0);
+
+ new_block.dirty = true;
+ rc = ext4_block_set(dir->fs->bdev, &new_block);
+ if (rc != EOK) {
+ ext4_block_set(dir->fs->bdev, &block);
+ return rc;
+ }
+
+ /* Connect new block to the only entry in index */
+ struct ext4_directory_dx_entry *entry = root->entries;
+ ext4_dir_dx_entry_set_block(entry, iblock);
+
+ block.dirty = true;
+
+ return ext4_block_set(dir->fs->bdev, &block);
+}
+
+static int ext4_dir_hinfo_init(struct ext4_hash_info *hinfo,
+ struct ext4_block *root_block, struct ext4_sblock *sb, size_t name_len,
+ const char *name)
+{
+ struct ext4_directory_dx_root *root =
+ (struct ext4_directory_dx_root *) root_block->data;
+
+ if ((root->info.hash_version != EXT2_HTREE_LEGACY) &&
+ (root->info.hash_version != EXT2_HTREE_HALF_MD4) &&
+ (root->info.hash_version != EXT2_HTREE_TEA))
+ return EXT4_ERR_BAD_DX_DIR;
+
+ /* Check unused flags */
+ if (root->info.unused_flags != 0)
+ return EXT4_ERR_BAD_DX_DIR;
+
+ /* Check indirect levels */
+ if (root->info.indirect_levels > 1)
+ return EXT4_ERR_BAD_DX_DIR;
+
+ /* Check if node limit is correct */
+ uint32_t block_size = ext4_sb_get_block_size(sb);
+ uint32_t entry_space = block_size;
+ entry_space -= 2 * sizeof(struct ext4_directory_dx_dot_entry);
+ entry_space -= sizeof(struct ext4_directory_dx_root_info);
+ entry_space = entry_space / sizeof(struct ext4_directory_dx_entry);
+
+ uint16_t limit = ext4_dir_dx_countlimit_get_limit(
+ (struct ext4_directory_dx_countlimit *) &root->entries);
+ if (limit != entry_space)
+ return EXT4_ERR_BAD_DX_DIR;
+
+ /* Check hash version and modify if necessary */
+ hinfo->hash_version =
+ ext4_dir_dx_root_info_get_hash_version(&root->info);
+ if ((hinfo->hash_version <= EXT2_HTREE_TEA) &&
+ (ext4_sb_check_flag(sb, EXT4_SUPERBLOCK_FLAGS_UNSIGNED_HASH))) {
+ /* Use unsigned hash */
+ hinfo->hash_version += 3;
+ }
+
+ /* Load hash seed from superblock */
+
+ hinfo->seed = ext4_get8(sb, hash_seed);
+
+ /* Compute hash value of name */
+ if (name)
+ return ext4_dir_dx_hash_string(hinfo, name_len, name);
+
+ return EOK;
+}
+
+
+static int ext4_dir_dx_get_leaf(struct ext4_hash_info *hinfo,
+ struct ext4_inode_ref *inode_ref, struct ext4_block *root_block,
+ struct ext4_directory_dx_block **dx_block,
+ struct ext4_directory_dx_block *dx_blocks)
+{
+ struct ext4_directory_dx_block *tmp_dx_block = dx_blocks;
+ struct ext4_directory_dx_root *root =
+ (struct ext4_directory_dx_root *) root_block->data;
+ struct ext4_directory_dx_entry *entries =
+ (struct ext4_directory_dx_entry *) &root->entries;
+
+ uint16_t limit = ext4_dir_dx_countlimit_get_limit(
+ (struct ext4_directory_dx_countlimit *) entries);
+ uint8_t indirect_level =
+ ext4_dir_dx_root_info_get_indirect_levels(&root->info);
+
+ struct ext4_block *tmp_block = root_block;
+ struct ext4_directory_dx_entry *p;
+ struct ext4_directory_dx_entry *q;
+ struct ext4_directory_dx_entry *m;
+ struct ext4_directory_dx_entry *at;
+
+ /* Walk through the index tree */
+ while (true) {
+ uint16_t count = ext4_dir_dx_countlimit_get_count(
+ (struct ext4_directory_dx_countlimit *) entries);
+ if ((count == 0) || (count > limit))
+ return EXT4_ERR_BAD_DX_DIR;
+
+ /* Do binary search in every node */
+ p = entries + 1;
+ q = entries + count - 1;
+
+ while (p <= q) {
+ m = p + (q - p) / 2;
+ if (ext4_dir_dx_entry_get_hash(m) > hinfo->hash)
+ q = m - 1;
+ else
+ p = m + 1;
+ }
+
+ at = p - 1;
+
+ /* Write results */
+
+ memcpy(&tmp_dx_block->block, tmp_block, sizeof(struct ext4_block));
+ tmp_dx_block->entries = entries;
+ tmp_dx_block->position = at;
+
+ /* Is algorithm in the leaf? */
+ if (indirect_level == 0) {
+ *dx_block = tmp_dx_block;
+ return EOK;
+ }
+
+ /* Goto child node */
+ uint32_t next_block = ext4_dir_dx_entry_get_block(at);
+
+ indirect_level--;
+
+ uint32_t fblock;
+ int rc = ext4_fs_get_inode_data_block_index(inode_ref,
+ next_block, &fblock);
+ if (rc != EOK)
+ return rc;
+
+ rc = ext4_block_get(inode_ref->fs->bdev, tmp_block, fblock);
+ if (rc != EOK)
+ return rc;
+
+ entries = ((struct ext4_directory_dx_node *) tmp_block->data)->entries;
+ limit = ext4_dir_dx_countlimit_get_limit(
+ (struct ext4_directory_dx_countlimit *) entries);
+
+ uint16_t entry_space =
+ ext4_sb_get_block_size(&inode_ref->fs->sb) -
+ sizeof(struct ext4_directory_dx_dot_entry);
+
+ entry_space = entry_space / sizeof(struct ext4_directory_dx_entry);
+
+ if (limit != entry_space) {
+ ext4_block_set(inode_ref->fs->bdev, tmp_block);
+ return EXT4_ERR_BAD_DX_DIR;
+ }
+
+ ++tmp_dx_block;
+ }
+
+ /* Unreachable */
+ return EOK;
+}
+
+static int ext4_dir_dx_next_block(struct ext4_inode_ref *inode_ref,
+ uint32_t hash, struct ext4_directory_dx_block *dx_block,
+ struct ext4_directory_dx_block *dx_blocks)
+{
+ uint32_t num_handles = 0;
+ struct ext4_directory_dx_block *p = dx_block;
+
+ /* Try to find data block with next bunch of entries */
+ while (true) {
+ p->position++;
+ uint16_t count = ext4_dir_dx_countlimit_get_count(
+ (struct ext4_directory_dx_countlimit *) p->entries);
+
+ if (p->position < p->entries + count)
+ break;
+
+ if (p == dx_blocks)
+ return EOK;
+
+ num_handles++;
+ p--;
+ }
+
+ /* Check hash collision (if not occured - no next block cannot be used)*/
+ uint32_t current_hash = ext4_dir_dx_entry_get_hash(p->position);
+ if ((hash & 1) == 0) {
+ if ((current_hash & ~1) != hash)
+ return 0;
+ }
+
+ /* Fill new path */
+ while (num_handles--) {
+ uint32_t block_idx =
+ ext4_dir_dx_entry_get_block(p->position);
+ uint32_t block_addr;
+
+ int rc = ext4_fs_get_inode_data_block_index(inode_ref,
+ block_idx, &block_addr);
+ if (rc != EOK)
+ return rc;
+
+
+ struct ext4_block block;
+ rc = ext4_block_get(inode_ref->fs->bdev, &block, block_addr);
+ if (rc != EOK)
+ return rc;
+
+ p++;
+
+ /* Don't forget to put old block (prevent memory leak) */
+ ext4_block_set(inode_ref->fs->bdev, &p->block);
+
+
+
+ memcpy(&p->block, &p->block, sizeof(block));
+ p->entries = ((struct ext4_directory_dx_node *) block.data)->entries;
+ p->position = p->entries;
+ }
+
+ return ENOENT;
+}
+
+
+
+int ext4_dir_dx_find_entry(struct ext4_directory_search_result * result,
+ struct ext4_inode_ref *inode_ref, size_t name_len, const char *name)
+{
+ /* Load direct block 0 (index root) */
+ uint32_t root_block_addr;
+ int rc = ext4_fs_get_inode_data_block_index(inode_ref, 0,
+ &root_block_addr);
+ if (rc != EOK)
+ return rc;
+
+ struct ext4_fs *fs = inode_ref->fs;
+
+ struct ext4_block root_block;
+ rc = ext4_block_get(fs->bdev, &root_block, root_block_addr);
+ if (rc != EOK)
+ return rc;
+
+ /* Initialize hash info (compute hash value) */
+ struct ext4_hash_info hinfo;
+ rc = ext4_dir_hinfo_init(&hinfo, &root_block, &fs->sb,
+ name_len, name);
+ if (rc != EOK) {
+ ext4_block_set(fs->bdev, &root_block);
+ return EXT4_ERR_BAD_DX_DIR;
+ }
+
+ /*
+ * Hardcoded number 2 means maximum height of index tree,
+ * specified in the Linux driver.
+ */
+ struct ext4_directory_dx_block dx_blocks[2];
+ struct ext4_directory_dx_block *dx_block;
+ struct ext4_directory_dx_block *tmp;
+
+ rc = ext4_dir_dx_get_leaf(&hinfo, inode_ref, &root_block,
+ &dx_block, dx_blocks);
+ if (rc != EOK) {
+ ext4_block_set(fs->bdev, &root_block);
+ return EXT4_ERR_BAD_DX_DIR;
+ }
+
+ do {
+ /* Load leaf block */
+ uint32_t leaf_block_idx =
+ ext4_dir_dx_entry_get_block(dx_block->position);
+ uint32_t leaf_block_addr;
+
+ rc = ext4_fs_get_inode_data_block_index(inode_ref,
+ leaf_block_idx, &leaf_block_addr);
+ if (rc != EOK)
+ goto cleanup;
+
+ struct ext4_block leaf_block;
+ rc = ext4_block_get(fs->bdev, &leaf_block, leaf_block_addr);
+ if (rc != EOK)
+ goto cleanup;
+
+ /* Linear search inside block */
+ struct ext4_directory_entry_ll *res_dentry;
+ rc = ext4_dir_find_in_block(&leaf_block, &fs->sb,
+ name_len, name, &res_dentry);
+
+ /* Found => return it */
+ if (rc == EOK) {
+ result->block = leaf_block;
+ result->dentry = res_dentry;
+ goto cleanup;
+ }
+
+ /* Not found, leave untouched */
+ ext4_block_set(fs->bdev, &leaf_block);
+
+ if (rc != ENOENT)
+ goto cleanup;
+
+ /* check if the next block could be checked */
+ rc = ext4_dir_dx_next_block(inode_ref, hinfo.hash,
+ dx_block, &dx_blocks[0]);
+ if (rc < 0)
+ goto cleanup;
+ } while (rc == ENOENT);
+
+ /* Entry not found */
+ rc = ENOENT;
+
+ cleanup:
+ /* The whole path must be released (preventing memory leak) */
+ tmp = dx_blocks;
+
+ while (tmp <= dx_block) {
+ ext4_block_set(fs->bdev, &tmp->block);
+ ++tmp;
+ }
+
+ return rc;
+}
+
+static int ext4_dir_dx_entry_comparator(const void *arg1, const void *arg2)
+{
+ struct ext4_dx_sort_entry *entry1 = (void *)arg1;
+ struct ext4_dx_sort_entry *entry2 = (void *)arg2;
+
+ if (entry1->hash == entry2->hash)
+ return 0;
+
+ if (entry1->hash < entry2->hash)
+ return -1;
+ else
+ return 1;
+}
+
+static void ext4_dir_dx_insert_entry(
+ struct ext4_directory_dx_block *index_block, uint32_t hash,
+ uint32_t iblock)
+{
+ struct ext4_directory_dx_entry *old_index_entry = index_block->position;
+ struct ext4_directory_dx_entry *new_index_entry = old_index_entry + 1;
+
+ struct ext4_directory_dx_countlimit *countlimit =
+ (struct ext4_directory_dx_countlimit *) index_block->entries;
+ uint32_t count = ext4_dir_dx_countlimit_get_count(countlimit);
+
+ struct ext4_directory_dx_entry *start_index = index_block->entries;
+ size_t bytes = (void *) (start_index + count) - (void *) (new_index_entry);
+
+ memmove(new_index_entry + 1, new_index_entry, bytes);
+
+ ext4_dir_dx_entry_set_block(new_index_entry, iblock);
+ ext4_dir_dx_entry_set_hash(new_index_entry, hash);
+
+ ext4_dir_dx_countlimit_set_count(countlimit, count + 1);
+
+ index_block->block.dirty = true;
+}
+
+static int ext4_dir_dx_split_data(struct ext4_inode_ref *inode_ref,
+ struct ext4_hash_info *hinfo, struct ext4_block *old_data_block,
+ struct ext4_directory_dx_block *index_block,
+ struct ext4_block *new_data_block)
+{
+ int rc = EOK;
+
+ /* Allocate buffer for directory entries */
+ uint32_t block_size =
+ ext4_sb_get_block_size(&inode_ref->fs->sb);
+
+ void *entry_buffer = malloc(block_size);
+ if (entry_buffer == NULL)
+ return ENOMEM;
+
+ /* dot entry has the smallest size available */
+ uint32_t max_entry_count =
+ block_size / sizeof(struct ext4_directory_dx_dot_entry);
+
+ /* Allocate sort entry */
+ struct ext4_dx_sort_entry *sort_array =
+ malloc(max_entry_count * sizeof(struct ext4_dx_sort_entry));
+
+ if (sort_array == NULL) {
+ free(entry_buffer);
+ return ENOMEM;
+ }
+
+ uint32_t idx = 0;
+ uint32_t real_size = 0;
+
+ /* Initialize hinfo */
+ struct ext4_hash_info tmp_hinfo;
+ memcpy(&tmp_hinfo, hinfo, sizeof(struct ext4_hash_info));
+
+ /* Load all valid entries to the buffer */
+ struct ext4_directory_entry_ll *dentry = (void *)old_data_block->data;
+ void *entry_buffer_ptr = entry_buffer;
+ while ((void *)dentry < (void *)(old_data_block->data + block_size)) {
+ /* Read only valid entries */
+ if (ext4_dir_entry_ll_get_inode(dentry) != 0) {
+ uint8_t len = ext4_dir_entry_ll_get_name_length(
+ &inode_ref->fs->sb, dentry);
+
+ rc = ext4_dir_dx_hash_string(&tmp_hinfo, len, (char*)dentry->name);
+ if(rc != EOK) {
+ free(sort_array);
+ free(entry_buffer);
+ return rc;
+ }
+
+ uint32_t rec_len = 8 + len;
+
+ if ((rec_len % 4) != 0)
+ rec_len += 4 - (rec_len % 4);
+
+ memcpy(entry_buffer_ptr, dentry, rec_len);
+
+ sort_array[idx].dentry = entry_buffer_ptr;
+ sort_array[idx].rec_len = rec_len;
+ sort_array[idx].hash = tmp_hinfo.hash;
+
+ entry_buffer_ptr += rec_len;
+ real_size += rec_len;
+ idx++;
+ }
+
+ dentry = (void *) dentry +
+ ext4_dir_entry_ll_get_entry_length(dentry);
+ }
+
+ /* Sort all entries */
+ qsort(sort_array, idx, sizeof(struct ext4_dx_sort_entry),
+ ext4_dir_dx_entry_comparator);
+
+ /* Allocate new block for store the second part of entries */
+ uint32_t new_fblock;
+ uint32_t new_iblock;
+ rc = ext4_fs_append_inode_block(inode_ref, &new_fblock,
+ &new_iblock);
+ if (rc != EOK) {
+ free(sort_array);
+ free(entry_buffer);
+ return rc;
+ }
+
+ /* Load new block */
+ struct ext4_block new_data_block_tmp;
+ rc = ext4_block_get(inode_ref->fs->bdev, &new_data_block_tmp,
+ new_fblock);
+ if (rc != EOK) {
+ free(sort_array);
+ free(entry_buffer);
+ return rc;
+ }
+
+ /*
+ * Distribute entries to two blocks (by size)
+ * - compute the half
+ */
+ uint32_t new_hash = 0;
+ uint32_t current_size = 0;
+ uint32_t mid = 0;
+ uint32_t i;
+ for ( i = 0; i < idx; ++i) {
+ if ((current_size + sort_array[i].rec_len) > (real_size / 2)) {
+ new_hash = sort_array[i].hash;
+ mid = i;
+ break;
+ }
+
+ current_size += sort_array[i].rec_len;
+ }
+
+ /* Check hash collision */
+ uint32_t continued = 0;
+ if (new_hash == sort_array[mid-1].hash)
+ continued = 1;
+
+ uint32_t offset = 0;
+ void *ptr;
+
+ /* First part - to the old block */
+ for (i = 0; i < mid; ++i) {
+ ptr = old_data_block->data + offset;
+ memcpy(ptr, sort_array[i].dentry, sort_array[i].rec_len);
+
+ struct ext4_directory_entry_ll *tmp = ptr;
+ if (i < (mid - 1))
+ ext4_dir_entry_ll_set_entry_length(tmp,
+ sort_array[i].rec_len);
+ else
+ ext4_dir_entry_ll_set_entry_length(tmp,
+ block_size - offset);
+
+ offset += sort_array[i].rec_len;
+ }
+
+ /* Second part - to the new block */
+ offset = 0;
+ for (i = mid; i < idx; ++i) {
+ ptr = new_data_block_tmp.data + offset;
+ memcpy(ptr, sort_array[i].dentry, sort_array[i].rec_len);
+
+ struct ext4_directory_entry_ll *tmp = ptr;
+ if (i < (idx - 1))
+ ext4_dir_entry_ll_set_entry_length(tmp,
+ sort_array[i].rec_len);
+ else
+ ext4_dir_entry_ll_set_entry_length(tmp,
+ block_size - offset);
+
+ offset += sort_array[i].rec_len;
+ }
+
+ /* Do some steps to finish operation */
+ old_data_block->dirty = true;
+ new_data_block_tmp.dirty = true;
+
+ free(sort_array);
+ free(entry_buffer);
+
+ ext4_dir_dx_insert_entry(index_block, new_hash + continued,
+ new_iblock);
+
+ *new_data_block = new_data_block_tmp;
+
+ return EOK;
+}
+
+/** Split index node and maybe some parent nodes in the tree hierarchy.
+ *
+ * @param inode_ref Directory i-node
+ * @param dx_blocks Array with path from root to leaf node
+ * @param dx_block Leaf block to be split if needed
+ *
+ * @return Error code
+ *
+ */
+static int ext4_dir_dx_split_index(struct ext4_inode_ref *inode_ref,
+ struct ext4_directory_dx_block *dx_blocks,
+ struct ext4_directory_dx_block *dx_block)
+{
+ struct ext4_directory_dx_entry *entries;
+ if (dx_block == dx_blocks)
+ entries =
+ ((struct ext4_directory_dx_root *) dx_block->block.data)->entries;
+ else
+ entries =
+ ((struct ext4_directory_dx_node *) dx_block->block.data)->entries;
+
+ struct ext4_directory_dx_countlimit *countlimit =
+ (struct ext4_directory_dx_countlimit *) entries;
+
+ uint16_t leaf_limit =
+ ext4_dir_dx_countlimit_get_limit(countlimit);
+ uint16_t leaf_count =
+ ext4_dir_dx_countlimit_get_count(countlimit);
+
+ /* Check if is necessary to split index block */
+ if (leaf_limit == leaf_count) {
+ size_t levels = dx_block - dx_blocks;
+
+ struct ext4_directory_dx_entry *root_entries =
+ ((struct ext4_directory_dx_root *) dx_blocks[0].block.data)->entries;
+
+ struct ext4_directory_dx_countlimit *root_countlimit =
+ (struct ext4_directory_dx_countlimit *) root_entries;
+ uint16_t root_limit =
+ ext4_dir_dx_countlimit_get_limit(root_countlimit);
+ uint16_t root_count =
+ ext4_dir_dx_countlimit_get_count(root_countlimit);
+
+ /* Linux limitation */
+ if ((levels > 0) && (root_limit == root_count))
+ return ENOSPC;
+
+ /* Add new block to directory */
+ uint32_t new_fblock;
+ uint32_t new_iblock;
+ int rc = ext4_fs_append_inode_block(inode_ref,
+ &new_fblock, &new_iblock);
+ if (rc != EOK)
+ return rc;
+
+ /* load new block */
+ struct ext4_block new_block;
+ rc = ext4_block_get(inode_ref->fs->bdev, &new_block,
+ new_fblock);
+ if (rc != EOK)
+ return rc;
+
+ struct ext4_directory_dx_node *new_node = (void *)new_block.data;
+ struct ext4_directory_dx_entry *new_entries = new_node->entries;
+
+ uint32_t block_size =
+ ext4_sb_get_block_size(&inode_ref->fs->sb);
+
+ /* Split leaf node */
+ if (levels > 0) {
+ uint32_t count_left = leaf_count / 2;
+ uint32_t count_right = leaf_count - count_left;
+ uint32_t hash_right =
+ ext4_dir_dx_entry_get_hash(entries + count_left);
+
+ /* Copy data to new node */
+ memcpy((void *) new_entries, (void *) (entries + count_left),
+ count_right * sizeof(struct ext4_directory_dx_entry));
+
+ /* Initialize new node */
+ struct ext4_directory_dx_countlimit *left_countlimit =
+ (struct ext4_directory_dx_countlimit *) entries;
+ struct ext4_directory_dx_countlimit *right_countlimit =
+ (struct ext4_directory_dx_countlimit *) new_entries;
+
+ ext4_dir_dx_countlimit_set_count(left_countlimit, count_left);
+ ext4_dir_dx_countlimit_set_count(right_countlimit, count_right);
+
+ uint32_t entry_space =
+ block_size - sizeof(struct ext4_fake_directory_entry);
+ uint32_t node_limit =
+ entry_space / sizeof(struct ext4_directory_dx_entry);
+ ext4_dir_dx_countlimit_set_limit(right_countlimit, node_limit);
+
+ /* Which index block is target for new entry */
+ uint32_t position_index = (dx_block->position - dx_block->entries);
+ if (position_index >= count_left) {
+ dx_block->block.dirty = true;
+
+ struct ext4_block block_tmp = dx_block->block;
+
+
+ dx_block->block = new_block;
+
+ dx_block->position =
+ new_entries + position_index - count_left;
+ dx_block->entries = new_entries;
+
+ new_block = block_tmp;
+ }
+
+ /* Finally insert new entry */
+ ext4_dir_dx_insert_entry(dx_blocks, hash_right, new_iblock);
+
+ return ext4_block_set(inode_ref->fs->bdev, &new_block);
+ } else {
+ /* Create second level index */
+
+ /* Copy data from root to child block */
+ memcpy((void *) new_entries, (void *) entries,
+ leaf_count * sizeof(struct ext4_directory_dx_entry));
+
+ struct ext4_directory_dx_countlimit *new_countlimit =
+ (struct ext4_directory_dx_countlimit *) new_entries;
+
+ uint32_t entry_space =
+ block_size - sizeof(struct ext4_fake_directory_entry);
+ uint32_t node_limit =
+ entry_space / sizeof(struct ext4_directory_dx_entry);
+ ext4_dir_dx_countlimit_set_limit(new_countlimit, node_limit);
+
+ /* Set values in root node */
+ struct ext4_directory_dx_countlimit *new_root_countlimit =
+ (struct ext4_directory_dx_countlimit *) entries;
+
+ ext4_dir_dx_countlimit_set_count(new_root_countlimit, 1);
+ ext4_dir_dx_entry_set_block(entries, new_iblock);
+
+ ((struct ext4_directory_dx_root *)
+ dx_blocks[0].block.data)->info.indirect_levels = 1;
+
+ /* Add new entry to the path */
+ dx_block = dx_blocks + 1;
+ dx_block->position = dx_block->position - entries + new_entries;
+ dx_block->entries = new_entries;
+ dx_block->block = new_block;
+ }
+ }
+
+ return EOK;
+}
+
+int ext4_dir_dx_add_entry(struct ext4_inode_ref *parent,
+ struct ext4_inode_ref *child, const char *name)
+{
+ int rc2 = EOK;
+
+ /* Get direct block 0 (index root) */
+ uint32_t root_block_addr;
+ int rc = ext4_fs_get_inode_data_block_index(parent, 0,
+ &root_block_addr);
+ if (rc != EOK)
+ return rc;
+
+ struct ext4_fs *fs = parent->fs;
+ struct ext4_block root_block;
+
+ rc = ext4_block_get(fs->bdev, &root_block, root_block_addr);
+ if (rc != EOK)
+ return rc;
+
+ /* Initialize hinfo structure (mainly compute hash) */
+ uint32_t name_len = strlen(name);
+ struct ext4_hash_info hinfo;
+ rc = ext4_dir_hinfo_init(&hinfo, &root_block, &fs->sb,
+ name_len, name);
+ if (rc != EOK) {
+ ext4_block_set(fs->bdev, &root_block);
+ return EXT4_ERR_BAD_DX_DIR;
+ }
+
+ /*
+ * Hardcoded number 2 means maximum height of index
+ * tree defined in Linux.
+ */
+ struct ext4_directory_dx_block dx_blocks[2];
+ struct ext4_directory_dx_block *dx_block;
+ struct ext4_directory_dx_block *dx_it;
+
+ rc = ext4_dir_dx_get_leaf(&hinfo, parent, &root_block,
+ &dx_block, dx_blocks);
+ if (rc != EOK) {
+ rc = EXT4_ERR_BAD_DX_DIR;
+ goto release_index;
+ }
+
+ /* Try to insert to existing data block */
+ uint32_t leaf_block_idx =
+ ext4_dir_dx_entry_get_block(dx_block->position);
+ uint32_t leaf_block_addr;
+ rc = ext4_fs_get_inode_data_block_index(parent, leaf_block_idx,
+ &leaf_block_addr);
+ if (rc != EOK)
+ goto release_index;
+
+ struct ext4_block target_block;
+ rc = ext4_block_get(fs->bdev, &target_block, leaf_block_addr);
+ if (rc != EOK)
+ goto release_index;
+
+ /* Check if insert operation passed */
+ rc = ext4_dir_try_insert_entry(&fs->sb, &target_block, child,
+ name, name_len);
+ if (rc == EOK)
+ goto release_target_index;
+
+ /*
+ * Check if there is needed to split index node
+ * (and recursively also parent nodes)
+ */
+ rc = ext4_dir_dx_split_index(parent, dx_blocks, dx_block);
+ if (rc != EOK)
+ goto release_target_index;
+
+ /* Split entries to two blocks (includes sorting by hash value) */
+ struct ext4_block new_block;
+ rc = ext4_dir_dx_split_data(parent, &hinfo, &target_block,
+ dx_block, &new_block);
+ if (rc != EOK) {
+ rc2 = rc;
+ goto release_target_index;
+ }
+
+ /* Where to save new entry */
+ uint32_t new_block_hash =
+ ext4_dir_dx_entry_get_hash(dx_block->position + 1);
+ if (hinfo.hash >= new_block_hash)
+ rc = ext4_dir_try_insert_entry(&fs->sb, &new_block,
+ child, name, name_len);
+ else
+ rc = ext4_dir_try_insert_entry(&fs->sb, &target_block,
+ child, name, name_len);
+
+ /* Cleanup */
+ rc = ext4_block_set(fs->bdev, &new_block);
+ if (rc != EOK)
+ return rc;
+
+ /* Cleanup operations */
+
+ release_target_index:
+ rc2 = rc;
+
+ rc = ext4_block_set(fs->bdev, &target_block);
+ if (rc != EOK)
+ return rc;
+
+ release_index:
+ if (rc != EOK)
+ rc2 = rc;
+
+ dx_it = dx_blocks;
+
+ while (dx_it <= dx_block) {
+ rc = ext4_block_set(fs->bdev, &dx_it->block);
+ if (rc != EOK)
+ return rc;
+
+ dx_it++;
+ }
+
+ return rc2;
+}
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/lwext4/ext4_dir_idx.h
@@ -1,0 +1,103 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_dir_idx.h
+ * @brief Directory indexing procedures.
+ */
+
+#ifndef EXT4_DIR_IDX_H_
+#define EXT4_DIR_IDX_H_
+
+#include <ext4_config.h>
+#include <ext4_types.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+
+uint8_t ext4_dir_dx_root_info_get_hash_version(
+ struct ext4_directory_dx_root_info *root_info);
+void ext4_dir_dx_root_info_set_hash_version(
+ struct ext4_directory_dx_root_info *root_info, uint8_t v);
+
+uint8_t ext4_dir_dx_root_info_get_info_length(
+ struct ext4_directory_dx_root_info *root_info);
+void ext4_dir_dx_root_info_set_info_length(
+ struct ext4_directory_dx_root_info *root_info, uint8_t len);
+
+uint8_t ext4_dir_dx_root_info_get_indirect_levels(
+ struct ext4_directory_dx_root_info *root_info);
+void ext4_dir_dx_root_info_set_indirect_levels(
+ struct ext4_directory_dx_root_info *root_info, uint8_t lvl);
+
+
+
+uint16_t ext4_dir_dx_countlimit_get_limit(
+ struct ext4_directory_dx_countlimit *climit);
+void ext4_dir_dx_countlimit_set_limit(
+ struct ext4_directory_dx_countlimit *climit, uint16_t limit);
+
+uint16_t ext4_dir_dx_countlimit_get_count(
+ struct ext4_directory_dx_countlimit *climit);
+void ext4_dir_dx_countlimit_set_count(
+ struct ext4_directory_dx_countlimit *climit, uint16_t count);
+
+
+uint32_t ext4_dir_dx_entry_get_hash(
+ struct ext4_directory_dx_entry *entry);
+void ext4_dir_dx_entry_set_hash(
+ struct ext4_directory_dx_entry *entry, uint32_t hash);
+
+uint32_t ext4_dir_dx_entry_get_block(
+ struct ext4_directory_dx_entry *entry);
+void ext4_dir_dx_entry_set_block(
+ struct ext4_directory_dx_entry *entry, uint32_t block);
+
+
+int ext4_dir_dx_init(struct ext4_inode_ref *dir);
+
+int ext4_dir_dx_find_entry(struct ext4_directory_search_result * result,
+ struct ext4_inode_ref *inode_ref, size_t name_len, const char *name);
+
+int ext4_dir_dx_add_entry(struct ext4_inode_ref *parent,
+ struct ext4_inode_ref *child, const char *name);
+
+#endif /* EXT4_DIR_IDX_H_ */
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/lwext4/ext4_errno.h
@@ -1,0 +1,92 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_errno.h
+ * @brief Error codes.
+ */
+#ifndef EXT4_ERRNO_H_
+#define EXT4_ERRNO_H_
+
+#include <ext4_config.h>
+
+#ifndef CONFIG_HAVE_OWN_ERRNO
+#include <errno.h>
+#else
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* I/O error */
+#define ENXIO 6 /* No such device or address */
+#define E2BIG 7 /* Argument list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file number */
+#define ECHILD 10 /* No child processes */
+#define EAGAIN 11 /* Try again */
+#define ENOMEM 12 /* Out of memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#define ENOTBLK 15 /* Block device required */
+#define EBUSY 16 /* Device or resource busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* No such device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* File table overflow */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Not a typewriter */
+#define ETXTBSY 26 /* Text file busy */
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+#define EDOM 33 /* Math argument out of domain of func */
+#define ERANGE 34 /* Math result not representable */
+
+#define ENOTSUP 95
+#endif
+
+/**@brief OK return value*/
+#ifndef EOK
+#define EOK 0
+#endif
+
+#endif /* EXT4_ERRNO_H_ */
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/lwext4/ext4_fs.c
@@ -1,0 +1,1189 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_fs.c
+ * @brief More complex filesystem functions.
+ */
+
+#include <ext4_config.h>
+#include <ext4_types.h>
+#include <ext4_fs.h>
+#include <ext4_errno.h>
+#include <ext4_blockdev.h>
+#include <ext4_super.h>
+#include <ext4_debug.h>
+#include <ext4_block_group.h>
+#include <ext4_balloc.h>
+#include <ext4_bitmap.h>
+#include <ext4_inode.h>
+#include <ext4_ialloc.h>
+#include <string.h>
+
+int ext4_fs_init(struct ext4_fs *fs, struct ext4_blockdev *bdev)
+{
+ int r, i;
+ uint16_t tmp;
+ uint32_t bsize;
+ bool read_only = false;
+
+ ext4_assert(fs && bdev);
+
+ fs->bdev = bdev;
+
+ r = ext4_sb_read(fs->bdev, &fs->sb);
+ if(r != EOK)
+ return r;
+
+ if(!ext4_sb_check(&fs->sb))
+ return ENOTSUP;
+
+ bsize = ext4_sb_get_block_size(&fs->sb);
+ if (bsize > EXT4_MAX_BLOCK_SIZE)
+ return ENXIO;
+
+ r = ext4_fs_check_features(fs, &read_only);
+ if(r != EOK)
+ return r;
+
+ if(read_only)
+ return ENOTSUP;
+
+ /* Compute limits for indirect block levels */
+ uint32_t blocks_id = bsize / sizeof(uint32_t);
+
+ fs->inode_block_limits[0] = EXT4_INODE_DIRECT_BLOCK_COUNT;
+ fs->inode_blocks_per_level[0] = 1;
+
+ for (i = 1; i < 4; i++) {
+ fs->inode_blocks_per_level[i] = fs->inode_blocks_per_level[i - 1] *
+ blocks_id;
+ fs->inode_block_limits[i] = fs->inode_block_limits[i - 1] +
+ fs->inode_blocks_per_level[i];
+ }
+
+ /*Validate FS*/
+ tmp = ext4_get16(&fs->sb, state);
+ if (tmp & EXT4_SUPERBLOCK_STATE_ERROR_FS) {
+ ext4_dprintf(EXT4_DEBUG_FS,
+ "Filesystem was not cleanly unmounted before \n");
+ }
+
+ /* Mark system as mounted */
+ ext4_set16(&fs->sb, state, EXT4_SUPERBLOCK_STATE_ERROR_FS);
+ r = ext4_sb_write(fs->bdev, &fs->sb);
+ if (r != EOK)
+ return r;
+
+
+ /*Update mount count*/
+ ext4_set16(&fs->sb, mount_count, ext4_get16(&fs->sb, mount_count) + 1);
+
+ return r;
+}
+
+
+int ext4_fs_fini(struct ext4_fs *fs)
+{
+ ext4_assert(fs);
+
+ /*Set superblock state*/
+ ext4_set16(&fs->sb, state, EXT4_SUPERBLOCK_STATE_VALID_FS);
+
+ return ext4_sb_write(fs->bdev, &fs->sb);
+}
+
+int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only)
+{
+ ext4_assert(fs && read_only);
+
+ if(ext4_get32(&fs->sb, rev_level) == 0){
+ *read_only = false;
+ return EOK;
+ }
+
+ /*Check features_incompatible*/
+ if ((ext4_get32(&fs->sb, features_incompatible) &
+ (~EXT4_FEATURE_INCOMPAT_SUPP)) )
+ return ENOTSUP;
+
+
+ /*Check features_read_only*/
+ if ((ext4_get32(&fs->sb, features_read_only) &
+ (~EXT4_FEATURE_RO_COMPAT_SUPP))){
+ *read_only = true;
+ return EOK;
+ }
+
+ *read_only = false;
+
+ return EOK;
+}
+
+uint32_t ext4_fs_baddr2_index_in_group(struct ext4_sblock *s, uint32_t baddr)
+{
+ ext4_assert(baddr);
+ if(ext4_get32(s, first_data_block))
+ baddr--;
+
+ return baddr % ext4_get32(s, blocks_per_group);
+}
+
+
+
+uint32_t ext4_fs_index_in_group2_baddr(struct ext4_sblock *s, uint32_t index,
+ uint32_t bgid)
+{
+ if(ext4_get32(s, first_data_block))
+ index++;
+
+ return ext4_get32(s, blocks_per_group) * bgid + index;
+}
+
+
+
+
+static int ext4_fs_init_block_bitmap(struct ext4_block_group_ref *bg_ref)
+{
+ uint32_t i;
+ uint32_t bitmap_block_addr = ext4_bg_get_block_bitmap(
+ bg_ref->block_group, &bg_ref->fs->sb);
+
+ struct ext4_block block_bitmap;
+ int rc = ext4_block_get(bg_ref->fs->bdev, &block_bitmap,
+ bitmap_block_addr);
+ if (rc != EOK)
+ return rc;
+
+
+ memset(block_bitmap.data, 0, ext4_sb_get_block_size(&bg_ref->fs->sb));
+
+ /* Determine first block and first data block in group */
+ uint32_t first_idx = 0;
+
+ uint32_t first_data = ext4_balloc_get_first_data_block_in_group(
+ &bg_ref->fs->sb, bg_ref);
+ uint32_t first_data_idx = ext4_fs_baddr2_index_in_group(
+ &bg_ref->fs->sb, first_data);
+
+ /*Set bits from to first block to first data block - 1 to one (allocated)*/
+ /*TODO: Optimize it*/
+ for (i = first_idx; i < first_data_idx; ++i)
+ ext4_bmap_bit_set(block_bitmap.data, i);
+
+
+ block_bitmap.dirty = true;
+
+ /* Save bitmap */
+ return ext4_block_set(bg_ref->fs->bdev, &block_bitmap);
+}
+
+static int ext4_fs_init_inode_bitmap(struct ext4_block_group_ref *bg_ref)
+{
+ /* Load bitmap */
+ uint32_t bitmap_block_addr = ext4_bg_get_inode_bitmap(
+ bg_ref->block_group, &bg_ref->fs->sb);
+
+ struct ext4_block block_bitmap;
+ int rc = ext4_block_get(bg_ref->fs->bdev, &block_bitmap,
+ bitmap_block_addr);
+ if (rc != EOK)
+ return rc;
+
+ /* Initialize all bitmap bits to zero */
+ uint32_t block_size = ext4_sb_get_block_size(&bg_ref->fs->sb);
+ uint32_t inodes_per_group = ext4_get32(&bg_ref->fs->sb, inodes_per_group);
+
+ memset(block_bitmap.data, 0, (inodes_per_group + 7) / 8);
+
+ uint32_t start_bit = inodes_per_group;
+ uint32_t end_bit = block_size * 8;
+
+ uint32_t i;
+ for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++)
+ ext4_bmap_bit_set(block_bitmap.data, i);
+
+ if (i < end_bit)
+ memset(block_bitmap.data + (i >> 3), 0xff, (end_bit - i) >> 3);
+
+ block_bitmap.dirty = true;
+
+ /* Save bitmap */
+ return ext4_block_set(bg_ref->fs->bdev, &block_bitmap);
+}
+
+static int ext4_fs_init_inode_table(struct ext4_block_group_ref *bg_ref)
+{
+ struct ext4_sblock *sb = &bg_ref->fs->sb;
+
+ uint32_t inode_size = ext4_get32(sb, inode_size);
+ uint32_t block_size = ext4_sb_get_block_size(sb);
+ uint32_t inodes_per_block = block_size / inode_size;
+ uint32_t inodes_in_group = ext4_inodes_in_group_cnt(sb, bg_ref->index);
+ uint32_t table_blocks = inodes_in_group / inodes_per_block;
+ uint32_t fblock;
+
+ if (inodes_in_group % inodes_per_block)
+ table_blocks++;
+
+ /* Compute initialization bounds */
+ uint32_t first_block = ext4_bg_get_inode_table_first_block(
+ bg_ref->block_group, sb);
+
+ uint32_t last_block = first_block + table_blocks - 1;
+
+ /* Initialization of all itable blocks */
+ for (fblock = first_block; fblock <= last_block; ++fblock) {
+
+ struct ext4_block block;
+ int rc = ext4_block_get(bg_ref->fs->bdev, &block, fblock);
+ if (rc != EOK)
+ return rc;
+
+ memset(block.data, 0, block_size);
+ block.dirty = true;
+
+ ext4_block_set(bg_ref->fs->bdev, &block);
+ if (rc != EOK)
+ return rc;
+ }
+
+ return EOK;
+}
+
+
+int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid,
+ struct ext4_block_group_ref *ref)
+{
+ /* Compute number of descriptors, that fits in one data block */
+ uint32_t dsc_per_block = ext4_sb_get_block_size(&fs->sb) /
+ ext4_sb_get_desc_size(&fs->sb);
+
+ /* Block group descriptor table starts at the next block after superblock */
+ uint64_t block_id = ext4_get32(&fs->sb, first_data_block) + 1;
+
+ /* Find the block containing the descriptor we are looking for */
+ block_id += bgid / dsc_per_block;
+ uint32_t offset = (bgid % dsc_per_block) *
+ ext4_sb_get_desc_size(&fs->sb);
+
+
+ int rc = ext4_block_get(fs->bdev, &ref->block, block_id);
+ if (rc != EOK)
+ return rc;
+
+ ref->block_group = (void *)(ref->block.data + offset);
+ ref->fs = fs;
+ ref->index = bgid;
+ ref->dirty = false;
+
+ if (ext4_bg_has_flag(ref->block_group,
+ EXT4_BLOCK_GROUP_BLOCK_UNINIT)) {
+ rc = ext4_fs_init_block_bitmap(ref);
+ if (rc != EOK) {
+ ext4_block_set(fs->bdev, &ref->block);
+ return rc;
+ }
+ ext4_bg_clear_flag(ref->block_group,
+ EXT4_BLOCK_GROUP_BLOCK_UNINIT);
+
+ ref->dirty = true;
+ }
+
+ if (ext4_bg_has_flag(ref->block_group,
+ EXT4_BLOCK_GROUP_INODE_UNINIT)) {
+ rc = ext4_fs_init_inode_bitmap(ref);
+ if (rc != EOK) {
+ ext4_block_set(ref->fs->bdev, &ref->block);
+ return rc;
+ }
+
+ ext4_bg_clear_flag(ref->block_group,
+ EXT4_BLOCK_GROUP_INODE_UNINIT);
+
+ if (!ext4_bg_has_flag(ref->block_group,
+ EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
+ rc = ext4_fs_init_inode_table(ref);
+ if (rc != EOK){
+ ext4_block_set(fs->bdev, &ref->block);
+ return rc;
+ }
+
+ ext4_bg_set_flag(ref->block_group,
+ EXT4_BLOCK_GROUP_ITABLE_ZEROED);
+ }
+
+ ref->dirty = true;
+ }
+
+ return EOK;
+}
+
+static uint16_t ext4_fs_bg_checksum(struct ext4_sblock *sb, uint32_t bgid,
+ struct ext4_bgroup *bg)
+{
+ /* If checksum not supported, 0 will be returned */
+ uint16_t crc = 0;
+
+ /* Compute the checksum only if the filesystem supports it */
+ if (ext4_sb_check_read_only(sb,
+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+ void *base = bg;
+ void *checksum = &bg->checksum;
+
+ uint32_t offset = (uint32_t) (checksum - base);
+
+ /* Convert block group index to little endian */
+ uint32_t le_group = to_le32(bgid);
+
+ /* Initialization */
+ crc = ext4_bg_crc16(~0, sb->uuid, sizeof(sb->uuid));
+
+ /* Include index of block group */
+ crc = ext4_bg_crc16(crc, (uint8_t *) &le_group, sizeof(le_group));
+
+ /* Compute crc from the first part (stop before checksum field) */
+ crc = ext4_bg_crc16(crc, (uint8_t *) bg, offset);
+
+ /* Skip checksum */
+ offset += sizeof(bg->checksum);
+
+ /* Checksum of the rest of block group descriptor */
+ if ((ext4_sb_check_feature_incompatible(sb,
+ EXT4_FEATURE_INCOMPAT_64BIT)) &&
+ (offset < ext4_sb_get_desc_size(sb)))
+
+ crc = ext4_bg_crc16(crc, ((uint8_t *) bg) + offset,
+ ext4_sb_get_desc_size(sb) - offset);
+ }
+ return crc;
+}
+
+int ext4_fs_put_block_group_ref(struct ext4_block_group_ref *ref)
+{
+ /* Check if reference modified */
+ if (ref->dirty) {
+ /* Compute new checksum of block group */
+ uint16_t checksum =
+ ext4_fs_bg_checksum(&ref->fs->sb, ref->index,
+ ref->block_group);
+
+ ref->block_group->checksum = to_le16(checksum);
+
+ /* Mark block dirty for writing changes to physical device */
+ ref->block.dirty = true;
+ }
+
+ /* Put back block, that contains block group descriptor */
+ return ext4_block_set(ref->fs->bdev, &ref->block);
+}
+
+int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index,
+ struct ext4_inode_ref *ref)
+{
+ /* Compute number of i-nodes, that fits in one data block */
+ uint32_t inodes_per_group = ext4_get32(&fs->sb, inodes_per_group);
+
+ /*
+ * Inode numbers are 1-based, but it is simpler to work with 0-based
+ * when computing indices
+ */
+ index -= 1;
+ uint32_t block_group = index / inodes_per_group;
+ uint32_t offset_in_group = index % inodes_per_group;
+
+ /* Load block group, where i-node is located */
+ struct ext4_block_group_ref bg_ref;
+
+ int rc = ext4_fs_get_block_group_ref(fs, block_group, &bg_ref);
+ if (rc != EOK) {
+ return rc;
+ }
+
+ /* Load block address, where i-node table is located */
+ uint32_t inode_table_start =
+ ext4_bg_get_inode_table_first_block(bg_ref.block_group,
+ &fs->sb);
+
+ /* Put back block group reference (not needed more) */
+ rc = ext4_fs_put_block_group_ref(&bg_ref);
+ if (rc != EOK) {
+ return rc;
+ }
+
+ /* Compute position of i-node in the block group */
+ uint16_t inode_size = ext4_get16(&fs->sb, inode_size);
+ uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
+ uint32_t byte_offset_in_group = offset_in_group * inode_size;
+
+ /* Compute block address */
+ uint64_t block_id = inode_table_start +
+ (byte_offset_in_group / block_size);
+
+
+ rc = ext4_block_get(fs->bdev, &ref->block, block_id);
+ if (rc != EOK) {
+ return rc;
+ }
+
+ /* Compute position of i-node in the data block */
+ uint32_t offset_in_block = byte_offset_in_group % block_size;
+ ref->inode = (struct ext4_inode *)(ref->block.data + offset_in_block);
+
+ /* We need to store the original value of index in the reference */
+ ref->index = index + 1;
+ ref->fs = fs;
+ ref->dirty = false;
+
+ return EOK;
+}
+
+int ext4_fs_put_inode_ref(struct ext4_inode_ref *ref)
+{
+ /* Check if reference modified */
+ if (ref->dirty) {
+ /* Mark block dirty for writing changes to physical device */
+ ref->block.dirty = true;
+ }
+
+ /* Put back block, that contains i-node */
+ return ext4_block_set(ref->fs->bdev, &ref->block);
+}
+
+int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
+ bool is_directory)
+{
+ /* Check if newly allocated i-node will be a directory */
+ uint32_t i;
+ bool is_dir;
+
+ is_dir = is_directory;
+
+ /* Allocate inode by allocation algorithm */
+ uint32_t index;
+ int rc = ext4_ialloc_alloc_inode(fs, &index, is_dir);
+ if (rc != EOK)
+ return rc;
+
+ /* Load i-node from on-disk i-node table */
+ rc = ext4_fs_get_inode_ref(fs, index, inode_ref);
+ if (rc != EOK) {
+ ext4_ialloc_free_inode(fs, index, is_dir);
+ return rc;
+ }
+
+ /* Initialize i-node */
+ struct ext4_inode *inode = inode_ref->inode;
+
+ uint16_t mode;
+ if (is_dir) {
+ /*
+ * Default directory permissions to be compatible with other systems
+ * 0777 (octal) == rwxrwxrwx
+ */
+
+ mode = 0777;
+ mode |= EXT4_INODE_MODE_DIRECTORY;
+ ext4_inode_set_mode(&fs->sb, inode, mode);
+ ext4_inode_set_links_count(inode, 1); /* '.' entry */
+
+ } else {
+ /*
+ * Default file permissions to be compatible with other systems
+ * 0666 (octal) == rw-rw-rw-
+ */
+
+ mode = 0666;
+ mode |= EXT4_INODE_MODE_FILE;
+ ext4_inode_set_mode(&fs->sb, inode, mode);
+ ext4_inode_set_links_count(inode, 0);
+ }
+
+ ext4_inode_set_uid(inode, 0);
+ ext4_inode_set_gid(inode, 0);
+ ext4_inode_set_size(inode, 0);
+ ext4_inode_set_access_time(inode, 0);
+ ext4_inode_set_change_inode_time(inode, 0);
+ ext4_inode_set_modification_time(inode, 0);
+ ext4_inode_set_deletion_time(inode, 0);
+ ext4_inode_set_blocks_count(&fs->sb, inode, 0);
+ ext4_inode_set_flags(inode, 0);
+ ext4_inode_set_generation(inode, 0);
+
+ /* Reset blocks array */
+ for (i = 0; i < EXT4_INODE_BLOCKS; i++)
+ inode->blocks[i] = 0;
+
+#if 0
+ /* Initialize extents if needed */
+ if (ext4_sb_check_feature_incompatible(
+ &fs->sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
+ ext4_inode_set_flag(inode, EXT4_INODE_FLAG_EXTENTS);
+
+
+ /* Initialize extent root header */
+ ext4_extent_header_t *header = ext4_inode_get_extent_header(inode);
+ ext4_extent_header_set_depth(header, 0);
+ ext4_extent_header_set_entries_count(header, 0);
+ ext4_extent_header_set_generation(header, 0);
+ ext4_extent_header_set_magic(header, EXT4_EXTENT_MAGIC);
+
+ uint16_t max_entries = (EXT4_INODE_BLOCKS * sizeof(uint32_t) -
+ sizeof(ext4_extent_header_t)) / sizeof(ext4_extent_t);
+
+ ext4_extent_header_set_max_entries_count(header, max_entries);
+ }
+#endif
+
+ inode_ref->dirty = true;
+
+ return EOK;
+}
+
+int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref)
+{
+ struct ext4_fs *fs = inode_ref->fs;
+ uint32_t offset;
+ uint32_t suboffset;
+ /* For extents must be data block destroyed by other way */
+ if ((ext4_sb_check_feature_incompatible(&fs->sb,
+ EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
+ (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))){
+ /* Data structures are released during truncate operation... */
+ goto finish;
+ }
+
+ /* Release all indirect (no data) blocks */
+
+ /* 1) Single indirect */
+ uint32_t fblock = ext4_inode_get_indirect_block(inode_ref->inode, 0);
+ if (fblock != 0) {
+ int rc = ext4_balloc_free_block(inode_ref, fblock);
+ if (rc != EOK)
+ return rc;
+
+ ext4_inode_set_indirect_block(inode_ref->inode, 0, 0);
+ }
+
+ uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
+ uint32_t count = block_size / sizeof(uint32_t);
+
+ struct ext4_block block;
+
+ /* 2) Double indirect */
+ fblock = ext4_inode_get_indirect_block(inode_ref->inode, 1);
+ if (fblock != 0) {
+ int rc = ext4_block_get(fs->bdev, &block, fblock);
+ if (rc != EOK)
+ return rc;
+
+ uint32_t ind_block;
+ for (offset = 0; offset < count; ++offset) {
+ ind_block = to_le32(((uint32_t *) block.data)[offset]);
+
+ if (ind_block != 0) {
+ rc = ext4_balloc_free_block(inode_ref, ind_block);
+ if (rc != EOK) {
+ ext4_block_set(fs->bdev, &block);
+ return rc;
+ }
+ }
+ }
+
+ ext4_block_set(fs->bdev, &block);
+ rc = ext4_balloc_free_block(inode_ref, fblock);
+ if (rc != EOK)
+ return rc;
+
+ ext4_inode_set_indirect_block(inode_ref->inode, 1, 0);
+ }
+
+ /* 3) Tripple indirect */
+ struct ext4_block subblock;
+ fblock = ext4_inode_get_indirect_block(inode_ref->inode, 2);
+ if (fblock != 0) {
+ int rc = ext4_block_get(fs->bdev, &block, fblock);
+ if (rc != EOK)
+ return rc;
+
+ uint32_t ind_block;
+ for ( offset = 0; offset < count; ++offset) {
+ ind_block = to_le32(((uint32_t *) block.data)[offset]);
+
+ if (ind_block != 0) {
+ rc = ext4_block_get(fs->bdev, &subblock, ind_block);
+ if (rc != EOK) {
+ ext4_block_set(fs->bdev, &block);
+ return rc;
+ }
+
+ uint32_t ind_subblock;
+ for (suboffset = 0; suboffset < count;
+ ++suboffset) {
+ ind_subblock = to_le32(((uint32_t *)
+ subblock.data)[suboffset]);
+
+ if (ind_subblock != 0) {
+ rc = ext4_balloc_free_block(inode_ref, ind_subblock);
+ if (rc != EOK) {
+ ext4_block_set(fs->bdev, &subblock);
+ ext4_block_set(fs->bdev, &block);
+ return rc;
+ }
+ }
+ }
+
+ ext4_block_set(fs->bdev, &subblock);
+
+
+ rc = ext4_balloc_free_block(inode_ref, ind_block);
+ if (rc != EOK) {
+ ext4_block_set(fs->bdev, &block);
+ return rc;
+ }
+ }
+ }
+
+ ext4_block_set(fs->bdev, &block);
+ rc = ext4_balloc_free_block(inode_ref, fblock);
+ if (rc != EOK)
+ return rc;
+
+ ext4_inode_set_indirect_block(inode_ref->inode, 2, 0);
+ }
+
+ finish:
+ /* Mark inode dirty for writing to the physical device */
+ inode_ref->dirty = true;
+
+ /* Free block with extended attributes if present */
+ uint32_t xattr_block = ext4_inode_get_file_acl(
+ inode_ref->inode, &fs->sb);
+ if (xattr_block) {
+ int rc = ext4_balloc_free_block(inode_ref, xattr_block);
+ if (rc != EOK)
+ return rc;
+
+ ext4_inode_set_file_acl(inode_ref->inode, &fs->sb, 0);
+ }
+
+ /* Free inode by allocator */
+ int rc;
+ if (ext4_inode_is_type(&fs->sb, inode_ref->inode,
+ EXT4_INODE_MODE_DIRECTORY))
+ rc = ext4_ialloc_free_inode(fs, inode_ref->index, true);
+ else
+ rc = ext4_ialloc_free_inode(fs, inode_ref->index, false);
+
+ return rc;
+}
+
+int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref,
+ uint64_t new_size)
+{
+ struct ext4_sblock *sb = &inode_ref->fs->sb;
+ uint32_t i;
+
+ /* Check flags, if i-node can be truncated */
+ if (!ext4_inode_can_truncate(sb, inode_ref->inode))
+ return EINVAL;
+
+ /* If sizes are equal, nothing has to be done. */
+ uint64_t old_size = ext4_inode_get_size(sb, inode_ref->inode);
+ if (old_size == new_size)
+ return EOK;
+
+ /* It's not suppported to make the larger file by truncate operation */
+ if (old_size < new_size)
+ return EINVAL;
+
+ /* Compute how many blocks will be released */
+ uint64_t size_diff = old_size - new_size;
+ uint32_t block_size = ext4_sb_get_block_size(sb);
+ uint32_t diff_blocks_count = size_diff / block_size;
+ if (size_diff % block_size != 0)
+ diff_blocks_count++;
+
+ uint32_t old_blocks_count = old_size / block_size;
+ if (old_size % block_size != 0)
+ old_blocks_count++;
+
+ if ((ext4_sb_check_feature_incompatible(sb,
+ EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
+ (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
+#if 0
+ /* Extents require special operation */
+ int rc = ext4_extent_release_blocks_from(inode_ref,
+ old_blocks_count - diff_blocks_count);
+ if (rc != EOK)
+ return rc;
+#endif
+ } else {
+ /* Release data blocks from the end of file */
+
+ /* Starting from 1 because of logical blocks are numbered from 0 */
+ for (i = 1; i <= diff_blocks_count; ++i) {
+ int rc = ext4_fs_release_inode_block(inode_ref,
+ old_blocks_count - i);
+ if (rc != EOK)
+ return rc;
+ }
+ }
+
+ /* Update i-node */
+ ext4_inode_set_size(inode_ref->inode, new_size);
+ inode_ref->dirty = true;
+
+ return EOK;
+}
+
+int ext4_fs_get_inode_data_block_index(struct ext4_inode_ref *inode_ref,
+ uint64_t iblock, uint32_t *fblock)
+{
+ struct ext4_fs *fs = inode_ref->fs;
+
+ /* For empty file is situation simple */
+ if (ext4_inode_get_size(&fs->sb, inode_ref->inode) == 0) {
+ *fblock = 0;
+ return EOK;
+ }
+
+ uint32_t current_block;
+
+ /* Handle i-node using extents */
+ if ((ext4_sb_check_feature_incompatible(&fs->sb,
+ EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
+ (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
+
+#if 0
+ int rc = ext4_extent_find_block(inode_ref, iblock, ¤t_block);
+ if (rc != EOK)
+ return rc;
+
+ *fblock = current_block;
+ return EOK;
+#endif
+ }
+
+ struct ext4_inode *inode = inode_ref->inode;
+
+ /* Direct block are read directly from array in i-node structure */
+ if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
+ current_block = ext4_inode_get_direct_block(inode, (uint32_t) iblock);
+ *fblock = current_block;
+ return EOK;
+ }
+
+ /* Determine indirection level of the target block */
+ unsigned int level = 0;
+ unsigned int i;
+ for (i = 1; i < 4; i++) {
+ if (iblock < fs->inode_block_limits[i]) {
+ level = i;
+ break;
+ }
+ }
+
+ if (level == 0)
+ return EIO;
+
+ /* Compute offsets for the topmost level */
+ uint64_t block_offset_in_level =
+ iblock - fs->inode_block_limits[level - 1];
+ current_block = ext4_inode_get_indirect_block(inode, level - 1);
+ uint32_t offset_in_block =
+ block_offset_in_level / fs->inode_blocks_per_level[level - 1];
+
+ /* Sparse file */
+ if (current_block == 0) {
+ *fblock = 0;
+ return EOK;
+ }
+
+ struct ext4_block block;
+
+ /*
+ * Navigate through other levels, until we find the block number
+ * or find null reference meaning we are dealing with sparse file
+ */
+ while (level > 0) {
+ /* Load indirect block */
+ int rc = ext4_block_get(fs->bdev, &block, current_block);
+ if (rc != EOK)
+ return rc;
+
+ /* Read block address from indirect block */
+ current_block =
+ to_le32(((uint32_t *) block.data)[offset_in_block]);
+
+ /* Put back indirect block untouched */
+ rc = ext4_block_set(fs->bdev, &block);
+ if (rc != EOK)
+ return rc;
+
+ /* Check for sparse file */
+ if (current_block == 0) {
+ *fblock = 0;
+ return EOK;
+ }
+
+ /* Jump to the next level */
+ level--;
+
+ /* Termination condition - we have address of data block loaded */
+ if (level == 0)
+ break;
+
+ /* Visit the next level */
+ block_offset_in_level %= fs->inode_blocks_per_level[level];
+ offset_in_block =
+ block_offset_in_level / fs->inode_blocks_per_level[level - 1];
+ }
+
+ *fblock = current_block;
+
+ return EOK;
+}
+
+int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
+ uint64_t iblock, uint32_t fblock)
+{
+ struct ext4_fs *fs = inode_ref->fs;
+
+ /* Handle inode using extents */
+ if ((ext4_sb_check_feature_incompatible(&fs->sb,
+ EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
+ (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
+ /* Not reachable */
+ return ENOTSUP;
+ }
+
+ /* Handle simple case when we are dealing with direct reference */
+ if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
+ ext4_inode_set_direct_block(inode_ref->inode, (uint32_t) iblock,
+ fblock);
+ inode_ref->dirty = true;
+
+ return EOK;
+ }
+
+ /* Determine the indirection level needed to get the desired block */
+ unsigned int level = 0;
+ unsigned int i;
+ for (i = 1; i < 4; i++) {
+ if (iblock < fs->inode_block_limits[i]) {
+ level = i;
+ break;
+ }
+ }
+
+ if (level == 0)
+ return EIO;
+
+ uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
+
+ /* Compute offsets for the topmost level */
+ uint64_t block_offset_in_level =
+ iblock - fs->inode_block_limits[level - 1];
+ uint32_t current_block =
+ ext4_inode_get_indirect_block(inode_ref->inode, level - 1);
+ uint32_t offset_in_block =
+ block_offset_in_level / fs->inode_blocks_per_level[level - 1];
+
+ uint32_t new_block_addr;
+
+ struct ext4_block block;
+ struct ext4_block new_block;
+
+ /* Is needed to allocate indirect block on the i-node level */
+ if (current_block == 0) {
+ /* Allocate new indirect block */
+ int rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr);
+ if (rc != EOK)
+ return rc;
+
+ /* Update i-node */
+ ext4_inode_set_indirect_block(inode_ref->inode, level - 1,
+ new_block_addr);
+ inode_ref->dirty = true;
+
+ /* Load newly allocated block */
+ rc = ext4_block_get(fs->bdev, &new_block, new_block_addr);
+ if (rc != EOK) {
+ ext4_balloc_free_block(inode_ref, new_block_addr);
+ return rc;
+ }
+
+ /* Initialize new block */
+ memset(new_block.data, 0, block_size);
+ new_block.dirty = true;
+
+ /* Put back the allocated block */
+ rc = ext4_block_set(fs->bdev, &new_block);
+ if (rc != EOK)
+ return rc;
+
+ current_block = new_block_addr;
+ }
+
+ /*
+ * Navigate through other levels, until we find the block number
+ * or find null reference meaning we are dealing with sparse file
+ */
+ while (level > 0) {
+ int rc = ext4_block_get(fs->bdev, &block, current_block);
+ if (rc != EOK)
+ return rc;
+
+ current_block =
+ to_le32(((uint32_t *) block.data)[offset_in_block]);
+
+ if ((level > 1) && (current_block == 0)) {
+ /* Allocate new block */
+ rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr);
+ if (rc != EOK) {
+ ext4_block_set(fs->bdev, &block);
+ return rc;
+ }
+
+ /* Load newly allocated block */
+ rc = ext4_block_get(fs->bdev, &new_block, new_block_addr);
+
+ if (rc != EOK) {
+ ext4_block_set(fs->bdev, &block);
+ return rc;
+ }
+
+ /* Initialize allocated block */
+ memset(new_block.data, 0, block_size);
+ new_block.dirty = true;
+
+ rc = ext4_block_set(fs->bdev, &new_block);
+ if (rc != EOK) {
+ ext4_block_set(fs->bdev, &block);
+ return rc;
+ }
+
+ /* Write block address to the parent */
+ ((uint32_t *) block.data)[offset_in_block] =
+ to_le32(new_block_addr);
+ block.dirty = true;
+ current_block = new_block_addr;
+ }
+
+ /* Will be finished, write the fblock address */
+ if (level == 1) {
+ ((uint32_t *) block.data)[offset_in_block] =
+ to_le32(fblock);
+ block.dirty = true;
+ }
+
+ rc = ext4_block_set(fs->bdev, &block);
+ if (rc != EOK)
+ return rc;
+
+ level--;
+
+ /*
+ * If we are on the last level, break here as
+ * there is no next level to visit
+ */
+ if (level == 0)
+ break;
+
+ /* Visit the next level */
+ block_offset_in_level %= fs->inode_blocks_per_level[level];
+ offset_in_block =
+ block_offset_in_level / fs->inode_blocks_per_level[level - 1];
+ }
+
+ return EOK;
+}
+
+int ext4_fs_release_inode_block(struct ext4_inode_ref *inode_ref,
+ uint32_t iblock)
+{
+ uint32_t fblock;
+
+ struct ext4_fs *fs = inode_ref->fs;
+
+ /* Extents are handled otherwise = there is not support in this function */
+ ext4_assert(!(ext4_sb_check_feature_incompatible(&fs->sb,
+ EXT4_FEATURE_INCOMPAT_EXTENTS) &&
+ (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))));
+
+ struct ext4_inode *inode = inode_ref->inode;
+
+ /* Handle simple case when we are dealing with direct reference */
+ if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
+ fblock = ext4_inode_get_direct_block(inode, iblock);
+
+ /* Sparse file */
+ if (fblock == 0)
+ return EOK;
+
+ ext4_inode_set_direct_block(inode, iblock, 0);
+ return ext4_balloc_free_block(inode_ref, fblock);
+ }
+
+ /* Determine the indirection level needed to get the desired block */
+ unsigned int level = 0;
+ unsigned int i;
+ for (i = 1; i < 4; i++) {
+ if (iblock < fs->inode_block_limits[i]) {
+ level = i;
+ break;
+ }
+ }
+
+ if (level == 0)
+ return EIO;
+
+ /* Compute offsets for the topmost level */
+ uint64_t block_offset_in_level =
+ iblock - fs->inode_block_limits[level - 1];
+ uint32_t current_block =
+ ext4_inode_get_indirect_block(inode, level - 1);
+ uint32_t offset_in_block =
+ block_offset_in_level / fs->inode_blocks_per_level[level - 1];
+
+ /*
+ * Navigate through other levels, until we find the block number
+ * or find null reference meaning we are dealing with sparse file
+ */
+ struct ext4_block block;
+
+ while (level > 0) {
+
+ /* Sparse check */
+ if (current_block == 0)
+ return EOK;
+
+ int rc = ext4_block_get(fs->bdev, &block, current_block);
+ if (rc != EOK)
+ return rc;
+
+ current_block =
+ to_le32(((uint32_t *) block.data)[offset_in_block]);
+
+ /* Set zero if physical data block address found */
+ if (level == 1) {
+ ((uint32_t *) block.data)[offset_in_block] =
+ to_le32(0);
+ block.dirty = true;
+ }
+
+ rc = ext4_block_set(fs->bdev, &block);
+ if (rc != EOK)
+ return rc;
+
+ level--;
+
+ /*
+ * If we are on the last level, break here as
+ * there is no next level to visit
+ */
+ if (level == 0)
+ break;
+
+ /* Visit the next level */
+ block_offset_in_level %= fs->inode_blocks_per_level[level];
+ offset_in_block =
+ block_offset_in_level / fs->inode_blocks_per_level[level - 1];
+ }
+
+ fblock = current_block;
+ if (fblock == 0)
+ return EOK;
+
+ /* Physical block is not referenced, it can be released */
+ return ext4_balloc_free_block(inode_ref, fblock);
+}
+
+
+int ext4_fs_append_inode_block(struct ext4_inode_ref *inode_ref,
+ uint32_t *fblock, uint32_t *iblock)
+{
+ /* Handle extents separately */
+ if ((ext4_sb_check_feature_incompatible(&inode_ref->fs->sb,
+ EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
+ (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))){
+
+#if 0
+ return ext4_extent_append_block(inode_ref, iblock, fblock, true);
+#endif
+ }
+
+ struct ext4_sblock *sb = &inode_ref->fs->sb;
+
+ /* Compute next block index and allocate data block */
+ uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
+ uint32_t block_size = ext4_sb_get_block_size(sb);
+
+ /* Align size i-node size */
+ if ((inode_size % block_size) != 0)
+ inode_size += block_size - (inode_size % block_size);
+
+ /* Logical blocks are numbered from 0 */
+ uint32_t new_block_idx = inode_size / block_size;
+
+ /* Allocate new physical block */
+ uint32_t phys_block;
+ int rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
+ if (rc != EOK)
+ return rc;
+
+ /* Add physical block address to the i-node */
+ rc = ext4_fs_set_inode_data_block_index(inode_ref,
+ new_block_idx, phys_block);
+ if (rc != EOK) {
+ ext4_balloc_free_block(inode_ref, phys_block);
+ return rc;
+ }
+
+ /* Update i-node */
+ ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
+ inode_ref->dirty = true;
+
+ *fblock = phys_block;
+ *iblock = new_block_idx;
+
+ return EOK;
+}
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/lwext4/ext4_fs.h
@@ -1,0 +1,95 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_fs.c
+ * @brief More complex filesystem functions.
+ */
+
+#ifndef EXT4_FS_H_
+#define EXT4_FS_H_
+
+#include <ext4_config.h>
+#include <ext4_types.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+
+int ext4_fs_init(struct ext4_fs *fs, struct ext4_blockdev *bdev);
+int ext4_fs_fini(struct ext4_fs *fs);
+
+int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only);
+
+
+uint32_t ext4_fs_baddr2_index_in_group(struct ext4_sblock *s, uint32_t baddr);
+uint32_t ext4_fs_index_in_group2_baddr(struct ext4_sblock *s, uint32_t index,
+ uint32_t bgid);
+
+
+int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid,
+ struct ext4_block_group_ref *ref);
+int ext4_fs_put_block_group_ref(struct ext4_block_group_ref *ref);
+
+
+int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index,
+ struct ext4_inode_ref *ref);
+int ext4_fs_put_inode_ref(struct ext4_inode_ref *ref);
+
+
+int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
+ bool is_directory);
+int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref);
+
+int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref,
+ uint64_t new_size);
+
+int ext4_fs_get_inode_data_block_index(struct ext4_inode_ref *inode_ref,
+ uint64_t iblock, uint32_t *fblock);
+
+int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
+ uint64_t iblock, uint32_t fblock);
+
+int ext4_fs_release_inode_block(struct ext4_inode_ref *inode_ref,
+ uint32_t iblock);
+
+int ext4_fs_append_inode_block(struct ext4_inode_ref *inode_ref,
+ uint32_t *fblock, uint32_t *iblock);
+
+#endif /* EXT4_FS_H_ */
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/lwext4/ext4_hash.c
@@ -1,0 +1,320 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ * FreeBSD:
+ * Copyright (c) 2010, 2013 Zheng Liu <lz@freebsd.org>
+ * Copyright (c) 2012, Vyacheslav Matyushin
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * The following notice applies to the code in ext2_half_md4():
+ *
+ * Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD4 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD4 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_hash.c
+ * @brief Directory indexing hash functions.
+ */
+
+#include <ext4_config.h>
+#include <ext4_types.h>
+#include <string.h>
+#include <ext4_errno.h>
+
+/* F, G, and H are MD4 functions */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/* ROTATE_LEFT rotates x left n bits */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+/*
+ * FF, GG, and HH are transformations for rounds 1, 2, and 3.
+ * Rotation is separated from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s) { \
+ (a) += F ((b), (c), (d)) + (x); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+}
+
+#define GG(a, b, c, d, x, s) { \
+ (a) += G ((b), (c), (d)) + (x) + (uint32_t)0x5A827999; \
+ (a) = ROTATE_LEFT ((a), (s)); \
+}
+
+#define HH(a, b, c, d, x, s) { \
+ (a) += H ((b), (c), (d)) + (x) + (uint32_t)0x6ED9EBA1; \
+ (a) = ROTATE_LEFT ((a), (s)); \
+}
+
+/*
+ * MD4 basic transformation. It transforms state based on block.
+ *
+ * This is a half md4 algorithm since Linux uses this algorithm for dir
+ * index. This function is derived from the RSA Data Security, Inc. MD4
+ * Message-Digest Algorithm and was modified as necessary.
+ *
+ * The return value of this function is uint32_t in Linux, but actually we don't
+ * need to check this value, so in our version this function doesn't return any
+ * value.
+ */
+static void
+ext2_half_md4(uint32_t hash[4], uint32_t data[8])
+{
+ uint32_t a = hash[0], b = hash[1], c = hash[2], d = hash[3];
+
+ /* Round 1 */
+ FF(a, b, c, d, data[0], 3);
+ FF(d, a, b, c, data[1], 7);
+ FF(c, d, a, b, data[2], 11);
+ FF(b, c, d, a, data[3], 19);
+ FF(a, b, c, d, data[4], 3);
+ FF(d, a, b, c, data[5], 7);
+ FF(c, d, a, b, data[6], 11);
+ FF(b, c, d, a, data[7], 19);
+
+ /* Round 2 */
+ GG(a, b, c, d, data[1], 3);
+ GG(d, a, b, c, data[3], 5);
+ GG(c, d, a, b, data[5], 9);
+ GG(b, c, d, a, data[7], 13);
+ GG(a, b, c, d, data[0], 3);
+ GG(d, a, b, c, data[2], 5);
+ GG(c, d, a, b, data[4], 9);
+ GG(b, c, d, a, data[6], 13);
+
+ /* Round 3 */
+ HH(a, b, c, d, data[3], 3);
+ HH(d, a, b, c, data[7], 9);
+ HH(c, d, a, b, data[2], 11);
+ HH(b, c, d, a, data[6], 15);
+ HH(a, b, c, d, data[1], 3);
+ HH(d, a, b, c, data[5], 9);
+ HH(c, d, a, b, data[0], 11);
+ HH(b, c, d, a, data[4], 15);
+
+ hash[0] += a;
+ hash[1] += b;
+ hash[2] += c;
+ hash[3] += d;
+}
+
+/*
+ * Tiny Encryption Algorithm.
+ */
+static void
+ext2_tea(uint32_t hash[4], uint32_t data[8])
+{
+ uint32_t tea_delta = 0x9E3779B9;
+ uint32_t sum;
+ uint32_t x = hash[0], y = hash[1];
+ int n = 16;
+ int i = 1;
+
+ while (n-- > 0) {
+ sum = i * tea_delta;
+ x += ((y << 4) + data[0]) ^ (y + sum) ^ ((y >> 5) + data[1]);
+ y += ((x << 4) + data[2]) ^ (x + sum) ^ ((x >> 5) + data[3]);
+ i++;
+ }
+
+ hash[0] += x;
+ hash[1] += y;
+}
+
+static uint32_t
+ext2_legacy_hash(const char *name, int len, int unsigned_char)
+{
+ uint32_t h0, h1 = 0x12A3FE2D, h2 = 0x37ABE8F9;
+ uint32_t multi = 0x6D22F5;
+ const unsigned char *uname = (const unsigned char *)name;
+ const signed char *sname = (const signed char *)name;
+ int val, i;
+
+ for (i = 0; i < len; i++) {
+ if (unsigned_char)
+ val = (unsigned int)*uname++;
+ else
+ val = (int)*sname++;
+
+ h0 = h2 + (h1 ^ (val * multi));
+ if (h0 & 0x80000000)
+ h0 -= 0x7FFFFFFF;
+ h2 = h1;
+ h1 = h0;
+ }
+
+ return (h1 << 1);
+}
+
+static void
+ext2_prep_hashbuf(const char *src, int slen, uint32_t *dst, int dlen,
+ int unsigned_char)
+{
+ uint32_t padding = slen | (slen << 8) | (slen << 16) | (slen << 24);
+ uint32_t buf_val;
+ int len, i;
+ int buf_byte;
+ const unsigned char *ubuf = (const unsigned char *)src;
+ const signed char *sbuf = (const signed char *)src;
+
+ if (slen > dlen)
+ len = dlen;
+ else
+ len = slen;
+
+ buf_val = padding;
+
+ for (i = 0; i < len; i++) {
+ if (unsigned_char)
+ buf_byte = (unsigned int)ubuf[i];
+ else
+ buf_byte = (int)sbuf[i];
+
+ if ((i % 4) == 0)
+ buf_val = padding;
+
+ buf_val <<= 8;
+ buf_val += buf_byte;
+
+ if ((i % 4) == 3) {
+ *dst++ = buf_val;
+ dlen -= sizeof(uint32_t);
+ buf_val = padding;
+ }
+ }
+
+ dlen -= sizeof(uint32_t);
+ if (dlen >= 0)
+ *dst++ = buf_val;
+
+ dlen -= sizeof(uint32_t);
+ while (dlen >= 0) {
+ *dst++ = padding;
+ dlen -= sizeof(uint32_t);
+ }
+}
+
+int
+ext2_htree_hash(const char *name, int len,
+ const uint32_t *hash_seed, int hash_version,
+ uint32_t *hash_major, uint32_t *hash_minor)
+{
+ uint32_t hash[4];
+ uint32_t data[8];
+ uint32_t major = 0, minor = 0;
+ int unsigned_char = 0;
+
+ if (!name || !hash_major)
+ return (-1);
+
+ if (len < 1 || len > 255)
+ goto error;
+
+ hash[0] = 0x67452301;
+ hash[1] = 0xEFCDAB89;
+ hash[2] = 0x98BADCFE;
+ hash[3] = 0x10325476;
+
+ if (hash_seed)
+ memcpy(hash, hash_seed, sizeof(hash));
+
+ switch (hash_version) {
+ case EXT2_HTREE_TEA_UNSIGNED:
+ unsigned_char = 1;
+ case EXT2_HTREE_TEA:
+ while (len > 0) {
+ ext2_prep_hashbuf(name, len, data, 16, unsigned_char);
+ ext2_tea(hash, data);
+ len -= 16;
+ name += 16;
+ }
+ major = hash[0];
+ minor = hash[1];
+ break;
+ case EXT2_HTREE_LEGACY_UNSIGNED:
+ unsigned_char = 1;
+ case EXT2_HTREE_LEGACY:
+ major = ext2_legacy_hash(name, len, unsigned_char);
+ break;
+ case EXT2_HTREE_HALF_MD4_UNSIGNED:
+ unsigned_char = 1;
+ case EXT2_HTREE_HALF_MD4:
+ while (len > 0) {
+ ext2_prep_hashbuf(name, len, data, 32, unsigned_char);
+ ext2_half_md4(hash, data);
+ len -= 32;
+ name += 32;
+ }
+ major = hash[0];
+ minor = hash[1];
+ break;
+ default:
+ goto error;
+ }
+
+ major &= ~1;
+ if (major == (EXT2_HTREE_EOF << 1))
+ major = (EXT2_HTREE_EOF - 1) << 1;
+ *hash_major = major;
+ if (hash_minor)
+ *hash_minor = minor;
+
+ return EOK;
+
+ error:
+ *hash_major = 0;
+ if (hash_minor)
+ *hash_minor = 0;
+ return ENOTSUP;
+}
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/lwext4/ext4_hash.h
@@ -1,0 +1,61 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_hash.h
+ * @brief Directory indexing hash functions.
+ */
+
+#ifndef EXT4_HASH_H_
+#define EXT4_HASH_H_
+
+#include <ext4_config.h>
+
+#include <stdint.h>
+
+/**@brief Directory entry name hash function.
+ * @param name entry name
+ * @param len entry name length
+ * @param hash_seed (from superblock)
+ * @param hash version (from superblock)
+ * @param hash_minor output value
+ * @param hash_major output value
+ * @return standard error code*/
+int ext2_htree_hash(const char *name, int len,
+ const uint32_t *hash_seed, int hash_version,
+ uint32_t *hash_major, uint32_t *hash_minor);
+
+
+#endif /* EXT4_HASH_H_ */
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/lwext4/ext4_ialloc.c
@@ -1,0 +1,250 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_ialloc.c
+ * @brief Inode allocation procedures.
+ */
+
+#include <ext4_config.h>
+#include <ext4_types.h>
+#include <ext4_ialloc.h>
+#include <ext4_super.h>
+#include <ext4_fs.h>
+#include <ext4_blockdev.h>
+#include <ext4_block_group.h>
+#include <ext4_bitmap.h>
+
+static uint32_t ext4_ialloc_inode2index_in_group(struct ext4_sblock *sb,
+ uint32_t inode)
+{
+ uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
+ return (inode - 1) % inodes_per_group;
+}
+
+static uint32_t ext4_ialloc_index_in_group2inode(struct ext4_sblock *sb,
+ uint32_t index, uint32_t bgid)
+{
+ uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
+ return bgid * inodes_per_group + (index + 1);
+}
+
+static uint32_t ext4_ialloc_get_bgid_of_inode(struct ext4_sblock *sb,
+ uint32_t inode)
+{
+ uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
+ return (inode - 1) / inodes_per_group;
+}
+
+
+int ext4_ialloc_free_inode(struct ext4_fs *fs, uint32_t index, bool is_dir)
+{
+ struct ext4_sblock *sb = &fs->sb;
+
+ /* Compute index of block group and load it */
+ uint32_t block_group = ext4_ialloc_get_bgid_of_inode(sb, index);
+
+ struct ext4_block_group_ref bg_ref;
+ int rc = ext4_fs_get_block_group_ref(fs, block_group, &bg_ref);
+ if (rc != EOK)
+ return rc;
+
+ /* Load i-node bitmap */
+ uint32_t bitmap_block_addr = ext4_bg_get_inode_bitmap(
+ bg_ref.block_group, sb);
+
+ struct ext4_block bitmap_block;
+ rc = ext4_block_get(fs->bdev, &bitmap_block, bitmap_block_addr);
+ if (rc != EOK)
+ return rc;
+
+ /* Free i-node in the bitmap */
+ uint32_t index_in_group = ext4_ialloc_inode2index_in_group(sb, index);
+ ext4_bmap_bit_clr(bitmap_block.data, index_in_group);
+ bitmap_block.dirty = true;
+
+ /* Put back the block with bitmap */
+ rc = ext4_block_set(fs->bdev, &bitmap_block);
+ if (rc != EOK) {
+ /* Error in saving bitmap */
+ ext4_fs_put_block_group_ref(&bg_ref);
+ return rc;
+ }
+
+ /* If released i-node is a directory, decrement used directories count */
+ if (is_dir) {
+ uint32_t bg_used_dirs = ext4_bg_get_used_dirs_count(
+ bg_ref.block_group, sb);
+ bg_used_dirs--;
+ ext4_bg_set_used_dirs_count(bg_ref.block_group, sb,
+ bg_used_dirs);
+ }
+
+ /* Update block group free inodes count */
+ uint32_t free_inodes = ext4_bg_get_free_inodes_count(
+ bg_ref.block_group, sb);
+ free_inodes++;
+ ext4_bg_set_free_inodes_count(bg_ref.block_group, sb,
+ free_inodes);
+
+ bg_ref.dirty = true;
+
+ /* Put back the modified block group */
+ rc = ext4_fs_put_block_group_ref(&bg_ref);
+ if (rc != EOK)
+ return rc;
+
+ /* Update superblock free inodes count */
+ ext4_set32(sb, free_inodes_count, ext4_get32(sb, free_inodes_count) + 1);
+
+ return EOK;
+}
+
+int ext4_ialloc_alloc_inode(struct ext4_fs *fs, uint32_t *index, bool is_dir)
+{
+ struct ext4_sblock *sb = &fs->sb;
+
+ uint32_t bgid = 0;
+ uint32_t bg_count = ext4_block_group_cnt(sb);
+ uint32_t sb_free_inodes = ext4_get32(sb, free_inodes_count);
+ uint32_t avg_free_inodes = sb_free_inodes / bg_count;
+
+ /* Try to find free i-node in all block groups */
+ while (bgid < bg_count) {
+ /* Load block group to check */
+ struct ext4_block_group_ref bg_ref;
+ int rc = ext4_fs_get_block_group_ref(fs, bgid, &bg_ref);
+ if (rc != EOK)
+ return rc;
+
+ struct ext4_bgroup *bg = bg_ref.block_group;
+
+ /* Read necessary values for algorithm */
+ uint32_t free_blocks = ext4_bg_get_free_blocks_count(bg, sb);
+ uint32_t free_inodes = ext4_bg_get_free_inodes_count(bg, sb);
+ uint32_t used_dirs = ext4_bg_get_used_dirs_count(bg, sb);
+
+ /* Check if this block group is good candidate for allocation */
+ if ((free_inodes >= avg_free_inodes) && (free_blocks > 0)) {
+ /* Load block with bitmap */
+ uint32_t bitmap_block_addr = ext4_bg_get_inode_bitmap(
+ bg_ref.block_group, sb);
+
+ struct ext4_block bitmap_block;
+ rc = ext4_block_get(fs->bdev, &bitmap_block, bitmap_block_addr);
+ if (rc != EOK)
+ return rc;
+
+ /* Try to allocate i-node in the bitmap */
+ uint32_t inodes_in_group = ext4_inodes_in_group_cnt(sb, bgid);
+ uint32_t index_in_group;
+
+ rc = ext4_bmap_bit_find_clr(bitmap_block.data, 0, inodes_in_group,
+ &index_in_group);
+ /* Block group has not any free i-node */
+ if (rc == ENOSPC) {
+ ext4_block_set(fs->bdev, &bitmap_block);
+ ext4_fs_put_block_group_ref(&bg_ref);
+ continue;
+ }
+
+ ext4_bmap_bit_set(bitmap_block.data, index_in_group);
+
+ /* Free i-node found, save the bitmap */
+ bitmap_block.dirty = true;
+
+ ext4_block_set(fs->bdev, &bitmap_block);
+ if (rc != EOK)
+ return rc;
+
+ /* Modify filesystem counters */
+ free_inodes--;
+ ext4_bg_set_free_inodes_count(bg, sb, free_inodes);
+
+ /* Increment used directories counter */
+ if (is_dir) {
+ used_dirs++;
+ ext4_bg_set_used_dirs_count(bg, sb, used_dirs);
+ }
+
+ /* Decrease unused inodes count */
+ if (ext4_bg_has_flag(bg,
+ EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
+ uint32_t unused =
+ ext4_bg_get_itable_unused(bg, sb);
+
+ uint32_t inodes_in_group =
+ ext4_inodes_in_group_cnt(sb, bgid);
+
+ uint32_t free = inodes_in_group - unused;
+
+ if (index_in_group >= free) {
+ unused = inodes_in_group - (index_in_group + 1);
+ ext4_bg_set_itable_unused(bg, sb, unused);
+ }
+ }
+
+ /* Save modified block group */
+ bg_ref.dirty = true;
+
+ rc = ext4_fs_put_block_group_ref(&bg_ref);
+ if (rc != EOK)
+ return rc;
+
+ /* Update superblock */
+ sb_free_inodes--;
+ ext4_set32(sb, free_inodes_count, sb_free_inodes);
+
+
+ /* Compute the absolute i-nodex number */
+ *index = ext4_ialloc_index_in_group2inode(sb,
+ index_in_group, bgid);
+
+ return EOK;
+ }
+
+ /* Block group not modified, put it and jump to the next block group */
+ ext4_fs_put_block_group_ref(&bg_ref);
+ ++bgid;
+ }
+
+ return ENOSPC;
+}
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/lwext4/ext4_ialloc.h
@@ -1,0 +1,63 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_ialloc.c
+ * @brief Inode allocation procedures.
+ */
+
+#ifndef EXT4_IALLOC_H_
+#define EXT4_IALLOC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ext4_config.h>
+#include <ext4_types.h>
+
+
+int ext4_ialloc_free_inode(struct ext4_fs *fs, uint32_t index, bool is_dir);
+int ext4_ialloc_alloc_inode(struct ext4_fs *fs, uint32_t *index, bool is_dir);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* EXT4_IALLOC_H_ */
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/lwext4/ext4_inode.c
@@ -1,0 +1,353 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_inode.c
+ * @brief Inode handle functions
+ */
+
+#include <ext4_config.h>
+#include <ext4_types.h>
+#include <ext4_inode.h>
+#include <ext4_super.h>
+
+static uint32_t ext4_inode_block_bits_count(uint32_t block_size)
+{
+ uint32_t bits = 8;
+ uint32_t size = block_size;
+
+ do {
+ bits++;
+ size = size >> 1;
+ } while (size > 256);
+
+ return bits;
+}
+
+
+uint32_t ext4_inode_get_mode(struct ext4_sblock *sb, struct ext4_inode *inode)
+{
+ uint32_t v = to_le16(inode->mode);
+
+ if(ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_HURD){
+ v |= ((uint32_t) to_le16(inode->osd2.hurd2.mode_high)) << 16;
+ }
+
+ return v;
+}
+
+void ext4_inode_set_mode(struct ext4_sblock *sb, struct ext4_inode *inode,
+ uint32_t mode)
+{
+ inode->mode = to_le16((mode << 16) >> 16);
+
+ if(ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_HURD)
+ inode->osd2.hurd2.mode_high = to_le16(mode >> 16);
+}
+
+
+
+uint32_t ext4_inode_get_uid(struct ext4_inode *inode)
+{
+ return to_le32(inode->uid);
+}
+
+void ext4_inode_set_uid(struct ext4_inode *inode, uint32_t uid)
+{
+ inode->uid = to_le32(uid);
+}
+
+
+uint64_t ext4_inode_get_size(struct ext4_sblock *sb, struct ext4_inode *inode)
+{
+ uint64_t v = to_le32(inode->size_lo);
+
+ if ((ext4_get32(sb, rev_level) > 0) && (ext4_inode_is_type(sb, inode,
+ EXT4_INODE_MODE_FILE)))
+ v |= ((uint64_t)to_le32(inode->size_hi)) << 32;
+
+ return v;
+}
+
+void ext4_inode_set_size(struct ext4_inode *inode, uint64_t size)
+{
+ inode->size_lo = to_le32((size << 32) >> 32);
+ inode->size_hi = to_le32(size >> 32);
+}
+
+
+uint32_t ext4_inode_get_access_time(struct ext4_inode *inode)
+{
+ return to_le32(inode->access_time);
+}
+void ext4_inode_set_access_time(struct ext4_inode *inode, uint32_t time)
+{
+ inode->access_time = to_le32(time);
+}
+
+
+uint32_t ext4_inode_get_change_inode_time(struct ext4_inode *inode)
+{
+ return to_le32(inode->change_inode_time);
+}
+void ext4_inode_set_change_inode_time(struct ext4_inode *inode,
+ uint32_t time)
+{
+ inode->change_inode_time = to_le32(time);
+}
+
+
+uint32_t ext4_inode_get_modification_time(struct ext4_inode *inode)
+{
+ return to_le32(inode->modification_time);
+}
+
+void ext4_inode_set_modification_time(struct ext4_inode *inode,
+ uint32_t time)
+{
+ inode->modification_time = to_le32(time);
+}
+
+
+uint32_t ext4_inode_get_deletion_time(struct ext4_inode *inode)
+{
+ return to_le32(inode->deletion_time);
+}
+
+void ext4_inode_set_deletion_time(struct ext4_inode *inode, uint32_t time)
+{
+ inode->deletion_time = to_le32(time);
+}
+
+uint32_t ext4_inode_get_gid(struct ext4_inode *inode)
+{
+ return to_le32(inode->gid);
+}
+void ext4_inode_set_gid(struct ext4_inode *inode, uint32_t gid)
+{
+ inode->gid = to_le32(gid);
+}
+
+uint16_t ext4_inode_get_links_count(struct ext4_inode *inode)
+{
+ return to_le16(inode->links_count);
+}
+void ext4_inode_set_links_count(struct ext4_inode *inode, uint16_t cnt)
+{
+ inode->links_count = to_le16(cnt);
+}
+
+
+uint64_t ext4_inode_get_blocks_count(struct ext4_sblock *sb,
+ struct ext4_inode *inode)
+{
+ uint64_t count = to_le32(inode->blocks_count_lo);
+
+ if (ext4_sb_check_read_only(sb,
+ EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
+
+ /* 48-bit field */
+ count = ((uint64_t) to_le16(inode->osd2.linux2.blocks_high)) << 32;
+
+ if (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_HUGE_FILE)) {
+
+ uint32_t block_bits =
+ ext4_inode_block_bits_count(ext4_sb_get_block_size(sb));
+ return count << (block_bits - 9);
+ } else
+ return count;
+ }
+
+ return count;
+}
+
+
+int ext4_inode_set_blocks_count(struct ext4_sblock *sb,
+ struct ext4_inode *inode, uint64_t count)
+{
+ /* 32-bit maximum */
+ uint64_t max = 0;
+ max = ~max >> 32;
+
+ if (count <= max) {
+ inode->blocks_count_lo = to_le32(count);
+ inode->osd2.linux2.blocks_high = 0;
+ ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
+
+ return EOK;
+ }
+
+ /* Check if there can be used huge files (many blocks) */
+ if (!ext4_sb_check_read_only(sb,
+ EXT4_FEATURE_RO_COMPAT_HUGE_FILE))
+ return EINVAL;
+
+ /* 48-bit maximum */
+ max = 0;
+ max = ~max >> 16;
+
+ if (count <= max) {
+ inode->blocks_count_lo = to_le32(count);
+ inode->osd2.linux2.blocks_high = to_le16(count >> 32);
+ ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
+ } else {
+ uint32_t block_bits = ext4_inode_block_bits_count(ext4_sb_get_block_size(sb));
+
+ ext4_inode_set_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
+ count = count >> (block_bits - 9);
+ inode->blocks_count_lo = to_le32(count);
+ inode->osd2.linux2.blocks_high = to_le16(count >> 32);
+ }
+
+ return EOK;
+}
+
+
+uint32_t ext4_inode_get_flags(struct ext4_inode *inode)
+{
+ return to_le32(inode->flags);
+}
+void ext4_inode_set_flags(struct ext4_inode *inode, uint32_t flags)
+{
+ inode->flags = to_le32(flags);
+}
+
+uint32_t ext4_inode_get_generation(struct ext4_inode *inode)
+{
+ return to_le32(inode->generation);
+}
+void ext4_inode_set_generation(struct ext4_inode *inode, uint32_t gen)
+{
+ inode->generation = to_le32(gen);
+}
+
+uint64_t ext4_inode_get_file_acl(struct ext4_inode *inode,
+ struct ext4_sblock *sb)
+{
+ /*TODO: Verify it*/
+ uint64_t v = to_le32(inode->file_acl_lo);
+
+ if (ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_LINUX)
+ v |= ((uint32_t) to_le16(inode->osd2.linux2.file_acl_high)) << 16;
+
+
+ return v;
+}
+
+void ext4_inode_set_file_acl(struct ext4_inode *inode, struct ext4_sblock *sb,
+ uint64_t acl)
+{
+ /*TODO: Verify it*/
+ inode->file_acl_lo = to_le32((acl << 32) >> 32);
+
+ if (ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_LINUX)
+ inode->osd2.linux2.file_acl_high = to_le16(acl >> 32);
+}
+
+
+
+uint32_t ext4_inode_get_direct_block(struct ext4_inode *inode, uint32_t idx)
+{
+ return to_le32(inode->blocks[idx]);
+}
+void ext4_inode_set_direct_block(struct ext4_inode *inode, uint32_t idx,
+ uint32_t block)
+{
+ inode->blocks[idx] = to_le32(block);
+}
+
+
+uint32_t ext4_inode_get_indirect_block(struct ext4_inode *inode, uint32_t idx)
+{
+ return to_le32(inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK]);
+}
+
+void ext4_inode_set_indirect_block(struct ext4_inode *inode, uint32_t idx,
+ uint32_t block)
+{
+ inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK] = to_le32(block);
+}
+
+bool ext4_inode_is_type(struct ext4_sblock *sb, struct ext4_inode *inode,
+ uint32_t type)
+{
+ return (ext4_inode_get_mode(sb, inode) &
+ EXT4_INODE_MODE_TYPE_MASK) == type;
+}
+
+bool ext4_inode_has_flag(struct ext4_inode *inode, uint32_t f)
+{
+ return ext4_inode_get_flags(inode) & f;
+}
+
+void ext4_inode_clear_flag(struct ext4_inode *inode, uint32_t f)
+{
+ uint32_t flags = ext4_inode_get_flags(inode);
+ flags = flags & (~f);
+ ext4_inode_set_flags(inode, flags);
+}
+
+void ext4_inode_set_flag(struct ext4_inode *inode, uint32_t f)
+{
+ uint32_t flags = ext4_inode_get_flags(inode);
+ flags = flags | f;
+ ext4_inode_set_flags(inode, flags);
+}
+
+bool ext4_inode_can_truncate(struct ext4_sblock *sb,
+ struct ext4_inode *inode)
+{
+ if ((ext4_inode_has_flag(inode, EXT4_INODE_FLAG_APPEND)) ||
+ (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_IMMUTABLE)))
+ return false;
+
+ if ((ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)) ||
+ (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_DIRECTORY)))
+ return true;
+
+ return false;
+}
+
+
+struct ext4_extent_header * ext4_inode_get_extent_header(
+ struct ext4_inode *inode)
+{
+ return (struct ext4_extent_header *) inode->blocks;
+}
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/lwext4/ext4_inode.h
@@ -1,0 +1,129 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_inode.h
+ * @brief Inode handle functions
+ */
+
+#ifndef EXT4_INODE_H_
+#define EXT4_INODE_H_
+
+#include <ext4_config.h>
+#include <stdint.h>
+
+uint32_t ext4_inode_get_mode(struct ext4_sblock *sb, struct ext4_inode *inode);
+void ext4_inode_set_mode(struct ext4_sblock *sb, struct ext4_inode *inode,
+ uint32_t mode);
+
+
+uint32_t ext4_inode_get_uid(struct ext4_inode *inode);
+void ext4_inode_set_uid(struct ext4_inode *inode, uint32_t uid);
+
+
+uint64_t ext4_inode_get_size(struct ext4_sblock *sb, struct ext4_inode *inode);
+void ext4_inode_set_size(struct ext4_inode *inode, uint64_t size);
+
+
+uint32_t ext4_inode_get_access_time(struct ext4_inode *inode);
+void ext4_inode_set_access_time(struct ext4_inode *inode, uint32_t time);
+
+
+uint32_t ext4_inode_get_change_inode_time(struct ext4_inode *inode);
+void ext4_inode_set_change_inode_time(struct ext4_inode *inode,
+ uint32_t time);
+
+
+uint32_t ext4_inode_get_modification_time(struct ext4_inode *inode);
+void ext4_inode_set_modification_time(struct ext4_inode *inode, uint32_t time);
+
+
+uint32_t ext4_inode_get_deletion_time(struct ext4_inode *inode);
+void ext4_inode_set_deletion_time(struct ext4_inode *inode, uint32_t time);
+
+uint32_t ext4_inode_get_gid(struct ext4_inode *inode);
+void ext4_inode_set_gid(struct ext4_inode *inode, uint32_t gid);
+
+uint16_t ext4_inode_get_links_count(struct ext4_inode *inode);
+void ext4_inode_set_links_count(struct ext4_inode *inode, uint16_t cnt);
+
+
+uint64_t ext4_inode_get_blocks_count(struct ext4_sblock *sb,
+ struct ext4_inode *inode);
+int ext4_inode_set_blocks_count(struct ext4_sblock *sb,
+ struct ext4_inode *inode, uint64_t cnt);
+
+
+uint32_t ext4_inode_get_flags(struct ext4_inode *inode);
+void ext4_inode_set_flags(struct ext4_inode *inode, uint32_t flags);
+
+uint32_t ext4_inode_get_generation(struct ext4_inode *inode);
+void ext4_inode_set_generation(struct ext4_inode *inode, uint32_t gen);
+
+uint64_t ext4_inode_get_file_acl(struct ext4_inode *inode,
+ struct ext4_sblock *sb);
+void ext4_inode_set_file_acl(struct ext4_inode *inode,
+ struct ext4_sblock *sb, uint64_t acl);
+
+
+uint32_t ext4_inode_get_direct_block(struct ext4_inode *inode, uint32_t idx);
+void ext4_inode_set_direct_block(struct ext4_inode *inode, uint32_t idx,
+ uint32_t block);
+
+
+uint32_t ext4_inode_get_indirect_block(struct ext4_inode *inode, uint32_t idx);
+void ext4_inode_set_indirect_block(struct ext4_inode *inode, uint32_t idx,
+ uint32_t block);
+
+bool ext4_inode_is_type(struct ext4_sblock *sb, struct ext4_inode *inode,
+ uint32_t type);
+
+
+bool ext4_inode_has_flag(struct ext4_inode *inode, uint32_t f);
+void ext4_inode_clear_flag(struct ext4_inode *inode, uint32_t f);
+void ext4_inode_set_flag(struct ext4_inode *inode, uint32_t f);
+
+bool ext4_inode_can_truncate(struct ext4_sblock *sb, struct ext4_inode *inode);
+
+
+struct ext4_extent_header * ext4_inode_get_extent_header(struct ext4_inode *inode);
+
+#endif /* EXT4_INODE_H_ */
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/lwext4/ext4_super.c
@@ -1,0 +1,133 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_super.h
+ * @brief Superblock operations.
+ */
+
+#include <ext4_config.h>
+#include <ext4_super.h>
+
+
+uint32_t ext4_block_group_cnt(struct ext4_sblock *s)
+{
+ uint64_t blocks_count = ext4_sb_get_blocks_cnt(s);
+ uint32_t blocks_per_group = ext4_get32(s, blocks_per_group);
+
+ uint32_t block_groups_count = blocks_count / blocks_per_group;
+
+ if (blocks_count % blocks_per_group)
+ block_groups_count++;
+
+ return block_groups_count;
+}
+
+uint32_t ext4_blocks_in_group_cnt(struct ext4_sblock *s, uint32_t bgid)
+{
+ uint32_t block_group_count = ext4_block_group_cnt(s);
+ uint32_t blocks_per_group = ext4_get32(s, blocks_per_group);
+ uint64_t total_blocks = ext4_sb_get_blocks_cnt(s);
+
+ if (bgid < block_group_count - 1)
+ return blocks_per_group;
+
+
+ return (total_blocks - ((block_group_count - 1) * blocks_per_group));
+}
+
+uint32_t ext4_inodes_in_group_cnt(struct ext4_sblock *s, uint32_t bgid)
+{
+ uint32_t block_group_count = ext4_block_group_cnt(s);
+ uint32_t inodes_per_group = ext4_get32(s, inodes_per_group);
+ uint32_t total_inodes = ext4_get32(s, inodes_count);
+
+
+ if (bgid < block_group_count - 1)
+ return inodes_per_group;
+
+ return (total_inodes - ((block_group_count - 1) * inodes_per_group));
+}
+
+int ext4_sb_write(struct ext4_blockdev *bdev, struct ext4_sblock *s)
+{
+ return ext4_block_writebytes(bdev, EXT4_SUPERBLOCK_OFFSET,
+ s, EXT4_SUPERBLOCK_SIZE);
+}
+
+int ext4_sb_read(struct ext4_blockdev *bdev, struct ext4_sblock *s)
+{
+ return ext4_block_readbytes(bdev, EXT4_SUPERBLOCK_OFFSET,
+ s, EXT4_SUPERBLOCK_SIZE);
+}
+
+bool ext4_sb_check(struct ext4_sblock *s)
+{
+ if (ext4_get16(s, magic) != EXT4_SUPERBLOCK_MAGIC)
+ return false;
+
+ if (ext4_get32(s, inodes_count) == 0)
+ return false;
+
+ if (ext4_sb_get_blocks_cnt(s) == 0)
+ return false;
+
+ if (ext4_get32(s, blocks_per_group) == 0)
+ return false;
+
+ if (ext4_get32(s, inodes_per_group) == 0)
+ return false;
+
+ if (ext4_get16(s, inode_size) < 128)
+ return false;
+
+ if (ext4_get32(s, first_inode) < 11)
+ return false;
+
+ if (ext4_sb_get_desc_size(s) <
+ EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
+ return false;
+
+ if (ext4_sb_get_desc_size(s) >
+ EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE)
+ return false;
+
+ return true;
+}
+
+/**
+ * @}
+ */
--- /dev/null
+++ b/lwext4/ext4_super.h
@@ -1,0 +1,187 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_super.c
+ * @brief Superblock operations.
+ */
+
+#ifndef EXT4_SUPER_H_
+#define EXT4_SUPER_H_
+
+
+#include <ext4_config.h>
+#include <ext4_types.h>
+
+
+/****************************Unstandard access to superblock*****************/
+
+/**@brief Blocks count get stored in superblock.
+ * @param s superblock descriptor
+ * @return count of blocks*/
+static inline uint64_t ext4_sb_get_blocks_cnt(struct ext4_sblock *s)
+{
+ return ((uint64_t) to_le32(s->blocks_count_hi) << 32) |
+ to_le32(s->blocks_count_lo);
+}
+
+/**@brief Free blocks count get stored in superblock.
+ * @param s superblock descriptor
+ * @return free blocks*/
+static inline uint64_t ext4_sb_get_free_blocks_cnt(struct ext4_sblock *s)
+{
+ return ((uint64_t) to_le32(s->free_blocks_count_hi) << 32) |
+ to_le32(s->free_blocks_count_lo);
+}
+
+/**@brief Free blocks count set.
+ * @param s superblock descriptor
+ * @param cnt new value of free blocks*/
+static inline void ext4_sb_set_free_blocks_cnt(struct ext4_sblock *s,
+ uint64_t cnt)
+{
+ s->free_blocks_count_lo = to_le32((cnt << 32) >> 32);
+ s->free_blocks_count_hi = to_le32(cnt >> 32);
+}
+
+/**@brief Block size get from superblock.
+ * @param s superblock descriptor
+ * @return block size in bytes*/
+static inline uint32_t ext4_sb_get_block_size(struct ext4_sblock *s)
+{
+ return 1024 << to_le32(s->log_block_size);
+}
+
+/**@brief Block group descriptor size.
+ * @param s superblock descriptor
+ * @return block group descriptor size in bytes*/
+static inline uint16_t ext4_sb_get_desc_size(struct ext4_sblock *s)
+{
+ uint16_t size = to_le16(s->desc_size);
+
+ return size < EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE ?
+ EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE : size;
+}
+
+/*************************Flags and features*********************************/
+
+/**@brief Support check of flag.
+ * @param s superblock descriptor
+ * @param v flag to check
+ * @return true if flag is supported*/
+static inline bool ext4_sb_check_flag(struct ext4_sblock *s, uint32_t v)
+{
+ return to_le32(s->flags) & v;
+}
+
+/**@brief Support check of feature compatible.
+ * @param s superblock descriptor
+ * @param v feature to check
+ * @return true if feature is supported*/
+static inline bool ext4_sb_check_feature_compatible(struct ext4_sblock *s,
+ uint32_t v)
+{
+ return to_le32(s->features_compatible) & v;
+}
+
+
+/**@brief Support check of feature incompatible.
+ * @param s superblock descriptor
+ * @param v feature to check
+ * @return true if feature is supported*/
+static inline bool ext4_sb_check_feature_incompatible(struct ext4_sblock *s,
+ uint32_t v)
+{
+ return to_le32(s->features_incompatible) & v;
+}
+
+
+/**@brief Support check of read only flag.
+ * @param s superblock descriptor
+ * @param v flag to check
+ * @return true if flag is supported*/
+static inline bool ext4_sb_check_read_only(struct ext4_sblock *s, uint32_t v)
+{
+ return to_le32(s->features_read_only) & v;
+}
+
+/**************************More complex functions****************************/
+
+/**@brief Returns a block group count.
+ * @param s superblock descriptor
+ * @return count of block groups*/
+uint32_t ext4_block_group_cnt(struct ext4_sblock *s);
+
+/**@brief Returns block count in block group
+ * (last block group may have less blocks)
+ * @param s superblock descriptor
+ * @param bgid block group id
+ * @return blocks count*/
+uint32_t ext4_blocks_in_group_cnt(struct ext4_sblock *s, uint32_t bgid);
+
+/**@brief Returns inodes count in block group
+ * (last block group may have less inodes)
+ * @param s superblock descriptor
+ * @param bgid block group id
+ * @return inodes count*/
+uint32_t ext4_inodes_in_group_cnt(struct ext4_sblock *s, uint32_t bgid);
+
+/***************************Read/write/check superblock**********************/
+
+/**@brief Superblock write.
+ * @param bdev block device descriptor.
+ * @param s superblock descruptor
+ * @return Standard error code */
+int ext4_sb_write(struct ext4_blockdev *bdev, struct ext4_sblock *s);
+
+/**@brief Superblock read.
+ * @param bdev block device descriptor.
+ * @param s superblock descruptor
+ * @return Standard error code */
+int ext4_sb_read(struct ext4_blockdev *bdev, struct ext4_sblock *s);
+
+/**@brief Superblock simple validation.
+ * @param s superblock dsecriptor
+ * @return true if OK*/
+bool ext4_sb_check(struct ext4_sblock *s);
+
+
+#endif /* EXT4_SUPER_H_ */
+
+/**
+ * @}
+ */
+
--- /dev/null
+++ b/lwext4/ext4_types.h
@@ -1,0 +1,613 @@
+/*
+ * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
+ *
+ *
+ * HelenOS:
+ * Copyright (c) 2012 Martin Sucha
+ * Copyright (c) 2012 Frantisek Princ
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup lwext4
+ * @{
+ */
+/**
+ * @file ext4_types.h
+ * @brief Ext4 data structure definitions.
+ */
+
+#ifndef EXT4_TYPES_H_
+#define EXT4_TYPES_H_
+
+#include <ext4_config.h>
+#include <ext4_blockdev.h>
+
+#include <stdint.h>
+
+
+/*
+ * Structure of the super block
+ */
+struct ext4_sblock {
+ uint32_t inodes_count; /* I-nodes count */
+ uint32_t blocks_count_lo; /* Blocks count */
+ uint32_t reserved_blocks_count_lo; /* Reserved blocks count */
+ uint32_t free_blocks_count_lo; /* Free blocks count */
+ uint32_t free_inodes_count; /* Free inodes count */
+ uint32_t first_data_block; /* First Data Block */
+ uint32_t log_block_size; /* Block size */
+ uint32_t log_frag_size; /* Obsoleted fragment size */
+ uint32_t blocks_per_group; /* Number of blocks per group */
+ uint32_t frags_per_group; /* Obsoleted fragments per group */
+ uint32_t inodes_per_group; /* Number of inodes per group */
+ uint32_t mount_time; /* Mount time */
+ uint32_t write_time; /* Write time */
+ uint16_t mount_count; /* Mount count */
+ uint16_t max_mount_count; /* Maximal mount count */
+ uint16_t magic; /* Magic signature */
+ uint16_t state; /* File system state */
+ uint16_t errors; /* Behaviour when detecting errors */
+ uint16_t minor_rev_level; /* Minor revision level */
+ uint32_t last_check_time; /* Time of last check */
+ uint32_t check_interval; /* Maximum time between checks */
+ uint32_t creator_os; /* Creator OS */
+ uint32_t rev_level; /* Revision level */
+ uint16_t def_resuid; /* Default uid for reserved blocks */
+ uint16_t def_resgid; /* Default gid for reserved blocks */
+
+ /* Fields for EXT4_DYNAMIC_REV superblocks only. */
+ uint32_t first_inode; /* First non-reserved inode */
+ uint16_t inode_size; /* Size of inode structure */
+ uint16_t block_group_index; /* Block group index of this superblock */
+ uint32_t features_compatible; /* Compatible feature set */
+ uint32_t features_incompatible; /* Incompatible feature set */
+ uint32_t features_read_only; /* Readonly-compatible feature set */
+ uint8_t uuid[16]; /* 128-bit uuid for volume */
+ char volume_name[16]; /* Volume name */
+ char last_mounted[64]; /* Directory where last mounted */
+ uint32_t algorithm_usage_bitmap; /* For compression */
+
+ /*
+ * Performance hints. Directory preallocation should only
+ * happen if the EXT4_FEATURE_COMPAT_DIR_PREALLOC flag is on.
+ */
+ uint8_t s_prealloc_blocks; /* Number of blocks to try to preallocate */
+ uint8_t s_prealloc_dir_blocks; /* Number to preallocate for dirs */
+ uint16_t s_reserved_gdt_blocks; /* Per group desc for online growth */
+
+ /*
+ * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set.
+ */
+ uint8_t journal_uuid[16]; /* UUID of journal superblock */
+ uint32_t journal_inode_number; /* Inode number of journal file */
+ uint32_t journal_dev; /* Device number of journal file */
+ uint32_t last_orphan; /* Head of list of inodes to delete */
+ uint32_t hash_seed[4]; /* HTREE hash seed */
+ uint8_t default_hash_version; /* Default hash version to use */
+ uint8_t journal_backup_type;
+ uint16_t desc_size; /* Size of group descriptor */
+ uint32_t default_mount_opts; /* Default mount options */
+ uint32_t first_meta_bg; /* First metablock block group */
+ uint32_t mkfs_time; /* When the filesystem was created */
+ uint32_t journal_blocks[17]; /* Backup of the journal inode */
+
+ /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
+ uint32_t blocks_count_hi; /* Blocks count */
+ uint32_t reserved_blocks_count_hi; /* Reserved blocks count */
+ uint32_t free_blocks_count_hi; /* Free blocks count */
+ uint16_t min_extra_isize; /* All inodes have at least # bytes */
+ uint16_t want_extra_isize; /* New inodes should reserve # bytes */
+ uint32_t flags; /* Miscellaneous flags */
+ uint16_t raid_stride; /* RAID stride */
+ uint16_t mmp_interval; /* # seconds to wait in MMP checking */
+ uint64_t mmp_block; /* Block for multi-mount protection */
+ uint32_t raid_stripe_width; /* Blocks on all data disks (N * stride) */
+ uint8_t log_groups_per_flex; /* FLEX_BG group size */
+ uint8_t reserved_char_pad;
+ uint16_t reserved_pad;
+ uint64_t kbytes_written; /* Number of lifetime kilobytes written */
+ uint32_t snapshot_inum; /* I-node number of active snapshot */
+ uint32_t snapshot_id; /* Sequential ID of active snapshot */
+ uint64_t snapshot_r_blocks_count; /* Reserved blocks for active snapshot's future use */
+ uint32_t snapshot_list; /* I-node number of the head of the on-disk snapshot list */
+ uint32_t error_count; /* Number of file system errors */
+ uint32_t first_error_time; /* First time an error happened */
+ uint32_t first_error_ino; /* I-node involved in first error */
+ uint64_t first_error_block; /* Block involved of first error */
+ uint8_t first_error_func[32]; /* Function where the error happened */
+ uint32_t first_error_line; /* Line number where error happened */
+ uint32_t last_error_time; /* Most recent time of an error */
+ uint32_t last_error_ino; /* I-node involved in last error */
+ uint32_t last_error_line; /* Line number where error happened */
+ uint64_t last_error_block; /* Block involved of last error */
+ uint8_t last_error_func[32]; /* Function where the error happened */
+ uint8_t mount_opts[64];
+ uint32_t padding[112]; /* Padding to the end of the block */
+} __attribute__((packed));
+
+
+#define EXT4_SUPERBLOCK_MAGIC 0xEF53
+#define EXT4_SUPERBLOCK_SIZE 1024
+#define EXT4_SUPERBLOCK_OFFSET 1024
+
+#define EXT4_SUPERBLOCK_OS_LINUX 0
+#define EXT4_SUPERBLOCK_OS_HURD 1
+
+/*
+ * Misc. filesystem flags
+ */
+#define EXT4_SUPERBLOCK_FLAGS_SIGNED_HASH 0x0001 /* Signed dirhash in use */
+#define EXT4_SUPERBLOCK_FLAGS_UNSIGNED_HASH 0x0002 /* Unsigned dirhash in use */
+#define EXT4_SUPERBLOCK_FLAGS_TEST_FILESYS 0x0004 /* to test development code */
+
+/*
+ * Filesystem states
+ */
+#define EXT4_SUPERBLOCK_STATE_VALID_FS 0x0001 /* Unmounted cleanly */
+#define EXT4_SUPERBLOCK_STATE_ERROR_FS 0x0002 /* Errors detected */
+#define EXT4_SUPERBLOCK_STATE_ORPHAN_FS 0x0004 /* Orphans being recovered */
+
+/*
+ * Behaviour when errors detected
+ */
+#define EXT4_SUPERBLOCK_ERRORS_CONTINUE 1 /* Continue execution */
+#define EXT4_SUPERBLOCK_ERRORS_RO 2 /* Remount fs read-only */
+#define EXT4_SUPERBLOCK_ERRORS_PANIC 3 /* Panic */
+#define EXT4_SUPERBLOCK_ERRORS_DEFAULT EXT4_ERRORS_CONTINUE
+
+/*
+ * Compatible features
+ */
+#define EXT4_FEATURE_COMPAT_DIR_PREALLOC 0x0001
+#define EXT4_FEATURE_COMPAT_IMAGIC_INODES 0x0002
+#define EXT4_FEATURE_COMPAT_HAS_JOURNAL 0x0004
+#define EXT4_FEATURE_COMPAT_EXT_ATTR 0x0008
+#define EXT4_FEATURE_COMPAT_RESIZE_INODE 0x0010
+#define EXT4_FEATURE_COMPAT_DIR_INDEX 0x0020
+
+/*
+ * Read-only compatible features
+ */
+#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
+#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
+#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
+#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008
+#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
+#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
+#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
+
+/*
+ * Incompatible features
+ */
+#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001
+#define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002
+#define EXT4_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
+#define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
+#define EXT4_FEATURE_INCOMPAT_META_BG 0x0010
+#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */
+#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
+#define EXT4_FEATURE_INCOMPAT_MMP 0x0100
+#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
+#define EXT4_FEATURE_INCOMPAT_EA_INODE 0x0400 /* EA in inode */
+#define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000 /* data in dirent */
+
+#define EXT4_FEATURE_COMPAT_SUPP (EXT4_FEATURE_COMPAT_DIR_INDEX)
+
+#define EXT4_FEATURE_INCOMPAT_SUPP \
+ (EXT4_FEATURE_INCOMPAT_FILETYPE | \
+ EXT4_FEATURE_INCOMPAT_EXTENTS | \
+ EXT4_FEATURE_INCOMPAT_64BIT)
+
+#define EXT4_FEATURE_RO_COMPAT_SUPP \
+ (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER | \
+ EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \
+ EXT4_FEATURE_RO_COMPAT_HUGE_FILE | \
+ EXT4_FEATURE_RO_COMPAT_LARGE_FILE | \
+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM | \
+ EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)
+
+struct ext4_fs {
+ struct ext4_blockdev *bdev;
+ struct ext4_sblock sb;
+
+ uint64_t inode_block_limits[4];
+ uint64_t inode_blocks_per_level[4];
+};
+
+
+#define EXT4_BLOCK_GROUP_INODE_UNINIT 0x0001 /* Inode table/bitmap not in use */
+#define EXT4_BLOCK_GROUP_BLOCK_UNINIT 0x0002 /* Block bitmap not in use */
+#define EXT4_BLOCK_GROUP_ITABLE_ZEROED 0x0004 /* On-disk itable initialized to zero */
+
+/*
+ * Structure of a blocks group descriptor
+ */
+struct ext4_bgroup {
+ uint32_t block_bitmap_lo; /* Blocks bitmap block */
+ uint32_t inode_bitmap_lo; /* Inodes bitmap block */
+ uint32_t inode_table_first_block_lo; /* Inodes table block */
+ uint16_t free_blocks_count_lo; /* Free blocks count */
+ uint16_t free_inodes_count_lo; /* Free inodes count */
+ uint16_t used_dirs_count_lo; /* Directories count */
+ uint16_t flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */
+ uint32_t reserved[2]; /* Likely block/inode bitmap checksum */
+ uint16_t itable_unused_lo; /* Unused inodes count */
+ uint16_t checksum; /* crc16(sb_uuid+group+desc) */
+
+ uint32_t block_bitmap_hi; /* Blocks bitmap block MSB */
+ uint32_t inode_bitmap_hi; /* I-nodes bitmap block MSB */
+ uint32_t inode_table_first_block_hi; /* I-nodes table block MSB */
+ uint16_t free_blocks_count_hi; /* Free blocks count MSB */
+ uint16_t free_inodes_count_hi; /* Free i-nodes count MSB */
+ uint16_t used_dirs_count_hi; /* Directories count MSB */
+ uint16_t itable_unused_hi; /* Unused inodes count MSB */
+ uint32_t reserved2[3]; /* Padding */
+} ;
+
+struct ext4_block_group_ref {
+ struct ext4_block block;
+ struct ext4_bgroup *block_group;
+ struct ext4_fs *fs;
+ uint32_t index;
+ bool dirty;
+};
+
+#define EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE 32
+#define EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE 64
+
+#define EXT4_MIN_BLOCK_SIZE 1024 /* 1 KiB */
+#define EXT4_MAX_BLOCK_SIZE 65536 /* 64 KiB */
+#define EXT4_REV0_INODE_SIZE 128
+
+#define EXT4_INODE_BLOCK_SIZE 512
+
+#define EXT4_INODE_DIRECT_BLOCK_COUNT 12
+#define EXT4_INODE_INDIRECT_BLOCK EXT4_INODE_DIRECT_BLOCK_COUNT
+#define EXT4_INODE_DOUBLE_INDIRECT_BLOCK (EXT4_INODE_INDIRECT_BLOCK + 1)
+#define EXT4_INODE_TRIPPLE_INDIRECT_BLOCK (EXT4_INODE_DOUBLE_INDIRECT_BLOCK + 1)
+#define EXT4_INODE_BLOCKS (EXT4_INODE_TRIPPLE_INDIRECT_BLOCK + 1)
+#define EXT4_INODE_INDIRECT_BLOCK_COUNT (EXT4_INODE_BLOCKS - EXT4_INODE_DIRECT_BLOCK_COUNT)
+
+/*
+ * Structure of an inode on the disk
+ */
+struct ext4_inode {
+ uint16_t mode; /* File mode */
+ uint16_t uid; /* Low 16 bits of owner uid */
+ uint32_t size_lo; /* Size in bytes */
+ uint32_t access_time; /* Access time */
+ uint32_t change_inode_time; /* I-node change time */
+ uint32_t modification_time; /* Modification time */
+ uint32_t deletion_time; /* Deletion time */
+ uint16_t gid; /* Low 16 bits of group id */
+ uint16_t links_count; /* Links count */
+ uint32_t blocks_count_lo; /* Blocks count */
+ uint32_t flags; /* File flags */
+ uint32_t unused_osd1; /* OS dependent - not used in HelenOS */
+ uint32_t blocks[EXT4_INODE_BLOCKS]; /* Pointers to blocks */
+ uint32_t generation; /* File version (for NFS) */
+ uint32_t file_acl_lo; /* File ACL */
+ uint32_t size_hi;
+ uint32_t obso_faddr; /* Obsoleted fragment address */
+
+ union {
+ struct {
+ uint16_t blocks_high;
+ uint16_t file_acl_high;
+ uint16_t uid_high;
+ uint16_t gid_high;
+ uint32_t reserved2;
+ } linux2;
+ struct {
+ uint16_t reserved1;
+ uint16_t mode_high;
+ uint16_t uid_high;
+ uint16_t gid_high;
+ uint32_t author;
+ } hurd2;
+ } __attribute__ ((packed)) osd2;
+
+ uint16_t extra_isize;
+ uint16_t pad1;
+ uint32_t ctime_extra; /* Extra change time (nsec << 2 | epoch) */
+ uint32_t mtime_extra; /* Extra Modification time (nsec << 2 | epoch) */
+ uint32_t atime_extra; /* Extra Access time (nsec << 2 | epoch) */
+ uint32_t crtime; /* File creation time */
+ uint32_t crtime_extra; /* Extra file creation time (nsec << 2 | epoch) */
+ uint32_t version_hi; /* High 32 bits for 64-bit version */
+} __attribute__ ((packed)) ;
+
+#define EXT4_INODE_MODE_FIFO 0x1000
+#define EXT4_INODE_MODE_CHARDEV 0x2000
+#define EXT4_INODE_MODE_DIRECTORY 0x4000
+#define EXT4_INODE_MODE_BLOCKDEV 0x6000
+#define EXT4_INODE_MODE_FILE 0x8000
+#define EXT4_INODE_MODE_SOFTLINK 0xA000
+#define EXT4_INODE_MODE_SOCKET 0xC000
+#define EXT4_INODE_MODE_TYPE_MASK 0xF000
+
+/*
+ * Inode flags
+ */
+#define EXT4_INODE_FLAG_SECRM 0x00000001 /* Secure deletion */
+#define EXT4_INODE_FLAG_UNRM 0x00000002 /* Undelete */
+#define EXT4_INODE_FLAG_COMPR 0x00000004 /* Compress file */
+#define EXT4_INODE_FLAG_SYNC 0x00000008 /* Synchronous updates */
+#define EXT4_INODE_FLAG_IMMUTABLE 0x00000010 /* Immutable file */
+#define EXT4_INODE_FLAG_APPEND 0x00000020 /* writes to file may only append */
+#define EXT4_INODE_FLAG_NODUMP 0x00000040 /* do not dump file */
+#define EXT4_INODE_FLAG_NOATIME 0x00000080 /* do not update atime */
+
+/* Compression flags */
+#define EXT4_INODE_FLAG_DIRTY 0x00000100
+#define EXT4_INODE_FLAG_COMPRBLK 0x00000200 /* One or more compressed clusters */
+#define EXT4_INODE_FLAG_NOCOMPR 0x00000400 /* Don't compress */
+#define EXT4_INODE_FLAG_ECOMPR 0x00000800 /* Compression error */
+
+#define EXT4_INODE_FLAG_INDEX 0x00001000 /* hash-indexed directory */
+#define EXT4_INODE_FLAG_IMAGIC 0x00002000 /* AFS directory */
+#define EXT4_INODE_FLAG_JOURNAL_DATA 0x00004000 /* File data should be journaled */
+#define EXT4_INODE_FLAG_NOTAIL 0x00008000 /* File tail should not be merged */
+#define EXT4_INODE_FLAG_DIRSYNC 0x00010000 /* Dirsync behaviour (directories only) */
+#define EXT4_INODE_FLAG_TOPDIR 0x00020000 /* Top of directory hierarchies */
+#define EXT4_INODE_FLAG_HUGE_FILE 0x00040000 /* Set to each huge file */
+#define EXT4_INODE_FLAG_EXTENTS 0x00080000 /* Inode uses extents */
+#define EXT4_INODE_FLAG_EA_INODE 0x00200000 /* Inode used for large EA */
+#define EXT4_INODE_FLAG_EOFBLOCKS 0x00400000 /* Blocks allocated beyond EOF */
+#define EXT4_INODE_FLAG_RESERVED 0x80000000 /* reserved for ext4 lib */
+
+#define EXT4_INODE_ROOT_INDEX 2
+
+struct ext4_inode_ref {
+ struct ext4_block block;
+ struct ext4_inode *inode;
+ struct ext4_fs *fs;
+ uint32_t index;
+ bool dirty;
+} ;
+
+
+#define EXT4_DIRECTORY_FILENAME_LEN 255
+
+#define EXT4_DIRECTORY_FILETYPE_UNKNOWN 0
+#define EXT4_DIRECTORY_FILETYPE_REG_FILE 1
+#define EXT4_DIRECTORY_FILETYPE_DIR 2
+#define EXT4_DIRECTORY_FILETYPE_CHRDEV 3
+#define EXT4_DIRECTORY_FILETYPE_BLKDEV 4
+#define EXT4_DIRECTORY_FILETYPE_FIFO 5
+#define EXT4_DIRECTORY_FILETYPE_SOCK 6
+#define EXT4_DIRECTORY_FILETYPE_SYMLINK 7
+
+/**
+ * Linked list directory entry structure
+ */
+struct ext4_directory_entry_ll {
+ uint32_t inode; /* I-node for the entry */
+ uint16_t entry_length; /* Distance to the next directory entry */
+ uint8_t name_length; /* Lower 8 bits of name length */
+
+ union {
+ uint8_t name_length_high; /* Higher 8 bits of name length */
+ uint8_t inode_type; /* Type of referenced inode (in rev >= 0.5) */
+ } __attribute__ ((packed));
+
+ uint8_t name[EXT4_DIRECTORY_FILENAME_LEN]; /* Entry name */
+} __attribute__((packed)) ;
+
+struct ext4_directory_iterator {
+ struct ext4_inode_ref *inode_ref;
+ struct ext4_block current_block;
+ uint64_t current_offset;
+ struct ext4_directory_entry_ll *current;
+};
+
+struct ext4_directory_search_result {
+ struct ext4_block block;
+ struct ext4_directory_entry_ll *dentry;
+};
+
+/* Structures for indexed directory */
+
+struct ext4_directory_dx_countlimit {
+ uint16_t limit;
+ uint16_t count;
+} ;
+
+struct ext4_directory_dx_dot_entry {
+ uint32_t inode;
+ uint16_t entry_length;
+ uint8_t name_length;
+ uint8_t inode_type;
+ uint8_t name[4];
+} ;
+
+struct ext4_directory_dx_root_info {
+ uint32_t reserved_zero;
+ uint8_t hash_version;
+ uint8_t info_length;
+ uint8_t indirect_levels;
+ uint8_t unused_flags;
+} ;
+
+struct ext4_directory_dx_entry {
+ uint32_t hash;
+ uint32_t block;
+} ;
+
+struct ext4_directory_dx_root {
+ struct ext4_directory_dx_dot_entry dots[2];
+ struct ext4_directory_dx_root_info info;
+ struct ext4_directory_dx_entry entries[0];
+};
+
+struct ext4_fake_directory_entry {
+ uint32_t inode;
+ uint16_t entry_length;
+ uint8_t name_length;
+ uint8_t inode_type;
+};
+
+struct ext4_directory_dx_node {
+ struct ext4_fake_directory_entry fake;
+ struct ext4_directory_dx_entry entries[0];
+};
+
+struct ext4_directory_dx_block {
+ struct ext4_block block;
+ struct ext4_directory_dx_entry *entries;
+ struct ext4_directory_dx_entry *position;
+} ;
+
+#define EXT4_ERR_BAD_DX_DIR (-75000)
+
+
+/*
+ * This is the extent on-disk structure.
+ * It's used at the bottom of the tree.
+ */
+struct ext4_extent {
+ uint32_t first_block; /* First logical block extent covers */
+ uint16_t block_count; /* Number of blocks covered by extent */
+ uint16_t start_hi; /* High 16 bits of physical block */
+ uint32_t start_lo; /* Low 32 bits of physical block */
+} ;
+
+/*
+ * This is index on-disk structure.
+ * It's used at all the levels except the bottom.
+ */
+struct ext4_extent_index {
+ uint32_t first_block; /* Index covers logical blocks from 'block' */
+
+ /**
+ * Pointer to the physical block of the next
+ * level. leaf or next index could be there
+ * high 16 bits of physical block
+ */
+ uint32_t leaf_lo;
+ uint16_t leaf_hi;
+ uint16_t padding;
+} ;
+
+/*
+ * Each block (leaves and indexes), even inode-stored has header.
+ */
+struct ext4_extent_header {
+ uint16_t magic;
+ uint16_t entries_count; /* Number of valid entries */
+ uint16_t max_entries_count; /* Capacity of store in entries */
+ uint16_t depth; /* Has tree real underlying blocks? */
+ uint32_t generation; /* generation of the tree */
+} ;
+
+struct ext4_extent_path {
+ struct ext4_block block;
+ uint16_t depth;
+ struct ext4_extent_header *header;
+ struct ext4_extent_index *index;
+ struct ext4_extent *extent;
+} ;
+
+#define EXT4_EXTENT_MAGIC 0xF30A
+
+#define EXT4_EXTENT_FIRST(header) \
+ ((struct ext4_extent *) (((void *) (header)) + sizeof(struct ext4_extent_header)))
+
+#define EXT4_EXTENT_FIRST_INDEX(header) \
+ ((struct ext4_extent_index *) (((void *) (header)) + sizeof(struct ext4_extent_header)))
+
+
+/* EXT3 HTree directory indexing */
+#define EXT2_HTREE_LEGACY 0
+#define EXT2_HTREE_HALF_MD4 1
+#define EXT2_HTREE_TEA 2
+#define EXT2_HTREE_LEGACY_UNSIGNED 3
+#define EXT2_HTREE_HALF_MD4_UNSIGNED 4
+#define EXT2_HTREE_TEA_UNSIGNED 5
+
+#define EXT2_HTREE_EOF 0x7FFFFFFF
+
+
+struct ext4_hash_info {
+ uint32_t hash;
+ uint32_t minor_hash;
+ uint32_t hash_version;
+ const uint32_t *seed;
+};
+
+/*****************************************************************************/
+
+
+#ifdef CONFIG_BIG_ENDIAN
+static inline uint64_t to_le64(uint64_t n)
+{
+ return ((n & 0xff) << 56) |
+ ((n & 0xff00) << 40) |
+ ((n & 0xff0000) << 24) |
+ ((n & 0xff000000LL) << 8) |
+ ((n & 0xff00000000LL) >> 8) |
+ ((n & 0xff0000000000LL) >> 24) |
+ ((n & 0xff000000000000LL) >> 40) |
+ ((n & 0xff00000000000000LL) >> 56);
+}
+
+static inline uint32_t to_le32(uint32_t n)
+{
+ return ((n & 0xff) << 24) |
+ ((n & 0xff00) << 8) |
+ ((n & 0xff0000) >> 8) |
+ ((n & 0xff000000) >> 24);
+}
+
+static inline uint16_t to_le16(uint16_t n)
+{
+ return ((n & 0xff) << 8) |
+ ((n & 0xff00) >> 8);
+}
+
+
+#else
+#define to_le64(_n) _n
+#define to_le32(_n) _n
+#define to_le16(_n) _n
+#endif
+
+/****************************Access macros to ext4 structures*****************/
+
+#define ext4_get32(s, f) to_le32((s)->f)
+#define ext4_get16(s, f) to_le16((s)->f)
+#define ext4_get8(s, f) (s)->f
+
+
+#define ext4_set32(s, f, v) do { (s)->f = to_le32(v); }while(0)
+#define ext4_set16(s, f, v) do { (s)->f = to_le16(v); }while(0)
+#define ext4_set8 (s, f, v) do { (s)->f = (v); }while(0)
+
+#endif /* EXT4_TYPES_H_ */
+
+/**
+ * @}
+ */
--- a/src/CMakeLists.txt
+++ /dev/null
@@ -1,46 +1,0 @@
-project(lwext4 C)
-cmake_minimum_required(VERSION 2.8)
-
-
-#LIBRARY
-include_directories(. lwext4)
-aux_source_directory(lwext4 LWEXT4_SRC)
-add_library(lwext4 ${LWEXT4_SRC})
-
-
-#EXECUTABLE
-
-if(CMAKE_SYSTEM_PROCESSOR STREQUAL cortex-m3)
-#Library size print
-add_custom_target(size ALL DEPENDS lwext4 COMMAND ${SIZE} -B liblwext4.a)
-
-elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL cortex-m4)
-#Library size print
-add_custom_target(size ALL DEPENDS lwext4 COMMAND ${SIZE} -B liblwext4.a)
-
-elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL bf518)
-#Library size print
-add_custom_target(size ALL DEPENDS lwext4 COMMAND ${SIZE} -B liblwext4.a)
-
-else()
-#Generic example target
-include_directories(blockdev/filedev)
-aux_source_directory(blockdev/filedev FILEDEV_SRC)
-aux_source_directory(demos/generic GENERIC_SRC)
-add_executable(fileimage_demo ${GENERIC_SRC} ${FILEDEV_SRC})
-target_link_libraries(fileimage_demo lwext4)
-add_custom_target(size ALL DEPENDS lwext4 COMMAND size -B liblwext4.a)
-endif()
-
-#DISTRIBUTION
-set(CPACK_PACKAGE_VERSION_MAJOR "0")
-set(CPACK_PACKAGE_VERSION_MINOR "1")
-set(CPACK_PACKAGE_VERSION_PATCH "1")
-set(CPACK_SOURCE_GENERATOR "TBZ2")
-set(CPACK_SOURCE_PACKAGE_FILE_NAME
- "${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
-set(CPACK_SOURCE_IGNORE_FILES
-"/build")
-include(CPack)
-
-add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source)
--- a/src/Makefile
+++ /dev/null
@@ -1,36 +1,0 @@
-
-all: generic bf518 cortex-m3 cortex-m4 generic
-
-bf518:
- rm -R -f build_bf518
- mkdir build_bf518
- cd build_bf518 && cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../toolchain/bf518.cmake ..
- cd build_bf518 && make
-
-cortex-m3:
- rm -R -f build_cortex-m3
- mkdir build_cortex-m3
- cd build_cortex-m3 && cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../toolchain/cortex-m3.cmake ..
- cd build_cortex-m3 && make
-
-cortex-m4:
- rm -R -f build_cortex-m4
- mkdir build_cortex-m4
- cd build_cortex-m4 && cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=../toolchain/cortex-m4.cmake ..
- cd build_cortex-m4 && make
-
-
-generic:
- rm -R -f build_generic
- mkdir build_generic
- cd build_generic && cmake -G"Unix Makefiles" ../
- cd build_generic && make
-
-
-clean:
- rm -R -f build_bf518
- rm -R -f build_cortex-m3
- rm -R -f build_cortex-m4
- rm -R -f build_generic
-
-
\ No newline at end of file
--- a/src/blockdev/filedev/ext4_filedev.c
+++ /dev/null
@@ -1,135 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include <ext4_config.h>
-#include <ext4_blockdev.h>
-#include <ext4_errno.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <string.h>
-
-/**@brief Default filename.*/
-const char *fname = "ext2";
-
-/**@brief Image block size.*/
-#define EXT4_FILEDEV_BSIZE 512
-
-/**@brief Image file descriptor.*/
-static FILE *dev_file;
-
-
-/**********************BLOCKDEV INTERFACE**************************************/
-static int filedev_open(struct ext4_blockdev *bdev);
-static int filedev_bread(struct ext4_blockdev *bdev, void *buf, uint64_t blk_id,
- uint32_t blk_cnt);
-static int filedev_bwrite(struct ext4_blockdev *bdev, const void *buf,
- uint64_t blk_id, uint32_t blk_cnt);
-static int filedev_close(struct ext4_blockdev *bdev);
-
-
-/******************************************************************************/
-EXT4_BLOCKDEV_STATIC_INSTANCE(
- _filedev,
- EXT4_FILEDEV_BSIZE,
- 0,
- filedev_open,
- filedev_bread,
- filedev_bwrite,
- filedev_close
-);
-
-/******************************************************************************/
-EXT4_BCACHE_STATIC_INSTANCE(__cache, 8, 1024);
-
-/******************************************************************************/
-static int filedev_open(struct ext4_blockdev *bdev)
-{
- dev_file = fopen(fname, "r+b");
-
- if(!dev_file)
- return ENOENT;
-
- if(fseek(dev_file, 0, SEEK_END))
- return EFAULT;
-
- _filedev.ph_bcnt = ftell(dev_file) / _filedev.ph_bsize;
-
- return EOK;
-}
-
-/******************************************************************************/
-
-static int filedev_bread(struct ext4_blockdev *bdev, void *buf, uint64_t blk_id,
- uint32_t blk_cnt)
-{
- if(fseek(dev_file, blk_id * bdev->ph_bsize, SEEK_SET))
- return EIO;
-
- if(!fread(buf, bdev->ph_bsize * blk_cnt, 1, dev_file))
- return EIO;
-
- return EOK;
-}
-
-/******************************************************************************/
-static int filedev_bwrite(struct ext4_blockdev *bdev, const void *buf,
- uint64_t blk_id, uint32_t blk_cnt)
-{
- if(fseek(dev_file, blk_id * bdev->ph_bsize, SEEK_SET))
- return EIO;
-
- if(!fwrite(buf, bdev->ph_bsize * blk_cnt, 1, dev_file))
- return EIO;
- return EOK;
-}
-
-/******************************************************************************/
-static int filedev_close(struct ext4_blockdev *bdev)
-{
- fclose(dev_file);
- return EOK;
-}
-
-
-/******************************************************************************/
-
-struct ext4_bcache* ext4_filecache_get(void)
-{
- return &__cache;
-}
-/******************************************************************************/
-struct ext4_blockdev* ext4_filedev_get(void)
-{
- return &_filedev;
-}
-/******************************************************************************/
-void ext4_filedev_filename(const char *n)
-{
- fname = n;
-}
-
-/******************************************************************************/
--- a/src/blockdev/filedev/ext4_filedev.h
+++ /dev/null
@@ -1,45 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef EXT4_FILEDEV_H_
-#define EXT4_FILEDEV_H_
-
-#include <ext4_config.h>
-#include <ext4_blockdev.h>
-
-#include <stdint.h>
-#include <stdbool.h>
-
-/**@brief Filecache get.*/
-struct ext4_bcache* ext4_filecache_get(void);
-
-/**@brief File blockdev get.*/
-struct ext4_blockdev* ext4_filedev_get(void);
-
-void ext4_filedev_filename(const char *n);
-
-#endif /* EXT4_FILEDEV_H_ */
--- a/src/demos/generic/main.c
+++ /dev/null
@@ -1,344 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <stdbool.h>
-
-#include <ext4_filedev.h>
-#include <ext4.h>
-
-
-
-char input_name[128] = "ext2";
-
-/**@brief Read-write size*/
-static int rw_szie = 1024;
-
-/**@brief Read-write size*/
-static int rw_count = 1024;
-
-static bool cache_mode = false;
-
-
-/**@brief File write buffer*/
-static uint8_t *wr_buff;
-
-/**@brief File read buffer.*/
-static uint8_t *rd_buff;
-
-/**@brief Block device handle.*/
-static struct ext4_blockdev *bd;
-
-/**@brief Block cache handle.*/
-static struct ext4_bcache *bc;
-
-static const char *usage = " \n\
-Welcome in ext4 generic demo. \n\
-Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com) \n\
-Usage: \n\
- -i - input file (default = ext2) \n\
- -rws - single R/W size (default = 1024) \n\
- -rwc - R/W count (default = 1024) \n\
- -cache - 0 static, 1 dynamic (default = 0) \n\
-\n";
-
-static char* entry_to_str(uint8_t type)
-{
- switch(type){
- case EXT4_DIRENTRY_UNKNOWN:
- return "[UNK] ";
- case EXT4_DIRENTRY_REG_FILE:
- return "[FIL] ";
- case EXT4_DIRENTRY_DIR:
- return "[DIR] ";
- case EXT4_DIRENTRY_CHRDEV:
- return "[CHA] ";
- case EXT4_DIRENTRY_BLKDEV:
- return "[BLK] ";
- case EXT4_DIRENTRY_FIFO:
- return "[FIF] ";
- case EXT4_DIRENTRY_SOCK:
- return "[SOC] ";
- case EXT4_DIRENTRY_SYMLINK:
- return "[SYM] ";
- default:
- break;
- }
- return "[???]";
-}
-
-static void dir_ls(const char *path)
-{
- int j = 0;
- char sss[255];
- ext4_dir d;
- ext4_direntry *de;
-
- printf("**********************************************\n");
-
- ext4_dir_open(&d, path);
- de = ext4_entry_get(&d, j++);
- printf("ls %s\n", path);
-
- while(de){
- memcpy(sss, de->name, de->name_length);
- sss[de->name_length] = 0;
- printf(entry_to_str(de->inode_type));
- printf(sss);
- printf("\n");
- de = ext4_entry_get(&d, j++);
- }
- printf("**********************************************\n");
- ext4_dir_close(&d);
-}
-
-static void mp_stats(void)
-{
- struct ext4_mount_stats stats;
- ext4_mount_point_stats("/mp/", &stats);
-
- printf("**********************************************\n");
- printf("ext4_mount_point_stats\n");
- printf("inodes_count = %d\n", stats.inodes_count);
- printf("free_inodes_count = %d\n", stats.free_inodes_count);
- printf("blocks_count = %d\n", stats.blocks_count);
- printf("free_blocks_count = %d\n", stats.free_blocks_count);
- printf("block_size = %d\n", stats.block_size);
- printf("block_group_count = %d\n", stats.block_group_count);
- printf("blocks_per_group = %d\n", stats.blocks_per_group);
- printf("inodes_per_group = %d\n", stats.inodes_per_group);
- printf("volume_name = %s\n", stats.volume_name);
-
- printf("**********************************************\n");
-
-}
-
-static void block_stats(void)
-{
- uint32_t i;
-
- printf("**********************************************\n");
- printf("ext4 blockdev stats\n");
- printf("bdev->bread_ctr = %d\n", bd->bread_ctr);
- printf("bdev->bwrite_ctr = %d\n", bd->bwrite_ctr);
-
-
- printf("bcache->ref_blocks = %d\n", bc->ref_blocks);
- printf("bcache->max_ref_blocks = %d\n", bc->max_ref_blocks);
- printf("bcache->lru_ctr = %d\n", bc->lru_ctr);
-
- printf("\n");
- for (i = 0; i < bc->cnt; ++i) {
- printf("bcache->refctr[%d] = %d\n", i, bc->refctr[i]);
- }
-
- printf("\n");
- for (i = 0; i < bc->cnt; ++i) {
- printf("bcache->lru_id[%d] = %d\n", i, bc->lru_id[i]);
- }
-
- printf("\n");
- for (i = 0; i < bc->cnt; ++i) {
- printf("bcache->free_delay[%d] = %d\n", i, bc->free_delay[i]);
- }
-
- printf("\n");
- for (i = 0; i < bc->cnt; ++i) {
- printf("bcache->lba[%d] = %d\n", i, bc->lba[i]);
- }
-
-
-
- printf("**********************************************\n");
-}
-
-
-int main(int argc, char **argv)
-{
- int option_index = 0;
- int c;
- int r;
- int i;
- uint32_t size;
- ext4_file f;
-
- static struct option long_options[] =
- {
- {"in", required_argument, 0, 'a'},
- {"rws", required_argument, 0, 'b'},
- {"rwc", required_argument, 0, 'c'},
- {"cache", required_argument, 0, 'd'},
- {0, 0, 0, 0}
- };
-
- while(-1 != (c = getopt_long (argc, argv, "a:b:c:d:", long_options, &option_index))) {
-
- switch(c){
- case 'a':
- strcpy(input_name, optarg);
- break;
- case 'b':
- rw_szie = atoi(optarg);
- break;
- case 'c':
- rw_count = atoi(optarg);
- break;
- case 'd':
- cache_mode = atoi(optarg);
- break;
- default:
- printf(usage);
- return EXIT_FAILURE;
-
- }
- }
-
- printf("Test conditions:\n");
- printf("Imput name: %s\n", input_name);
- printf("RW size: %d\n", rw_szie);
- printf("RW count: %d\n", rw_count);
- printf("Cache mode: %s\n", cache_mode ? "dynamic" : "static");
-
-
-
- ext4_filedev_filename(input_name);
-
- wr_buff = malloc(rw_szie);
- rd_buff = malloc(rw_szie);
-
- if(!wr_buff || !rd_buff){
- printf("Read-Write allocation ERROR\n");
- return EXIT_FAILURE;
- }
-
- bd = ext4_filedev_get();
- bc = ext4_filecache_get();
-
- if(!bd || !bc){
- printf("Block device ERROR\n");
- return EXIT_FAILURE;
- }
-
- ext4_dmask_set(EXT4_DEBUG_ALL);
-
- r = ext4_device_register(bd, cache_mode ? 0 : bc, "ext4_filesim");
- if(r != EOK){
- printf("ext4_device_register ERROR = %d\n", r);
- return EXIT_FAILURE;
- }
-
- r = ext4_mount("ext4_filesim", "/mp/");
- if(r != EOK){
- printf("ext4_mount ERROR = %d\n", r);
- return EXIT_FAILURE;
- }
-
-
- ext4_fremove("/mp/hello.txt");
- ext4_fremove("/mp/test1");
- mp_stats();
- dir_ls("/mp/");
-
- /*Add hello world file.*/
- r = ext4_fopen(&f, "/mp/hello.txt", "wb");
- r = ext4_fwrite(&f, "Hello World !\n", strlen("Hello World !\n"), 0);
- r = ext4_fclose(&f);
-
-
- printf("ext4_fopen: test1\n");
-
- r = ext4_fopen(&f, "/mp/test1", "wb");
- if(r != EOK){
- printf("ext4_fopen ERROR = %d\n", r);
- return EXIT_FAILURE;
- }
-
- printf("ext4_write: %d * %d ..." , rw_count, rw_szie);
-
- for (i = 0; i < rw_count; ++i) {
-
- memset(wr_buff, i & 0xFF, rw_szie);
-
- r = ext4_fwrite(&f, wr_buff, rw_szie, &size);
-
- if((r != EOK) || (size != rw_szie))
- break;
- }
-
- if(i != rw_count){
- printf("ERROR: rw_count = %d\n", i);
- return EXIT_FAILURE;
- }
-
- printf("OK\n");
- r = ext4_fclose(&f);
- printf("ext4_fopen: test1\n");
-
- r = ext4_fopen(&f, "/mp/test1", "r+");
- if(r != EOK){
- printf("ext4_fopen ERROR = %d\n", r);
- return EXIT_FAILURE;
- }
-
- printf("ext4_read: %d * %d ..." , rw_count, rw_szie);
-
- for (i = 0; i < rw_count; ++i) {
- memset(wr_buff, i & 0xFF, rw_szie);
- r = ext4_fread(&f, rd_buff, rw_szie, &size);
-
- if((r != EOK) || (size != rw_szie))
- break;
-
- if(memcmp(rd_buff, wr_buff, rw_szie)){
- break;
- }
- }
- if(i != rw_count){
- printf("ERROR: rw_count = %d\n", i);
- return EXIT_FAILURE;
- }
-
- printf("OK\n");
-
- r = ext4_fclose(&f);
-
-
- mp_stats();
- dir_ls("/mp/");
-
- block_stats();
- r = ext4_umount("/mp/");
-
- printf("Test finish: OK\n");
- return EXIT_SUCCESS;
-
-}
--- a/src/ext4.h
+++ /dev/null
@@ -1,267 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4.h
- * @brief Ext4 high level operations (files, directories, mountpoints...).
- * Client has to include only this file.
- */
-
-#ifndef EXT4_H_
-#define EXT4_H_
-
-#include <ext4_config.h>
-#include <ext4_blockdev.h>
-#include <stdint.h>
-
-/********************************FILE OPEN FLAGS********************************/
-
-#ifndef O_RDONLY
-#define O_RDONLY 00
-#endif
-
-#ifndef O_WRONLY
-#define O_WRONLY 01
-#endif
-
-#ifndef O_RDWR
-#define O_RDWR 02
-#endif
-
-#ifndef O_CREAT
-#define O_CREAT 0100
-#endif
-
-#ifndef O_EXCL
-#define O_EXCL 0200
-#endif
-
-#ifndef O_TRUNC
-#define O_TRUNC 01000
-#endif
-
-#ifndef O_APPEND
-#define O_APPEND 02000
-#endif
-
-/********************************FILE SEEK FLAGS*****************************/
-
-#ifndef SEEK_SET
-#define SEEK_SET 0
-#endif
-
-#ifndef SEEK_CUR
-#define SEEK_CUR 1
-#endif
-
-#ifndef SEEK_END
-#define SEEK_END 2
-#endif
-
-/********************************OS LOCK INFERFACE***************************/
-
-/**@brief OS dependent lock interface.*/
-struct ext4_lock {
-
- /**@brief Lock access to mountpoint*/
- void (*lock)(void);
-
- /**@brief Unlock access to mountpoint*/
- void (*unlock)(void);
-};
-
-
-/********************************FILE DESCRIPTOR*****************************/
-
-/**@brief File descriptor*/
-typedef struct ext4_file {
-
- /**@brief Pountpoint handle.*/
- struct ext4_mountpoint *mp;
-
- /**@brief File inode id*/
- uint32_t inode;
-
- /**@brief Open flags.*/
- uint32_t flags;
-
- /**@brief File size.*/
- uint64_t fsize;
-
- /**@brief File position*/
- uint64_t fpos;
-}ext4_file;
-
-/*****************************DIRECTORY DESCRIPTOR***************************/
-/**@brief Directory entry types. Copy from ext4_types.h*/
-enum {
- EXT4_DIRENTRY_UNKNOWN = 0,
- EXT4_DIRENTRY_REG_FILE,
- EXT4_DIRENTRY_DIR,
- EXT4_DIRENTRY_CHRDEV,
- EXT4_DIRENTRY_BLKDEV,
- EXT4_DIRENTRY_FIFO,
- EXT4_DIRENTRY_SOCK,
- EXT4_DIRENTRY_SYMLINK
-};
-
-/**@brief Directory entry descriptor. Copy from ext4_types.h*/
-typedef struct {
- uint32_t inode;
- uint16_t entry_length;
- uint8_t name_length;
- union {
- uint8_t name_length_high;
- uint8_t inode_type;
- };
- uint8_t name[255];
-}ext4_direntry;
-
-typedef struct {
- /**@brief File descriptor*/
- ext4_file f;
- /**@brief Current direntry.*/
- ext4_direntry de;
-}ext4_dir;
-
-/********************************MOUNT OPERATIONS****************************/
-
-/**@brief Register a block device to a name.
- * @warning Block device has to be filled by
- * @ref EXT4_BLOCKDEV_STATIC_INSTANCE. Block cache may be created
- * @ref EXT4_BCACHE_STATIC_INSTANCE.
- * Block cache may by created automaticly when bc parameter is 0.
- * @param bd block device
- * @param bd block device cache (0 = automatic cache mode)
- * @param dev_name register name
- * @param standard error code*/
-int ext4_device_register(struct ext4_blockdev *bd, struct ext4_bcache *bc,
- const char *dev_name);
-
-/**@brief Mount a block device with EXT4 partition to the mountpoint.
- * @param dev_name block device name (@ref ext4_device_register)
- * @param mount_point pount point, for example
- * - /
- * - /my_partition/
- * - /my_second_partition/
- *
- * @return standard error code */
-int ext4_mount(const char * dev_name, char *mount_point);
-
-/**@brief Umount operation.
- * @param mount_point mount name
- * @return standard error code */
-int ext4_umount(char *mount_point);
-
-
-/**@brief Some of the filesystem params.*/
-struct ext4_mount_stats {
- uint32_t inodes_count;
- uint32_t free_inodes_count;
- uint64_t blocks_count;
- uint64_t free_blocks_count;
-
- uint32_t block_size;
- uint32_t block_group_count;
- uint32_t blocks_per_group;
- uint32_t inodes_per_group;
-
- char volume_name[16];
-};
-
-int ext4_mount_point_stats(const char *mount_point,
- struct ext4_mount_stats *stats);
-
-/********************************FILE OPERATIONS*****************************/
-
-/**@brief */
-int ext4_fremove(const char *path);
-
-/**@brief File open function.
- * @param filename, (has to start from mountpoint)
- * /my_partition/my_file
- * @param flags open file flags
- * |---------------------------------------------------------------|
- * | r or rb O_RDONLY |
- * |---------------------------------------------------------------|
- * | w or wb O_WRONLY|O_CREAT|O_TRUNC |
- * |---------------------------------------------------------------|
- * | a or ab O_WRONLY|O_CREAT|O_APPEND |
- * |---------------------------------------------------------------|
- * | r+ or rb+ or r+b O_RDWR |
- * |---------------------------------------------------------------|
- * | w+ or wb+ or w+b O_RDWR|O_CREAT|O_TRUNC |
- * |---------------------------------------------------------------|
- * | a+ or ab+ or a+b O_RDWR|O_CREAT|O_APPEND |
- * |---------------------------------------------------------------|
- *
- * @return standard error code*/
-int ext4_fopen (ext4_file *f, const char *path, const char *flags);
-
-/**@brief */
-int ext4_fclose(ext4_file *f);
-
-/**@brief */
-int ext4_fread (ext4_file *f, void *buf, uint32_t size, uint32_t *rcnt);
-
-/**@brief */
-int ext4_fwrite(ext4_file *f, void *buf, uint32_t size, uint32_t *wcnt);
-
-/**@brief */
-int ext4_fseek (ext4_file *f, uint64_t offset, uint32_t origin);
-
-/**@brief */
-uint64_t ext4_ftell (ext4_file *f);
-
-/**@brief */
-uint64_t ext4_fsize (ext4_file *f);
-
-/*********************************DIRECTORY OPERATION***********************/
-/**@brief */
-int ext4_mkdir(const char *path);
-
-/**@brief */
-int ext4_rmdir(const char *path);
-
-/**@brief */
-int ext4_dir_open (ext4_dir *d, const char *path);
-
-/**@brief */
-int ext4_dir_close(ext4_dir *d);
-
-/**@brief */
-ext4_direntry* ext4_entry_get(ext4_dir *d, uint32_t id);
-
-#endif /* EXT4_H_ */
-
-/**
- * @}
- */
--- a/src/lwext4/ext4.c
+++ /dev/null
@@ -1,1205 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4.h
- * @brief Ext4 high level operations (file, directory, mountpoints...)
- */
-
-#include <ext4_config.h>
-#include <ext4_blockdev.h>
-#include <ext4_types.h>
-#include <ext4_debug.h>
-#include <ext4_errno.h>
-#include <ext4_fs.h>
-#include <ext4_dir.h>
-#include <ext4_inode.h>
-#include <ext4_super.h>
-#include <ext4_dir_idx.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <ext4.h>
-
-/**@brief Mount point OS dependent lock*/
-#define EXT4_MP_LOCK(_m) \
- do { (_m)->os_locks ? (_m)->os_locks->lock() : 0; }while(0)
-
-/**@brief Mount point OS dependent unlock*/
-#define EXT4_MP_UNLOCK(_m) \
- do { (_m)->os_locks ? (_m)->os_locks->unlock() : 0; }while(0)
-
-/**@brief Mount point descrpitor.*/
-struct ext4_mountpoint {
-
- /**@brief Mount point name (@ref ext4_mount)*/
- const char *name;
-
- /**@brief Os dependent lock/unlock functions.*/
- struct ext4_lock *os_locks;
-
- /**@brief Ext4 filesystem internals.*/
- struct ext4_fs fs;
-
- /**@brief Dynamic alocation cache flag.*/
- bool cache_dynamic;
-};
-
-/**@brief Block devices descriptor.*/
-struct _ext4_devices {
-
- /**@brief Block device name (@ref ext4_device_register)*/
- const char *name;
-
- /**@brief Block device handle.*/
- struct ext4_blockdev *bd;
-
- /**@brief Block cache handle.*/
- struct ext4_bcache *bc;
-};
-
-/**@brief Block devices.*/
-struct _ext4_devices _bdevices[CONFIG_EXT4_BLOCKDEVS_COUNT];
-
-
-/**@brief Mountpoints.*/
-struct ext4_mountpoint _mp[CONFIG_EXT4_MOUNTPOINTS_COUNT];
-
-
-
-int ext4_device_register(struct ext4_blockdev *bd, struct ext4_bcache *bc,
- const char *dev_name)
-{
- uint32_t i;
- ext4_assert(bd && dev_name);
-
- for (i = 0; i < CONFIG_EXT4_BLOCKDEVS_COUNT; ++i) {
- if(!_bdevices[i].name){
- _bdevices[i].name = dev_name;
- _bdevices[i].bd = bd;
- _bdevices[i].bc = bc;
- return EOK;
- }
- }
- return ENOSPC;
-}
-
-/****************************************************************************/
-
-
-static bool ext4_is_dots(const uint8_t *name, size_t name_size)
-{
- if ((name_size == 1) && (name[0] == '.'))
- return true;
-
- if ((name_size == 2) && (name[0] == '.') && (name[1] == '.'))
- return true;
-
- return false;
-}
-
-static int ext4_has_children(bool *has_children, struct ext4_inode_ref *enode)
-{
-
- struct ext4_fs *fs = enode->fs;
-
- /* Check if node is directory */
- if (!ext4_inode_is_type(&fs->sb, enode->inode,
- EXT4_INODE_MODE_DIRECTORY)) {
- *has_children = false;
- return EOK;
- }
-
- struct ext4_directory_iterator it;
- int rc = ext4_dir_iterator_init(&it, enode, 0);
- if (rc != EOK)
- return rc;
-
- /* Find a non-empty directory entry */
- bool found = false;
- while (it.current != NULL) {
- if (it.current->inode != 0) {
- uint16_t name_size =
- ext4_dir_entry_ll_get_name_length(&fs->sb,
- it.current);
- if (!ext4_is_dots(it.current->name, name_size)) {
- found = true;
- break;
- }
- }
-
- rc = ext4_dir_iterator_next(&it);
- if (rc != EOK) {
- ext4_dir_iterator_fini(&it);
- return rc;
- }
- }
-
- rc = ext4_dir_iterator_fini(&it);
- if (rc != EOK)
- return rc;
-
- *has_children = found;
-
- return EOK;
-}
-
-
-static int ext4_link(struct ext4_mountpoint *mp, struct ext4_inode_ref *parent,
- struct ext4_inode_ref *child, const char *name, uint32_t name_len)
-{
- /* Check maximum name length */
- if(name_len > EXT4_DIRECTORY_FILENAME_LEN)
- return EINVAL;
-
- /* Add entry to parent directory */
- int rc = ext4_dir_add_entry(parent, name, name_len,
- child);
- if (rc != EOK)
- return rc;
-
- /* Fill new dir -> add '.' and '..' entries */
- if (ext4_inode_is_type(&mp->fs.sb, child->inode,
- EXT4_INODE_MODE_DIRECTORY)) {
- rc = ext4_dir_add_entry(child, ".", strlen("."),
- child);
- if (rc != EOK) {
- ext4_dir_remove_entry(parent, name, strlen(name));
- return rc;
- }
-
- rc = ext4_dir_add_entry(child, "..", strlen(".."),
- parent);
- if (rc != EOK) {
- ext4_dir_remove_entry(parent, name, strlen(name));
- ext4_dir_remove_entry(child, ".", strlen("."));
- return rc;
- }
-
-#if CONFIG_DIR_INDEX_ENABLE
- /* Initialize directory index if supported */
- if (ext4_sb_check_feature_compatible(&mp->fs.sb,
- EXT4_FEATURE_COMPAT_DIR_INDEX)) {
- rc = ext4_dir_dx_init(child);
- if (rc != EOK)
- return rc;
-
- ext4_inode_set_flag(child->inode,
- EXT4_INODE_FLAG_INDEX);
- child->dirty = true;
- }
-#endif
-
- uint16_t parent_links =
- ext4_inode_get_links_count(parent->inode);
- parent_links++;
- ext4_inode_set_links_count(parent->inode, parent_links);
-
- parent->dirty = true;
- }
-
- uint16_t child_links =
- ext4_inode_get_links_count(child->inode);
- child_links++;
- ext4_inode_set_links_count(child->inode, child_links);
-
- child->dirty = true;
-
- return EOK;
-}
-
-static int ext4_unlink(struct ext4_mountpoint *mp,
- struct ext4_inode_ref *parent, struct ext4_inode_ref *child_inode_ref,
- const char *name, uint32_t name_len)
-{
- bool has_children;
- int rc = ext4_has_children(&has_children, child_inode_ref);
- if (rc != EOK)
- return rc;
-
- /* Cannot unlink non-empty node */
- if (has_children)
- return ENOTSUP;
-
- /* Remove entry from parent directory */
-
- rc = ext4_dir_remove_entry(parent, name, name_len);
- if (rc != EOK)
- return rc;
-
-
- uint32_t lnk_count =
- ext4_inode_get_links_count(child_inode_ref->inode);
- lnk_count--;
-
- bool is_dir = ext4_inode_is_type(&mp->fs.sb, child_inode_ref->inode,
- EXT4_INODE_MODE_DIRECTORY);
-
- /* If directory - handle links from parent */
- if ((lnk_count <= 1) && (is_dir)) {
- ext4_assert(lnk_count == 1);
-
- lnk_count--;
-
- uint32_t parent_lnk_count = ext4_inode_get_links_count(
- parent->inode);
-
- parent_lnk_count--;
- ext4_inode_set_links_count(parent->inode, parent_lnk_count);
-
- parent->dirty = true;
- }
-
- /*
- * TODO: Update timestamps of the parent
- * (when we have wall-clock time).
- *
- * ext4_inode_set_change_inode_time(parent->inode, (uint32_t) now);
- * ext4_inode_set_modification_time(parent->inode, (uint32_t) now);
- * parent->dirty = true;
- */
-
- /*
- * TODO: Update timestamp for inode.
- *
- * ext4_inode_set_change_inode_time(child_inode_ref->inode,
- * (uint32_t) now);
- */
-
- ext4_inode_set_deletion_time(child_inode_ref->inode, 1);
- ext4_inode_set_links_count(child_inode_ref->inode, lnk_count);
- child_inode_ref->dirty = true;
-
- return EOK;
-}
-
-/****************************************************************************/
-
-int ext4_mount(const char * dev_name, char *mount_point)
-{
- ext4_assert(mount_point && dev_name);
- int r = EOK;
- int i;
-
- uint32_t bsize;
- struct ext4_blockdev *bd = 0;
- struct ext4_bcache *bc = 0;
- struct ext4_mountpoint *mp = 0;
-
- if(mount_point[strlen(mount_point) - 1] != '/')
- return ENOTSUP;
-
- for (i = 0; i < CONFIG_EXT4_BLOCKDEVS_COUNT; ++i) {
- if(_bdevices[i].name){
- if(!strcmp(dev_name, _bdevices[i].name)){
- bd = _bdevices[i].bd;
- bc = _bdevices[i].bc;
- break;
- }
- }
- }
-
- if(!bd)
- return ENODEV;
-
- for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) {
- if(!_mp[i].name){
- _mp[i].name = mount_point;
- mp = &_mp[i];
- break;
- }
- }
-
- if(!mp)
- return ENOMEM;
-
- r = ext4_block_init(bd);
- if(r != EOK)
- return r;
-
- r = ext4_fs_init(&mp->fs, bd);
- if(r != EOK){
- ext4_block_fini(bd);
- return r;
- }
-
- bsize = ext4_sb_get_block_size(&mp->fs.sb);
- ext4_block_set_lb_size(bd, bsize);
-
-
- mp->cache_dynamic = 0;
-
- if(!bc){
- /*Automatic block cache alloc.*/
- mp->cache_dynamic = 1;
- bc = malloc(sizeof(struct ext4_bcache));
-
- r = ext4_bcache_init_dynamic(bc, 8, bsize);
- if(r != EOK){
- free(bc);
- ext4_block_fini(bd);
- return r;
- }
- }
-
- if(bsize != bc->itemsize)
- return ENOTSUP;
-
-
- /*Bind block cache to block device*/
- r = ext4_block_bind_bcache(bd, bc);
- if(r != EOK){
- ext4_block_fini(bd);
- if(mp->cache_dynamic){
- ext4_bcache_fini_dynamic(bc);
- free(bc);
- }
- return r;
- }
-
- return r;
-}
-
-
-int ext4_umount(char *mount_point)
-{
- int i;
- int r = EOK;
- struct ext4_mountpoint *mp = 0;
-
- for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) {
- if(_mp[i].name){
- if(!strcmp(_mp[i].name, mount_point))
- mp = &_mp[i];
- break;
- }
- }
-
- if(!mp)
- return ENODEV;
-
- r = ext4_fs_fini(&mp->fs);
- if(r != EOK)
- return r;
-
- mp->name = 0;
-
- if(mp->cache_dynamic){
- ext4_bcache_fini_dynamic(mp->fs.bdev->bc);
- free(mp->fs.bdev->bc);
- }
-
- return ext4_block_fini(mp->fs.bdev);
-}
-
-int ext4_mount_point_stats(const char *mount_point,
- struct ext4_mount_stats *stats)
-{
- uint32_t i;
- struct ext4_mountpoint *mp = 0;
-
- for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) {
- if(_mp[i].name){
- if(!strcmp(_mp[i].name, mount_point))
- mp = &_mp[i];
- break;
- }
- }
-
- if(!mp)
- return ENOENT;
-
-
- EXT4_MP_LOCK(mp);
- stats->inodes_count = ext4_get32(&mp->fs.sb, inodes_count);
- stats->free_inodes_count = ext4_get32(&mp->fs.sb, free_inodes_count);
- stats->blocks_count = ext4_sb_get_blocks_cnt(&mp->fs.sb);
- stats->free_blocks_count = ext4_sb_get_free_blocks_cnt(&mp->fs.sb);
- stats->block_size = ext4_sb_get_block_size(&mp->fs.sb);
-
- stats->block_group_count = ext4_block_group_cnt(&mp->fs.sb);
- stats->blocks_per_group = ext4_get32(&mp->fs.sb, blocks_per_group);
- stats->inodes_per_group = ext4_get32(&mp->fs.sb, inodes_per_group);
-
- memcpy(stats->volume_name, mp->fs.sb.volume_name, 16);
- EXT4_MP_UNLOCK(mp);
-
- return EOK;
-}
-
-/********************************FILE OPERATIONS*****************************/
-
-static struct ext4_mountpoint* ext4_get_mount(const char *path)
-{
- int i;
- for (i = 0; i < CONFIG_EXT4_MOUNTPOINTS_COUNT; ++i) {
- if(_mp[i].name){
- if(!strncmp(_mp[i].name, path, strlen(_mp[i].name)))
- return &_mp[i];
- }
- }
- return 0;
-}
-
-
-static int ext4_path_check(const char *path, bool* is_goal)
-{
- int i;
-
- for (i = 0; i < EXT4_DIRECTORY_FILENAME_LEN; ++i) {
-
- if(path[i] == '/'){
- *is_goal = false;
- return i;
- }
-
- if(path[i] == 0){
- *is_goal = true;
- return i;
- }
- }
-
- return 0;
-}
-
-
-static bool ext4_parse_flags(const char *flags, uint32_t *file_flags)
-{
- if(!flags)
- return false;
-
- if(!strcmp(flags, "r") || !strcmp(flags, "rb")){
- *file_flags = O_RDONLY;
- return true;
- }
-
- if(!strcmp(flags, "w") || !strcmp(flags, "wb")){
- *file_flags = O_WRONLY | O_CREAT | O_TRUNC;
- return true;
- }
-
- if(!strcmp(flags, "a") || !strcmp(flags, "ab")){
- *file_flags = O_WRONLY | O_CREAT | O_APPEND ;
- return true;
- }
-
- if(!strcmp(flags, "r+") || !strcmp(flags, "rb+") || !strcmp(flags, "r+b")){
- *file_flags = O_RDWR;
- return true;
- }
-
- if(!strcmp(flags, "w+") || !strcmp(flags, "wb+") || !strcmp(flags, "w+b")){
- *file_flags = O_RDWR | O_CREAT | O_TRUNC;
- return true;
- }
-
- if(!strcmp(flags, "a+") || !strcmp(flags, "ab+") || !strcmp(flags, "a+b")){
- *file_flags = O_RDWR | O_CREAT | O_APPEND;
- return true;
- }
-
- return false;
-}
-
-/****************************************************************************/
-
-static int ext4_generic_open (ext4_file *f, const char *path,
- const char *flags, bool file_expect)
-{
- struct ext4_mountpoint *mp = ext4_get_mount(path);
- struct ext4_directory_search_result result;
- struct ext4_inode_ref ref;
- bool is_goal = false;
- uint8_t inode_type;
- int r = ENOENT;
- uint32_t next_inode;
-
- f->mp = 0;
-
- if(!mp)
- return ENOENT;
-
- if(ext4_parse_flags(flags, &f->flags) == false)
- return EINVAL;
-
- /*Skip mount point*/
- path += strlen(mp->name);
-
- EXT4_MP_LOCK(mp);
-
- /*Load root*/
- r = ext4_fs_get_inode_ref(&mp->fs, EXT4_INODE_ROOT_INDEX, &ref);
-
- if(r != EOK)
- return r;
-
- int len = ext4_path_check(path, &is_goal);
-
- /*If root open was request.*/
- if(!len && is_goal)
- goto IsGoal;
-
- while(1){
-
- len = ext4_path_check(path, &is_goal);
-
- if(!len){
- r = ENOENT;
- break;
- }
-
- r = ext4_dir_find_entry(&result, &ref, path, len);
- if(r != EOK){
-
- if(r != ENOENT)
- break;
-
- if(!(f->flags & O_CREAT))
- break;
-
- /*O_CREAT allows to create new entry*/
- struct ext4_inode_ref child_ref;
- r = ext4_fs_alloc_inode(&mp->fs, &child_ref, !is_goal);
- if(r != EOK)
- break;
-
- /*Destroy last result*/
- ext4_dir_destroy_result(&ref, &result);
-
- /*Link with root dir.*/
- r = ext4_link(mp, &ref, &child_ref, path, len);
- if(r != EOK){
- /*Fali. Free new inode.*/
- ext4_fs_free_inode(&child_ref);
- /*We do not want to write new inode.
- But block has to be released.*/
- child_ref.dirty = false;
- ext4_fs_put_inode_ref(&child_ref);
- break;
- }
-
- ext4_fs_put_inode_ref(&child_ref);
-
- continue;
- }
-
- next_inode = result.dentry->inode;
- inode_type = ext4_dir_entry_ll_get_inode_type(&mp->fs.sb, result.dentry);
-
- r = ext4_dir_destroy_result(&ref, &result);
- if(r != EOK)
- break;
-
- /*If expected file error*/
- if((inode_type == EXT4_DIRECTORY_FILETYPE_REG_FILE)
- && !file_expect && is_goal){
- r = ENOENT;
- break;
- }
-
- /*If expected directory error*/
- if((inode_type == EXT4_DIRECTORY_FILETYPE_DIR)
- && file_expect && is_goal){
- r = ENOENT;
- break;
- }
-
- r = ext4_fs_put_inode_ref(&ref);
- if(r != EOK)
- break;
-
- r = ext4_fs_get_inode_ref(&mp->fs, next_inode, &ref);
- if(r != EOK)
- break;
-
- if(is_goal)
- break;
-
- path += len + 1;
- };
-
- if(r != EOK){
- ext4_fs_put_inode_ref(&ref);
- EXT4_MP_UNLOCK(mp);
- return r;
- }
-
- IsGoal:
- if(is_goal){
-
- if(f->flags & O_TRUNC){
- /*Turncate.*/
- ext4_block_delay_cache_flush(mp->fs.bdev, 1);
- /*Truncate may be IO heavy.
- Do it with delayed cache flush mode.*/
- r = ext4_fs_truncate_inode(&ref, 0);
- ext4_block_delay_cache_flush(mp->fs.bdev, 0);
-
- if(r != EOK){
- ext4_fs_put_inode_ref(&ref);
- EXT4_MP_UNLOCK(mp);
- return r;
- }
- }
-
- f->mp = mp;
- f->fsize = ext4_inode_get_size(&f->mp->fs.sb, ref.inode);
- f->inode = ref.index;
- f->fpos = 0;
-
- if(f->flags & O_APPEND)
- f->fpos = f->fsize;
-
- }
-
- r = ext4_fs_put_inode_ref(&ref);
- EXT4_MP_UNLOCK(mp);
- return r;
-}
-
-/****************************************************************************/
-
-int ext4_fremove(const char *path)
-{
- struct ext4_mountpoint *mp = ext4_get_mount(path);
- struct ext4_directory_search_result result;
- bool is_goal = false;
- uint8_t inode_type;
- int r = ENOENT;
- uint32_t next_inode;
-
- struct ext4_inode_ref parent;
- struct ext4_inode_ref child;
- int len = 0;
-
- if(!mp)
- return ENOENT;
-
-
- /*Skip mount point*/
- path += strlen(mp->name);
-
- /*Lock mountpoint*/
- EXT4_MP_LOCK(mp);
-
- /*Load root*/
- r = ext4_fs_get_inode_ref(&mp->fs, EXT4_INODE_ROOT_INDEX, &parent);
-
- if(r != EOK){
- EXT4_MP_UNLOCK(mp);
- return r;
- }
-
- while(1){
-
- len = ext4_path_check(path, &is_goal);
-
- if(!len){
- r = ENOENT;
- break;
- }
-
- r = ext4_dir_find_entry(&result, &parent, path, len);
- if(r != EOK){
- ext4_dir_destroy_result(&parent, &result);
- break;
- }
-
- next_inode = result.dentry->inode;
- inode_type = ext4_dir_entry_ll_get_inode_type(&mp->fs.sb,
- result.dentry);
-
- r = ext4_dir_destroy_result(&parent, &result);
- if(r != EOK)
- break;
-
- /*If expected file error*/
- if((inode_type == EXT4_DIRECTORY_FILETYPE_REG_FILE) && !is_goal){
- r = ENOENT;
- break;
- }
-
- /*If expected directory error*/
- if((inode_type == EXT4_DIRECTORY_FILETYPE_DIR) && is_goal){
- r = ENOENT;
- break;
- }
-
- if(is_goal)
- break;
-
- r = ext4_fs_put_inode_ref(&parent);
- if(r != EOK)
- break;
-
-
- r = ext4_fs_get_inode_ref(&mp->fs, next_inode, &parent);
- if(r != EOK)
- break;
-
- path += len + 1;
- };
-
- if(r != EOK){
- /*No entry or other error.*/
- ext4_fs_put_inode_ref(&parent);
- EXT4_MP_UNLOCK(mp);
- return r;
- }
-
-
- /*We have file to delete. Load it.*/
- r = ext4_fs_get_inode_ref(&mp->fs, next_inode, &child);
- if(r != EOK){
- /*Parent free*/
- ext4_fs_put_inode_ref(&parent);
- EXT4_MP_UNLOCK(mp);
- return r;
- }
-
- /*Turncate.*/
- ext4_block_delay_cache_flush(mp->fs.bdev, 1);
-
- /*Truncate may be IO heavy. Do it with delayed cache flush mode.*/
- r = ext4_fs_truncate_inode(&child, 0);
-
- ext4_block_delay_cache_flush(mp->fs.bdev, 0);
- if(r != EOK)
- goto Finish;
-
- /*Unlink from parent.*/
- r = ext4_unlink(mp, &parent, &child, path, len);
- if(r != EOK)
- goto Finish;
-
- r = ext4_fs_free_inode(&child);
- if(r != EOK)
- goto Finish;
-
-
- Finish:
- ext4_fs_put_inode_ref(&child);
- ext4_fs_put_inode_ref(&parent);
- EXT4_MP_UNLOCK(mp);
- return r;
-}
-
-
-int ext4_fopen (ext4_file *f, const char *path, const char *flags)
-{
- return ext4_generic_open(f, path, flags, true);
-}
-
-int ext4_fclose(ext4_file *f)
-{
- ext4_assert(f && f->mp);
-
- f->mp = 0;
- f->flags = 0;
- f->inode = 0;
- f->fpos = f->fsize = 0;
-
- return EOK;
-}
-int ext4_fread (ext4_file *f, void *buf, uint32_t size, uint32_t *rcnt)
-{
- int r = EOK;
- uint32_t u;
- uint32_t fblock;
- struct ext4_block b;
- uint8_t *u8_buf = buf;
- struct ext4_inode_ref ref;
- uint32_t sblock;
- uint32_t block_size;
-
- ext4_assert(f && f->mp);
-
- if(f->flags & O_WRONLY)
- return EPERM;
-
- if(!size)
- return EOK;
-
- EXT4_MP_LOCK(f->mp);
-
- if(rcnt)
- *rcnt = 0;
-
- r = ext4_fs_get_inode_ref(&f->mp->fs, f->inode, &ref);
- if(r != EOK){
- EXT4_MP_UNLOCK(f->mp);
- return r;
- }
-
- /*Sync file size*/
- f->fsize = ext4_inode_get_size(&f->mp->fs.sb, ref.inode);
-
-
- block_size = ext4_sb_get_block_size(&f->mp->fs.sb);
- size = size > (f->fsize - f->fpos) ? (f->fsize - f->fpos) : size;
-
- sblock = (f->fpos) / block_size;
-
- u = (f->fpos) % block_size;
-
-
- if(u){
-
- uint32_t ll = size > (block_size - u) ? (block_size - u) : size;
-
- r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
- if(r != EOK)
- goto Finish;
-
- r = ext4_block_get(f->mp->fs.bdev, &b, fblock);
- if(r != EOK)
- goto Finish;
-
- memcpy(u8_buf, b.data + u, ll);
-
- r = ext4_block_set(f->mp->fs.bdev, &b);
- if(r != EOK)
- goto Finish;
-
- u8_buf += ll;
- size -= ll;
- f->fpos += ll;
-
- if(rcnt)
- *rcnt += ll;
-
- sblock++;
- }
-
- while(size >= block_size){
-
- r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
- if(r != EOK)
- goto Finish;
-
- r = ext4_block_get_direct(f->mp->fs.bdev, u8_buf, fblock);
- if(r != EOK)
- goto Finish;
-
-
- u8_buf += block_size;
- size -= block_size;
- f->fpos += block_size;
-
- if(rcnt)
- *rcnt += block_size;
-
- sblock++;
- }
-
- if(size){
- r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
- if(r != EOK)
- goto Finish;
-
- r = ext4_block_get(f->mp->fs.bdev, &b, fblock);
- if(r != EOK)
- goto Finish;
-
- memcpy(u8_buf, b.data , size);
-
- r = ext4_block_set(f->mp->fs.bdev, &b);
- if(r != EOK)
- goto Finish;
-
- f->fpos += size;
-
- if(rcnt)
- *rcnt += size;
- }
-
- Finish:
- ext4_fs_put_inode_ref(&ref);
- EXT4_MP_UNLOCK(f->mp);
- return r;
-}
-
-int ext4_fwrite(ext4_file *f, void *buf, uint32_t size, uint32_t *wcnt)
-{
- int r = EOK;
- uint32_t u;
- uint32_t fblock;
- struct ext4_block b;
- uint8_t *u8_buf = buf;
- struct ext4_inode_ref ref;
- uint32_t sblock;
- uint32_t file_blocks;
- uint32_t block_size;
-
- ext4_assert(f && f->mp);
-
- if(f->flags & O_RDONLY)
- return EPERM;
-
- if(!size)
- return EOK;
-
- EXT4_MP_LOCK(f->mp);
-
- if(wcnt)
- *wcnt = 0;
-
- r = ext4_fs_get_inode_ref(&f->mp->fs, f->inode, &ref);
- if(r != EOK){
- EXT4_MP_UNLOCK(f->mp);
- return r;
- }
-
- /*Sync file size*/
- f->fsize = ext4_inode_get_size(&f->mp->fs.sb, ref.inode);
-
- block_size = ext4_sb_get_block_size(&f->mp->fs.sb);
-
- file_blocks = (f->fsize / block_size);
-
- if(f->fsize % block_size)
- file_blocks++;
-
- sblock = (f->fpos) / block_size;
-
- u = (f->fpos) % block_size;
-
-
- if(u){
- uint32_t ll = size > (block_size - u) ? (block_size - u) : size;
-
- r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
- if(r != EOK)
- goto Finish;
-
- r = ext4_block_get(f->mp->fs.bdev, &b, fblock);
- if(r != EOK)
- goto Finish;
-
- memcpy(b.data + u, u8_buf, ll);
- b.dirty = true;
-
- r = ext4_block_set(f->mp->fs.bdev, &b);
- if(r != EOK)
- goto Finish;
-
- u8_buf += ll;
- size -= ll;
- f->fpos += ll;
-
- if(wcnt)
- *wcnt += ll;
-
- sblock++;
- }
-
-
- /*Start delay cache flush mode.*/
- r = ext4_block_delay_cache_flush(f->mp->fs.bdev, 1);
- if(r != EOK)
- goto Finish;
-
- while(size >= block_size){
-
- if(sblock < file_blocks){
- r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
- if(r != EOK)
- break;
- }
- else {
- r = ext4_fs_append_inode_block(&ref, &fblock, &sblock);
- if(r != EOK)
- break;
- }
-
- r = ext4_block_set_direct(f->mp->fs.bdev, u8_buf, fblock);
- if(r != EOK)
- break;
-
- u8_buf += block_size;
- size -= block_size;
- f->fpos += block_size;
-
- if(wcnt)
- *wcnt += block_size;
-
- sblock++;
- }
-
- /*Stop delay cache flush mode*/
- ext4_block_delay_cache_flush(f->mp->fs.bdev, 0);
-
- if(r != EOK)
- goto Finish;
-
- if(size){
- if(sblock < file_blocks){
- r = ext4_fs_get_inode_data_block_index(&ref, sblock, &fblock);
- if(r != EOK)
- goto Finish;
- }
- else {
- r = ext4_fs_append_inode_block(&ref, &fblock, &sblock);
- if(r != EOK)
- goto Finish;
- }
-
- r = ext4_block_get(f->mp->fs.bdev, &b, fblock);
- if(r != EOK)
- goto Finish;
-
- memcpy(b.data, u8_buf , size);
- b.dirty = true;
-
- r = ext4_block_set(f->mp->fs.bdev, &b);
- if(r != EOK)
- goto Finish;
-
- f->fpos += size;
-
- if(wcnt)
- *wcnt += size;
- }
-
- if(f->fpos > f->fsize){
- f->fsize = f->fpos;
- ext4_inode_set_size(ref.inode, f->fsize);
- ref.dirty = true;
- }
-
- Finish:
- ext4_fs_put_inode_ref(&ref);
- EXT4_MP_UNLOCK(f->mp);
- return r;
-
-}
-
-
-
-int ext4_fseek (ext4_file *f, uint64_t offset, uint32_t origin)
-{
- switch(origin){
- case SEEK_SET:
-
- if(offset > f->fsize)
- return EINVAL;
-
- f->fpos = offset;
- return EOK;
- case SEEK_CUR:
- if((offset + f->fpos) > f->fsize)
- return EINVAL;
-
- f->fpos += offset;
- return EOK;
- case SEEK_END:
- if(offset > f->fsize)
- return EINVAL;
- f->fpos = f->fsize - offset;
- return EOK;
-
- }
-
- return EINVAL;
-}
-
-uint64_t ext4_ftell (ext4_file *f)
-{
- return f->fpos;
-}
-
-uint64_t ext4_fsize (ext4_file *f)
-{
- return f->fsize;
-}
-
-/*********************************DIRECTORY OPERATION************************/
-
-int ext4_dir_open (ext4_dir *d, const char *path)
-{
- return ext4_generic_open(&d->f, path, "r", false);
-}
-
-int ext4_dir_close(ext4_dir *d)
-{
- return ext4_fclose(&d->f);
-}
-
-ext4_direntry* ext4_entry_get(ext4_dir *d, uint32_t id)
-{
- int r;
- uint32_t i;
- ext4_direntry *de = 0;
- struct ext4_inode_ref dir;
- struct ext4_directory_iterator it;
-
- EXT4_MP_LOCK(d->f.mp);
-
- r = ext4_fs_get_inode_ref(&d->f.mp->fs, d->f.inode, &dir);
- if(r != EOK){
- goto Finish;
- }
-
- r = ext4_dir_iterator_init(&it, &dir, 0);
- if(r != EOK){
- ext4_fs_put_inode_ref(&dir);
- goto Finish;
- }
-
- i = 0;
- while(r == EOK){
-
- if(!it.current)
- break;
-
- if(i == id){
- memcpy(&d->de, it.current, sizeof(ext4_direntry));
- de = &d->de;
- break;
- }
-
-
- i++;
- r = ext4_dir_iterator_next(&it);
- }
-
- ext4_dir_iterator_fini(&it);
- ext4_fs_put_inode_ref(&dir);
-
- Finish:
- EXT4_MP_UNLOCK(d->f.mp);
- return de;
-}
-
-/**
- * @}
- */
--- a/src/lwext4/ext4_balloc.c
+++ /dev/null
@@ -1,609 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_balloc.c
- * @brief Physical block allocator.
- */
-
-#include <ext4_config.h>
-#include <ext4_balloc.h>
-#include <ext4_super.h>
-#include <ext4_block_group.h>
-#include <ext4_fs.h>
-#include <ext4_bitmap.h>
-#include <ext4_inode.h>
-
-
-
-static uint32_t ext4_balloc_get_bgid_of_block(struct ext4_sblock *s,
- uint32_t baddr)
-{
- if(ext4_get32(s, first_data_block))
- baddr--;
-
- return baddr / ext4_get32(s, blocks_per_group);
-}
-
-
-uint32_t ext4_balloc_get_first_data_block_in_group(struct ext4_sblock *s,
- struct ext4_block_group_ref * bg_ref)
-{
- uint32_t block_group_count = ext4_block_group_cnt(s);
- uint32_t inode_table_first_block =
- ext4_bg_get_inode_table_first_block(bg_ref->block_group, s);
- uint32_t block_size = ext4_sb_get_block_size(s);
-
- uint16_t inode_size = ext4_get16(s, inode_size);
- uint32_t inodes_per_group = ext4_get32(s, inodes_per_group);
-
- uint32_t inode_table_bytes;
-
-
- if (bg_ref->index < block_group_count - 1) {
- inode_table_bytes = inodes_per_group * inode_size;
- } else {
- /* Last block group could be smaller */
- uint32_t inodes_count_total = ext4_get32(s, inodes_count);
- inode_table_bytes =
- (inodes_count_total - ((block_group_count - 1) *
- inodes_per_group)) * inode_size;
- }
-
- uint32_t inode_table_blocks = inode_table_bytes / block_size;
-
- if (inode_table_bytes % block_size)
- inode_table_blocks++;
-
- return inode_table_first_block + inode_table_blocks;
-}
-
-int ext4_balloc_free_block(struct ext4_inode_ref *inode_ref, uint32_t baddr)
-{
- struct ext4_fs *fs = inode_ref->fs;
- struct ext4_sblock *sb = &fs->sb;
-
-
- uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, baddr);
- uint32_t index_in_group = ext4_fs_baddr2_index_in_group(sb, baddr);
-
- /* Load block group reference */
- struct ext4_block_group_ref bg_ref;
- int rc = ext4_fs_get_block_group_ref(fs, block_group, &bg_ref);
- if (rc != EOK)
- return rc;
-
- /* Load block with bitmap */
- uint32_t bitmap_block_addr =
- ext4_bg_get_block_bitmap(bg_ref.block_group, sb);
-
- struct ext4_block bitmap_block;
-
- rc = ext4_block_get(fs->bdev, &bitmap_block, bitmap_block_addr);
- if (rc != EOK)
- return rc;
-
- /* Modify bitmap */
- ext4_bmap_bit_clr(bitmap_block.data, index_in_group);
- bitmap_block.dirty = true;
-
- /* Release block with bitmap */
- rc = ext4_block_set(fs->bdev, &bitmap_block);
- if (rc != EOK) {
- /* Error in saving bitmap */
- ext4_fs_put_block_group_ref(&bg_ref);
- return rc;
- }
-
- uint32_t block_size = ext4_sb_get_block_size(sb);
-
- /* Update superblock free blocks count */
- uint64_t sb_free_blocks =
- ext4_sb_get_free_blocks_cnt(sb);
- sb_free_blocks++;
- ext4_sb_set_free_blocks_cnt(sb, sb_free_blocks);
-
- /* Update inode blocks count */
- uint64_t ino_blocks =
- ext4_inode_get_blocks_count(sb, inode_ref->inode);
- ino_blocks -= block_size / EXT4_INODE_BLOCK_SIZE;
- ext4_inode_set_blocks_count(sb, inode_ref->inode, ino_blocks);
- inode_ref->dirty = true;
-
- /* Update block group free blocks count */
- uint32_t free_blocks =
- ext4_bg_get_free_blocks_count(bg_ref.block_group, sb);
- free_blocks++;
- ext4_bg_set_free_blocks_count(bg_ref.block_group,
- sb, free_blocks);
-
- bg_ref.dirty = true;
-
- /* Release block group reference */
- rc = ext4_fs_put_block_group_ref(&bg_ref);
- if (rc != EOK)
- return rc;
-
- return EOK;
-}
-
-int ext4_balloc_free_blocks(struct ext4_inode_ref *inode_ref, uint32_t first,
- uint32_t count)
-{
- struct ext4_fs *fs = inode_ref->fs;
- struct ext4_sblock *sb = &fs->sb;
-
- /* Compute indexes */
- uint32_t block_group_first =
- ext4_balloc_get_bgid_of_block(sb, first);
- uint32_t block_group_last =
- ext4_balloc_get_bgid_of_block(sb, first + count - 1);
-
- ext4_assert(block_group_first == block_group_last);
-
- /* Load block group reference */
- struct ext4_block_group_ref bg_ref;
- int rc = ext4_fs_get_block_group_ref(fs, block_group_first, &bg_ref);
- if (rc != EOK)
- return rc;
-
- uint32_t index_in_group_first =
- ext4_fs_baddr2_index_in_group(sb, first);
-
- /* Load block with bitmap */
- uint32_t bitmap_block_addr =
- ext4_bg_get_block_bitmap(bg_ref.block_group, sb);
-
- struct ext4_block bitmap_block;
-
- rc = ext4_block_get(fs->bdev, &bitmap_block, bitmap_block_addr);
- if (rc != EOK)
- return rc;
-
- /* Modify bitmap */
- ext4_bmap_bits_free(bitmap_block.data, index_in_group_first, count);
- bitmap_block.dirty = true;
-
- /* Release block with bitmap */
- rc = ext4_block_set(fs->bdev, &bitmap_block);
- if (rc != EOK) {
- ext4_fs_put_block_group_ref(&bg_ref);
- return rc;
- }
-
- uint32_t block_size = ext4_sb_get_block_size(sb);
-
- /* Update superblock free blocks count */
- uint64_t sb_free_blocks =
- ext4_sb_get_free_blocks_cnt(sb);
- sb_free_blocks += count;
- ext4_sb_set_free_blocks_cnt(sb, sb_free_blocks);
-
- /* Update inode blocks count */
- uint64_t ino_blocks =
- ext4_inode_get_blocks_count(sb, inode_ref->inode);
- ino_blocks -= count * (block_size / EXT4_INODE_BLOCK_SIZE);
- ext4_inode_set_blocks_count(sb, inode_ref->inode, ino_blocks);
- inode_ref->dirty = true;
-
- /* Update block group free blocks count */
- uint32_t free_blocks =
- ext4_bg_get_free_blocks_count(bg_ref.block_group, sb);
- free_blocks += count;
- ext4_bg_set_free_blocks_count(bg_ref.block_group,
- sb, free_blocks);
- bg_ref.dirty = true;
-
- /* Release block group reference */
- rc = ext4_fs_put_block_group_ref(&bg_ref);
- if (rc != EOK)
- return rc;
-
- return EOK;
-}
-
-static uint32_t ext4_balloc_find_goal(struct ext4_inode_ref *inode_ref)
-{
- uint32_t goal = 0;
-
- struct ext4_sblock *sb = &inode_ref->fs->sb;
-
- uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
- uint32_t block_size = ext4_sb_get_block_size(sb);
- uint32_t inode_block_count = inode_size / block_size;
-
- if (inode_size % block_size != 0)
- inode_block_count++;
-
- /* If inode has some blocks, get last block address + 1 */
- if (inode_block_count > 0) {
- int rc = ext4_fs_get_inode_data_block_index(inode_ref,
- inode_block_count - 1, &goal);
- if (rc != EOK)
- return 0;
-
- if (goal != 0) {
- goal++;
- return goal;
- }
-
- /* If goal == 0, sparse file -> continue */
- }
-
- /* Identify block group of inode */
-
- uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
- uint32_t block_group = (inode_ref->index - 1) / inodes_per_group;
- block_size = ext4_sb_get_block_size(sb);
-
- /* Load block group reference */
- struct ext4_block_group_ref bg_ref;
- int rc = ext4_fs_get_block_group_ref(inode_ref->fs,
- block_group, &bg_ref);
- if (rc != EOK)
- return 0;
-
- /* Compute indexes */
- uint32_t block_group_count = ext4_block_group_cnt(sb);
- uint32_t inode_table_first_block =
- ext4_bg_get_inode_table_first_block(bg_ref.block_group, sb);
- uint16_t inode_table_item_size = ext4_get16(sb, inode_size);
- uint32_t inode_table_bytes;
-
- /* Check for last block group */
- if (block_group < block_group_count - 1) {
- inode_table_bytes = inodes_per_group * inode_table_item_size;
- } else {
- /* Last block group could be smaller */
- uint32_t inodes_count_total = ext4_get32(sb, inodes_count);
-
- inode_table_bytes =
- (inodes_count_total - ((block_group_count - 1) *
- inodes_per_group)) * inode_table_item_size;
- }
-
- uint32_t inode_table_blocks = inode_table_bytes / block_size;
-
- if (inode_table_bytes % block_size)
- inode_table_blocks++;
-
- goal = inode_table_first_block + inode_table_blocks;
-
- ext4_fs_put_block_group_ref(&bg_ref);
-
- return goal;
-}
-
-
-int ext4_balloc_alloc_block(struct ext4_inode_ref *inode_ref,
- uint32_t *fblock)
-{
- uint32_t allocated_block = 0;
- uint32_t bitmap_block_addr;
- uint32_t rel_block_idx = 0;
-
- struct ext4_block bitmap_block;
-
- /* Find GOAL */
- uint32_t goal = ext4_balloc_find_goal(inode_ref);
- if (goal == 0) {
- /* no goal found => partition is full */
- return ENOSPC;
- }
-
- struct ext4_sblock *sb = &inode_ref->fs->sb;
-
- /* Load block group number for goal and relative index */
- uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, goal);
- uint32_t index_in_group =
- ext4_fs_baddr2_index_in_group(sb, goal);
-
- /* Load block group reference */
- struct ext4_block_group_ref bg_ref;
- int rc = ext4_fs_get_block_group_ref(inode_ref->fs,
- block_group, &bg_ref);
- if (rc != EOK)
- return rc;
-
- /* Compute indexes */
- uint32_t first_in_group =
- ext4_balloc_get_first_data_block_in_group(sb, &bg_ref);
-
- uint32_t first_in_group_index =
- ext4_fs_baddr2_index_in_group(sb, first_in_group);
-
- if (index_in_group < first_in_group_index)
- index_in_group = first_in_group_index;
-
- /* Load block with bitmap */
- bitmap_block_addr =
- ext4_bg_get_block_bitmap(bg_ref.block_group, sb);
-
- rc = ext4_block_get(inode_ref->fs->bdev, &bitmap_block,
- bitmap_block_addr);
- if (rc != EOK) {
- ext4_fs_put_block_group_ref(&bg_ref);
- return rc;
- }
-
- /* Check if goal is free */
- if (ext4_bmap_is_bit_clr(bitmap_block.data, index_in_group)) {
- ext4_bmap_bit_set(bitmap_block.data, index_in_group);
- bitmap_block.dirty = true;
- rc = ext4_block_set(inode_ref->fs->bdev, &bitmap_block);
- if (rc != EOK) {
- ext4_fs_put_block_group_ref(&bg_ref);
- return rc;
- }
-
- allocated_block =
- ext4_fs_index_in_group2_baddr(sb, index_in_group,
- block_group);
-
- goto success;
- }
-
- uint32_t blocks_in_group =
- ext4_blocks_in_group_cnt(sb, block_group);
-
- uint32_t end_idx = (index_in_group + 63) & ~63;
- if (end_idx > blocks_in_group)
- end_idx = blocks_in_group;
-
- /* Try to find free block near to goal */
- uint32_t tmp_idx;
- for (tmp_idx = index_in_group + 1; tmp_idx < end_idx;
- ++tmp_idx) {
- if (ext4_bmap_is_bit_clr(bitmap_block.data, tmp_idx)) {
- ext4_bmap_bit_set(bitmap_block.data, tmp_idx);
-
- bitmap_block.dirty = true;
- rc = ext4_block_set(inode_ref->fs->bdev, &bitmap_block);
- if (rc != EOK)
- return rc;
-
- allocated_block =
- ext4_fs_index_in_group2_baddr(sb, tmp_idx,
- block_group);
-
- goto success;
- }
- }
-
-
-
- /* Find free bit in bitmap */
- rc = ext4_bmap_bit_find_clr(bitmap_block.data,
- index_in_group, blocks_in_group, &rel_block_idx);
- if (rc == EOK) {
- ext4_bmap_bit_set(bitmap_block.data, rel_block_idx);
- bitmap_block.dirty = true;
- rc = ext4_block_set(inode_ref->fs->bdev, &bitmap_block);
- if (rc != EOK)
- return rc;
-
- allocated_block =
- ext4_fs_index_in_group2_baddr(sb, rel_block_idx,
- block_group);
-
- goto success;
- }
-
- /* No free block found yet */
- ext4_block_set(inode_ref->fs->bdev, &bitmap_block);
- ext4_fs_put_block_group_ref(&bg_ref);
-
- /* Try other block groups */
- uint32_t block_group_count = ext4_block_group_cnt(sb);
-
- uint32_t bgid = (block_group + 1) % block_group_count;
- uint32_t count = block_group_count;
-
- while (count > 0) {
- rc = ext4_fs_get_block_group_ref(inode_ref->fs, bgid,
- &bg_ref);
- if (rc != EOK)
- return rc;
-
- /* Load block with bitmap */
- bitmap_block_addr =
- ext4_bg_get_block_bitmap(bg_ref.block_group, sb);
-
- rc = ext4_block_get(inode_ref->fs->bdev, &bitmap_block,
- bitmap_block_addr);
-
- if (rc != EOK) {
- ext4_fs_put_block_group_ref(&bg_ref);
- return rc;
- }
-
- /* Compute indexes */
- first_in_group =
- ext4_balloc_get_first_data_block_in_group(sb, &bg_ref);
- index_in_group =
- ext4_fs_baddr2_index_in_group(sb, first_in_group);
- blocks_in_group = ext4_blocks_in_group_cnt(sb, bgid);
-
- first_in_group_index =
- ext4_fs_baddr2_index_in_group(sb, first_in_group);
-
- if (index_in_group < first_in_group_index)
- index_in_group = first_in_group_index;
-
-
- rc = ext4_bmap_bit_find_clr(bitmap_block.data,
- index_in_group, blocks_in_group, &rel_block_idx);
-
- if (rc == EOK) {
-
- ext4_bmap_bit_set(bitmap_block.data, rel_block_idx);
-
- bitmap_block.dirty = true;
- rc = ext4_block_set(inode_ref->fs->bdev, &bitmap_block);
- if (rc != EOK)
- return rc;
-
- allocated_block =
- ext4_fs_index_in_group2_baddr(sb, rel_block_idx,
- bgid);
-
- goto success;
- }
-
- ext4_block_set(inode_ref->fs->bdev, &bitmap_block);
- ext4_fs_put_block_group_ref(&bg_ref);
-
- /* Goto next group */
- bgid = (bgid + 1) % block_group_count;
- count--;
- }
-
- return ENOSPC;
-
- success:
- /* Empty command - because of syntax */
- ;
-
- uint32_t block_size = ext4_sb_get_block_size(sb);
-
- /* Update superblock free blocks count */
- uint64_t sb_free_blocks = ext4_sb_get_free_blocks_cnt(sb);
- sb_free_blocks--;
- ext4_sb_set_free_blocks_cnt(sb, sb_free_blocks);
-
- /* Update inode blocks (different block size!) count */
- uint64_t ino_blocks =
- ext4_inode_get_blocks_count(sb, inode_ref->inode);
- ino_blocks += block_size / EXT4_INODE_BLOCK_SIZE;
- ext4_inode_set_blocks_count(sb, inode_ref->inode, ino_blocks);
- inode_ref->dirty = true;
-
- /* Update block group free blocks count */
- uint32_t bg_free_blocks =
- ext4_bg_get_free_blocks_count(bg_ref.block_group, sb);
- bg_free_blocks--;
- ext4_bg_set_free_blocks_count(bg_ref.block_group, sb,
- bg_free_blocks);
-
- bg_ref.dirty = true;
-
- ext4_fs_put_block_group_ref(&bg_ref);
-
- *fblock = allocated_block;
- return EOK;
-}
-
-int ext4_balloc_try_alloc_block(struct ext4_inode_ref *inode_ref,
- uint32_t baddr, bool *free)
-{
- int rc = EOK;
-
- struct ext4_fs *fs = inode_ref->fs;
- struct ext4_sblock *sb = &fs->sb;
-
- /* Compute indexes */
- uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, baddr);
- uint32_t index_in_group =
- ext4_fs_baddr2_index_in_group(sb, baddr);
-
- /* Load block group reference */
- struct ext4_block_group_ref bg_ref;
- rc = ext4_fs_get_block_group_ref(fs, block_group, &bg_ref);
- if (rc != EOK)
- return rc;
-
- /* Load block with bitmap */
- uint32_t bitmap_block_addr =
- ext4_bg_get_block_bitmap(bg_ref.block_group, sb);
-
-
- struct ext4_block bitmap_block;
-
- rc = ext4_block_get(fs->bdev, &bitmap_block, bitmap_block_addr);
- if (rc != EOK)
- return rc;
-
- /* Check if block is free */
- *free = ext4_bmap_is_bit_clr(bitmap_block.data, index_in_group);
-
- /* Allocate block if possible */
- if (*free) {
- ext4_bmap_bit_set(bitmap_block.data, index_in_group);
- bitmap_block.dirty = true;
- }
-
- /* Release block with bitmap */
- rc = ext4_block_set(fs->bdev, &bitmap_block);
- if (rc != EOK) {
- /* Error in saving bitmap */
- ext4_fs_put_block_group_ref(&bg_ref);
- return rc;
- }
-
- /* If block is not free, return */
- if (!(*free))
- goto terminate;
-
- uint32_t block_size = ext4_sb_get_block_size(sb);
-
- /* Update superblock free blocks count */
- uint64_t sb_free_blocks = ext4_sb_get_free_blocks_cnt(sb);
- sb_free_blocks--;
- ext4_sb_set_free_blocks_cnt(sb, sb_free_blocks);
-
- /* Update inode blocks count */
- uint64_t ino_blocks =
- ext4_inode_get_blocks_count(sb, inode_ref->inode);
- ino_blocks += block_size / EXT4_INODE_BLOCK_SIZE;
- ext4_inode_set_blocks_count(sb, inode_ref->inode, ino_blocks);
- inode_ref->dirty = true;
-
- /* Update block group free blocks count */
- uint32_t free_blocks =
- ext4_bg_get_free_blocks_count(bg_ref.block_group, sb);
- free_blocks--;
- ext4_bg_set_free_blocks_count(bg_ref.block_group,
- sb, free_blocks);
-
- bg_ref.dirty = true;
-
- terminate:
- return ext4_fs_put_block_group_ref(&bg_ref);
-}
-
-/**
- * @}
- */
--- a/src/lwext4/ext4_balloc.h
+++ /dev/null
@@ -1,93 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_balloc.h
- * @brief Physical block allocator.
- */
-
-#ifndef EXT4_BALLOC_H_
-#define EXT4_BALLOC_H_
-
-#include <ext4_config.h>
-#include <ext4_types.h>
-
-#include <stdint.h>
-#include <stdbool.h>
-
-
-/**@brief Get first datablock in block group
- * @param s superblock descriptor
- * @param bg_ref block group reference
- * @return block id of the first datablock in block group*/
-uint32_t ext4_balloc_get_first_data_block_in_group(struct ext4_sblock *s,
- struct ext4_block_group_ref * bg_ref);
-
-/**@brief Free block from inode.
- * @param inode_ref inode reference
- * @param baddr block address
- * @return standard error code*/
-int ext4_balloc_free_block(struct ext4_inode_ref *inode_ref,
- uint32_t baddr);
-
-/**@brief Free blocks from inode.
- * @param inode_ref inode reference
- * @param baddr block address
- * @return standard error code*/
-int ext4_balloc_free_blocks(struct ext4_inode_ref *inode_ref,
- uint32_t first, uint32_t count);
-
-/**@brief Allocate block procedure.
- * @param inode_ref inode reference
- * @param baddr allocated block address
- * @return standard error code*/
-int ext4_balloc_alloc_block(struct ext4_inode_ref *inode_ref,
- uint32_t *baddr);
-
-/**@brief Try allocate selected block.
- * @param inode_ref inode reference
- * @param baddr block address to allocate
- * @param free if baddr is not allocated
- * @return standard error code*/
-int ext4_balloc_try_alloc_block(struct ext4_inode_ref *inode_ref,
- uint32_t baddr, bool *free);
-
-#endif /* EXT4_BALLOC_H_ */
-
-/**
- * @}
- */
-
--- a/src/lwext4/ext4_bcache.c
+++ /dev/null
@@ -1,276 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_bcache.c
- * @brief Block cache allocator.
- */
-
-#include <ext4_config.h>
-#include <ext4_bcache.h>
-#include <ext4_debug.h>
-#include <ext4_errno.h>
-
-#include <string.h>
-#include <stdlib.h>
-
-
-int ext4_bcache_init_dynamic(struct ext4_bcache *bc, uint32_t cnt,
- uint32_t itemsize)
-{
- ext4_assert(bc && cnt && itemsize);
-
- bc->lru_ctr= 0;
-
- bc->refctr = 0;
- bc->lru_id = 0;
- bc->free_delay = 0;
- bc->lba = 0;
- bc->data = 0;
-
- bc->refctr = malloc(cnt * sizeof(uint32_t));
- if(!bc->refctr)
- goto error;
-
- bc->lru_id = malloc(cnt * sizeof(uint32_t));
- if(!bc->lru_id)
- goto error;
-
- bc->free_delay = malloc(cnt * sizeof(uint8_t));
- if(!bc->free_delay)
- goto error;
-
- bc->lba = malloc(cnt * sizeof(uint64_t));
- if(!bc->lba)
- goto error;
-
- bc->data = malloc(cnt * itemsize);
- if(!bc->data)
- goto error;
-
- memset(bc->refctr, 0, cnt * sizeof(uint32_t));
- memset(bc->lru_id, 0, cnt * sizeof(uint32_t));
- memset(bc->free_delay, 0, cnt * sizeof(uint8_t));
- memset(bc->lba, 0, cnt * sizeof(uint64_t));
-
- bc->cnt = cnt;
- bc->itemsize = itemsize;
- bc->ref_blocks = 0;
- bc->max_ref_blocks = 0;
-
- return EOK;
-
- error:
-
- if(bc->refctr)
- free(bc->refctr);
-
- if(bc->lru_id)
- free(bc->lru_id);
-
- if(bc->free_delay)
- free(bc->free_delay);
-
- if(bc->lba)
- free(bc->lba);
-
- if(bc->data)
- free(bc->data);
-
- return ENOMEM;
-}
-
-int ext4_bcache_fini_dynamic(struct ext4_bcache *bc)
-{
- if(bc->refctr)
- free(bc->refctr);
-
- if(bc->lru_id)
- free(bc->lru_id);
-
- if(bc->free_delay)
- free(bc->free_delay);
-
- if(bc->lba)
- free(bc->lba);
-
- if(bc->data)
- free(bc->data);
-
- bc->lru_ctr= 0;
-
- bc->refctr = 0;
- bc->lru_id = 0;
- bc->free_delay = 0;
- bc->lba = 0;
- bc->data = 0;
-
- return EOK;
-}
-
-
-int ext4_bcache_alloc(struct ext4_bcache *bc, struct ext4_block *b,
- bool *is_new)
-{
- uint32_t i;
- ext4_assert(bc && b && is_new);
-
- /*Check if valid.*/
- ext4_assert(b->lb_id);
- if(!b->lb_id){
- ext4_assert(b->lb_id);
- }
-
- uint32_t cache_id = bc->cnt;
- uint32_t alloc_id;
-
- *is_new = false;
-
- /*Find in free blocks (Last Recently Used).*/
- for (i = 0; i < bc->cnt; ++i) {
-
- /*Check if block is already in cache*/
- if(b->lb_id == bc->lba[i]){
-
- if(!bc->refctr[i] && !bc->free_delay[i])
- bc->ref_blocks++;
-
- /*Update reference counter*/
- bc->refctr[i]++;
-
- /*Update usage marker*/
- bc->lru_id[i] = ++bc->lru_ctr;
-
- /*Set valid cache data and id*/
- b->data = bc->data + i * bc->itemsize;
- b->cache_id = i;
-
- return EOK;
- }
-
- /*Best fit calculations.*/
- if(bc->refctr[i])
- continue;
-
- if(bc->free_delay[i])
- continue;
-
- /*Block is unreferenced, but it may exist block with
- * lower usage marker*/
-
- /*First find.*/
- if(cache_id == bc->cnt){
- cache_id = i;
- alloc_id = bc->lru_id[i];
- continue;
- }
-
- /*Next find*/
- if(alloc_id <= bc->lru_id[i])
- continue;
-
- /*This block has lower alloc id marker*/
- cache_id = i;
- alloc_id = bc->lru_id[i];
- }
-
-
- if(cache_id != bc->cnt){
- /*There was unreferenced block*/
- bc->lba[cache_id] = b->lb_id;
- bc->refctr[cache_id] = 1;
- bc->lru_id[cache_id] = ++bc->lru_ctr;
-
- /*Set valid cache data and id*/
- b->data = bc->data + cache_id * bc->itemsize;
- b->cache_id = cache_id;
-
- /*Statistics*/
- bc->ref_blocks++;
- if(bc->ref_blocks > bc->max_ref_blocks)
- bc->max_ref_blocks = bc->ref_blocks;
-
-
- /*Block needs to be read.*/
- *is_new = true;
-
- return EOK;
- }
-
- ext4_dprintf(EXT4_DEBUG_BCACHE,
- "ext4_bcache_alloc: FAIL, unable to alloc block cache!\n");
- return ENOMEM;
-}
-
-int ext4_bcache_free (struct ext4_bcache *bc, struct ext4_block *b,
- uint8_t free_delay)
-{
- ext4_assert(bc && b);
-
- /*Check if valid.*/
- ext4_assert(b->lb_id);
-
- /*Block should be in cache.*/
- ext4_assert(b->cache_id < bc->cnt);
-
- /*Check if someone don't try free unreferenced block cache.*/
- ext4_assert(bc->refctr[b->cache_id]);
-
- /*Just decrease reference counter*/
- if(bc->refctr[b->cache_id])
- bc->refctr[b->cache_id]--;
-
- if(free_delay)
- bc->free_delay[b->cache_id] = free_delay;
-
- /*Update statistics*/
- if(!bc->refctr[b->cache_id] && !bc->free_delay[b->cache_id])
- bc->ref_blocks--;
-
- b->lb_id = 0;
- b->data = 0;
- b->cache_id = 0;
-
- return EOK;
-}
-
-
-
-bool ext4_bcache_is_full(struct ext4_bcache *bc)
-{
- return (bc->cnt == bc->ref_blocks);
-}
-
-/**
- * @}
- */
-
-
--- a/src/lwext4/ext4_bcache.h
+++ /dev/null
@@ -1,155 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_bcache.h
- * @brief Block cache allocator.
- */
-
-#ifndef EXT4_BCACHE_H_
-#define EXT4_BCACHE_H_
-
-#include <ext4_config.h>
-
-#include <stdint.h>
-#include <stdbool.h>
-
-/**@brief Single block descriptor.*/
-struct ext4_block {
- /**@brief Dirty flag.*/
- bool dirty;
-
- /**@brief Logical block ID*/
- uint64_t lb_id;
-
- /**@brief Cache id*/
- uint32_t cache_id;
-
- /**@brief Data buffer.*/
- uint8_t *data;
-};
-
-
-/**@brief Block cache descriptor.*/
-struct ext4_bcache {
-
- /**@brief Item count in block cache*/
- uint32_t cnt;
-
- /**@brief Item size in block cache*/
- uint32_t itemsize;
-
- /**@brief Last recently used counter.*/
- uint32_t lru_ctr;
-
- /**@brief Reference count table (cnt).*/
- uint32_t *refctr;
-
- /**@brief Last recently used ID table (cnt)*/
- uint32_t *lru_id;
-
- /**@brief Free delay mode table (cnt)*/
- uint8_t *free_delay;
-
- /**@brief Logical block table (cnt).*/
- uint64_t *lba;
-
- /**@brief Cache data buffers (cnt * itemsize)*/
- uint8_t *data;
-
- /**@brief Currently referenced datablocks*/
- uint32_t ref_blocks;
-
- /**@brief Maximum referenced datablocks*/
- uint32_t max_ref_blocks;
-
-};
-
-/**@brief Static initializer of block cache structure.*/
-#define EXT4_BCACHE_STATIC_INSTANCE(__name, __cnt, __itemsize) \
- static uint32_t __name##_refctr[(__cnt)]; \
- static uint32_t __name##_lru_id[(__cnt)]; \
- static uint8_t __name##_free_delay[(__cnt)]; \
- static uint64_t __name##_lba[(__cnt)]; \
- static uint8_t __name##_data[(__cnt) * (__itemsize)]; \
- static struct ext4_bcache __name = { \
- .cnt = __cnt, \
- .itemsize = __itemsize, \
- .lru_ctr = 0, \
- .refctr = __name##_refctr, \
- .lru_id = __name##_lru_id, \
- .lba = __name##_lba, \
- .free_delay= __name##_free_delay, \
- .data = __name##_data, \
- }
-
-
-/**@brief Dynamic initialization of block cache.
- * @param bc block cache descriptor
- * @param cnt items count in block cache
- * @param itemsize single item size (in bytes)
- * @return standard error code*/
-int ext4_bcache_init_dynamic(struct ext4_bcache *bc, uint32_t cnt,
- uint32_t itemsize);
-
-/**@brief Dynamic de-initialization of block cache.
- * @param bc block cache descriptor
- * @return standard error code*/
-int ext4_bcache_fini_dynamic(struct ext4_bcache *bc);
-
-/**@brief Allocate block from block cache memory.
- * Unreferenced block allocation is based on LRU
- * (Last Recently Used) algorithm.
- * @param bc block cache descriptor
- * @param b block to alloc
- * @param is_new block is new (needs to be read)
- * @return standard error code*/
-int ext4_bcache_alloc(struct ext4_bcache *bc, struct ext4_block *b,
- bool *is_new);
-
-/**@brief Free block from cache memory (decrement reference counter).
- * @param bc block cache descriptor
- * @param b block to free
- * @return standard error code*/
-int ext4_bcache_free (struct ext4_bcache *bc, struct ext4_block *b,
- uint8_t free_delay);
-
-
-/**@brief Return a full status of block cache.
- * @param bc block cache descriptor
- * @return full status*/
-bool ext4_bcache_is_full(struct ext4_bcache *bc);
-
-#endif /* EXT4_BCACHE_H_ */
-
-/**
- * @}
- */
--- a/src/lwext4/ext4_bitmap.c
+++ /dev/null
@@ -1,173 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_bitmap.c
- * @brief Block/inode bitmap allocator.
- */
-
-#include <ext4_config.h>
-#include <ext4_bitmap.h>
-
-#include <ext4_errno.h>
-
-
-void ext4_bmap_bits_free(uint8_t *bmap, uint32_t sbit, uint32_t bcnt)
-{
- uint32_t i;
-
- i = sbit;
-
- while(i & 7){
-
- if(!bcnt)
- return;
-
- ext4_bmap_bit_clr(bmap, i);
-
- bcnt--;
- i++;
- }
-
- sbit = i;
- bmap += (sbit >> 3);
-
-
-
- while(bcnt >= 32){
- *(uint32_t *)bmap = 0;
-
- bmap += 4;
- bcnt -= 32;
- sbit += 32;
- }
-
- while(bcnt >= 16){
- *(uint16_t *)bmap = 0;
-
- bmap += 2;
- bcnt -= 16;
- sbit += 16;
- }
-
- while(bcnt >= 8){
- *bmap = 0;
-
- bmap += 1;
- bcnt -= 8;
- sbit += 8;
- }
-
- for (i = 0; i < bcnt; ++i) {
- ext4_bmap_bit_clr(bmap, i);
- }
-}
-
-
-
-int ext4_bmap_bit_find_clr(uint8_t *bmap, uint32_t sbit, uint32_t ebit,
- uint32_t *bit_id)
-{
- uint32_t i;
- uint32_t bcnt = ebit - sbit;
-
- i = sbit;
-
- while(i & 7){
-
- if(!bcnt)
- return ENOSPC;
-
- if(ext4_bmap_is_bit_clr(bmap, i)){
- *bit_id = sbit;
- return EOK;
- }
-
- i++;
- bcnt--;
- }
-
- sbit = i;
- bmap += (sbit >> 3);
-
-
- while(bcnt >= 32){
- if(*(uint32_t *)bmap != 0xFFFFFFFF)
- goto finish_it;
-
-
- bmap += 4;
- bcnt -= 32;
- sbit += 32;
- }
-
- while(bcnt >= 16){
- if(*(uint16_t *)bmap != 0xFFFF)
- goto finish_it;
-
-
- bmap += 2;
- bcnt -= 16;
- sbit += 16;
- }
-
- finish_it:
- while(bcnt >= 8){
- if(*bmap != 0xFF){
- for (i = 0; i < 8; ++i) {
- if(ext4_bmap_is_bit_clr(bmap, i)){
- *bit_id = sbit + i;
- return EOK;
- }
- }
- }
-
- bmap += 1;
- bcnt -= 8;
- sbit += 8;
- }
-
- for (i = 0; i < bcnt; ++i) {
- if(ext4_bmap_is_bit_clr(bmap, i)){
- *bit_id = sbit + i;
- return EOK;
- }
- }
-
-
- return ENOSPC;
-}
-
-/**
- * @}
- */
-
-
--- a/src/lwext4/ext4_bitmap.h
+++ /dev/null
@@ -1,98 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_bitmap.h
- * @brief Block/inode bitmap allocator.
- */
-
-
-#ifndef EXT4_BITMAP_H_
-#define EXT4_BITMAP_H_
-
-#include <ext4_config.h>
-#include <stdint.h>
-#include <stdbool.h>
-
-/**@brief Set bitmap bit.
- * @param bmap bitmap
- * @param bit bit to set*/
-static inline void ext4_bmap_bit_set(uint8_t *bmap, uint32_t bit)
-{
- *(bmap + (bit >> 3)) |= (1 << (bit & 7));
-}
-
-/**@brief Clear bitmap bit.
- * @param bmap bitmap buffer
- * @param bit bit to clear*/
-static inline void ext4_bmap_bit_clr(uint8_t *bmap, uint32_t bit)
-{
- *(bmap + (bit >> 3)) &= ~(1 << (bit & 7));
-}
-
-
-/**@brief Check if the bitmap bit is set.
- * @param bmap bitmap buffer
- * @param bit bit to check*/
-static inline bool ext4_bmap_is_bit_set(uint8_t *bmap, uint32_t bit)
-{
- return (*(bmap + (bit >> 3)) & (1 << (bit & 7)));
-}
-
-/**@brief Check if the bitmap bit is clear.
- * @param bmap bitmap buffer
- * @param bit bit to check*/
-static inline bool ext4_bmap_is_bit_clr(uint8_t *bmap, uint32_t bit)
-{
- return !ext4_bmap_is_bit_set(bmap, bit);
-}
-
-/**@brief Free range of bits in bitmap.
- * @param bmap bitmap buffer
- * @param sbit start bit
- * @param bcnt bit count*/
-void ext4_bmap_bits_free(uint8_t *bmap, uint32_t sbit, uint32_t bcnt);
-
-/**@brief Find first clear bit in bitmap.
- * @param sbit start bit of search
- * @param ebit end bit of search
- * @param bit_id output parameter (first free bit)
- * @return standard error code*/
-int ext4_bmap_bit_find_clr(uint8_t *bmap, uint32_t sbit, uint32_t ebit,
- uint32_t *bit_id);
-
-
-#endif /* EXT4_BITMAP_H_ */
-
-/**
- * @}
- */
-
--- a/src/lwext4/ext4_block_group.c
+++ /dev/null
@@ -1,55 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_block_group.c
- * @brief Block group function set.
- */
-
-#include <ext4_config.h>
-#include <ext4_block_group.h>
-
-
-
-uint16_t ext4_bg_crc16(uint16_t crc, const uint8_t *buffer, size_t len)
-{
- // TODO
- return 0;
-}
-
-/**
- * @}
- */
--- a/src/lwext4/ext4_block_group.h
+++ /dev/null
@@ -1,199 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_block_group.h
- * @brief Block group function set.
- */
-
-#ifndef EXT4_BLOCK_GROUP_H_
-#define EXT4_BLOCK_GROUP_H_
-
-
-#include <ext4_config.h>
-#include <ext4_types.h>
-#include <ext4_super.h>
-
-#include <stdint.h>
-#include <stdbool.h>
-
-static inline uint64_t ext4_bg_get_block_bitmap(struct ext4_bgroup *bg,
- struct ext4_sblock *s)
-{
- uint64_t v = to_le32(bg->block_bitmap_lo);
-
- if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
- v |= (uint64_t) to_le32(bg->block_bitmap_hi) << 32;
-
- return v;
-}
-
-static inline uint64_t ext4_bg_get_inode_bitmap(struct ext4_bgroup *bg,
- struct ext4_sblock *s)
-{
-
- uint64_t v = to_le32(bg->inode_bitmap_lo);
-
- if (ext4_sb_get_desc_size(s)> EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
- v |= (uint64_t) to_le32(bg->inode_bitmap_hi) << 32;
-
- return v;
-}
-
-static inline uint64_t ext4_bg_get_inode_table_first_block(
- struct ext4_bgroup *bg, struct ext4_sblock *s)
-{
- uint64_t v = to_le32(bg->inode_table_first_block_lo);
-
- if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
- v |= (uint64_t) to_le32(bg->inode_table_first_block_hi) << 32;
-
- return v;
-}
-
-static inline uint32_t ext4_bg_get_free_blocks_count(struct ext4_bgroup *bg,
- struct ext4_sblock *s)
-{
- uint32_t v = to_le16(bg->free_blocks_count_lo);
-
- if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
- v |= (uint32_t) to_le16(bg->free_blocks_count_hi) << 16;
-
- return v;
-}
-
-static inline void ext4_bg_set_free_blocks_count(struct ext4_bgroup *bg,
- struct ext4_sblock *s, uint32_t cnt)
-{
- bg->free_blocks_count_lo = to_le16((cnt << 16) >> 16);
- if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
- bg->free_blocks_count_hi = to_le16(cnt >> 16);
-}
-
-static inline uint32_t ext4_bg_get_free_inodes_count(struct ext4_bgroup *bg,
- struct ext4_sblock *s)
-{
- uint32_t v = to_le16(bg->free_inodes_count_lo);
-
- if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
- v |= (uint32_t) to_le16(bg->free_inodes_count_hi) << 16;
-
- return v;
-}
-
-static inline void ext4_bg_set_free_inodes_count(struct ext4_bgroup *bg,
- struct ext4_sblock *s, uint32_t cnt)
-{
- bg->free_inodes_count_lo = to_le16((cnt << 16) >> 16);
- if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
- bg->free_inodes_count_hi = to_le16(cnt >> 16);
-}
-
-
-static inline uint32_t ext4_bg_get_used_dirs_count(struct ext4_bgroup *bg,
- struct ext4_sblock *s)
-{
- uint32_t v = to_le16(bg->used_dirs_count_lo);
-
- if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
- v |= (uint32_t) to_le16(bg->used_dirs_count_hi) << 16;
-
- return v;
-}
-
-static inline void ext4_bg_set_used_dirs_count(struct ext4_bgroup *bg,
- struct ext4_sblock *s, uint32_t cnt)
-{
- bg->used_dirs_count_lo = to_le16((cnt << 16) >> 16);
- if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
- bg->used_dirs_count_hi = to_le16(cnt >> 16);
-}
-
-
-static inline uint32_t ext4_bg_get_itable_unused(struct ext4_bgroup *bg,
- struct ext4_sblock *s)
-{
-
- uint32_t v = to_le16(bg->itable_unused_lo);
-
- if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
- v |= (uint32_t) to_le16(bg->itable_unused_hi) << 16;
-
- return v;
-}
-
-static inline void ext4_bg_set_itable_unused(struct ext4_bgroup *bg,
- struct ext4_sblock *s, uint32_t cnt)
-{
- bg->itable_unused_lo = to_le16((cnt << 16) >> 16);
- if (ext4_sb_get_desc_size(s) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
- bg->itable_unused_hi = to_le16(cnt >> 16);
-}
-
-
-static inline void ext4_bg_set_checksum(struct ext4_bgroup *bg,
- uint16_t crc)
-{
- bg->checksum = to_le16(crc);
-}
-
-static inline bool ext4_bg_has_flag(struct ext4_bgroup *bg, uint32_t f)
-{
- return to_le16(bg->flags) & f;
-}
-
-static inline void ext4_bg_set_flag(struct ext4_bgroup *bg, uint32_t f)
-{
- uint16_t flags = to_le16(bg->flags);
- flags |= f;
- bg->flags = to_le16(flags);
-}
-
-static inline void ext4_bg_clear_flag(struct ext4_bgroup *bg, uint32_t f)
-{
- uint16_t flags = to_le16(bg->flags);
- flags &= ~f;
- bg->flags = to_le16(flags);
-}
-
-
-uint16_t ext4_bg_crc16(uint16_t crc, const uint8_t *buffer, size_t len);
-
-#endif /* EXT4_BLOCK_GROUP_H_ */
-
-/**
- * @}
- */
--- a/src/lwext4/ext4_blockdev.c
+++ /dev/null
@@ -1,448 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_blockdev.c
- * @brief Block device module.
- */
-
-#include <ext4_config.h>
-#include <ext4_blockdev.h>
-#include <ext4_errno.h>
-#include <ext4_debug.h>
-
-#include <string.h>
-#include <stdlib.h>
-
-
-
-int ext4_block_init(struct ext4_blockdev *bdev)
-{
- int rc;
- ext4_assert(bdev);
-
- ext4_assert(bdev->open && bdev->close && bdev->bread && bdev->bwrite);
-
- /*Low level block init*/
- rc = bdev->open(bdev);
- if(EOK != rc)
- return rc;
-
- bdev->flags |= EXT4_BDEV_INITIALIZED;
-
- return EOK;
-}
-
-int ext4_block_bind_bcache(struct ext4_blockdev *bdev, struct ext4_bcache *bc)
-{
- ext4_assert(bdev && bc);
- bdev->bc = bc;
- return EOK;
-}
-
-void ext4_block_set_lb_size(struct ext4_blockdev *bdev, uint64_t lb_bsize)
-{
- /*Logical block size has to be multiply of physical */
- ext4_assert(!(lb_bsize % bdev->ph_bsize));
-
- bdev->lg_bsize = lb_bsize;
- bdev->lg_bcnt = (bdev->ph_bcnt * bdev->ph_bsize) / lb_bsize;
-
-}
-
-int ext4_block_fini(struct ext4_blockdev *bdev)
-{
- ext4_assert(bdev);
-
- bdev->flags &= ~(EXT4_BDEV_INITIALIZED);
-
- /*Low level block fini*/
- return bdev->close(bdev);
-}
-
-
-int ext4_block_get(struct ext4_blockdev *bdev, struct ext4_block *b,
- uint64_t lba)
-{
- uint64_t pba;
- uint32_t pb_cnt;
- bool is_new;
- int r;
- ext4_assert(bdev && b);
-
- if(!(bdev->flags & EXT4_BDEV_INITIALIZED))
- return EIO;
-
- if(!(lba < bdev->lg_bcnt))
- return ERANGE;
-
- b->dirty = 0;
- b->lb_id = lba;
-
- r = ext4_bcache_alloc(bdev->bc, b, &is_new);
- if(r != EOK)
- return r;
-
-
- if(!is_new){
- /*Block is in cache. Read from physical device is not required*/
- return EOK;
- }
-
- if(!b->data)
- return ENOMEM;
-
- pba = (lba * bdev->lg_bsize) / bdev->ph_bsize;
- pb_cnt = bdev->lg_bsize / bdev->ph_bsize;
-
-
- r = bdev->bread(bdev, b->data, pba, pb_cnt);
-
- if(r != EOK){
- ext4_bcache_free(bdev->bc, b, 0);
- b->lb_id = 0;
- return r;
- }
-
- bdev->bread_ctr++;
-
- return EOK;
-}
-
-int ext4_block_set(struct ext4_blockdev *bdev, struct ext4_block *b)
-{
- uint64_t pba;
- uint32_t pb_cnt;
- uint32_t i;
- int r;
-
- ext4_assert(bdev && b);
-
- if(!(bdev->flags & EXT4_BDEV_INITIALIZED))
- return EIO;
-
- /*Doesn,t need to write.*/
- if(b->dirty == false){
- ext4_bcache_free(bdev->bc, b, 0);
- return EOK;
- }
-
- /*Free cache delay mode*/
- if(bdev->cache_flush_delay){
-
- /*Free cahe block and mark as free delayed*/
- ext4_bcache_free(bdev->bc, b, bdev->cache_flush_delay);
-
- /*If cache is full we have to flush it anyway :(*/
- if(ext4_bcache_is_full(bdev->bc)){
- for (i = 0; i < bdev->bc->cnt; ++i) {
- /*Check if buffer free was delayed.*/
- if(!bdev->bc->free_delay[i])
- continue;
-
- /*Check reference counter.*/
- if(bdev->bc->refctr[i])
- continue;
-
- /*Buffer free was delayed and have no reference. Flush it.*/
- r = ext4_block_set_direct(bdev,
- bdev->bc->data + bdev->bc->itemsize * i,
- bdev->bc->lba[i]);
- if(r != EOK)
- return r;
-
- /*No delayed anymore*/
- bdev->bc->free_delay[i] = 0;
-
- /*Reduce refered block count*/
- bdev->bc->ref_blocks--;
- }
- }
-
- return EOK;
- }
-
- pba = (b->lb_id * bdev->lg_bsize) / bdev->ph_bsize;
- pb_cnt = bdev->lg_bsize / bdev->ph_bsize;
-
-
- r = bdev->bwrite(bdev, b->data, pba, pb_cnt);
-
- if(r != EOK){
- b->dirty = false;
- ext4_bcache_free(bdev->bc, b, 0);
- return r;
- }
-
- bdev->bwrite_ctr++;
- b->dirty = false;
- ext4_bcache_free(bdev->bc, b, 0);
- return EOK;
-}
-
-int ext4_block_get_direct(struct ext4_blockdev *bdev, void *buf,
- uint64_t lba)
-{
- uint64_t pba;
- uint32_t pb_cnt;
-
- ext4_assert(bdev && buf);
-
- pba = (lba * bdev->lg_bsize) / bdev->ph_bsize;
- pb_cnt = bdev->lg_bsize / bdev->ph_bsize;
-
- bdev->bread_ctr++;
-
- return bdev->bread(bdev, buf, pba, pb_cnt);
-}
-
-
-
-int ext4_block_set_direct(struct ext4_blockdev *bdev, const void *buf,
- uint64_t lba)
-{
- uint64_t pba;
- uint32_t pb_cnt;
-
- ext4_assert(bdev && buf);
-
- pba = (lba * bdev->lg_bsize) / bdev->ph_bsize;
- pb_cnt = bdev->lg_bsize / bdev->ph_bsize;
-
- bdev->bwrite_ctr++;
-
- return bdev->bwrite(bdev, buf, pba, pb_cnt);
-}
-
-
-int ext4_block_writebytes(struct ext4_blockdev *bdev, uint64_t off,
- const void *buf, uint32_t len)
-{
- uint64_t block_idx;
- uint64_t block_end;
-
- uint32_t blen;
-
- uint32_t unalg;
- int r = EOK;
-
- const uint8_t *p = (void *)buf;
-
- ext4_assert(bdev && buf);
-
- if(!(bdev->flags & EXT4_BDEV_INITIALIZED))
- return EIO;
-
-
- block_idx = off / bdev->ph_bsize;
- block_end = block_idx + len / bdev->ph_bsize;
-
- if(!(block_end < bdev->ph_bcnt))
- return EINVAL; /*Ups. Out of range operation*/
-
-
- /*OK lets deal with the first possible unaligned block*/
- unalg = (off & (bdev->ph_bsize - 1));
- if(unalg){
-
- uint32_t wlen = (bdev->ph_bsize - unalg) > len ?
- len : (bdev->ph_bsize - unalg);
-
- r = bdev->bread(bdev, bdev->ph_bbuf, block_idx, 1);
-
- if(r != EOK)
- return r;
-
- memcpy(bdev->ph_bbuf + unalg, p, wlen);
-
- r = bdev->bwrite(bdev, bdev->ph_bbuf, block_idx, 1);
-
- if(r != EOK)
- return r;
-
- p += wlen;
- len -= wlen;
- block_idx++;
- }
-
-
- /*Aligned data*/
- blen = len / bdev->ph_bsize;
-
- r = bdev->bwrite(bdev, p, block_idx, blen);
-
- if(r != EOK)
- return r;
-
- p += bdev->ph_bsize * blen;
- len -= bdev->ph_bsize * blen;
-
- block_idx += blen;
-
-
- /*Rest of the data*/
- if(len){
-
- r = bdev->bread(bdev, bdev->ph_bbuf, block_idx, 1);
-
- if(r != EOK)
- return r;
-
- memcpy(bdev->ph_bbuf, p, len);
-
- r = bdev->bwrite(bdev, bdev->ph_bbuf, block_idx, 1);
-
- if(r != EOK)
- return r;
- }
-
- return r;
-}
-
-
-
-
-int ext4_block_readbytes(struct ext4_blockdev *bdev, uint64_t off, void *buf,
- uint32_t len)
-{
-
- uint64_t block_idx;
- uint64_t block_end;
- uint32_t blen;
-
- uint32_t unalg;
- int r = EOK;
-
- uint8_t *p = (void *)buf;
-
- ext4_assert(bdev && buf);
-
- if(!(bdev->flags & EXT4_BDEV_INITIALIZED))
- return EIO;
-
-
- block_idx = off / bdev->ph_bsize;
- block_end = block_idx + len / bdev->ph_bsize;
-
- if(!(block_end < bdev->ph_bcnt))
- return EINVAL; /*Ups. Out of range operation*/
-
-
- /*OK lets deal with the first possible unaligned block*/
- unalg = (off & (bdev->ph_bsize - 1));
- if(unalg){
-
- uint32_t rlen = (bdev->ph_bsize - unalg) > len ?
- len : (bdev->ph_bsize - unalg);
-
- r = bdev->bread(bdev, bdev->ph_bbuf, block_idx, 1);
-
- if(r != EOK)
- return r;
-
- memcpy(p, bdev->ph_bbuf + unalg, rlen);
-
- p += rlen;
- len -= rlen;
- block_idx++;
- }
-
-
- /*Aligned data*/
- blen = len / bdev->ph_bsize;
-
- r = bdev->bread(bdev, p, block_idx, blen);
-
- if(r != EOK)
- return r;
-
- p += bdev->ph_bsize * blen;
- len -= bdev->ph_bsize * blen;
-
- block_idx += blen;
-
-
- /*Rest of the data*/
- if(len){
-
- r = bdev->bread(bdev, bdev->ph_bbuf, block_idx, 1);
-
- if(r != EOK)
- return r;
-
- memcpy(p, bdev->ph_bbuf, len);
-
- }
-
- return r;
-}
-
-int ext4_block_delay_cache_flush(struct ext4_blockdev *bdev,
- uint8_t on_off)
-{
- int r;
- uint32_t i;
- bdev->cache_flush_delay = on_off;
-
- /*Flush all delayed cache blocks*/
- if(!on_off){
- for (i = 0; i < bdev->bc->cnt; ++i) {
-
- /*Check if buffer free was delayed.*/
- if(!bdev->bc->free_delay[i])
- continue;
-
- /*Check reference counter.*/
- if(bdev->bc->refctr[i])
- continue;
-
- /*Buffer free was delayed and have no reference. Flush it.*/
- r = ext4_block_set_direct(bdev,
- bdev->bc->data + bdev->bc->itemsize * i,
- bdev->bc->lba[i]);
- if(r != EOK)
- return r;
-
- /*No delayed anymore*/
- bdev->bc->free_delay[i] = 0;
-
- /*Reduce refered block count*/
- bdev->bc->ref_blocks--;
- }
- }
-
- return EOK;
-}
-
-/**
- * @}
- */
-
--- a/src/lwext4/ext4_blockdev.h
+++ /dev/null
@@ -1,211 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef EXT4_BLOCKDEV_H_
-#define EXT4_BLOCKDEV_H_
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_blockdev.h
- * @brief Block device module.
- */
-
-#include <ext4_config.h>
-#include <ext4_bcache.h>
-#include <ext4_debug.h>
-
-
-#include <stdbool.h>
-#include <stdint.h>
-
-/**@brief Initialization status flag*/
-#define EXT4_BDEV_INITIALIZED (1 << 0)
-
-
-/**@brief Definiton of the simple block device.*/
-struct ext4_blockdev {
-
- /**@brief Open device function
- * @param bdev block device.*/
- int (*open)(struct ext4_blockdev *bdev);
-
- /**@brief Block read function.
- * @param bdev block device
- * @param buf output buffer
- * @param blk_id block id
- * @param blk_cnt block count*/
- int (*bread)(struct ext4_blockdev *bdev, void *buf,
- uint64_t blk_id, uint32_t blk_cnt);
-
- /**@brief Block write function.
- * @param buf input buffer
- * @param blk_id block id
- * @param blk_cnt block count*/
- int (*bwrite)(struct ext4_blockdev *bdev, const void *buf,
- uint64_t blk_id, uint32_t blk_cnt);
-
- /**@brief Close device function.
- * @param bdev block device.*/
- int (*close)(struct ext4_blockdev *bdev);
-
- /**@brief Block size (bytes): physical*/
- uint32_t ph_bsize;
-
- /**@brief Block count: physical.*/
- uint64_t ph_bcnt;
-
- /**@brief Block size buffer: physical.*/
- uint8_t *ph_bbuf;
-
- /**@brief Block size (bytes) logical*/
- uint32_t lg_bsize;
-
- /**@brief Block count: phisical.*/
- uint64_t lg_bcnt;
-
- /**@brief Flags of te block device.*/
- uint8_t flags;
-
- /**@brief Block cache.*/
- struct ext4_bcache *bc;
-
- uint8_t cache_flush_delay;
-
- uint32_t bread_ctr;
- uint32_t bwrite_ctr;
-};
-
-
-/**@brief Static initialization fo the block device.*/
-#define EXT4_BLOCKDEV_STATIC_INSTANCE(__name, __bsize, __bcnt, __open, \
- __bread, __bwrite, __close) \
- static uint8_t __name##_ph_bbuf[(__bsize)]; \
- static struct ext4_blockdev __name = { \
- .open = __open, \
- .bread = __bread, \
- .bwrite = __bwrite, \
- .close = __close, \
- .ph_bsize = __bsize, \
- .ph_bcnt = __bcnt, \
- .ph_bbuf = __name##_ph_bbuf, \
- }
-
-/**@brief Block device initialization.
- * @param bdev block device descriptor
- * @param bg_bsize logical block size
- * @param bdev block device descriptor
- * @return standard error code*/
-int ext4_block_init(struct ext4_blockdev *bdev);
-
-
-/**@brief Binds a bcache to block device.
- * @param bdev block device descriptor
- * @param bc block cache descriptor
- * @return standard error code*/
-int ext4_block_bind_bcache(struct ext4_blockdev *bdev,
- struct ext4_bcache *bc);
-
-/**@brief Close block device
- * @param bdev block device descriptor
- * @return standard error code*/
-int ext4_block_fini(struct ext4_blockdev *bdev);
-
-
-/**@brief Set logical block size in block device.
- * @param bdev block device descriptor
- * @param lb_size ligical block size (in bytes)
- * @return standard error code*/
-void ext4_block_set_lb_size(struct ext4_blockdev *bdev,
- uint64_t lb_bsize);
-
-/**@brief Block get function (through cache).
- * @param bdev block device descriptor
- * @param b block descriptor
- * @param lba logical block address
- * @return standard error code*/
-int ext4_block_get(struct ext4_blockdev *bdev, struct ext4_block *b,
- uint64_t lba);
-
-/**@brief Block set procedure (through cache).
- * @param bdev block device descriptor
- * @param b block descriptor
- * @return standard error code*/
-int ext4_block_set(struct ext4_blockdev *bdev, struct ext4_block *b);
-
-
-/**@brief Block read procedure (without cache)
- * @param bdev block device descriptor
- * @param buf output buffer
- * @param lba logical block adderss
- * @return standard error code*/
-int ext4_block_get_direct(struct ext4_blockdev *bdev, void *buf,
- uint64_t lba);
-
-
-/**@brief Block write procedure (without cache)
- * @param bdev block device descriptor
- * @param buf output buffer
- * @param lba logical block address
- * @return standard error code*/
-int ext4_block_set_direct(struct ext4_blockdev *bdev, const void *buf,
- uint64_t lba);
-
-/**@brief Write to block device (by direct adress).
- * @param bdev block device descriptor
- * @param off byte offset in block device
- * @param buf input buffer
- * @param len length of the write nuffer
- * @return EOK when sucess*/
-int ext4_block_writebytes(struct ext4_blockdev *bdev, uint64_t off,
- const void *buf, uint32_t len);
-
-
-
-/**@brief Read freom block device (by direct adress).
- * @param bdev block device descriptor
- * @param off byte offset in block device
- * @param buf input buffer
- * @param len length of the write nuffer
- * @return EOK when sucess*/
-int ext4_block_readbytes(struct ext4_blockdev *bdev, uint64_t off,
- void *buf, uint32_t len);
-
-/**@brief Enable/disable delayed cache flush mode.
- * @param bdev block device descriptor
- * @param on_off
- * !0 - ENABLE
- * 0 - DISABLE (all delayed cache buffers will be flushed)
- * @return standard error code*/
-int ext4_block_delay_cache_flush(struct ext4_blockdev *bdev, uint8_t on_off);
-
-#endif /* EXT4_BLOCKDEV_H_ */
-
-/**
- * @}
- */
--- a/src/lwext4/ext4_config.h
+++ /dev/null
@@ -1,99 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_config.h
- * @brief Configuration file.
- */
-
-#ifndef EXT4_CONFIG_H_
-#define EXT4_CONFIG_H_
-
-#ifdef CONFIG_HAVE_OWN_CFG
-#include <config.h>
-#endif
-
-
-/**@brief Enable directory indexing feature (EXT3 feature)*/
-#ifndef CONFIG_DIR_INDEX_ENABLE
-#define CONFIG_DIR_INDEX_ENABLE 0
-#endif
-
-/**@brief Enable extents feature (EXT4 feature)*/
-#ifndef CONFIG_EXTENT_ENABLE
-#define CONFIG_EXTENT_ENABLE 0
-#endif
-
-
-
-/**@brief Include error codes from ext4_errno or sandard library.*/
-#ifndef CONFIG_HAVE_OWN_ERRNO
-#define CONFIG_HAVE_OWN_ERRNO 1
-#endif
-
-
-/**@brief Debug printf enable (stdout)*/
-#ifndef CONFIG_DEBUG_PRINTF
-#define CONFIG_DEBUG_PRINTF 1
-#endif
-
-/**@brief Assert printf enable (stdout)*/
-#ifndef CONFIG_DEBUG_ASSERT
-#define CONFIG_DEBUG_ASSERT 1
-#endif
-
-/**@brief Statistics of block device*/
-#ifndef CONFIG_BLOCK_DEV_ENABLE_STATS
-#define CONFIG_BLOCK_DEV_ENABLE_STATS 1
-#endif
-
-/**@brief Cache size of block device.*/
-#ifndef CONFIG_BLOCK_DEV_CACHE_SIZE
-#define CONFIG_BLOCK_DEV_CACHE_SIZE 8
-#endif
-
-
-/**@brief Ilosc urzadzen blokowych.*/
-#ifndef CONFIG_EXT4_BLOCKDEVS_COUNT
-#define CONFIG_EXT4_BLOCKDEVS_COUNT 2
-#endif
-
-/**@brief Ilosc punktow montowania systemu plikow*/
-#ifndef CONFIG_EXT4_MOUNTPOINTS_COUNT
-#define CONFIG_EXT4_MOUNTPOINTS_COUNT 2
-#endif
-
-
-#endif /* EXT4_CONFIG_H_ */
-
-/**
- * @}
- */
--- a/src/lwext4/ext4_debug.c
+++ /dev/null
@@ -1,58 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_debug.c
- * @brief Debug printf and assert macros.
- */
-
-#include <ext4_config.h>
-#include <ext4_debug.h>
-
-#include <stdarg.h>
-#include <stdio.h>
-
-static uint32_t __dbg_mask__;
-
-
-void ext4_dmask_set(uint32_t m)
-{
- __dbg_mask__ = m;
-}
-
-uint32_t ext4_dmask_get(void)
-{
- return __dbg_mask__;
-}
-
-/**
- * @}
- */
--- a/src/lwext4/ext4_debug.h
+++ /dev/null
@@ -1,116 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_debug.c
- * @brief Debug printf and assert macros.
- */
-
-#ifndef EXT4_DEBUG_H_
-#define EXT4_DEBUG_H_
-
-#include <ext4_config.h>
-#include <ext4_errno.h>
-#include <stdint.h>
-#include <stdio.h>
-
-/**@brief Debug mask: ext4_blockdev.c*/
-#define EXT4_DEBUG_BLOCKDEV (1 << 0)
-
-/**@brief Debug mask: ext4_fs.c*/
-#define EXT4_DEBUG_FS (1 << 1)
-
-/**@brief Debug mask: ext4_balloc.c*/
-#define EXT4_DEBUG_BALLOC (1 << 2)
-
-/**@brief Debug mask: ext4_bitmap.c*/
-#define EXT4_DEBUG_BITMAP (1 << 3)
-
-/**@brief Debug mask: ext4_dir_idx.c*/
-#define EXT4_DEBUG_DIR_IDX (1 << 4)
-
-/**@brief Debug mask: ext4_dir.c*/
-#define EXT4_DEBUG_DIR (1 << 5)
-
-/**@brief Debug mask: ext4_ialloc.c*/
-#define EXT4_DEBUG_IALLOC (1 << 6)
-
-/**@brief Debug mask: ext4_inode.c*/
-#define EXT4_DEBUG_INODE (1 << 7)
-
-/**@brief Debug mask: ext4_super.c*/
-#define EXT4_DEBUG_SUPER (1 << 8)
-
-/**@brief Debug mask: ext4_bcache.c*/
-#define EXT4_DEBUG_BCACHE (1 << 9)
-
-
-/**@brief All debug printf enabled.*/
-#define EXT4_DEBUG_ALL (0xFFFFFFFF)
-
-/**@brief Global mask debug settings.
- * @brief m new debug mask.*/
-void ext4_dmask_set(uint32_t m);
-
-/**@brief Global debug mask get.
- * @return debug mask*/
-uint32_t ext4_dmask_get(void);
-
-
-#if CONFIG_DEBUG_PRINTF
-/**@brief Debug printf.*/
-#define ext4_dprintf(m, ...) do { \
- (m & ext4_dmask_get()) ? printf(__VA_ARGS__) : (void)0; \
- fflush(stdout); \
-}while(0)
-#else
-#define ext4_dprintf(m, ...)
-#endif
-
-
-
-#if CONFIG_DEBUG_ASSERT
-#define ext4_assert(_v) do { \
- if(!(_v)){ \
- printf("Assertion failed:\nModule: %s\nFunc: %s\nLine: %d\n", \
- __FILE__, __FUNCTION__, __LINE__); \
- } \
-}while(0)
-#else
-#define ext4_assert(_v)
-#endif
-
-
-#endif /* EXT4_DEBUG_H_ */
-
-/**
- * @}
- */
--- a/src/lwext4/ext4_dir.c
+++ /dev/null
@@ -1,618 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_dir.h
- * @brief Directory handle procedures.
- */
-
-#include <ext4_config.h>
-#include <ext4_dir.h>
-#include <ext4_dir_idx.h>
-#include <ext4_inode.h>
-#include <ext4_fs.h>
-
-#include <string.h>
-
-uint32_t ext4_dir_entry_ll_get_inode(struct ext4_directory_entry_ll *de)
-{
- return to_le32(de->inode);
-}
-
-void ext4_dir_entry_ll_set_inode(struct ext4_directory_entry_ll *de,
- uint32_t inode)
-{
- de->inode = to_le32(inode);
-}
-
-
-uint16_t ext4_dir_entry_ll_get_entry_length(struct ext4_directory_entry_ll *de)
-{
- return to_le16(de->entry_length);
-}
-
-void ext4_dir_entry_ll_set_entry_length(struct ext4_directory_entry_ll *de,
- uint16_t len)
-{
- de->entry_length = to_le16(len);
-}
-
-
-uint16_t ext4_dir_entry_ll_get_name_length(struct ext4_sblock *sb,
- struct ext4_directory_entry_ll *de)
-{
- uint16_t v = de->name_length;
-
- if ((ext4_get32(sb, rev_level) == 0) &&
- (ext4_get32(sb, minor_rev_level) < 5))
- v |= ((uint16_t)de->name_length_high) << 8;
-
- return v;
-}
-void ext4_dir_entry_ll_set_name_length(struct ext4_sblock *sb,
- struct ext4_directory_entry_ll *de, uint16_t len)
-{
- de->name_length = (len << 8) >> 8;
-
- if ((ext4_get32(sb, rev_level) == 0) &&
- (ext4_get32(sb, minor_rev_level) < 5))
- de->name_length_high = len >> 8;
-}
-
-
-
-uint8_t ext4_dir_entry_ll_get_inode_type(struct ext4_sblock *sb,
- struct ext4_directory_entry_ll *de)
-{
- if ((ext4_get32(sb, rev_level) > 0) ||
- (ext4_get32(sb, minor_rev_level) >= 5))
- return de->inode_type;
-
- return EXT4_DIRECTORY_FILETYPE_UNKNOWN;
-}
-
-
-void ext4_dir_entry_ll_set_inode_type(struct ext4_sblock *sb,
- struct ext4_directory_entry_ll *de, uint8_t type)
-{
- if ((ext4_get32(sb, rev_level) > 0) ||
- (ext4_get32(sb, minor_rev_level) >= 5))
- de->inode_type = type;
-}
-
-/****************************************************************************/
-
-
-static int ext4_dir_iterator_set(struct ext4_directory_iterator *it,
- uint32_t block_size)
-{
- it->current = NULL;
-
- uint32_t offset_in_block = it->current_offset % block_size;
-
- /* Ensure proper alignment */
- if ((offset_in_block % 4) != 0)
- return EIO;
-
- /* Ensure that the core of the entry does not overflow the block */
- if (offset_in_block > block_size - 8)
- return EIO;
-
- struct ext4_directory_entry_ll *entry =
- (void *)(it->current_block.data + offset_in_block);
-
- /* Ensure that the whole entry does not overflow the block */
- uint16_t length = ext4_dir_entry_ll_get_entry_length(entry);
- if (offset_in_block + length > block_size)
- return EIO;
-
- /* Ensure the name length is not too large */
- if (ext4_dir_entry_ll_get_name_length(
- &it->inode_ref->fs->sb, entry) > length-8)
- return EIO;
-
- /* Everything OK - "publish" the entry */
- it->current = entry;
- return EOK;
-}
-
-static int ext4_dir_iterator_seek(struct ext4_directory_iterator *it,
- uint64_t pos)
-{
- uint64_t size = ext4_inode_get_size(&it->inode_ref->fs->sb,
- it->inode_ref->inode);
-
- /* The iterator is not valid until we seek to the desired position */
- it->current = NULL;
-
- /* Are we at the end? */
- if (pos >= size) {
- if (it->current_block.lb_id) {
-
- int rc = ext4_block_set(it->inode_ref->fs->bdev,
- &it->current_block);
- it->current_block.lb_id = 0;
-
- if (rc != EOK)
- return rc;
- }
-
- it->current_offset = pos;
- return EOK;
- }
-
- /* Compute next block address */
- uint32_t block_size =
- ext4_sb_get_block_size(&it->inode_ref->fs->sb);
- uint64_t current_block_idx = it->current_offset / block_size;
- uint64_t next_block_idx = pos / block_size;
-
- /*
- * If we don't have a block or are moving accross block boundary,
- * we need to get another block
- */
- if ((it->current_block.lb_id == 0) ||
- (current_block_idx != next_block_idx)) {
- if (it->current_block.lb_id) {
- int rc = ext4_block_set(it->inode_ref->fs->bdev, &it->current_block);
- it->current_block.lb_id = 0;
-
- if (rc != EOK)
- return rc;
- }
-
- uint32_t next_block_phys_idx;
- int rc = ext4_fs_get_inode_data_block_index(it->inode_ref,
- next_block_idx, &next_block_phys_idx);
- if (rc != EOK)
- return rc;
-
-
- rc = ext4_block_get(it->inode_ref->fs->bdev, &it->current_block,
- next_block_phys_idx);
- if (rc != EOK) {
- it->current_block.lb_id = 0;
- return rc;
- }
- }
-
- it->current_offset = pos;
-
- return ext4_dir_iterator_set(it, block_size);
-}
-
-
-int ext4_dir_iterator_init(struct ext4_directory_iterator *it,
- struct ext4_inode_ref *inode_ref, uint64_t pos)
-{
- it->inode_ref = inode_ref;
- it->current = 0;
- it->current_offset = 0;
- it->current_block.lb_id = 0;
-
- return ext4_dir_iterator_seek(it, pos);
-}
-
-int ext4_dir_iterator_next(struct ext4_directory_iterator *it)
-{
- uint16_t skip = ext4_dir_entry_ll_get_entry_length(it->current);
-
- return ext4_dir_iterator_seek(it, it->current_offset + skip);
-}
-
-int ext4_dir_iterator_fini(struct ext4_directory_iterator *it)
-{
- it->current = 0;
-
- if (it->current_block.lb_id)
- return ext4_block_set(it->inode_ref->fs->bdev, &it->current_block);
-
- return EOK;
-}
-
-void ext4_dir_write_entry(struct ext4_sblock *sb,
- struct ext4_directory_entry_ll *entry, uint16_t entry_len,
- struct ext4_inode_ref *child, const char *name, size_t name_len)
-{
- /* Check maximum entry length */
- uint32_t block_size = ext4_sb_get_block_size(sb);
- ext4_assert(entry_len <= block_size);
-
- /* Set basic attributes */
- ext4_dir_entry_ll_set_inode(entry, child->index);
- ext4_dir_entry_ll_set_entry_length(entry, entry_len);
- ext4_dir_entry_ll_set_name_length(sb, entry, name_len);
-
- /* Write name */
- memcpy(entry->name, name, name_len);
-
- /* Set type of entry */
- if (ext4_inode_is_type(sb, child->inode, EXT4_INODE_MODE_DIRECTORY))
- ext4_dir_entry_ll_set_inode_type(sb, entry,
- EXT4_DIRECTORY_FILETYPE_DIR);
- else
- ext4_dir_entry_ll_set_inode_type(sb, entry,
- EXT4_DIRECTORY_FILETYPE_REG_FILE);
-}
-
-int ext4_dir_add_entry(struct ext4_inode_ref *parent, const char *name,
- uint32_t name_len, struct ext4_inode_ref *child)
-{
- struct ext4_fs *fs = parent->fs;
-
-#if CONFIG_DIR_INDEX_ENABLE
- /* Index adding (if allowed) */
- if ((ext4_sb_check_feature_compatible(&fs->sb,
- EXT4_FEATURE_COMPAT_DIR_INDEX)) &&
- (ext4_inode_has_flag(parent->inode, EXT4_INODE_FLAG_INDEX))) {
- int rc = ext4_dir_dx_add_entry(parent, child, name);
-
- /* Check if index is not corrupted */
- if (rc != EXT4_ERR_BAD_DX_DIR) {
- if (rc != EOK)
- return rc;
-
- return EOK;
- }
-
- /* Needed to clear dir index flag if corrupted */
- ext4_inode_clear_flag(parent->inode, EXT4_INODE_FLAG_INDEX);
- parent->dirty = true;
- }
-#endif
-
- /* Linear algorithm */
- uint32_t iblock = 0;
- uint32_t fblock = 0;
- uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
- uint32_t inode_size = ext4_inode_get_size(&fs->sb, parent->inode);
- uint32_t total_blocks = inode_size / block_size;
-
-
- /* Find block, where is space for new entry and try to add */
- bool success = false;
- for (iblock = 0; iblock < total_blocks; ++iblock) {
- int rc = ext4_fs_get_inode_data_block_index(parent,
- iblock, &fblock);
- if (rc != EOK)
- return rc;
-
-
- struct ext4_block block;
- rc = ext4_block_get(fs->bdev, &block, fblock);
- if (rc != EOK)
- return rc;
-
- /* If adding is successful, function can finish */
- rc = ext4_dir_try_insert_entry(&fs->sb, &block,
- child, name, name_len);
- if (rc == EOK)
- success = true;
-
- rc = ext4_block_set(fs->bdev, &block);
- if (rc != EOK)
- return rc;
-
- if (success)
- return EOK;
- }
-
- /* No free block found - needed to allocate next data block */
-
- iblock = 0;
- fblock = 0;
- int rc = ext4_fs_append_inode_block(parent, &fblock, &iblock);
- if (rc != EOK)
- return rc;
-
- /* Load new block */
- struct ext4_block new_block;
-
- rc = ext4_block_get(fs->bdev, &new_block, fblock);
- if (rc != EOK)
- return rc;
-
- /* Fill block with zeroes */
- memset(new_block.data, 0, block_size);
- struct ext4_directory_entry_ll *block_entry = (void *)new_block.data;
- ext4_dir_write_entry(&fs->sb, block_entry, block_size,
- child, name, name_len);
-
- /* Save new block */
- new_block.dirty = true;
- rc = ext4_block_set(fs->bdev, &new_block);
-
- return rc;
-}
-
-int ext4_dir_find_entry(struct ext4_directory_search_result *result,
- struct ext4_inode_ref *parent, const char *name, uint32_t name_len)
-{
- struct ext4_sblock *sb = &parent->fs->sb;
-
-
-#if CONFIG_DIR_INDEX_ENABLE
- /* Index search */
- if ((ext4_sb_check_feature_compatible(sb,
- EXT4_FEATURE_COMPAT_DIR_INDEX)) &&
- (ext4_inode_has_flag(parent->inode, EXT4_INODE_FLAG_INDEX))) {
- int rc = ext4_dir_dx_find_entry(result, parent, name_len,
- name);
-
- /* Check if index is not corrupted */
- if (rc != EXT4_ERR_BAD_DX_DIR) {
- if (rc != EOK)
- return rc;
-
- return EOK;
- }
-
- /* Needed to clear dir index flag if corrupted */
- ext4_inode_clear_flag(parent->inode, EXT4_INODE_FLAG_INDEX);
- parent->dirty = true;
- }
-#endif
-
- /* Linear algorithm */
-
- uint32_t iblock;
- uint32_t fblock;
- uint32_t block_size = ext4_sb_get_block_size(sb);
- uint32_t inode_size = ext4_inode_get_size(sb, parent->inode);
- uint32_t total_blocks = inode_size / block_size;
-
- /* Walk through all data blocks */
- for (iblock = 0; iblock < total_blocks; ++iblock) {
- /* Load block address */
- int rc = ext4_fs_get_inode_data_block_index(parent, iblock,
- &fblock);
- if (rc != EOK)
- return rc;
-
- /* Load data block */
- struct ext4_block block;
- rc = ext4_block_get( parent->fs->bdev, &block, fblock);
- if (rc != EOK)
- return rc;
-
- /* Try to find entry in block */
- struct ext4_directory_entry_ll *res_entry;
- rc = ext4_dir_find_in_block(&block, sb, name_len, name,
- &res_entry);
- if (rc == EOK) {
- result->block = block;
- result->dentry = res_entry;
- return EOK;
- }
-
- /* Entry not found - put block and continue to the next block */
-
- rc = ext4_block_set(parent->fs->bdev, &block);
- if (rc != EOK)
- return rc;
- }
-
- /* Entry was not found */
-
- result->block.lb_id = 0;
- result->dentry = NULL;
-
- return ENOENT;
-}
-
-int ext4_dir_remove_entry(struct ext4_inode_ref *parent, const char *name,
- uint32_t name_len)
-{
- /* Check if removing from directory */
- if (!ext4_inode_is_type(&parent->fs->sb, parent->inode,
- EXT4_INODE_MODE_DIRECTORY))
- return ENOTDIR;
-
- /* Try to find entry */
- struct ext4_directory_search_result result;
- int rc = ext4_dir_find_entry(&result, parent, name, name_len);
- if (rc != EOK)
- return rc;
-
- /* Invalidate entry */
- ext4_dir_entry_ll_set_inode(result.dentry, 0);
-
- /* Store entry position in block */
- uint32_t pos = (uint8_t *) result.dentry - result.block.data;
-
- /*
- * If entry is not the first in block, it must be merged
- * with previous entry
- */
- if (pos != 0) {
- uint32_t offset = 0;
-
- /* Start from the first entry in block */
- struct ext4_directory_entry_ll *tmp_dentry = (void *)result.block.data;
- uint16_t tmp_dentry_length =
- ext4_dir_entry_ll_get_entry_length(tmp_dentry);
-
- /* Find direct predecessor of removed entry */
- while ((offset + tmp_dentry_length) < pos) {
- offset +=
- ext4_dir_entry_ll_get_entry_length(tmp_dentry);
- tmp_dentry = (void *)(result.block.data + offset);
- tmp_dentry_length =
- ext4_dir_entry_ll_get_entry_length(tmp_dentry);
- }
-
- ext4_assert(tmp_dentry_length + offset == pos);
-
- /* Add to removed entry length to predecessor's length */
- uint16_t del_entry_length =
- ext4_dir_entry_ll_get_entry_length(result.dentry);
- ext4_dir_entry_ll_set_entry_length(tmp_dentry,
- tmp_dentry_length + del_entry_length);
- }
-
- result.block.dirty = true;
-
- return ext4_dir_destroy_result(parent, &result);
-}
-
-int ext4_dir_try_insert_entry(struct ext4_sblock *sb,
- struct ext4_block *target_block, struct ext4_inode_ref *child,
- const char *name, uint32_t name_len)
-{
- /* Compute required length entry and align it to 4 bytes */
- uint32_t block_size = ext4_sb_get_block_size(sb);
- uint16_t required_len = sizeof(struct ext4_fake_directory_entry) + name_len;
-
- if ((required_len % 4) != 0)
- required_len += 4 - (required_len % 4);
-
- /* Initialize pointers, stop means to upper bound */
- struct ext4_directory_entry_ll *dentry = (void *)target_block->data;
- struct ext4_directory_entry_ll *stop =
- (void *)(target_block->data + block_size);
-
- /*
- * Walk through the block and check for invalid entries
- * or entries with free space for new entry
- */
- while (dentry < stop) {
- uint32_t inode = ext4_dir_entry_ll_get_inode(dentry);
- uint16_t rec_len = ext4_dir_entry_ll_get_entry_length(dentry);
-
- /* If invalid and large enough entry, use it */
- if ((inode == 0) && (rec_len >= required_len)) {
- ext4_dir_write_entry(sb, dentry, rec_len, child,
- name, name_len);
- target_block->dirty = true;
-
- return EOK;
- }
-
- /* Valid entry, try to split it */
- if (inode != 0) {
- uint16_t used_name_len =
- ext4_dir_entry_ll_get_name_length(sb, dentry);
-
- uint16_t used_space =
- sizeof(struct ext4_fake_directory_entry) + used_name_len;
-
- if ((used_name_len % 4) != 0)
- used_space += 4 - (used_name_len % 4);
-
- uint16_t free_space = rec_len - used_space;
-
- /* There is free space for new entry */
- if (free_space >= required_len) {
- /* Cut tail of current entry */
- ext4_dir_entry_ll_set_entry_length(dentry, used_space);
- struct ext4_directory_entry_ll *new_entry =
- (void *) dentry + used_space;
- ext4_dir_write_entry(sb, new_entry,
- free_space, child, name, name_len);
-
- target_block->dirty = true;
-
- return EOK;
- }
- }
-
- /* Jump to the next entry */
- dentry = (void *) dentry + rec_len;
- }
-
- /* No free space found for new entry */
- return ENOSPC;
-}
-
-
-int ext4_dir_find_in_block(struct ext4_block *block, struct ext4_sblock *sb,
- size_t name_len, const char *name,
- struct ext4_directory_entry_ll **res_entry)
-{
- /* Start from the first entry in block */
- struct ext4_directory_entry_ll *dentry =
- (struct ext4_directory_entry_ll *) block->data;
-
- /* Set upper bound for cycling */
- uint8_t *addr_limit = block->data + ext4_sb_get_block_size(sb);
-
- /* Walk through the block and check entries */
- while ((uint8_t *) dentry < addr_limit) {
- /* Termination condition */
- if ((uint8_t *) dentry + name_len > addr_limit)
- break;
-
- /* Valid entry - check it */
- if (dentry->inode != 0) {
- /* For more effectivity compare firstly only lengths */
- if (ext4_dir_entry_ll_get_name_length(sb, dentry) ==
- name_len) {
- /* Compare names */
- if (memcmp((uint8_t *) name, dentry->name, name_len) == 0) {
- *res_entry = dentry;
- return EOK;
- }
- }
- }
-
- uint16_t dentry_len =
- ext4_dir_entry_ll_get_entry_length(dentry);
-
- /* Corrupted entry */
- if (dentry_len == 0)
- return EINVAL;
-
- /* Jump to next entry */
- dentry = (struct ext4_directory_entry_ll *)
- ((uint8_t *) dentry + dentry_len);
- }
-
- /* Entry not found */
- return ENOENT;
-}
-
-int ext4_dir_destroy_result(struct ext4_inode_ref *parent,
- struct ext4_directory_search_result *result)
-{
- if (result->block.lb_id)
- return ext4_block_set(parent->fs->bdev, &result->block);
-
- return EOK;
-}
-
-/**
- * @}
- */
--- a/src/lwext4/ext4_dir.h
+++ /dev/null
@@ -1,114 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_dir.h
- * @brief Directory handle procedures.
- */
-
-#ifndef EXT4_DIR_H_
-#define EXT4_DIR_H_
-
-#include <ext4_config.h>
-#include <ext4_types.h>
-#include <ext4_blockdev.h>
-#include <ext4_super.h>
-
-
-#include <stdint.h>
-
-uint32_t ext4_dir_entry_ll_get_inode(struct ext4_directory_entry_ll *de);
-
-void ext4_dir_entry_ll_set_inode(struct ext4_directory_entry_ll *de,
- uint32_t inode);
-
-
-uint16_t ext4_dir_entry_ll_get_entry_length(struct ext4_directory_entry_ll *de);
-void ext4_dir_entry_ll_set_entry_length(struct ext4_directory_entry_ll *de,
- uint16_t len);
-
-
-uint16_t ext4_dir_entry_ll_get_name_length(struct ext4_sblock *sb,
- struct ext4_directory_entry_ll *de);
-void ext4_dir_entry_ll_set_name_length(struct ext4_sblock *sb,
- struct ext4_directory_entry_ll *de, uint16_t len);
-
-
-
-uint8_t ext4_dir_entry_ll_get_inode_type(struct ext4_sblock *sb,
- struct ext4_directory_entry_ll *de);
-void ext4_dir_entry_ll_set_inode_type(struct ext4_sblock *sb,
- struct ext4_directory_entry_ll *de, uint8_t type);
-
-
-int ext4_dir_iterator_init(struct ext4_directory_iterator *it,
- struct ext4_inode_ref *inode_ref, uint64_t pos);
-
-int ext4_dir_iterator_next(struct ext4_directory_iterator *it);
-int ext4_dir_iterator_fini(struct ext4_directory_iterator *it);
-
-void ext4_dir_write_entry(struct ext4_sblock *sb,
- struct ext4_directory_entry_ll *entry, uint16_t entry_len,
- struct ext4_inode_ref *child, const char *name, size_t name_len);
-
-int ext4_dir_add_entry(struct ext4_inode_ref *parent, const char *name,
- uint32_t name_len, struct ext4_inode_ref *child);
-
-int ext4_dir_find_entry(struct ext4_directory_search_result *result,
- struct ext4_inode_ref *parent, const char *name, uint32_t name_len);
-
-int ext4_dir_remove_entry(struct ext4_inode_ref *parent, const char *name,
- uint32_t name_len);
-
-int ext4_dir_try_insert_entry(struct ext4_sblock *sb,
- struct ext4_block *target_block, struct ext4_inode_ref *child,
- const char *name, uint32_t name_len);
-
-int ext4_dir_find_in_block(struct ext4_block *block, struct ext4_sblock *sb,
- size_t name_len, const char *name,
- struct ext4_directory_entry_ll **res_entry);
-
-int ext4_dir_destroy_result(struct ext4_inode_ref *parent,
- struct ext4_directory_search_result *result);
-
-
-#endif /* EXT4_DIR_H_ */
-
-/**
- * @}
- */
-
-
--- a/src/lwext4/ext4_dir_idx.c
+++ /dev/null
@@ -1,1016 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_dir_idx.c
- * @brief Directory indexing procedures.
- */
-
-#include <ext4_config.h>
-#include <ext4_dir_idx.h>
-#include <ext4_dir.h>
-#include <ext4_blockdev.h>
-#include <ext4_fs.h>
-#include <ext4_super.h>
-#include <ext4_hash.h>
-
-#include <string.h>
-#include <stdlib.h>
-
-struct ext4_dx_sort_entry {
- uint32_t hash;
- uint32_t rec_len;
- void *dentry;
-};
-
-static int ext4_dir_dx_hash_string(struct ext4_hash_info *hinfo, int len,
- const char *name)
-{
- return ext2_htree_hash(name, len, hinfo->seed, hinfo->hash_version,
- &hinfo->hash, &hinfo->minor_hash);
-}
-
-
-uint8_t ext4_dir_dx_root_info_get_hash_version(
- struct ext4_directory_dx_root_info *root_info)
-{
- return root_info->hash_version;
-}
-
-
-void ext4_dir_dx_root_info_set_hash_version(
- struct ext4_directory_dx_root_info *root_info, uint8_t v)
-{
- root_info->hash_version = v;
-}
-
-uint8_t ext4_dir_dx_root_info_get_info_length(
- struct ext4_directory_dx_root_info *root_info)
-{
- return root_info->info_length;
-}
-void ext4_dir_dx_root_info_set_info_length(
- struct ext4_directory_dx_root_info *root_info, uint8_t len)
-{
- root_info->info_length = len;
-}
-
-uint8_t ext4_dir_dx_root_info_get_indirect_levels(
- struct ext4_directory_dx_root_info *root_info)
-{
- return root_info->indirect_levels;
-}
-
-void ext4_dir_dx_root_info_set_indirect_levels(
- struct ext4_directory_dx_root_info *root_info, uint8_t lvl)
-{
- root_info->indirect_levels = lvl;
-}
-
-
-
-uint16_t ext4_dir_dx_countlimit_get_limit(
- struct ext4_directory_dx_countlimit *climit)
-{
- return to_le16(climit->limit);
-}
-void ext4_dir_dx_countlimit_set_limit(
- struct ext4_directory_dx_countlimit *climit, uint16_t limit)
-{
- climit->limit = to_le16(limit);
-}
-
-uint16_t ext4_dir_dx_countlimit_get_count(
- struct ext4_directory_dx_countlimit *climit)
-{
- return to_le16(climit->count);
-}
-
-void ext4_dir_dx_countlimit_set_count(
- struct ext4_directory_dx_countlimit *climit, uint16_t count)
-{
- climit->count = to_le16(count);
-}
-
-
-uint32_t ext4_dir_dx_entry_get_hash(
- struct ext4_directory_dx_entry *entry)
-{
- return to_le32(entry->hash);
-}
-void ext4_dir_dx_entry_set_hash(
- struct ext4_directory_dx_entry *entry, uint32_t hash)
-{
- entry->hash = to_le32(hash);
-}
-
-uint32_t ext4_dir_dx_entry_get_block(
- struct ext4_directory_dx_entry *entry)
-{
- return to_le32(entry->block);
-}
-void ext4_dir_dx_entry_set_block(
- struct ext4_directory_dx_entry *entry, uint32_t block)
-{
- entry->block = to_le32(block);
-}
-/****************************************************************************/
-
-int ext4_dir_dx_init(struct ext4_inode_ref *dir)
-{
- /* Load block 0, where will be index root located */
- uint32_t fblock;
- int rc = ext4_fs_get_inode_data_block_index(dir, 0,
- &fblock);
- if (rc != EOK)
- return rc;
-
- struct ext4_block block;
- rc = ext4_block_get(dir->fs->bdev, &block, fblock);
- if (rc != EOK)
- return rc;
-
- /* Initialize pointers to data structures */
- struct ext4_directory_dx_root *root = (void *)block.data;
- struct ext4_directory_dx_root_info *info = &(root->info);
-
- /* Initialize root info structure */
- uint8_t hash_version = ext4_get8(&dir->fs->sb, default_hash_version);
-
-
- ext4_dir_dx_root_info_set_hash_version(info, hash_version);
- ext4_dir_dx_root_info_set_indirect_levels(info, 0);
- ext4_dir_dx_root_info_set_info_length(info, 8);
-
- /* Set limit and current number of entries */
- struct ext4_directory_dx_countlimit *countlimit =
- (struct ext4_directory_dx_countlimit *) &root->entries;
-
- ext4_dir_dx_countlimit_set_count(countlimit, 1);
-
- uint32_t block_size =
- ext4_sb_get_block_size(&dir->fs->sb);
- uint32_t entry_space =
- block_size - 2 * sizeof(struct ext4_directory_dx_dot_entry) -
- sizeof(struct ext4_directory_dx_root_info);
- uint16_t root_limit = entry_space / sizeof(struct ext4_directory_dx_entry);
- ext4_dir_dx_countlimit_set_limit(countlimit, root_limit);
-
- /* Append new block, where will be new entries inserted in the future */
- uint32_t iblock;
- rc = ext4_fs_append_inode_block(dir, &fblock, &iblock);
- if (rc != EOK) {
- ext4_block_set(dir->fs->bdev, &block);
- return rc;
- }
-
- struct ext4_block new_block;
-
- rc = ext4_block_get(dir->fs->bdev, &new_block, fblock);
- if (rc != EOK) {
- ext4_block_set(dir->fs->bdev, &block);
- return rc;
- }
-
- /* Fill the whole block with empty entry */
- struct ext4_directory_entry_ll *block_entry = (void *)new_block.data;
-
- ext4_dir_entry_ll_set_entry_length(block_entry, block_size);
- ext4_dir_entry_ll_set_inode(block_entry, 0);
-
- new_block.dirty = true;
- rc = ext4_block_set(dir->fs->bdev, &new_block);
- if (rc != EOK) {
- ext4_block_set(dir->fs->bdev, &block);
- return rc;
- }
-
- /* Connect new block to the only entry in index */
- struct ext4_directory_dx_entry *entry = root->entries;
- ext4_dir_dx_entry_set_block(entry, iblock);
-
- block.dirty = true;
-
- return ext4_block_set(dir->fs->bdev, &block);
-}
-
-static int ext4_dir_hinfo_init(struct ext4_hash_info *hinfo,
- struct ext4_block *root_block, struct ext4_sblock *sb, size_t name_len,
- const char *name)
-{
- struct ext4_directory_dx_root *root =
- (struct ext4_directory_dx_root *) root_block->data;
-
- if ((root->info.hash_version != EXT2_HTREE_LEGACY) &&
- (root->info.hash_version != EXT2_HTREE_HALF_MD4) &&
- (root->info.hash_version != EXT2_HTREE_TEA))
- return EXT4_ERR_BAD_DX_DIR;
-
- /* Check unused flags */
- if (root->info.unused_flags != 0)
- return EXT4_ERR_BAD_DX_DIR;
-
- /* Check indirect levels */
- if (root->info.indirect_levels > 1)
- return EXT4_ERR_BAD_DX_DIR;
-
- /* Check if node limit is correct */
- uint32_t block_size = ext4_sb_get_block_size(sb);
- uint32_t entry_space = block_size;
- entry_space -= 2 * sizeof(struct ext4_directory_dx_dot_entry);
- entry_space -= sizeof(struct ext4_directory_dx_root_info);
- entry_space = entry_space / sizeof(struct ext4_directory_dx_entry);
-
- uint16_t limit = ext4_dir_dx_countlimit_get_limit(
- (struct ext4_directory_dx_countlimit *) &root->entries);
- if (limit != entry_space)
- return EXT4_ERR_BAD_DX_DIR;
-
- /* Check hash version and modify if necessary */
- hinfo->hash_version =
- ext4_dir_dx_root_info_get_hash_version(&root->info);
- if ((hinfo->hash_version <= EXT2_HTREE_TEA) &&
- (ext4_sb_check_flag(sb, EXT4_SUPERBLOCK_FLAGS_UNSIGNED_HASH))) {
- /* Use unsigned hash */
- hinfo->hash_version += 3;
- }
-
- /* Load hash seed from superblock */
-
- hinfo->seed = ext4_get8(sb, hash_seed);
-
- /* Compute hash value of name */
- if (name)
- return ext4_dir_dx_hash_string(hinfo, name_len, name);
-
- return EOK;
-}
-
-
-static int ext4_dir_dx_get_leaf(struct ext4_hash_info *hinfo,
- struct ext4_inode_ref *inode_ref, struct ext4_block *root_block,
- struct ext4_directory_dx_block **dx_block,
- struct ext4_directory_dx_block *dx_blocks)
-{
- struct ext4_directory_dx_block *tmp_dx_block = dx_blocks;
- struct ext4_directory_dx_root *root =
- (struct ext4_directory_dx_root *) root_block->data;
- struct ext4_directory_dx_entry *entries =
- (struct ext4_directory_dx_entry *) &root->entries;
-
- uint16_t limit = ext4_dir_dx_countlimit_get_limit(
- (struct ext4_directory_dx_countlimit *) entries);
- uint8_t indirect_level =
- ext4_dir_dx_root_info_get_indirect_levels(&root->info);
-
- struct ext4_block *tmp_block = root_block;
- struct ext4_directory_dx_entry *p;
- struct ext4_directory_dx_entry *q;
- struct ext4_directory_dx_entry *m;
- struct ext4_directory_dx_entry *at;
-
- /* Walk through the index tree */
- while (true) {
- uint16_t count = ext4_dir_dx_countlimit_get_count(
- (struct ext4_directory_dx_countlimit *) entries);
- if ((count == 0) || (count > limit))
- return EXT4_ERR_BAD_DX_DIR;
-
- /* Do binary search in every node */
- p = entries + 1;
- q = entries + count - 1;
-
- while (p <= q) {
- m = p + (q - p) / 2;
- if (ext4_dir_dx_entry_get_hash(m) > hinfo->hash)
- q = m - 1;
- else
- p = m + 1;
- }
-
- at = p - 1;
-
- /* Write results */
-
- memcpy(&tmp_dx_block->block, tmp_block, sizeof(struct ext4_block));
- tmp_dx_block->entries = entries;
- tmp_dx_block->position = at;
-
- /* Is algorithm in the leaf? */
- if (indirect_level == 0) {
- *dx_block = tmp_dx_block;
- return EOK;
- }
-
- /* Goto child node */
- uint32_t next_block = ext4_dir_dx_entry_get_block(at);
-
- indirect_level--;
-
- uint32_t fblock;
- int rc = ext4_fs_get_inode_data_block_index(inode_ref,
- next_block, &fblock);
- if (rc != EOK)
- return rc;
-
- rc = ext4_block_get(inode_ref->fs->bdev, tmp_block, fblock);
- if (rc != EOK)
- return rc;
-
- entries = ((struct ext4_directory_dx_node *) tmp_block->data)->entries;
- limit = ext4_dir_dx_countlimit_get_limit(
- (struct ext4_directory_dx_countlimit *) entries);
-
- uint16_t entry_space =
- ext4_sb_get_block_size(&inode_ref->fs->sb) -
- sizeof(struct ext4_directory_dx_dot_entry);
-
- entry_space = entry_space / sizeof(struct ext4_directory_dx_entry);
-
- if (limit != entry_space) {
- ext4_block_set(inode_ref->fs->bdev, tmp_block);
- return EXT4_ERR_BAD_DX_DIR;
- }
-
- ++tmp_dx_block;
- }
-
- /* Unreachable */
- return EOK;
-}
-
-static int ext4_dir_dx_next_block(struct ext4_inode_ref *inode_ref,
- uint32_t hash, struct ext4_directory_dx_block *dx_block,
- struct ext4_directory_dx_block *dx_blocks)
-{
- uint32_t num_handles = 0;
- struct ext4_directory_dx_block *p = dx_block;
-
- /* Try to find data block with next bunch of entries */
- while (true) {
- p->position++;
- uint16_t count = ext4_dir_dx_countlimit_get_count(
- (struct ext4_directory_dx_countlimit *) p->entries);
-
- if (p->position < p->entries + count)
- break;
-
- if (p == dx_blocks)
- return EOK;
-
- num_handles++;
- p--;
- }
-
- /* Check hash collision (if not occured - no next block cannot be used)*/
- uint32_t current_hash = ext4_dir_dx_entry_get_hash(p->position);
- if ((hash & 1) == 0) {
- if ((current_hash & ~1) != hash)
- return 0;
- }
-
- /* Fill new path */
- while (num_handles--) {
- uint32_t block_idx =
- ext4_dir_dx_entry_get_block(p->position);
- uint32_t block_addr;
-
- int rc = ext4_fs_get_inode_data_block_index(inode_ref,
- block_idx, &block_addr);
- if (rc != EOK)
- return rc;
-
-
- struct ext4_block block;
- rc = ext4_block_get(inode_ref->fs->bdev, &block, block_addr);
- if (rc != EOK)
- return rc;
-
- p++;
-
- /* Don't forget to put old block (prevent memory leak) */
- ext4_block_set(inode_ref->fs->bdev, &p->block);
-
-
-
- memcpy(&p->block, &p->block, sizeof(block));
- p->entries = ((struct ext4_directory_dx_node *) block.data)->entries;
- p->position = p->entries;
- }
-
- return ENOENT;
-}
-
-
-
-int ext4_dir_dx_find_entry(struct ext4_directory_search_result * result,
- struct ext4_inode_ref *inode_ref, size_t name_len, const char *name)
-{
- /* Load direct block 0 (index root) */
- uint32_t root_block_addr;
- int rc = ext4_fs_get_inode_data_block_index(inode_ref, 0,
- &root_block_addr);
- if (rc != EOK)
- return rc;
-
- struct ext4_fs *fs = inode_ref->fs;
-
- struct ext4_block root_block;
- rc = ext4_block_get(fs->bdev, &root_block, root_block_addr);
- if (rc != EOK)
- return rc;
-
- /* Initialize hash info (compute hash value) */
- struct ext4_hash_info hinfo;
- rc = ext4_dir_hinfo_init(&hinfo, &root_block, &fs->sb,
- name_len, name);
- if (rc != EOK) {
- ext4_block_set(fs->bdev, &root_block);
- return EXT4_ERR_BAD_DX_DIR;
- }
-
- /*
- * Hardcoded number 2 means maximum height of index tree,
- * specified in the Linux driver.
- */
- struct ext4_directory_dx_block dx_blocks[2];
- struct ext4_directory_dx_block *dx_block;
- struct ext4_directory_dx_block *tmp;
-
- rc = ext4_dir_dx_get_leaf(&hinfo, inode_ref, &root_block,
- &dx_block, dx_blocks);
- if (rc != EOK) {
- ext4_block_set(fs->bdev, &root_block);
- return EXT4_ERR_BAD_DX_DIR;
- }
-
- do {
- /* Load leaf block */
- uint32_t leaf_block_idx =
- ext4_dir_dx_entry_get_block(dx_block->position);
- uint32_t leaf_block_addr;
-
- rc = ext4_fs_get_inode_data_block_index(inode_ref,
- leaf_block_idx, &leaf_block_addr);
- if (rc != EOK)
- goto cleanup;
-
- struct ext4_block leaf_block;
- rc = ext4_block_get(fs->bdev, &leaf_block, leaf_block_addr);
- if (rc != EOK)
- goto cleanup;
-
- /* Linear search inside block */
- struct ext4_directory_entry_ll *res_dentry;
- rc = ext4_dir_find_in_block(&leaf_block, &fs->sb,
- name_len, name, &res_dentry);
-
- /* Found => return it */
- if (rc == EOK) {
- result->block = leaf_block;
- result->dentry = res_dentry;
- goto cleanup;
- }
-
- /* Not found, leave untouched */
- ext4_block_set(fs->bdev, &leaf_block);
-
- if (rc != ENOENT)
- goto cleanup;
-
- /* check if the next block could be checked */
- rc = ext4_dir_dx_next_block(inode_ref, hinfo.hash,
- dx_block, &dx_blocks[0]);
- if (rc < 0)
- goto cleanup;
- } while (rc == ENOENT);
-
- /* Entry not found */
- rc = ENOENT;
-
- cleanup:
- /* The whole path must be released (preventing memory leak) */
- tmp = dx_blocks;
-
- while (tmp <= dx_block) {
- ext4_block_set(fs->bdev, &tmp->block);
- ++tmp;
- }
-
- return rc;
-}
-
-static int ext4_dir_dx_entry_comparator(const void *arg1, const void *arg2)
-{
- struct ext4_dx_sort_entry *entry1 = (void *)arg1;
- struct ext4_dx_sort_entry *entry2 = (void *)arg2;
-
- if (entry1->hash == entry2->hash)
- return 0;
-
- if (entry1->hash < entry2->hash)
- return -1;
- else
- return 1;
-}
-
-static void ext4_dir_dx_insert_entry(
- struct ext4_directory_dx_block *index_block, uint32_t hash,
- uint32_t iblock)
-{
- struct ext4_directory_dx_entry *old_index_entry = index_block->position;
- struct ext4_directory_dx_entry *new_index_entry = old_index_entry + 1;
-
- struct ext4_directory_dx_countlimit *countlimit =
- (struct ext4_directory_dx_countlimit *) index_block->entries;
- uint32_t count = ext4_dir_dx_countlimit_get_count(countlimit);
-
- struct ext4_directory_dx_entry *start_index = index_block->entries;
- size_t bytes = (void *) (start_index + count) - (void *) (new_index_entry);
-
- memmove(new_index_entry + 1, new_index_entry, bytes);
-
- ext4_dir_dx_entry_set_block(new_index_entry, iblock);
- ext4_dir_dx_entry_set_hash(new_index_entry, hash);
-
- ext4_dir_dx_countlimit_set_count(countlimit, count + 1);
-
- index_block->block.dirty = true;
-}
-
-static int ext4_dir_dx_split_data(struct ext4_inode_ref *inode_ref,
- struct ext4_hash_info *hinfo, struct ext4_block *old_data_block,
- struct ext4_directory_dx_block *index_block,
- struct ext4_block *new_data_block)
-{
- int rc = EOK;
-
- /* Allocate buffer for directory entries */
- uint32_t block_size =
- ext4_sb_get_block_size(&inode_ref->fs->sb);
-
- void *entry_buffer = malloc(block_size);
- if (entry_buffer == NULL)
- return ENOMEM;
-
- /* dot entry has the smallest size available */
- uint32_t max_entry_count =
- block_size / sizeof(struct ext4_directory_dx_dot_entry);
-
- /* Allocate sort entry */
- struct ext4_dx_sort_entry *sort_array =
- malloc(max_entry_count * sizeof(struct ext4_dx_sort_entry));
-
- if (sort_array == NULL) {
- free(entry_buffer);
- return ENOMEM;
- }
-
- uint32_t idx = 0;
- uint32_t real_size = 0;
-
- /* Initialize hinfo */
- struct ext4_hash_info tmp_hinfo;
- memcpy(&tmp_hinfo, hinfo, sizeof(struct ext4_hash_info));
-
- /* Load all valid entries to the buffer */
- struct ext4_directory_entry_ll *dentry = (void *)old_data_block->data;
- void *entry_buffer_ptr = entry_buffer;
- while ((void *)dentry < (void *)(old_data_block->data + block_size)) {
- /* Read only valid entries */
- if (ext4_dir_entry_ll_get_inode(dentry) != 0) {
- uint8_t len = ext4_dir_entry_ll_get_name_length(
- &inode_ref->fs->sb, dentry);
-
- rc = ext4_dir_dx_hash_string(&tmp_hinfo, len, (char*)dentry->name);
- if(rc != EOK) {
- free(sort_array);
- free(entry_buffer);
- return rc;
- }
-
- uint32_t rec_len = 8 + len;
-
- if ((rec_len % 4) != 0)
- rec_len += 4 - (rec_len % 4);
-
- memcpy(entry_buffer_ptr, dentry, rec_len);
-
- sort_array[idx].dentry = entry_buffer_ptr;
- sort_array[idx].rec_len = rec_len;
- sort_array[idx].hash = tmp_hinfo.hash;
-
- entry_buffer_ptr += rec_len;
- real_size += rec_len;
- idx++;
- }
-
- dentry = (void *) dentry +
- ext4_dir_entry_ll_get_entry_length(dentry);
- }
-
- /* Sort all entries */
- qsort(sort_array, idx, sizeof(struct ext4_dx_sort_entry),
- ext4_dir_dx_entry_comparator);
-
- /* Allocate new block for store the second part of entries */
- uint32_t new_fblock;
- uint32_t new_iblock;
- rc = ext4_fs_append_inode_block(inode_ref, &new_fblock,
- &new_iblock);
- if (rc != EOK) {
- free(sort_array);
- free(entry_buffer);
- return rc;
- }
-
- /* Load new block */
- struct ext4_block new_data_block_tmp;
- rc = ext4_block_get(inode_ref->fs->bdev, &new_data_block_tmp,
- new_fblock);
- if (rc != EOK) {
- free(sort_array);
- free(entry_buffer);
- return rc;
- }
-
- /*
- * Distribute entries to two blocks (by size)
- * - compute the half
- */
- uint32_t new_hash = 0;
- uint32_t current_size = 0;
- uint32_t mid = 0;
- uint32_t i;
- for ( i = 0; i < idx; ++i) {
- if ((current_size + sort_array[i].rec_len) > (real_size / 2)) {
- new_hash = sort_array[i].hash;
- mid = i;
- break;
- }
-
- current_size += sort_array[i].rec_len;
- }
-
- /* Check hash collision */
- uint32_t continued = 0;
- if (new_hash == sort_array[mid-1].hash)
- continued = 1;
-
- uint32_t offset = 0;
- void *ptr;
-
- /* First part - to the old block */
- for (i = 0; i < mid; ++i) {
- ptr = old_data_block->data + offset;
- memcpy(ptr, sort_array[i].dentry, sort_array[i].rec_len);
-
- struct ext4_directory_entry_ll *tmp = ptr;
- if (i < (mid - 1))
- ext4_dir_entry_ll_set_entry_length(tmp,
- sort_array[i].rec_len);
- else
- ext4_dir_entry_ll_set_entry_length(tmp,
- block_size - offset);
-
- offset += sort_array[i].rec_len;
- }
-
- /* Second part - to the new block */
- offset = 0;
- for (i = mid; i < idx; ++i) {
- ptr = new_data_block_tmp.data + offset;
- memcpy(ptr, sort_array[i].dentry, sort_array[i].rec_len);
-
- struct ext4_directory_entry_ll *tmp = ptr;
- if (i < (idx - 1))
- ext4_dir_entry_ll_set_entry_length(tmp,
- sort_array[i].rec_len);
- else
- ext4_dir_entry_ll_set_entry_length(tmp,
- block_size - offset);
-
- offset += sort_array[i].rec_len;
- }
-
- /* Do some steps to finish operation */
- old_data_block->dirty = true;
- new_data_block_tmp.dirty = true;
-
- free(sort_array);
- free(entry_buffer);
-
- ext4_dir_dx_insert_entry(index_block, new_hash + continued,
- new_iblock);
-
- *new_data_block = new_data_block_tmp;
-
- return EOK;
-}
-
-/** Split index node and maybe some parent nodes in the tree hierarchy.
- *
- * @param inode_ref Directory i-node
- * @param dx_blocks Array with path from root to leaf node
- * @param dx_block Leaf block to be split if needed
- *
- * @return Error code
- *
- */
-static int ext4_dir_dx_split_index(struct ext4_inode_ref *inode_ref,
- struct ext4_directory_dx_block *dx_blocks,
- struct ext4_directory_dx_block *dx_block)
-{
- struct ext4_directory_dx_entry *entries;
- if (dx_block == dx_blocks)
- entries =
- ((struct ext4_directory_dx_root *) dx_block->block.data)->entries;
- else
- entries =
- ((struct ext4_directory_dx_node *) dx_block->block.data)->entries;
-
- struct ext4_directory_dx_countlimit *countlimit =
- (struct ext4_directory_dx_countlimit *) entries;
-
- uint16_t leaf_limit =
- ext4_dir_dx_countlimit_get_limit(countlimit);
- uint16_t leaf_count =
- ext4_dir_dx_countlimit_get_count(countlimit);
-
- /* Check if is necessary to split index block */
- if (leaf_limit == leaf_count) {
- size_t levels = dx_block - dx_blocks;
-
- struct ext4_directory_dx_entry *root_entries =
- ((struct ext4_directory_dx_root *) dx_blocks[0].block.data)->entries;
-
- struct ext4_directory_dx_countlimit *root_countlimit =
- (struct ext4_directory_dx_countlimit *) root_entries;
- uint16_t root_limit =
- ext4_dir_dx_countlimit_get_limit(root_countlimit);
- uint16_t root_count =
- ext4_dir_dx_countlimit_get_count(root_countlimit);
-
- /* Linux limitation */
- if ((levels > 0) && (root_limit == root_count))
- return ENOSPC;
-
- /* Add new block to directory */
- uint32_t new_fblock;
- uint32_t new_iblock;
- int rc = ext4_fs_append_inode_block(inode_ref,
- &new_fblock, &new_iblock);
- if (rc != EOK)
- return rc;
-
- /* load new block */
- struct ext4_block new_block;
- rc = ext4_block_get(inode_ref->fs->bdev, &new_block,
- new_fblock);
- if (rc != EOK)
- return rc;
-
- struct ext4_directory_dx_node *new_node = (void *)new_block.data;
- struct ext4_directory_dx_entry *new_entries = new_node->entries;
-
- uint32_t block_size =
- ext4_sb_get_block_size(&inode_ref->fs->sb);
-
- /* Split leaf node */
- if (levels > 0) {
- uint32_t count_left = leaf_count / 2;
- uint32_t count_right = leaf_count - count_left;
- uint32_t hash_right =
- ext4_dir_dx_entry_get_hash(entries + count_left);
-
- /* Copy data to new node */
- memcpy((void *) new_entries, (void *) (entries + count_left),
- count_right * sizeof(struct ext4_directory_dx_entry));
-
- /* Initialize new node */
- struct ext4_directory_dx_countlimit *left_countlimit =
- (struct ext4_directory_dx_countlimit *) entries;
- struct ext4_directory_dx_countlimit *right_countlimit =
- (struct ext4_directory_dx_countlimit *) new_entries;
-
- ext4_dir_dx_countlimit_set_count(left_countlimit, count_left);
- ext4_dir_dx_countlimit_set_count(right_countlimit, count_right);
-
- uint32_t entry_space =
- block_size - sizeof(struct ext4_fake_directory_entry);
- uint32_t node_limit =
- entry_space / sizeof(struct ext4_directory_dx_entry);
- ext4_dir_dx_countlimit_set_limit(right_countlimit, node_limit);
-
- /* Which index block is target for new entry */
- uint32_t position_index = (dx_block->position - dx_block->entries);
- if (position_index >= count_left) {
- dx_block->block.dirty = true;
-
- struct ext4_block block_tmp = dx_block->block;
-
-
- dx_block->block = new_block;
-
- dx_block->position =
- new_entries + position_index - count_left;
- dx_block->entries = new_entries;
-
- new_block = block_tmp;
- }
-
- /* Finally insert new entry */
- ext4_dir_dx_insert_entry(dx_blocks, hash_right, new_iblock);
-
- return ext4_block_set(inode_ref->fs->bdev, &new_block);
- } else {
- /* Create second level index */
-
- /* Copy data from root to child block */
- memcpy((void *) new_entries, (void *) entries,
- leaf_count * sizeof(struct ext4_directory_dx_entry));
-
- struct ext4_directory_dx_countlimit *new_countlimit =
- (struct ext4_directory_dx_countlimit *) new_entries;
-
- uint32_t entry_space =
- block_size - sizeof(struct ext4_fake_directory_entry);
- uint32_t node_limit =
- entry_space / sizeof(struct ext4_directory_dx_entry);
- ext4_dir_dx_countlimit_set_limit(new_countlimit, node_limit);
-
- /* Set values in root node */
- struct ext4_directory_dx_countlimit *new_root_countlimit =
- (struct ext4_directory_dx_countlimit *) entries;
-
- ext4_dir_dx_countlimit_set_count(new_root_countlimit, 1);
- ext4_dir_dx_entry_set_block(entries, new_iblock);
-
- ((struct ext4_directory_dx_root *)
- dx_blocks[0].block.data)->info.indirect_levels = 1;
-
- /* Add new entry to the path */
- dx_block = dx_blocks + 1;
- dx_block->position = dx_block->position - entries + new_entries;
- dx_block->entries = new_entries;
- dx_block->block = new_block;
- }
- }
-
- return EOK;
-}
-
-int ext4_dir_dx_add_entry(struct ext4_inode_ref *parent,
- struct ext4_inode_ref *child, const char *name)
-{
- int rc2 = EOK;
-
- /* Get direct block 0 (index root) */
- uint32_t root_block_addr;
- int rc = ext4_fs_get_inode_data_block_index(parent, 0,
- &root_block_addr);
- if (rc != EOK)
- return rc;
-
- struct ext4_fs *fs = parent->fs;
- struct ext4_block root_block;
-
- rc = ext4_block_get(fs->bdev, &root_block, root_block_addr);
- if (rc != EOK)
- return rc;
-
- /* Initialize hinfo structure (mainly compute hash) */
- uint32_t name_len = strlen(name);
- struct ext4_hash_info hinfo;
- rc = ext4_dir_hinfo_init(&hinfo, &root_block, &fs->sb,
- name_len, name);
- if (rc != EOK) {
- ext4_block_set(fs->bdev, &root_block);
- return EXT4_ERR_BAD_DX_DIR;
- }
-
- /*
- * Hardcoded number 2 means maximum height of index
- * tree defined in Linux.
- */
- struct ext4_directory_dx_block dx_blocks[2];
- struct ext4_directory_dx_block *dx_block;
- struct ext4_directory_dx_block *dx_it;
-
- rc = ext4_dir_dx_get_leaf(&hinfo, parent, &root_block,
- &dx_block, dx_blocks);
- if (rc != EOK) {
- rc = EXT4_ERR_BAD_DX_DIR;
- goto release_index;
- }
-
- /* Try to insert to existing data block */
- uint32_t leaf_block_idx =
- ext4_dir_dx_entry_get_block(dx_block->position);
- uint32_t leaf_block_addr;
- rc = ext4_fs_get_inode_data_block_index(parent, leaf_block_idx,
- &leaf_block_addr);
- if (rc != EOK)
- goto release_index;
-
- struct ext4_block target_block;
- rc = ext4_block_get(fs->bdev, &target_block, leaf_block_addr);
- if (rc != EOK)
- goto release_index;
-
- /* Check if insert operation passed */
- rc = ext4_dir_try_insert_entry(&fs->sb, &target_block, child,
- name, name_len);
- if (rc == EOK)
- goto release_target_index;
-
- /*
- * Check if there is needed to split index node
- * (and recursively also parent nodes)
- */
- rc = ext4_dir_dx_split_index(parent, dx_blocks, dx_block);
- if (rc != EOK)
- goto release_target_index;
-
- /* Split entries to two blocks (includes sorting by hash value) */
- struct ext4_block new_block;
- rc = ext4_dir_dx_split_data(parent, &hinfo, &target_block,
- dx_block, &new_block);
- if (rc != EOK) {
- rc2 = rc;
- goto release_target_index;
- }
-
- /* Where to save new entry */
- uint32_t new_block_hash =
- ext4_dir_dx_entry_get_hash(dx_block->position + 1);
- if (hinfo.hash >= new_block_hash)
- rc = ext4_dir_try_insert_entry(&fs->sb, &new_block,
- child, name, name_len);
- else
- rc = ext4_dir_try_insert_entry(&fs->sb, &target_block,
- child, name, name_len);
-
- /* Cleanup */
- rc = ext4_block_set(fs->bdev, &new_block);
- if (rc != EOK)
- return rc;
-
- /* Cleanup operations */
-
- release_target_index:
- rc2 = rc;
-
- rc = ext4_block_set(fs->bdev, &target_block);
- if (rc != EOK)
- return rc;
-
- release_index:
- if (rc != EOK)
- rc2 = rc;
-
- dx_it = dx_blocks;
-
- while (dx_it <= dx_block) {
- rc = ext4_block_set(fs->bdev, &dx_it->block);
- if (rc != EOK)
- return rc;
-
- dx_it++;
- }
-
- return rc2;
-}
-
-/**
- * @}
- */
-
--- a/src/lwext4/ext4_dir_idx.h
+++ /dev/null
@@ -1,103 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_dir_idx.h
- * @brief Directory indexing procedures.
- */
-
-#ifndef EXT4_DIR_IDX_H_
-#define EXT4_DIR_IDX_H_
-
-#include <ext4_config.h>
-#include <ext4_types.h>
-
-#include <stdint.h>
-#include <stdbool.h>
-
-uint8_t ext4_dir_dx_root_info_get_hash_version(
- struct ext4_directory_dx_root_info *root_info);
-void ext4_dir_dx_root_info_set_hash_version(
- struct ext4_directory_dx_root_info *root_info, uint8_t v);
-
-uint8_t ext4_dir_dx_root_info_get_info_length(
- struct ext4_directory_dx_root_info *root_info);
-void ext4_dir_dx_root_info_set_info_length(
- struct ext4_directory_dx_root_info *root_info, uint8_t len);
-
-uint8_t ext4_dir_dx_root_info_get_indirect_levels(
- struct ext4_directory_dx_root_info *root_info);
-void ext4_dir_dx_root_info_set_indirect_levels(
- struct ext4_directory_dx_root_info *root_info, uint8_t lvl);
-
-
-
-uint16_t ext4_dir_dx_countlimit_get_limit(
- struct ext4_directory_dx_countlimit *climit);
-void ext4_dir_dx_countlimit_set_limit(
- struct ext4_directory_dx_countlimit *climit, uint16_t limit);
-
-uint16_t ext4_dir_dx_countlimit_get_count(
- struct ext4_directory_dx_countlimit *climit);
-void ext4_dir_dx_countlimit_set_count(
- struct ext4_directory_dx_countlimit *climit, uint16_t count);
-
-
-uint32_t ext4_dir_dx_entry_get_hash(
- struct ext4_directory_dx_entry *entry);
-void ext4_dir_dx_entry_set_hash(
- struct ext4_directory_dx_entry *entry, uint32_t hash);
-
-uint32_t ext4_dir_dx_entry_get_block(
- struct ext4_directory_dx_entry *entry);
-void ext4_dir_dx_entry_set_block(
- struct ext4_directory_dx_entry *entry, uint32_t block);
-
-
-int ext4_dir_dx_init(struct ext4_inode_ref *dir);
-
-int ext4_dir_dx_find_entry(struct ext4_directory_search_result * result,
- struct ext4_inode_ref *inode_ref, size_t name_len, const char *name);
-
-int ext4_dir_dx_add_entry(struct ext4_inode_ref *parent,
- struct ext4_inode_ref *child, const char *name);
-
-#endif /* EXT4_DIR_IDX_H_ */
-
-/**
- * @}
- */
-
--- a/src/lwext4/ext4_errno.h
+++ /dev/null
@@ -1,92 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_errno.h
- * @brief Error codes.
- */
-#ifndef EXT4_ERRNO_H_
-#define EXT4_ERRNO_H_
-
-#include <ext4_config.h>
-
-#ifndef CONFIG_HAVE_OWN_ERRNO
-#include <errno.h>
-#else
-#define EPERM 1 /* Operation not permitted */
-#define ENOENT 2 /* No such file or directory */
-#define ESRCH 3 /* No such process */
-#define EINTR 4 /* Interrupted system call */
-#define EIO 5 /* I/O error */
-#define ENXIO 6 /* No such device or address */
-#define E2BIG 7 /* Argument list too long */
-#define ENOEXEC 8 /* Exec format error */
-#define EBADF 9 /* Bad file number */
-#define ECHILD 10 /* No child processes */
-#define EAGAIN 11 /* Try again */
-#define ENOMEM 12 /* Out of memory */
-#define EACCES 13 /* Permission denied */
-#define EFAULT 14 /* Bad address */
-#define ENOTBLK 15 /* Block device required */
-#define EBUSY 16 /* Device or resource busy */
-#define EEXIST 17 /* File exists */
-#define EXDEV 18 /* Cross-device link */
-#define ENODEV 19 /* No such device */
-#define ENOTDIR 20 /* Not a directory */
-#define EISDIR 21 /* Is a directory */
-#define EINVAL 22 /* Invalid argument */
-#define ENFILE 23 /* File table overflow */
-#define EMFILE 24 /* Too many open files */
-#define ENOTTY 25 /* Not a typewriter */
-#define ETXTBSY 26 /* Text file busy */
-#define EFBIG 27 /* File too large */
-#define ENOSPC 28 /* No space left on device */
-#define ESPIPE 29 /* Illegal seek */
-#define EROFS 30 /* Read-only file system */
-#define EMLINK 31 /* Too many links */
-#define EPIPE 32 /* Broken pipe */
-#define EDOM 33 /* Math argument out of domain of func */
-#define ERANGE 34 /* Math result not representable */
-
-#define ENOTSUP 95
-#endif
-
-/**@brief OK return value*/
-#ifndef EOK
-#define EOK 0
-#endif
-
-#endif /* EXT4_ERRNO_H_ */
-
-/**
- * @}
- */
-
--- a/src/lwext4/ext4_fs.c
+++ /dev/null
@@ -1,1189 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_fs.c
- * @brief More complex filesystem functions.
- */
-
-#include <ext4_config.h>
-#include <ext4_types.h>
-#include <ext4_fs.h>
-#include <ext4_errno.h>
-#include <ext4_blockdev.h>
-#include <ext4_super.h>
-#include <ext4_debug.h>
-#include <ext4_block_group.h>
-#include <ext4_balloc.h>
-#include <ext4_bitmap.h>
-#include <ext4_inode.h>
-#include <ext4_ialloc.h>
-#include <string.h>
-
-int ext4_fs_init(struct ext4_fs *fs, struct ext4_blockdev *bdev)
-{
- int r, i;
- uint16_t tmp;
- uint32_t bsize;
- bool read_only = false;
-
- ext4_assert(fs && bdev);
-
- fs->bdev = bdev;
-
- r = ext4_sb_read(fs->bdev, &fs->sb);
- if(r != EOK)
- return r;
-
- if(!ext4_sb_check(&fs->sb))
- return ENOTSUP;
-
- bsize = ext4_sb_get_block_size(&fs->sb);
- if (bsize > EXT4_MAX_BLOCK_SIZE)
- return ENXIO;
-
- r = ext4_fs_check_features(fs, &read_only);
- if(r != EOK)
- return r;
-
- if(read_only)
- return ENOTSUP;
-
- /* Compute limits for indirect block levels */
- uint32_t blocks_id = bsize / sizeof(uint32_t);
-
- fs->inode_block_limits[0] = EXT4_INODE_DIRECT_BLOCK_COUNT;
- fs->inode_blocks_per_level[0] = 1;
-
- for (i = 1; i < 4; i++) {
- fs->inode_blocks_per_level[i] = fs->inode_blocks_per_level[i - 1] *
- blocks_id;
- fs->inode_block_limits[i] = fs->inode_block_limits[i - 1] +
- fs->inode_blocks_per_level[i];
- }
-
- /*Validate FS*/
- tmp = ext4_get16(&fs->sb, state);
- if (tmp & EXT4_SUPERBLOCK_STATE_ERROR_FS) {
- ext4_dprintf(EXT4_DEBUG_FS,
- "Filesystem was not cleanly unmounted before \n");
- }
-
- /* Mark system as mounted */
- ext4_set16(&fs->sb, state, EXT4_SUPERBLOCK_STATE_ERROR_FS);
- r = ext4_sb_write(fs->bdev, &fs->sb);
- if (r != EOK)
- return r;
-
-
- /*Update mount count*/
- ext4_set16(&fs->sb, mount_count, ext4_get16(&fs->sb, mount_count) + 1);
-
- return r;
-}
-
-
-int ext4_fs_fini(struct ext4_fs *fs)
-{
- ext4_assert(fs);
-
- /*Set superblock state*/
- ext4_set16(&fs->sb, state, EXT4_SUPERBLOCK_STATE_VALID_FS);
-
- return ext4_sb_write(fs->bdev, &fs->sb);
-}
-
-int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only)
-{
- ext4_assert(fs && read_only);
-
- if(ext4_get32(&fs->sb, rev_level) == 0){
- *read_only = false;
- return EOK;
- }
-
- /*Check features_incompatible*/
- if ((ext4_get32(&fs->sb, features_incompatible) &
- (~EXT4_FEATURE_INCOMPAT_SUPP)) )
- return ENOTSUP;
-
-
- /*Check features_read_only*/
- if ((ext4_get32(&fs->sb, features_read_only) &
- (~EXT4_FEATURE_RO_COMPAT_SUPP))){
- *read_only = true;
- return EOK;
- }
-
- *read_only = false;
-
- return EOK;
-}
-
-uint32_t ext4_fs_baddr2_index_in_group(struct ext4_sblock *s, uint32_t baddr)
-{
- ext4_assert(baddr);
- if(ext4_get32(s, first_data_block))
- baddr--;
-
- return baddr % ext4_get32(s, blocks_per_group);
-}
-
-
-
-uint32_t ext4_fs_index_in_group2_baddr(struct ext4_sblock *s, uint32_t index,
- uint32_t bgid)
-{
- if(ext4_get32(s, first_data_block))
- index++;
-
- return ext4_get32(s, blocks_per_group) * bgid + index;
-}
-
-
-
-
-static int ext4_fs_init_block_bitmap(struct ext4_block_group_ref *bg_ref)
-{
- uint32_t i;
- uint32_t bitmap_block_addr = ext4_bg_get_block_bitmap(
- bg_ref->block_group, &bg_ref->fs->sb);
-
- struct ext4_block block_bitmap;
- int rc = ext4_block_get(bg_ref->fs->bdev, &block_bitmap,
- bitmap_block_addr);
- if (rc != EOK)
- return rc;
-
-
- memset(block_bitmap.data, 0, ext4_sb_get_block_size(&bg_ref->fs->sb));
-
- /* Determine first block and first data block in group */
- uint32_t first_idx = 0;
-
- uint32_t first_data = ext4_balloc_get_first_data_block_in_group(
- &bg_ref->fs->sb, bg_ref);
- uint32_t first_data_idx = ext4_fs_baddr2_index_in_group(
- &bg_ref->fs->sb, first_data);
-
- /*Set bits from to first block to first data block - 1 to one (allocated)*/
- /*TODO: Optimize it*/
- for (i = first_idx; i < first_data_idx; ++i)
- ext4_bmap_bit_set(block_bitmap.data, i);
-
-
- block_bitmap.dirty = true;
-
- /* Save bitmap */
- return ext4_block_set(bg_ref->fs->bdev, &block_bitmap);
-}
-
-static int ext4_fs_init_inode_bitmap(struct ext4_block_group_ref *bg_ref)
-{
- /* Load bitmap */
- uint32_t bitmap_block_addr = ext4_bg_get_inode_bitmap(
- bg_ref->block_group, &bg_ref->fs->sb);
-
- struct ext4_block block_bitmap;
- int rc = ext4_block_get(bg_ref->fs->bdev, &block_bitmap,
- bitmap_block_addr);
- if (rc != EOK)
- return rc;
-
- /* Initialize all bitmap bits to zero */
- uint32_t block_size = ext4_sb_get_block_size(&bg_ref->fs->sb);
- uint32_t inodes_per_group = ext4_get32(&bg_ref->fs->sb, inodes_per_group);
-
- memset(block_bitmap.data, 0, (inodes_per_group + 7) / 8);
-
- uint32_t start_bit = inodes_per_group;
- uint32_t end_bit = block_size * 8;
-
- uint32_t i;
- for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++)
- ext4_bmap_bit_set(block_bitmap.data, i);
-
- if (i < end_bit)
- memset(block_bitmap.data + (i >> 3), 0xff, (end_bit - i) >> 3);
-
- block_bitmap.dirty = true;
-
- /* Save bitmap */
- return ext4_block_set(bg_ref->fs->bdev, &block_bitmap);
-}
-
-static int ext4_fs_init_inode_table(struct ext4_block_group_ref *bg_ref)
-{
- struct ext4_sblock *sb = &bg_ref->fs->sb;
-
- uint32_t inode_size = ext4_get32(sb, inode_size);
- uint32_t block_size = ext4_sb_get_block_size(sb);
- uint32_t inodes_per_block = block_size / inode_size;
- uint32_t inodes_in_group = ext4_inodes_in_group_cnt(sb, bg_ref->index);
- uint32_t table_blocks = inodes_in_group / inodes_per_block;
- uint32_t fblock;
-
- if (inodes_in_group % inodes_per_block)
- table_blocks++;
-
- /* Compute initialization bounds */
- uint32_t first_block = ext4_bg_get_inode_table_first_block(
- bg_ref->block_group, sb);
-
- uint32_t last_block = first_block + table_blocks - 1;
-
- /* Initialization of all itable blocks */
- for (fblock = first_block; fblock <= last_block; ++fblock) {
-
- struct ext4_block block;
- int rc = ext4_block_get(bg_ref->fs->bdev, &block, fblock);
- if (rc != EOK)
- return rc;
-
- memset(block.data, 0, block_size);
- block.dirty = true;
-
- ext4_block_set(bg_ref->fs->bdev, &block);
- if (rc != EOK)
- return rc;
- }
-
- return EOK;
-}
-
-
-int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid,
- struct ext4_block_group_ref *ref)
-{
- /* Compute number of descriptors, that fits in one data block */
- uint32_t dsc_per_block = ext4_sb_get_block_size(&fs->sb) /
- ext4_sb_get_desc_size(&fs->sb);
-
- /* Block group descriptor table starts at the next block after superblock */
- uint64_t block_id = ext4_get32(&fs->sb, first_data_block) + 1;
-
- /* Find the block containing the descriptor we are looking for */
- block_id += bgid / dsc_per_block;
- uint32_t offset = (bgid % dsc_per_block) *
- ext4_sb_get_desc_size(&fs->sb);
-
-
- int rc = ext4_block_get(fs->bdev, &ref->block, block_id);
- if (rc != EOK)
- return rc;
-
- ref->block_group = (void *)(ref->block.data + offset);
- ref->fs = fs;
- ref->index = bgid;
- ref->dirty = false;
-
- if (ext4_bg_has_flag(ref->block_group,
- EXT4_BLOCK_GROUP_BLOCK_UNINIT)) {
- rc = ext4_fs_init_block_bitmap(ref);
- if (rc != EOK) {
- ext4_block_set(fs->bdev, &ref->block);
- return rc;
- }
- ext4_bg_clear_flag(ref->block_group,
- EXT4_BLOCK_GROUP_BLOCK_UNINIT);
-
- ref->dirty = true;
- }
-
- if (ext4_bg_has_flag(ref->block_group,
- EXT4_BLOCK_GROUP_INODE_UNINIT)) {
- rc = ext4_fs_init_inode_bitmap(ref);
- if (rc != EOK) {
- ext4_block_set(ref->fs->bdev, &ref->block);
- return rc;
- }
-
- ext4_bg_clear_flag(ref->block_group,
- EXT4_BLOCK_GROUP_INODE_UNINIT);
-
- if (!ext4_bg_has_flag(ref->block_group,
- EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
- rc = ext4_fs_init_inode_table(ref);
- if (rc != EOK){
- ext4_block_set(fs->bdev, &ref->block);
- return rc;
- }
-
- ext4_bg_set_flag(ref->block_group,
- EXT4_BLOCK_GROUP_ITABLE_ZEROED);
- }
-
- ref->dirty = true;
- }
-
- return EOK;
-}
-
-static uint16_t ext4_fs_bg_checksum(struct ext4_sblock *sb, uint32_t bgid,
- struct ext4_bgroup *bg)
-{
- /* If checksum not supported, 0 will be returned */
- uint16_t crc = 0;
-
- /* Compute the checksum only if the filesystem supports it */
- if (ext4_sb_check_read_only(sb,
- EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
- void *base = bg;
- void *checksum = &bg->checksum;
-
- uint32_t offset = (uint32_t) (checksum - base);
-
- /* Convert block group index to little endian */
- uint32_t le_group = to_le32(bgid);
-
- /* Initialization */
- crc = ext4_bg_crc16(~0, sb->uuid, sizeof(sb->uuid));
-
- /* Include index of block group */
- crc = ext4_bg_crc16(crc, (uint8_t *) &le_group, sizeof(le_group));
-
- /* Compute crc from the first part (stop before checksum field) */
- crc = ext4_bg_crc16(crc, (uint8_t *) bg, offset);
-
- /* Skip checksum */
- offset += sizeof(bg->checksum);
-
- /* Checksum of the rest of block group descriptor */
- if ((ext4_sb_check_feature_incompatible(sb,
- EXT4_FEATURE_INCOMPAT_64BIT)) &&
- (offset < ext4_sb_get_desc_size(sb)))
-
- crc = ext4_bg_crc16(crc, ((uint8_t *) bg) + offset,
- ext4_sb_get_desc_size(sb) - offset);
- }
- return crc;
-}
-
-int ext4_fs_put_block_group_ref(struct ext4_block_group_ref *ref)
-{
- /* Check if reference modified */
- if (ref->dirty) {
- /* Compute new checksum of block group */
- uint16_t checksum =
- ext4_fs_bg_checksum(&ref->fs->sb, ref->index,
- ref->block_group);
-
- ref->block_group->checksum = to_le16(checksum);
-
- /* Mark block dirty for writing changes to physical device */
- ref->block.dirty = true;
- }
-
- /* Put back block, that contains block group descriptor */
- return ext4_block_set(ref->fs->bdev, &ref->block);
-}
-
-int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index,
- struct ext4_inode_ref *ref)
-{
- /* Compute number of i-nodes, that fits in one data block */
- uint32_t inodes_per_group = ext4_get32(&fs->sb, inodes_per_group);
-
- /*
- * Inode numbers are 1-based, but it is simpler to work with 0-based
- * when computing indices
- */
- index -= 1;
- uint32_t block_group = index / inodes_per_group;
- uint32_t offset_in_group = index % inodes_per_group;
-
- /* Load block group, where i-node is located */
- struct ext4_block_group_ref bg_ref;
-
- int rc = ext4_fs_get_block_group_ref(fs, block_group, &bg_ref);
- if (rc != EOK) {
- return rc;
- }
-
- /* Load block address, where i-node table is located */
- uint32_t inode_table_start =
- ext4_bg_get_inode_table_first_block(bg_ref.block_group,
- &fs->sb);
-
- /* Put back block group reference (not needed more) */
- rc = ext4_fs_put_block_group_ref(&bg_ref);
- if (rc != EOK) {
- return rc;
- }
-
- /* Compute position of i-node in the block group */
- uint16_t inode_size = ext4_get16(&fs->sb, inode_size);
- uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
- uint32_t byte_offset_in_group = offset_in_group * inode_size;
-
- /* Compute block address */
- uint64_t block_id = inode_table_start +
- (byte_offset_in_group / block_size);
-
-
- rc = ext4_block_get(fs->bdev, &ref->block, block_id);
- if (rc != EOK) {
- return rc;
- }
-
- /* Compute position of i-node in the data block */
- uint32_t offset_in_block = byte_offset_in_group % block_size;
- ref->inode = (struct ext4_inode *)(ref->block.data + offset_in_block);
-
- /* We need to store the original value of index in the reference */
- ref->index = index + 1;
- ref->fs = fs;
- ref->dirty = false;
-
- return EOK;
-}
-
-int ext4_fs_put_inode_ref(struct ext4_inode_ref *ref)
-{
- /* Check if reference modified */
- if (ref->dirty) {
- /* Mark block dirty for writing changes to physical device */
- ref->block.dirty = true;
- }
-
- /* Put back block, that contains i-node */
- return ext4_block_set(ref->fs->bdev, &ref->block);
-}
-
-int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
- bool is_directory)
-{
- /* Check if newly allocated i-node will be a directory */
- uint32_t i;
- bool is_dir;
-
- is_dir = is_directory;
-
- /* Allocate inode by allocation algorithm */
- uint32_t index;
- int rc = ext4_ialloc_alloc_inode(fs, &index, is_dir);
- if (rc != EOK)
- return rc;
-
- /* Load i-node from on-disk i-node table */
- rc = ext4_fs_get_inode_ref(fs, index, inode_ref);
- if (rc != EOK) {
- ext4_ialloc_free_inode(fs, index, is_dir);
- return rc;
- }
-
- /* Initialize i-node */
- struct ext4_inode *inode = inode_ref->inode;
-
- uint16_t mode;
- if (is_dir) {
- /*
- * Default directory permissions to be compatible with other systems
- * 0777 (octal) == rwxrwxrwx
- */
-
- mode = 0777;
- mode |= EXT4_INODE_MODE_DIRECTORY;
- ext4_inode_set_mode(&fs->sb, inode, mode);
- ext4_inode_set_links_count(inode, 1); /* '.' entry */
-
- } else {
- /*
- * Default file permissions to be compatible with other systems
- * 0666 (octal) == rw-rw-rw-
- */
-
- mode = 0666;
- mode |= EXT4_INODE_MODE_FILE;
- ext4_inode_set_mode(&fs->sb, inode, mode);
- ext4_inode_set_links_count(inode, 0);
- }
-
- ext4_inode_set_uid(inode, 0);
- ext4_inode_set_gid(inode, 0);
- ext4_inode_set_size(inode, 0);
- ext4_inode_set_access_time(inode, 0);
- ext4_inode_set_change_inode_time(inode, 0);
- ext4_inode_set_modification_time(inode, 0);
- ext4_inode_set_deletion_time(inode, 0);
- ext4_inode_set_blocks_count(&fs->sb, inode, 0);
- ext4_inode_set_flags(inode, 0);
- ext4_inode_set_generation(inode, 0);
-
- /* Reset blocks array */
- for (i = 0; i < EXT4_INODE_BLOCKS; i++)
- inode->blocks[i] = 0;
-
-#if 0
- /* Initialize extents if needed */
- if (ext4_sb_check_feature_incompatible(
- &fs->sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
- ext4_inode_set_flag(inode, EXT4_INODE_FLAG_EXTENTS);
-
-
- /* Initialize extent root header */
- ext4_extent_header_t *header = ext4_inode_get_extent_header(inode);
- ext4_extent_header_set_depth(header, 0);
- ext4_extent_header_set_entries_count(header, 0);
- ext4_extent_header_set_generation(header, 0);
- ext4_extent_header_set_magic(header, EXT4_EXTENT_MAGIC);
-
- uint16_t max_entries = (EXT4_INODE_BLOCKS * sizeof(uint32_t) -
- sizeof(ext4_extent_header_t)) / sizeof(ext4_extent_t);
-
- ext4_extent_header_set_max_entries_count(header, max_entries);
- }
-#endif
-
- inode_ref->dirty = true;
-
- return EOK;
-}
-
-int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref)
-{
- struct ext4_fs *fs = inode_ref->fs;
- uint32_t offset;
- uint32_t suboffset;
- /* For extents must be data block destroyed by other way */
- if ((ext4_sb_check_feature_incompatible(&fs->sb,
- EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
- (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))){
- /* Data structures are released during truncate operation... */
- goto finish;
- }
-
- /* Release all indirect (no data) blocks */
-
- /* 1) Single indirect */
- uint32_t fblock = ext4_inode_get_indirect_block(inode_ref->inode, 0);
- if (fblock != 0) {
- int rc = ext4_balloc_free_block(inode_ref, fblock);
- if (rc != EOK)
- return rc;
-
- ext4_inode_set_indirect_block(inode_ref->inode, 0, 0);
- }
-
- uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
- uint32_t count = block_size / sizeof(uint32_t);
-
- struct ext4_block block;
-
- /* 2) Double indirect */
- fblock = ext4_inode_get_indirect_block(inode_ref->inode, 1);
- if (fblock != 0) {
- int rc = ext4_block_get(fs->bdev, &block, fblock);
- if (rc != EOK)
- return rc;
-
- uint32_t ind_block;
- for (offset = 0; offset < count; ++offset) {
- ind_block = to_le32(((uint32_t *) block.data)[offset]);
-
- if (ind_block != 0) {
- rc = ext4_balloc_free_block(inode_ref, ind_block);
- if (rc != EOK) {
- ext4_block_set(fs->bdev, &block);
- return rc;
- }
- }
- }
-
- ext4_block_set(fs->bdev, &block);
- rc = ext4_balloc_free_block(inode_ref, fblock);
- if (rc != EOK)
- return rc;
-
- ext4_inode_set_indirect_block(inode_ref->inode, 1, 0);
- }
-
- /* 3) Tripple indirect */
- struct ext4_block subblock;
- fblock = ext4_inode_get_indirect_block(inode_ref->inode, 2);
- if (fblock != 0) {
- int rc = ext4_block_get(fs->bdev, &block, fblock);
- if (rc != EOK)
- return rc;
-
- uint32_t ind_block;
- for ( offset = 0; offset < count; ++offset) {
- ind_block = to_le32(((uint32_t *) block.data)[offset]);
-
- if (ind_block != 0) {
- rc = ext4_block_get(fs->bdev, &subblock, ind_block);
- if (rc != EOK) {
- ext4_block_set(fs->bdev, &block);
- return rc;
- }
-
- uint32_t ind_subblock;
- for (suboffset = 0; suboffset < count;
- ++suboffset) {
- ind_subblock = to_le32(((uint32_t *)
- subblock.data)[suboffset]);
-
- if (ind_subblock != 0) {
- rc = ext4_balloc_free_block(inode_ref, ind_subblock);
- if (rc != EOK) {
- ext4_block_set(fs->bdev, &subblock);
- ext4_block_set(fs->bdev, &block);
- return rc;
- }
- }
- }
-
- ext4_block_set(fs->bdev, &subblock);
-
-
- rc = ext4_balloc_free_block(inode_ref, ind_block);
- if (rc != EOK) {
- ext4_block_set(fs->bdev, &block);
- return rc;
- }
- }
- }
-
- ext4_block_set(fs->bdev, &block);
- rc = ext4_balloc_free_block(inode_ref, fblock);
- if (rc != EOK)
- return rc;
-
- ext4_inode_set_indirect_block(inode_ref->inode, 2, 0);
- }
-
- finish:
- /* Mark inode dirty for writing to the physical device */
- inode_ref->dirty = true;
-
- /* Free block with extended attributes if present */
- uint32_t xattr_block = ext4_inode_get_file_acl(
- inode_ref->inode, &fs->sb);
- if (xattr_block) {
- int rc = ext4_balloc_free_block(inode_ref, xattr_block);
- if (rc != EOK)
- return rc;
-
- ext4_inode_set_file_acl(inode_ref->inode, &fs->sb, 0);
- }
-
- /* Free inode by allocator */
- int rc;
- if (ext4_inode_is_type(&fs->sb, inode_ref->inode,
- EXT4_INODE_MODE_DIRECTORY))
- rc = ext4_ialloc_free_inode(fs, inode_ref->index, true);
- else
- rc = ext4_ialloc_free_inode(fs, inode_ref->index, false);
-
- return rc;
-}
-
-int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref,
- uint64_t new_size)
-{
- struct ext4_sblock *sb = &inode_ref->fs->sb;
- uint32_t i;
-
- /* Check flags, if i-node can be truncated */
- if (!ext4_inode_can_truncate(sb, inode_ref->inode))
- return EINVAL;
-
- /* If sizes are equal, nothing has to be done. */
- uint64_t old_size = ext4_inode_get_size(sb, inode_ref->inode);
- if (old_size == new_size)
- return EOK;
-
- /* It's not suppported to make the larger file by truncate operation */
- if (old_size < new_size)
- return EINVAL;
-
- /* Compute how many blocks will be released */
- uint64_t size_diff = old_size - new_size;
- uint32_t block_size = ext4_sb_get_block_size(sb);
- uint32_t diff_blocks_count = size_diff / block_size;
- if (size_diff % block_size != 0)
- diff_blocks_count++;
-
- uint32_t old_blocks_count = old_size / block_size;
- if (old_size % block_size != 0)
- old_blocks_count++;
-
- if ((ext4_sb_check_feature_incompatible(sb,
- EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
- (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
-#if 0
- /* Extents require special operation */
- int rc = ext4_extent_release_blocks_from(inode_ref,
- old_blocks_count - diff_blocks_count);
- if (rc != EOK)
- return rc;
-#endif
- } else {
- /* Release data blocks from the end of file */
-
- /* Starting from 1 because of logical blocks are numbered from 0 */
- for (i = 1; i <= diff_blocks_count; ++i) {
- int rc = ext4_fs_release_inode_block(inode_ref,
- old_blocks_count - i);
- if (rc != EOK)
- return rc;
- }
- }
-
- /* Update i-node */
- ext4_inode_set_size(inode_ref->inode, new_size);
- inode_ref->dirty = true;
-
- return EOK;
-}
-
-int ext4_fs_get_inode_data_block_index(struct ext4_inode_ref *inode_ref,
- uint64_t iblock, uint32_t *fblock)
-{
- struct ext4_fs *fs = inode_ref->fs;
-
- /* For empty file is situation simple */
- if (ext4_inode_get_size(&fs->sb, inode_ref->inode) == 0) {
- *fblock = 0;
- return EOK;
- }
-
- uint32_t current_block;
-
- /* Handle i-node using extents */
- if ((ext4_sb_check_feature_incompatible(&fs->sb,
- EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
- (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
-
-#if 0
- int rc = ext4_extent_find_block(inode_ref, iblock, ¤t_block);
- if (rc != EOK)
- return rc;
-
- *fblock = current_block;
- return EOK;
-#endif
- }
-
- struct ext4_inode *inode = inode_ref->inode;
-
- /* Direct block are read directly from array in i-node structure */
- if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
- current_block = ext4_inode_get_direct_block(inode, (uint32_t) iblock);
- *fblock = current_block;
- return EOK;
- }
-
- /* Determine indirection level of the target block */
- unsigned int level = 0;
- unsigned int i;
- for (i = 1; i < 4; i++) {
- if (iblock < fs->inode_block_limits[i]) {
- level = i;
- break;
- }
- }
-
- if (level == 0)
- return EIO;
-
- /* Compute offsets for the topmost level */
- uint64_t block_offset_in_level =
- iblock - fs->inode_block_limits[level - 1];
- current_block = ext4_inode_get_indirect_block(inode, level - 1);
- uint32_t offset_in_block =
- block_offset_in_level / fs->inode_blocks_per_level[level - 1];
-
- /* Sparse file */
- if (current_block == 0) {
- *fblock = 0;
- return EOK;
- }
-
- struct ext4_block block;
-
- /*
- * Navigate through other levels, until we find the block number
- * or find null reference meaning we are dealing with sparse file
- */
- while (level > 0) {
- /* Load indirect block */
- int rc = ext4_block_get(fs->bdev, &block, current_block);
- if (rc != EOK)
- return rc;
-
- /* Read block address from indirect block */
- current_block =
- to_le32(((uint32_t *) block.data)[offset_in_block]);
-
- /* Put back indirect block untouched */
- rc = ext4_block_set(fs->bdev, &block);
- if (rc != EOK)
- return rc;
-
- /* Check for sparse file */
- if (current_block == 0) {
- *fblock = 0;
- return EOK;
- }
-
- /* Jump to the next level */
- level--;
-
- /* Termination condition - we have address of data block loaded */
- if (level == 0)
- break;
-
- /* Visit the next level */
- block_offset_in_level %= fs->inode_blocks_per_level[level];
- offset_in_block =
- block_offset_in_level / fs->inode_blocks_per_level[level - 1];
- }
-
- *fblock = current_block;
-
- return EOK;
-}
-
-int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
- uint64_t iblock, uint32_t fblock)
-{
- struct ext4_fs *fs = inode_ref->fs;
-
- /* Handle inode using extents */
- if ((ext4_sb_check_feature_incompatible(&fs->sb,
- EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
- (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
- /* Not reachable */
- return ENOTSUP;
- }
-
- /* Handle simple case when we are dealing with direct reference */
- if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
- ext4_inode_set_direct_block(inode_ref->inode, (uint32_t) iblock,
- fblock);
- inode_ref->dirty = true;
-
- return EOK;
- }
-
- /* Determine the indirection level needed to get the desired block */
- unsigned int level = 0;
- unsigned int i;
- for (i = 1; i < 4; i++) {
- if (iblock < fs->inode_block_limits[i]) {
- level = i;
- break;
- }
- }
-
- if (level == 0)
- return EIO;
-
- uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
-
- /* Compute offsets for the topmost level */
- uint64_t block_offset_in_level =
- iblock - fs->inode_block_limits[level - 1];
- uint32_t current_block =
- ext4_inode_get_indirect_block(inode_ref->inode, level - 1);
- uint32_t offset_in_block =
- block_offset_in_level / fs->inode_blocks_per_level[level - 1];
-
- uint32_t new_block_addr;
-
- struct ext4_block block;
- struct ext4_block new_block;
-
- /* Is needed to allocate indirect block on the i-node level */
- if (current_block == 0) {
- /* Allocate new indirect block */
- int rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr);
- if (rc != EOK)
- return rc;
-
- /* Update i-node */
- ext4_inode_set_indirect_block(inode_ref->inode, level - 1,
- new_block_addr);
- inode_ref->dirty = true;
-
- /* Load newly allocated block */
- rc = ext4_block_get(fs->bdev, &new_block, new_block_addr);
- if (rc != EOK) {
- ext4_balloc_free_block(inode_ref, new_block_addr);
- return rc;
- }
-
- /* Initialize new block */
- memset(new_block.data, 0, block_size);
- new_block.dirty = true;
-
- /* Put back the allocated block */
- rc = ext4_block_set(fs->bdev, &new_block);
- if (rc != EOK)
- return rc;
-
- current_block = new_block_addr;
- }
-
- /*
- * Navigate through other levels, until we find the block number
- * or find null reference meaning we are dealing with sparse file
- */
- while (level > 0) {
- int rc = ext4_block_get(fs->bdev, &block, current_block);
- if (rc != EOK)
- return rc;
-
- current_block =
- to_le32(((uint32_t *) block.data)[offset_in_block]);
-
- if ((level > 1) && (current_block == 0)) {
- /* Allocate new block */
- rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr);
- if (rc != EOK) {
- ext4_block_set(fs->bdev, &block);
- return rc;
- }
-
- /* Load newly allocated block */
- rc = ext4_block_get(fs->bdev, &new_block, new_block_addr);
-
- if (rc != EOK) {
- ext4_block_set(fs->bdev, &block);
- return rc;
- }
-
- /* Initialize allocated block */
- memset(new_block.data, 0, block_size);
- new_block.dirty = true;
-
- rc = ext4_block_set(fs->bdev, &new_block);
- if (rc != EOK) {
- ext4_block_set(fs->bdev, &block);
- return rc;
- }
-
- /* Write block address to the parent */
- ((uint32_t *) block.data)[offset_in_block] =
- to_le32(new_block_addr);
- block.dirty = true;
- current_block = new_block_addr;
- }
-
- /* Will be finished, write the fblock address */
- if (level == 1) {
- ((uint32_t *) block.data)[offset_in_block] =
- to_le32(fblock);
- block.dirty = true;
- }
-
- rc = ext4_block_set(fs->bdev, &block);
- if (rc != EOK)
- return rc;
-
- level--;
-
- /*
- * If we are on the last level, break here as
- * there is no next level to visit
- */
- if (level == 0)
- break;
-
- /* Visit the next level */
- block_offset_in_level %= fs->inode_blocks_per_level[level];
- offset_in_block =
- block_offset_in_level / fs->inode_blocks_per_level[level - 1];
- }
-
- return EOK;
-}
-
-int ext4_fs_release_inode_block(struct ext4_inode_ref *inode_ref,
- uint32_t iblock)
-{
- uint32_t fblock;
-
- struct ext4_fs *fs = inode_ref->fs;
-
- /* Extents are handled otherwise = there is not support in this function */
- ext4_assert(!(ext4_sb_check_feature_incompatible(&fs->sb,
- EXT4_FEATURE_INCOMPAT_EXTENTS) &&
- (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))));
-
- struct ext4_inode *inode = inode_ref->inode;
-
- /* Handle simple case when we are dealing with direct reference */
- if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
- fblock = ext4_inode_get_direct_block(inode, iblock);
-
- /* Sparse file */
- if (fblock == 0)
- return EOK;
-
- ext4_inode_set_direct_block(inode, iblock, 0);
- return ext4_balloc_free_block(inode_ref, fblock);
- }
-
- /* Determine the indirection level needed to get the desired block */
- unsigned int level = 0;
- unsigned int i;
- for (i = 1; i < 4; i++) {
- if (iblock < fs->inode_block_limits[i]) {
- level = i;
- break;
- }
- }
-
- if (level == 0)
- return EIO;
-
- /* Compute offsets for the topmost level */
- uint64_t block_offset_in_level =
- iblock - fs->inode_block_limits[level - 1];
- uint32_t current_block =
- ext4_inode_get_indirect_block(inode, level - 1);
- uint32_t offset_in_block =
- block_offset_in_level / fs->inode_blocks_per_level[level - 1];
-
- /*
- * Navigate through other levels, until we find the block number
- * or find null reference meaning we are dealing with sparse file
- */
- struct ext4_block block;
-
- while (level > 0) {
-
- /* Sparse check */
- if (current_block == 0)
- return EOK;
-
- int rc = ext4_block_get(fs->bdev, &block, current_block);
- if (rc != EOK)
- return rc;
-
- current_block =
- to_le32(((uint32_t *) block.data)[offset_in_block]);
-
- /* Set zero if physical data block address found */
- if (level == 1) {
- ((uint32_t *) block.data)[offset_in_block] =
- to_le32(0);
- block.dirty = true;
- }
-
- rc = ext4_block_set(fs->bdev, &block);
- if (rc != EOK)
- return rc;
-
- level--;
-
- /*
- * If we are on the last level, break here as
- * there is no next level to visit
- */
- if (level == 0)
- break;
-
- /* Visit the next level */
- block_offset_in_level %= fs->inode_blocks_per_level[level];
- offset_in_block =
- block_offset_in_level / fs->inode_blocks_per_level[level - 1];
- }
-
- fblock = current_block;
- if (fblock == 0)
- return EOK;
-
- /* Physical block is not referenced, it can be released */
- return ext4_balloc_free_block(inode_ref, fblock);
-}
-
-
-int ext4_fs_append_inode_block(struct ext4_inode_ref *inode_ref,
- uint32_t *fblock, uint32_t *iblock)
-{
- /* Handle extents separately */
- if ((ext4_sb_check_feature_incompatible(&inode_ref->fs->sb,
- EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
- (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))){
-
-#if 0
- return ext4_extent_append_block(inode_ref, iblock, fblock, true);
-#endif
- }
-
- struct ext4_sblock *sb = &inode_ref->fs->sb;
-
- /* Compute next block index and allocate data block */
- uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
- uint32_t block_size = ext4_sb_get_block_size(sb);
-
- /* Align size i-node size */
- if ((inode_size % block_size) != 0)
- inode_size += block_size - (inode_size % block_size);
-
- /* Logical blocks are numbered from 0 */
- uint32_t new_block_idx = inode_size / block_size;
-
- /* Allocate new physical block */
- uint32_t phys_block;
- int rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
- if (rc != EOK)
- return rc;
-
- /* Add physical block address to the i-node */
- rc = ext4_fs_set_inode_data_block_index(inode_ref,
- new_block_idx, phys_block);
- if (rc != EOK) {
- ext4_balloc_free_block(inode_ref, phys_block);
- return rc;
- }
-
- /* Update i-node */
- ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
- inode_ref->dirty = true;
-
- *fblock = phys_block;
- *iblock = new_block_idx;
-
- return EOK;
-}
-
-/**
- * @}
- */
-
--- a/src/lwext4/ext4_fs.h
+++ /dev/null
@@ -1,95 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_fs.c
- * @brief More complex filesystem functions.
- */
-
-#ifndef EXT4_FS_H_
-#define EXT4_FS_H_
-
-#include <ext4_config.h>
-#include <ext4_types.h>
-
-#include <stdint.h>
-#include <stdbool.h>
-
-int ext4_fs_init(struct ext4_fs *fs, struct ext4_blockdev *bdev);
-int ext4_fs_fini(struct ext4_fs *fs);
-
-int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only);
-
-
-uint32_t ext4_fs_baddr2_index_in_group(struct ext4_sblock *s, uint32_t baddr);
-uint32_t ext4_fs_index_in_group2_baddr(struct ext4_sblock *s, uint32_t index,
- uint32_t bgid);
-
-
-int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid,
- struct ext4_block_group_ref *ref);
-int ext4_fs_put_block_group_ref(struct ext4_block_group_ref *ref);
-
-
-int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index,
- struct ext4_inode_ref *ref);
-int ext4_fs_put_inode_ref(struct ext4_inode_ref *ref);
-
-
-int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
- bool is_directory);
-int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref);
-
-int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref,
- uint64_t new_size);
-
-int ext4_fs_get_inode_data_block_index(struct ext4_inode_ref *inode_ref,
- uint64_t iblock, uint32_t *fblock);
-
-int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
- uint64_t iblock, uint32_t fblock);
-
-int ext4_fs_release_inode_block(struct ext4_inode_ref *inode_ref,
- uint32_t iblock);
-
-int ext4_fs_append_inode_block(struct ext4_inode_ref *inode_ref,
- uint32_t *fblock, uint32_t *iblock);
-
-#endif /* EXT4_FS_H_ */
-
-/**
- * @}
- */
--- a/src/lwext4/ext4_hash.c
+++ /dev/null
@@ -1,320 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- * FreeBSD:
- * Copyright (c) 2010, 2013 Zheng Liu <lz@freebsd.org>
- * Copyright (c) 2012, Vyacheslav Matyushin
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
-/*
- * The following notice applies to the code in ext2_half_md4():
- *
- * Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
- *
- * License to copy and use this software is granted provided that it
- * is identified as the "RSA Data Security, Inc. MD4 Message-Digest
- * Algorithm" in all material mentioning or referencing this software
- * or this function.
- *
- * License is also granted to make and use derivative works provided
- * that such works are identified as "derived from the RSA Data
- * Security, Inc. MD4 Message-Digest Algorithm" in all material
- * mentioning or referencing the derived work.
- *
- * RSA Data Security, Inc. makes no representations concerning either
- * the merchantability of this software or the suitability of this
- * software for any particular purpose. It is provided "as is"
- * without express or implied warranty of any kind.
- *
- * These notices must be retained in any copies of any part of this
- * documentation and/or software.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_hash.c
- * @brief Directory indexing hash functions.
- */
-
-#include <ext4_config.h>
-#include <ext4_types.h>
-#include <string.h>
-#include <ext4_errno.h>
-
-/* F, G, and H are MD4 functions */
-#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
-#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-
-/* ROTATE_LEFT rotates x left n bits */
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
-
-/*
- * FF, GG, and HH are transformations for rounds 1, 2, and 3.
- * Rotation is separated from addition to prevent recomputation.
- */
-#define FF(a, b, c, d, x, s) { \
- (a) += F ((b), (c), (d)) + (x); \
- (a) = ROTATE_LEFT ((a), (s)); \
-}
-
-#define GG(a, b, c, d, x, s) { \
- (a) += G ((b), (c), (d)) + (x) + (uint32_t)0x5A827999; \
- (a) = ROTATE_LEFT ((a), (s)); \
-}
-
-#define HH(a, b, c, d, x, s) { \
- (a) += H ((b), (c), (d)) + (x) + (uint32_t)0x6ED9EBA1; \
- (a) = ROTATE_LEFT ((a), (s)); \
-}
-
-/*
- * MD4 basic transformation. It transforms state based on block.
- *
- * This is a half md4 algorithm since Linux uses this algorithm for dir
- * index. This function is derived from the RSA Data Security, Inc. MD4
- * Message-Digest Algorithm and was modified as necessary.
- *
- * The return value of this function is uint32_t in Linux, but actually we don't
- * need to check this value, so in our version this function doesn't return any
- * value.
- */
-static void
-ext2_half_md4(uint32_t hash[4], uint32_t data[8])
-{
- uint32_t a = hash[0], b = hash[1], c = hash[2], d = hash[3];
-
- /* Round 1 */
- FF(a, b, c, d, data[0], 3);
- FF(d, a, b, c, data[1], 7);
- FF(c, d, a, b, data[2], 11);
- FF(b, c, d, a, data[3], 19);
- FF(a, b, c, d, data[4], 3);
- FF(d, a, b, c, data[5], 7);
- FF(c, d, a, b, data[6], 11);
- FF(b, c, d, a, data[7], 19);
-
- /* Round 2 */
- GG(a, b, c, d, data[1], 3);
- GG(d, a, b, c, data[3], 5);
- GG(c, d, a, b, data[5], 9);
- GG(b, c, d, a, data[7], 13);
- GG(a, b, c, d, data[0], 3);
- GG(d, a, b, c, data[2], 5);
- GG(c, d, a, b, data[4], 9);
- GG(b, c, d, a, data[6], 13);
-
- /* Round 3 */
- HH(a, b, c, d, data[3], 3);
- HH(d, a, b, c, data[7], 9);
- HH(c, d, a, b, data[2], 11);
- HH(b, c, d, a, data[6], 15);
- HH(a, b, c, d, data[1], 3);
- HH(d, a, b, c, data[5], 9);
- HH(c, d, a, b, data[0], 11);
- HH(b, c, d, a, data[4], 15);
-
- hash[0] += a;
- hash[1] += b;
- hash[2] += c;
- hash[3] += d;
-}
-
-/*
- * Tiny Encryption Algorithm.
- */
-static void
-ext2_tea(uint32_t hash[4], uint32_t data[8])
-{
- uint32_t tea_delta = 0x9E3779B9;
- uint32_t sum;
- uint32_t x = hash[0], y = hash[1];
- int n = 16;
- int i = 1;
-
- while (n-- > 0) {
- sum = i * tea_delta;
- x += ((y << 4) + data[0]) ^ (y + sum) ^ ((y >> 5) + data[1]);
- y += ((x << 4) + data[2]) ^ (x + sum) ^ ((x >> 5) + data[3]);
- i++;
- }
-
- hash[0] += x;
- hash[1] += y;
-}
-
-static uint32_t
-ext2_legacy_hash(const char *name, int len, int unsigned_char)
-{
- uint32_t h0, h1 = 0x12A3FE2D, h2 = 0x37ABE8F9;
- uint32_t multi = 0x6D22F5;
- const unsigned char *uname = (const unsigned char *)name;
- const signed char *sname = (const signed char *)name;
- int val, i;
-
- for (i = 0; i < len; i++) {
- if (unsigned_char)
- val = (unsigned int)*uname++;
- else
- val = (int)*sname++;
-
- h0 = h2 + (h1 ^ (val * multi));
- if (h0 & 0x80000000)
- h0 -= 0x7FFFFFFF;
- h2 = h1;
- h1 = h0;
- }
-
- return (h1 << 1);
-}
-
-static void
-ext2_prep_hashbuf(const char *src, int slen, uint32_t *dst, int dlen,
- int unsigned_char)
-{
- uint32_t padding = slen | (slen << 8) | (slen << 16) | (slen << 24);
- uint32_t buf_val;
- int len, i;
- int buf_byte;
- const unsigned char *ubuf = (const unsigned char *)src;
- const signed char *sbuf = (const signed char *)src;
-
- if (slen > dlen)
- len = dlen;
- else
- len = slen;
-
- buf_val = padding;
-
- for (i = 0; i < len; i++) {
- if (unsigned_char)
- buf_byte = (unsigned int)ubuf[i];
- else
- buf_byte = (int)sbuf[i];
-
- if ((i % 4) == 0)
- buf_val = padding;
-
- buf_val <<= 8;
- buf_val += buf_byte;
-
- if ((i % 4) == 3) {
- *dst++ = buf_val;
- dlen -= sizeof(uint32_t);
- buf_val = padding;
- }
- }
-
- dlen -= sizeof(uint32_t);
- if (dlen >= 0)
- *dst++ = buf_val;
-
- dlen -= sizeof(uint32_t);
- while (dlen >= 0) {
- *dst++ = padding;
- dlen -= sizeof(uint32_t);
- }
-}
-
-int
-ext2_htree_hash(const char *name, int len,
- const uint32_t *hash_seed, int hash_version,
- uint32_t *hash_major, uint32_t *hash_minor)
-{
- uint32_t hash[4];
- uint32_t data[8];
- uint32_t major = 0, minor = 0;
- int unsigned_char = 0;
-
- if (!name || !hash_major)
- return (-1);
-
- if (len < 1 || len > 255)
- goto error;
-
- hash[0] = 0x67452301;
- hash[1] = 0xEFCDAB89;
- hash[2] = 0x98BADCFE;
- hash[3] = 0x10325476;
-
- if (hash_seed)
- memcpy(hash, hash_seed, sizeof(hash));
-
- switch (hash_version) {
- case EXT2_HTREE_TEA_UNSIGNED:
- unsigned_char = 1;
- case EXT2_HTREE_TEA:
- while (len > 0) {
- ext2_prep_hashbuf(name, len, data, 16, unsigned_char);
- ext2_tea(hash, data);
- len -= 16;
- name += 16;
- }
- major = hash[0];
- minor = hash[1];
- break;
- case EXT2_HTREE_LEGACY_UNSIGNED:
- unsigned_char = 1;
- case EXT2_HTREE_LEGACY:
- major = ext2_legacy_hash(name, len, unsigned_char);
- break;
- case EXT2_HTREE_HALF_MD4_UNSIGNED:
- unsigned_char = 1;
- case EXT2_HTREE_HALF_MD4:
- while (len > 0) {
- ext2_prep_hashbuf(name, len, data, 32, unsigned_char);
- ext2_half_md4(hash, data);
- len -= 32;
- name += 32;
- }
- major = hash[0];
- minor = hash[1];
- break;
- default:
- goto error;
- }
-
- major &= ~1;
- if (major == (EXT2_HTREE_EOF << 1))
- major = (EXT2_HTREE_EOF - 1) << 1;
- *hash_major = major;
- if (hash_minor)
- *hash_minor = minor;
-
- return EOK;
-
- error:
- *hash_major = 0;
- if (hash_minor)
- *hash_minor = 0;
- return ENOTSUP;
-}
-
-/**
- * @}
- */
--- a/src/lwext4/ext4_hash.h
+++ /dev/null
@@ -1,61 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_hash.h
- * @brief Directory indexing hash functions.
- */
-
-#ifndef EXT4_HASH_H_
-#define EXT4_HASH_H_
-
-#include <ext4_config.h>
-
-#include <stdint.h>
-
-/**@brief Directory entry name hash function.
- * @param name entry name
- * @param len entry name length
- * @param hash_seed (from superblock)
- * @param hash version (from superblock)
- * @param hash_minor output value
- * @param hash_major output value
- * @return standard error code*/
-int ext2_htree_hash(const char *name, int len,
- const uint32_t *hash_seed, int hash_version,
- uint32_t *hash_major, uint32_t *hash_minor);
-
-
-#endif /* EXT4_HASH_H_ */
-
-/**
- * @}
- */
--- a/src/lwext4/ext4_ialloc.c
+++ /dev/null
@@ -1,250 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_ialloc.c
- * @brief Inode allocation procedures.
- */
-
-#include <ext4_config.h>
-#include <ext4_types.h>
-#include <ext4_ialloc.h>
-#include <ext4_super.h>
-#include <ext4_fs.h>
-#include <ext4_blockdev.h>
-#include <ext4_block_group.h>
-#include <ext4_bitmap.h>
-
-static uint32_t ext4_ialloc_inode2index_in_group(struct ext4_sblock *sb,
- uint32_t inode)
-{
- uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
- return (inode - 1) % inodes_per_group;
-}
-
-static uint32_t ext4_ialloc_index_in_group2inode(struct ext4_sblock *sb,
- uint32_t index, uint32_t bgid)
-{
- uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
- return bgid * inodes_per_group + (index + 1);
-}
-
-static uint32_t ext4_ialloc_get_bgid_of_inode(struct ext4_sblock *sb,
- uint32_t inode)
-{
- uint32_t inodes_per_group = ext4_get32(sb, inodes_per_group);
- return (inode - 1) / inodes_per_group;
-}
-
-
-int ext4_ialloc_free_inode(struct ext4_fs *fs, uint32_t index, bool is_dir)
-{
- struct ext4_sblock *sb = &fs->sb;
-
- /* Compute index of block group and load it */
- uint32_t block_group = ext4_ialloc_get_bgid_of_inode(sb, index);
-
- struct ext4_block_group_ref bg_ref;
- int rc = ext4_fs_get_block_group_ref(fs, block_group, &bg_ref);
- if (rc != EOK)
- return rc;
-
- /* Load i-node bitmap */
- uint32_t bitmap_block_addr = ext4_bg_get_inode_bitmap(
- bg_ref.block_group, sb);
-
- struct ext4_block bitmap_block;
- rc = ext4_block_get(fs->bdev, &bitmap_block, bitmap_block_addr);
- if (rc != EOK)
- return rc;
-
- /* Free i-node in the bitmap */
- uint32_t index_in_group = ext4_ialloc_inode2index_in_group(sb, index);
- ext4_bmap_bit_clr(bitmap_block.data, index_in_group);
- bitmap_block.dirty = true;
-
- /* Put back the block with bitmap */
- rc = ext4_block_set(fs->bdev, &bitmap_block);
- if (rc != EOK) {
- /* Error in saving bitmap */
- ext4_fs_put_block_group_ref(&bg_ref);
- return rc;
- }
-
- /* If released i-node is a directory, decrement used directories count */
- if (is_dir) {
- uint32_t bg_used_dirs = ext4_bg_get_used_dirs_count(
- bg_ref.block_group, sb);
- bg_used_dirs--;
- ext4_bg_set_used_dirs_count(bg_ref.block_group, sb,
- bg_used_dirs);
- }
-
- /* Update block group free inodes count */
- uint32_t free_inodes = ext4_bg_get_free_inodes_count(
- bg_ref.block_group, sb);
- free_inodes++;
- ext4_bg_set_free_inodes_count(bg_ref.block_group, sb,
- free_inodes);
-
- bg_ref.dirty = true;
-
- /* Put back the modified block group */
- rc = ext4_fs_put_block_group_ref(&bg_ref);
- if (rc != EOK)
- return rc;
-
- /* Update superblock free inodes count */
- ext4_set32(sb, free_inodes_count, ext4_get32(sb, free_inodes_count) + 1);
-
- return EOK;
-}
-
-int ext4_ialloc_alloc_inode(struct ext4_fs *fs, uint32_t *index, bool is_dir)
-{
- struct ext4_sblock *sb = &fs->sb;
-
- uint32_t bgid = 0;
- uint32_t bg_count = ext4_block_group_cnt(sb);
- uint32_t sb_free_inodes = ext4_get32(sb, free_inodes_count);
- uint32_t avg_free_inodes = sb_free_inodes / bg_count;
-
- /* Try to find free i-node in all block groups */
- while (bgid < bg_count) {
- /* Load block group to check */
- struct ext4_block_group_ref bg_ref;
- int rc = ext4_fs_get_block_group_ref(fs, bgid, &bg_ref);
- if (rc != EOK)
- return rc;
-
- struct ext4_bgroup *bg = bg_ref.block_group;
-
- /* Read necessary values for algorithm */
- uint32_t free_blocks = ext4_bg_get_free_blocks_count(bg, sb);
- uint32_t free_inodes = ext4_bg_get_free_inodes_count(bg, sb);
- uint32_t used_dirs = ext4_bg_get_used_dirs_count(bg, sb);
-
- /* Check if this block group is good candidate for allocation */
- if ((free_inodes >= avg_free_inodes) && (free_blocks > 0)) {
- /* Load block with bitmap */
- uint32_t bitmap_block_addr = ext4_bg_get_inode_bitmap(
- bg_ref.block_group, sb);
-
- struct ext4_block bitmap_block;
- rc = ext4_block_get(fs->bdev, &bitmap_block, bitmap_block_addr);
- if (rc != EOK)
- return rc;
-
- /* Try to allocate i-node in the bitmap */
- uint32_t inodes_in_group = ext4_inodes_in_group_cnt(sb, bgid);
- uint32_t index_in_group;
-
- rc = ext4_bmap_bit_find_clr(bitmap_block.data, 0, inodes_in_group,
- &index_in_group);
- /* Block group has not any free i-node */
- if (rc == ENOSPC) {
- ext4_block_set(fs->bdev, &bitmap_block);
- ext4_fs_put_block_group_ref(&bg_ref);
- continue;
- }
-
- ext4_bmap_bit_set(bitmap_block.data, index_in_group);
-
- /* Free i-node found, save the bitmap */
- bitmap_block.dirty = true;
-
- ext4_block_set(fs->bdev, &bitmap_block);
- if (rc != EOK)
- return rc;
-
- /* Modify filesystem counters */
- free_inodes--;
- ext4_bg_set_free_inodes_count(bg, sb, free_inodes);
-
- /* Increment used directories counter */
- if (is_dir) {
- used_dirs++;
- ext4_bg_set_used_dirs_count(bg, sb, used_dirs);
- }
-
- /* Decrease unused inodes count */
- if (ext4_bg_has_flag(bg,
- EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
- uint32_t unused =
- ext4_bg_get_itable_unused(bg, sb);
-
- uint32_t inodes_in_group =
- ext4_inodes_in_group_cnt(sb, bgid);
-
- uint32_t free = inodes_in_group - unused;
-
- if (index_in_group >= free) {
- unused = inodes_in_group - (index_in_group + 1);
- ext4_bg_set_itable_unused(bg, sb, unused);
- }
- }
-
- /* Save modified block group */
- bg_ref.dirty = true;
-
- rc = ext4_fs_put_block_group_ref(&bg_ref);
- if (rc != EOK)
- return rc;
-
- /* Update superblock */
- sb_free_inodes--;
- ext4_set32(sb, free_inodes_count, sb_free_inodes);
-
-
- /* Compute the absolute i-nodex number */
- *index = ext4_ialloc_index_in_group2inode(sb,
- index_in_group, bgid);
-
- return EOK;
- }
-
- /* Block group not modified, put it and jump to the next block group */
- ext4_fs_put_block_group_ref(&bg_ref);
- ++bgid;
- }
-
- return ENOSPC;
-}
-
-/**
- * @}
- */
-
--- a/src/lwext4/ext4_ialloc.h
+++ /dev/null
@@ -1,63 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_ialloc.c
- * @brief Inode allocation procedures.
- */
-
-#ifndef EXT4_IALLOC_H_
-#define EXT4_IALLOC_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <ext4_config.h>
-#include <ext4_types.h>
-
-
-int ext4_ialloc_free_inode(struct ext4_fs *fs, uint32_t index, bool is_dir);
-int ext4_ialloc_alloc_inode(struct ext4_fs *fs, uint32_t *index, bool is_dir);
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* EXT4_IALLOC_H_ */
-
-/**
- * @}
- */
--- a/src/lwext4/ext4_inode.c
+++ /dev/null
@@ -1,353 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_inode.c
- * @brief Inode handle functions
- */
-
-#include <ext4_config.h>
-#include <ext4_types.h>
-#include <ext4_inode.h>
-#include <ext4_super.h>
-
-static uint32_t ext4_inode_block_bits_count(uint32_t block_size)
-{
- uint32_t bits = 8;
- uint32_t size = block_size;
-
- do {
- bits++;
- size = size >> 1;
- } while (size > 256);
-
- return bits;
-}
-
-
-uint32_t ext4_inode_get_mode(struct ext4_sblock *sb, struct ext4_inode *inode)
-{
- uint32_t v = to_le16(inode->mode);
-
- if(ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_HURD){
- v |= ((uint32_t) to_le16(inode->osd2.hurd2.mode_high)) << 16;
- }
-
- return v;
-}
-
-void ext4_inode_set_mode(struct ext4_sblock *sb, struct ext4_inode *inode,
- uint32_t mode)
-{
- inode->mode = to_le16((mode << 16) >> 16);
-
- if(ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_HURD)
- inode->osd2.hurd2.mode_high = to_le16(mode >> 16);
-}
-
-
-
-uint32_t ext4_inode_get_uid(struct ext4_inode *inode)
-{
- return to_le32(inode->uid);
-}
-
-void ext4_inode_set_uid(struct ext4_inode *inode, uint32_t uid)
-{
- inode->uid = to_le32(uid);
-}
-
-
-uint64_t ext4_inode_get_size(struct ext4_sblock *sb, struct ext4_inode *inode)
-{
- uint64_t v = to_le32(inode->size_lo);
-
- if ((ext4_get32(sb, rev_level) > 0) && (ext4_inode_is_type(sb, inode,
- EXT4_INODE_MODE_FILE)))
- v |= ((uint64_t)to_le32(inode->size_hi)) << 32;
-
- return v;
-}
-
-void ext4_inode_set_size(struct ext4_inode *inode, uint64_t size)
-{
- inode->size_lo = to_le32((size << 32) >> 32);
- inode->size_hi = to_le32(size >> 32);
-}
-
-
-uint32_t ext4_inode_get_access_time(struct ext4_inode *inode)
-{
- return to_le32(inode->access_time);
-}
-void ext4_inode_set_access_time(struct ext4_inode *inode, uint32_t time)
-{
- inode->access_time = to_le32(time);
-}
-
-
-uint32_t ext4_inode_get_change_inode_time(struct ext4_inode *inode)
-{
- return to_le32(inode->change_inode_time);
-}
-void ext4_inode_set_change_inode_time(struct ext4_inode *inode,
- uint32_t time)
-{
- inode->change_inode_time = to_le32(time);
-}
-
-
-uint32_t ext4_inode_get_modification_time(struct ext4_inode *inode)
-{
- return to_le32(inode->modification_time);
-}
-
-void ext4_inode_set_modification_time(struct ext4_inode *inode,
- uint32_t time)
-{
- inode->modification_time = to_le32(time);
-}
-
-
-uint32_t ext4_inode_get_deletion_time(struct ext4_inode *inode)
-{
- return to_le32(inode->deletion_time);
-}
-
-void ext4_inode_set_deletion_time(struct ext4_inode *inode, uint32_t time)
-{
- inode->deletion_time = to_le32(time);
-}
-
-uint32_t ext4_inode_get_gid(struct ext4_inode *inode)
-{
- return to_le32(inode->gid);
-}
-void ext4_inode_set_gid(struct ext4_inode *inode, uint32_t gid)
-{
- inode->gid = to_le32(gid);
-}
-
-uint16_t ext4_inode_get_links_count(struct ext4_inode *inode)
-{
- return to_le16(inode->links_count);
-}
-void ext4_inode_set_links_count(struct ext4_inode *inode, uint16_t cnt)
-{
- inode->links_count = to_le16(cnt);
-}
-
-
-uint64_t ext4_inode_get_blocks_count(struct ext4_sblock *sb,
- struct ext4_inode *inode)
-{
- uint64_t count = to_le32(inode->blocks_count_lo);
-
- if (ext4_sb_check_read_only(sb,
- EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
-
- /* 48-bit field */
- count = ((uint64_t) to_le16(inode->osd2.linux2.blocks_high)) << 32;
-
- if (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_HUGE_FILE)) {
-
- uint32_t block_bits =
- ext4_inode_block_bits_count(ext4_sb_get_block_size(sb));
- return count << (block_bits - 9);
- } else
- return count;
- }
-
- return count;
-}
-
-
-int ext4_inode_set_blocks_count(struct ext4_sblock *sb,
- struct ext4_inode *inode, uint64_t count)
-{
- /* 32-bit maximum */
- uint64_t max = 0;
- max = ~max >> 32;
-
- if (count <= max) {
- inode->blocks_count_lo = to_le32(count);
- inode->osd2.linux2.blocks_high = 0;
- ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
-
- return EOK;
- }
-
- /* Check if there can be used huge files (many blocks) */
- if (!ext4_sb_check_read_only(sb,
- EXT4_FEATURE_RO_COMPAT_HUGE_FILE))
- return EINVAL;
-
- /* 48-bit maximum */
- max = 0;
- max = ~max >> 16;
-
- if (count <= max) {
- inode->blocks_count_lo = to_le32(count);
- inode->osd2.linux2.blocks_high = to_le16(count >> 32);
- ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
- } else {
- uint32_t block_bits = ext4_inode_block_bits_count(ext4_sb_get_block_size(sb));
-
- ext4_inode_set_flag(inode, EXT4_INODE_FLAG_HUGE_FILE);
- count = count >> (block_bits - 9);
- inode->blocks_count_lo = to_le32(count);
- inode->osd2.linux2.blocks_high = to_le16(count >> 32);
- }
-
- return EOK;
-}
-
-
-uint32_t ext4_inode_get_flags(struct ext4_inode *inode)
-{
- return to_le32(inode->flags);
-}
-void ext4_inode_set_flags(struct ext4_inode *inode, uint32_t flags)
-{
- inode->flags = to_le32(flags);
-}
-
-uint32_t ext4_inode_get_generation(struct ext4_inode *inode)
-{
- return to_le32(inode->generation);
-}
-void ext4_inode_set_generation(struct ext4_inode *inode, uint32_t gen)
-{
- inode->generation = to_le32(gen);
-}
-
-uint64_t ext4_inode_get_file_acl(struct ext4_inode *inode,
- struct ext4_sblock *sb)
-{
- /*TODO: Verify it*/
- uint64_t v = to_le32(inode->file_acl_lo);
-
- if (ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_LINUX)
- v |= ((uint32_t) to_le16(inode->osd2.linux2.file_acl_high)) << 16;
-
-
- return v;
-}
-
-void ext4_inode_set_file_acl(struct ext4_inode *inode, struct ext4_sblock *sb,
- uint64_t acl)
-{
- /*TODO: Verify it*/
- inode->file_acl_lo = to_le32((acl << 32) >> 32);
-
- if (ext4_get32(sb, creator_os) == EXT4_SUPERBLOCK_OS_LINUX)
- inode->osd2.linux2.file_acl_high = to_le16(acl >> 32);
-}
-
-
-
-uint32_t ext4_inode_get_direct_block(struct ext4_inode *inode, uint32_t idx)
-{
- return to_le32(inode->blocks[idx]);
-}
-void ext4_inode_set_direct_block(struct ext4_inode *inode, uint32_t idx,
- uint32_t block)
-{
- inode->blocks[idx] = to_le32(block);
-}
-
-
-uint32_t ext4_inode_get_indirect_block(struct ext4_inode *inode, uint32_t idx)
-{
- return to_le32(inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK]);
-}
-
-void ext4_inode_set_indirect_block(struct ext4_inode *inode, uint32_t idx,
- uint32_t block)
-{
- inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK] = to_le32(block);
-}
-
-bool ext4_inode_is_type(struct ext4_sblock *sb, struct ext4_inode *inode,
- uint32_t type)
-{
- return (ext4_inode_get_mode(sb, inode) &
- EXT4_INODE_MODE_TYPE_MASK) == type;
-}
-
-bool ext4_inode_has_flag(struct ext4_inode *inode, uint32_t f)
-{
- return ext4_inode_get_flags(inode) & f;
-}
-
-void ext4_inode_clear_flag(struct ext4_inode *inode, uint32_t f)
-{
- uint32_t flags = ext4_inode_get_flags(inode);
- flags = flags & (~f);
- ext4_inode_set_flags(inode, flags);
-}
-
-void ext4_inode_set_flag(struct ext4_inode *inode, uint32_t f)
-{
- uint32_t flags = ext4_inode_get_flags(inode);
- flags = flags | f;
- ext4_inode_set_flags(inode, flags);
-}
-
-bool ext4_inode_can_truncate(struct ext4_sblock *sb,
- struct ext4_inode *inode)
-{
- if ((ext4_inode_has_flag(inode, EXT4_INODE_FLAG_APPEND)) ||
- (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_IMMUTABLE)))
- return false;
-
- if ((ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)) ||
- (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_DIRECTORY)))
- return true;
-
- return false;
-}
-
-
-struct ext4_extent_header * ext4_inode_get_extent_header(
- struct ext4_inode *inode)
-{
- return (struct ext4_extent_header *) inode->blocks;
-}
-
-/**
- * @}
- */
--- a/src/lwext4/ext4_inode.h
+++ /dev/null
@@ -1,129 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_inode.h
- * @brief Inode handle functions
- */
-
-#ifndef EXT4_INODE_H_
-#define EXT4_INODE_H_
-
-#include <ext4_config.h>
-#include <stdint.h>
-
-uint32_t ext4_inode_get_mode(struct ext4_sblock *sb, struct ext4_inode *inode);
-void ext4_inode_set_mode(struct ext4_sblock *sb, struct ext4_inode *inode,
- uint32_t mode);
-
-
-uint32_t ext4_inode_get_uid(struct ext4_inode *inode);
-void ext4_inode_set_uid(struct ext4_inode *inode, uint32_t uid);
-
-
-uint64_t ext4_inode_get_size(struct ext4_sblock *sb, struct ext4_inode *inode);
-void ext4_inode_set_size(struct ext4_inode *inode, uint64_t size);
-
-
-uint32_t ext4_inode_get_access_time(struct ext4_inode *inode);
-void ext4_inode_set_access_time(struct ext4_inode *inode, uint32_t time);
-
-
-uint32_t ext4_inode_get_change_inode_time(struct ext4_inode *inode);
-void ext4_inode_set_change_inode_time(struct ext4_inode *inode,
- uint32_t time);
-
-
-uint32_t ext4_inode_get_modification_time(struct ext4_inode *inode);
-void ext4_inode_set_modification_time(struct ext4_inode *inode, uint32_t time);
-
-
-uint32_t ext4_inode_get_deletion_time(struct ext4_inode *inode);
-void ext4_inode_set_deletion_time(struct ext4_inode *inode, uint32_t time);
-
-uint32_t ext4_inode_get_gid(struct ext4_inode *inode);
-void ext4_inode_set_gid(struct ext4_inode *inode, uint32_t gid);
-
-uint16_t ext4_inode_get_links_count(struct ext4_inode *inode);
-void ext4_inode_set_links_count(struct ext4_inode *inode, uint16_t cnt);
-
-
-uint64_t ext4_inode_get_blocks_count(struct ext4_sblock *sb,
- struct ext4_inode *inode);
-int ext4_inode_set_blocks_count(struct ext4_sblock *sb,
- struct ext4_inode *inode, uint64_t cnt);
-
-
-uint32_t ext4_inode_get_flags(struct ext4_inode *inode);
-void ext4_inode_set_flags(struct ext4_inode *inode, uint32_t flags);
-
-uint32_t ext4_inode_get_generation(struct ext4_inode *inode);
-void ext4_inode_set_generation(struct ext4_inode *inode, uint32_t gen);
-
-uint64_t ext4_inode_get_file_acl(struct ext4_inode *inode,
- struct ext4_sblock *sb);
-void ext4_inode_set_file_acl(struct ext4_inode *inode,
- struct ext4_sblock *sb, uint64_t acl);
-
-
-uint32_t ext4_inode_get_direct_block(struct ext4_inode *inode, uint32_t idx);
-void ext4_inode_set_direct_block(struct ext4_inode *inode, uint32_t idx,
- uint32_t block);
-
-
-uint32_t ext4_inode_get_indirect_block(struct ext4_inode *inode, uint32_t idx);
-void ext4_inode_set_indirect_block(struct ext4_inode *inode, uint32_t idx,
- uint32_t block);
-
-bool ext4_inode_is_type(struct ext4_sblock *sb, struct ext4_inode *inode,
- uint32_t type);
-
-
-bool ext4_inode_has_flag(struct ext4_inode *inode, uint32_t f);
-void ext4_inode_clear_flag(struct ext4_inode *inode, uint32_t f);
-void ext4_inode_set_flag(struct ext4_inode *inode, uint32_t f);
-
-bool ext4_inode_can_truncate(struct ext4_sblock *sb, struct ext4_inode *inode);
-
-
-struct ext4_extent_header * ext4_inode_get_extent_header(struct ext4_inode *inode);
-
-#endif /* EXT4_INODE_H_ */
-
-/**
- * @}
- */
-
--- a/src/lwext4/ext4_super.c
+++ /dev/null
@@ -1,133 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_super.h
- * @brief Superblock operations.
- */
-
-#include <ext4_config.h>
-#include <ext4_super.h>
-
-
-uint32_t ext4_block_group_cnt(struct ext4_sblock *s)
-{
- uint64_t blocks_count = ext4_sb_get_blocks_cnt(s);
- uint32_t blocks_per_group = ext4_get32(s, blocks_per_group);
-
- uint32_t block_groups_count = blocks_count / blocks_per_group;
-
- if (blocks_count % blocks_per_group)
- block_groups_count++;
-
- return block_groups_count;
-}
-
-uint32_t ext4_blocks_in_group_cnt(struct ext4_sblock *s, uint32_t bgid)
-{
- uint32_t block_group_count = ext4_block_group_cnt(s);
- uint32_t blocks_per_group = ext4_get32(s, blocks_per_group);
- uint64_t total_blocks = ext4_sb_get_blocks_cnt(s);
-
- if (bgid < block_group_count - 1)
- return blocks_per_group;
-
-
- return (total_blocks - ((block_group_count - 1) * blocks_per_group));
-}
-
-uint32_t ext4_inodes_in_group_cnt(struct ext4_sblock *s, uint32_t bgid)
-{
- uint32_t block_group_count = ext4_block_group_cnt(s);
- uint32_t inodes_per_group = ext4_get32(s, inodes_per_group);
- uint32_t total_inodes = ext4_get32(s, inodes_count);
-
-
- if (bgid < block_group_count - 1)
- return inodes_per_group;
-
- return (total_inodes - ((block_group_count - 1) * inodes_per_group));
-}
-
-int ext4_sb_write(struct ext4_blockdev *bdev, struct ext4_sblock *s)
-{
- return ext4_block_writebytes(bdev, EXT4_SUPERBLOCK_OFFSET,
- s, EXT4_SUPERBLOCK_SIZE);
-}
-
-int ext4_sb_read(struct ext4_blockdev *bdev, struct ext4_sblock *s)
-{
- return ext4_block_readbytes(bdev, EXT4_SUPERBLOCK_OFFSET,
- s, EXT4_SUPERBLOCK_SIZE);
-}
-
-bool ext4_sb_check(struct ext4_sblock *s)
-{
- if (ext4_get16(s, magic) != EXT4_SUPERBLOCK_MAGIC)
- return false;
-
- if (ext4_get32(s, inodes_count) == 0)
- return false;
-
- if (ext4_sb_get_blocks_cnt(s) == 0)
- return false;
-
- if (ext4_get32(s, blocks_per_group) == 0)
- return false;
-
- if (ext4_get32(s, inodes_per_group) == 0)
- return false;
-
- if (ext4_get16(s, inode_size) < 128)
- return false;
-
- if (ext4_get32(s, first_inode) < 11)
- return false;
-
- if (ext4_sb_get_desc_size(s) <
- EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE)
- return false;
-
- if (ext4_sb_get_desc_size(s) >
- EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE)
- return false;
-
- return true;
-}
-
-/**
- * @}
- */
--- a/src/lwext4/ext4_super.h
+++ /dev/null
@@ -1,187 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_super.c
- * @brief Superblock operations.
- */
-
-#ifndef EXT4_SUPER_H_
-#define EXT4_SUPER_H_
-
-
-#include <ext4_config.h>
-#include <ext4_types.h>
-
-
-/****************************Unstandard access to superblock*****************/
-
-/**@brief Blocks count get stored in superblock.
- * @param s superblock descriptor
- * @return count of blocks*/
-static inline uint64_t ext4_sb_get_blocks_cnt(struct ext4_sblock *s)
-{
- return ((uint64_t) to_le32(s->blocks_count_hi) << 32) |
- to_le32(s->blocks_count_lo);
-}
-
-/**@brief Free blocks count get stored in superblock.
- * @param s superblock descriptor
- * @return free blocks*/
-static inline uint64_t ext4_sb_get_free_blocks_cnt(struct ext4_sblock *s)
-{
- return ((uint64_t) to_le32(s->free_blocks_count_hi) << 32) |
- to_le32(s->free_blocks_count_lo);
-}
-
-/**@brief Free blocks count set.
- * @param s superblock descriptor
- * @param cnt new value of free blocks*/
-static inline void ext4_sb_set_free_blocks_cnt(struct ext4_sblock *s,
- uint64_t cnt)
-{
- s->free_blocks_count_lo = to_le32((cnt << 32) >> 32);
- s->free_blocks_count_hi = to_le32(cnt >> 32);
-}
-
-/**@brief Block size get from superblock.
- * @param s superblock descriptor
- * @return block size in bytes*/
-static inline uint32_t ext4_sb_get_block_size(struct ext4_sblock *s)
-{
- return 1024 << to_le32(s->log_block_size);
-}
-
-/**@brief Block group descriptor size.
- * @param s superblock descriptor
- * @return block group descriptor size in bytes*/
-static inline uint16_t ext4_sb_get_desc_size(struct ext4_sblock *s)
-{
- uint16_t size = to_le16(s->desc_size);
-
- return size < EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE ?
- EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE : size;
-}
-
-/*************************Flags and features*********************************/
-
-/**@brief Support check of flag.
- * @param s superblock descriptor
- * @param v flag to check
- * @return true if flag is supported*/
-static inline bool ext4_sb_check_flag(struct ext4_sblock *s, uint32_t v)
-{
- return to_le32(s->flags) & v;
-}
-
-/**@brief Support check of feature compatible.
- * @param s superblock descriptor
- * @param v feature to check
- * @return true if feature is supported*/
-static inline bool ext4_sb_check_feature_compatible(struct ext4_sblock *s,
- uint32_t v)
-{
- return to_le32(s->features_compatible) & v;
-}
-
-
-/**@brief Support check of feature incompatible.
- * @param s superblock descriptor
- * @param v feature to check
- * @return true if feature is supported*/
-static inline bool ext4_sb_check_feature_incompatible(struct ext4_sblock *s,
- uint32_t v)
-{
- return to_le32(s->features_incompatible) & v;
-}
-
-
-/**@brief Support check of read only flag.
- * @param s superblock descriptor
- * @param v flag to check
- * @return true if flag is supported*/
-static inline bool ext4_sb_check_read_only(struct ext4_sblock *s, uint32_t v)
-{
- return to_le32(s->features_read_only) & v;
-}
-
-/**************************More complex functions****************************/
-
-/**@brief Returns a block group count.
- * @param s superblock descriptor
- * @return count of block groups*/
-uint32_t ext4_block_group_cnt(struct ext4_sblock *s);
-
-/**@brief Returns block count in block group
- * (last block group may have less blocks)
- * @param s superblock descriptor
- * @param bgid block group id
- * @return blocks count*/
-uint32_t ext4_blocks_in_group_cnt(struct ext4_sblock *s, uint32_t bgid);
-
-/**@brief Returns inodes count in block group
- * (last block group may have less inodes)
- * @param s superblock descriptor
- * @param bgid block group id
- * @return inodes count*/
-uint32_t ext4_inodes_in_group_cnt(struct ext4_sblock *s, uint32_t bgid);
-
-/***************************Read/write/check superblock**********************/
-
-/**@brief Superblock write.
- * @param bdev block device descriptor.
- * @param s superblock descruptor
- * @return Standard error code */
-int ext4_sb_write(struct ext4_blockdev *bdev, struct ext4_sblock *s);
-
-/**@brief Superblock read.
- * @param bdev block device descriptor.
- * @param s superblock descruptor
- * @return Standard error code */
-int ext4_sb_read(struct ext4_blockdev *bdev, struct ext4_sblock *s);
-
-/**@brief Superblock simple validation.
- * @param s superblock dsecriptor
- * @return true if OK*/
-bool ext4_sb_check(struct ext4_sblock *s);
-
-
-#endif /* EXT4_SUPER_H_ */
-
-/**
- * @}
- */
-
--- a/src/lwext4/ext4_types.h
+++ /dev/null
@@ -1,613 +1,0 @@
-/*
- * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
- *
- *
- * HelenOS:
- * Copyright (c) 2012 Martin Sucha
- * Copyright (c) 2012 Frantisek Princ
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup lwext4
- * @{
- */
-/**
- * @file ext4_types.h
- * @brief Ext4 data structure definitions.
- */
-
-#ifndef EXT4_TYPES_H_
-#define EXT4_TYPES_H_
-
-#include <ext4_config.h>
-#include <ext4_blockdev.h>
-
-#include <stdint.h>
-
-
-/*
- * Structure of the super block
- */
-struct ext4_sblock {
- uint32_t inodes_count; /* I-nodes count */
- uint32_t blocks_count_lo; /* Blocks count */
- uint32_t reserved_blocks_count_lo; /* Reserved blocks count */
- uint32_t free_blocks_count_lo; /* Free blocks count */
- uint32_t free_inodes_count; /* Free inodes count */
- uint32_t first_data_block; /* First Data Block */
- uint32_t log_block_size; /* Block size */
- uint32_t log_frag_size; /* Obsoleted fragment size */
- uint32_t blocks_per_group; /* Number of blocks per group */
- uint32_t frags_per_group; /* Obsoleted fragments per group */
- uint32_t inodes_per_group; /* Number of inodes per group */
- uint32_t mount_time; /* Mount time */
- uint32_t write_time; /* Write time */
- uint16_t mount_count; /* Mount count */
- uint16_t max_mount_count; /* Maximal mount count */
- uint16_t magic; /* Magic signature */
- uint16_t state; /* File system state */
- uint16_t errors; /* Behaviour when detecting errors */
- uint16_t minor_rev_level; /* Minor revision level */
- uint32_t last_check_time; /* Time of last check */
- uint32_t check_interval; /* Maximum time between checks */
- uint32_t creator_os; /* Creator OS */
- uint32_t rev_level; /* Revision level */
- uint16_t def_resuid; /* Default uid for reserved blocks */
- uint16_t def_resgid; /* Default gid for reserved blocks */
-
- /* Fields for EXT4_DYNAMIC_REV superblocks only. */
- uint32_t first_inode; /* First non-reserved inode */
- uint16_t inode_size; /* Size of inode structure */
- uint16_t block_group_index; /* Block group index of this superblock */
- uint32_t features_compatible; /* Compatible feature set */
- uint32_t features_incompatible; /* Incompatible feature set */
- uint32_t features_read_only; /* Readonly-compatible feature set */
- uint8_t uuid[16]; /* 128-bit uuid for volume */
- char volume_name[16]; /* Volume name */
- char last_mounted[64]; /* Directory where last mounted */
- uint32_t algorithm_usage_bitmap; /* For compression */
-
- /*
- * Performance hints. Directory preallocation should only
- * happen if the EXT4_FEATURE_COMPAT_DIR_PREALLOC flag is on.
- */
- uint8_t s_prealloc_blocks; /* Number of blocks to try to preallocate */
- uint8_t s_prealloc_dir_blocks; /* Number to preallocate for dirs */
- uint16_t s_reserved_gdt_blocks; /* Per group desc for online growth */
-
- /*
- * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set.
- */
- uint8_t journal_uuid[16]; /* UUID of journal superblock */
- uint32_t journal_inode_number; /* Inode number of journal file */
- uint32_t journal_dev; /* Device number of journal file */
- uint32_t last_orphan; /* Head of list of inodes to delete */
- uint32_t hash_seed[4]; /* HTREE hash seed */
- uint8_t default_hash_version; /* Default hash version to use */
- uint8_t journal_backup_type;
- uint16_t desc_size; /* Size of group descriptor */
- uint32_t default_mount_opts; /* Default mount options */
- uint32_t first_meta_bg; /* First metablock block group */
- uint32_t mkfs_time; /* When the filesystem was created */
- uint32_t journal_blocks[17]; /* Backup of the journal inode */
-
- /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
- uint32_t blocks_count_hi; /* Blocks count */
- uint32_t reserved_blocks_count_hi; /* Reserved blocks count */
- uint32_t free_blocks_count_hi; /* Free blocks count */
- uint16_t min_extra_isize; /* All inodes have at least # bytes */
- uint16_t want_extra_isize; /* New inodes should reserve # bytes */
- uint32_t flags; /* Miscellaneous flags */
- uint16_t raid_stride; /* RAID stride */
- uint16_t mmp_interval; /* # seconds to wait in MMP checking */
- uint64_t mmp_block; /* Block for multi-mount protection */
- uint32_t raid_stripe_width; /* Blocks on all data disks (N * stride) */
- uint8_t log_groups_per_flex; /* FLEX_BG group size */
- uint8_t reserved_char_pad;
- uint16_t reserved_pad;
- uint64_t kbytes_written; /* Number of lifetime kilobytes written */
- uint32_t snapshot_inum; /* I-node number of active snapshot */
- uint32_t snapshot_id; /* Sequential ID of active snapshot */
- uint64_t snapshot_r_blocks_count; /* Reserved blocks for active snapshot's future use */
- uint32_t snapshot_list; /* I-node number of the head of the on-disk snapshot list */
- uint32_t error_count; /* Number of file system errors */
- uint32_t first_error_time; /* First time an error happened */
- uint32_t first_error_ino; /* I-node involved in first error */
- uint64_t first_error_block; /* Block involved of first error */
- uint8_t first_error_func[32]; /* Function where the error happened */
- uint32_t first_error_line; /* Line number where error happened */
- uint32_t last_error_time; /* Most recent time of an error */
- uint32_t last_error_ino; /* I-node involved in last error */
- uint32_t last_error_line; /* Line number where error happened */
- uint64_t last_error_block; /* Block involved of last error */
- uint8_t last_error_func[32]; /* Function where the error happened */
- uint8_t mount_opts[64];
- uint32_t padding[112]; /* Padding to the end of the block */
-} __attribute__((packed));
-
-
-#define EXT4_SUPERBLOCK_MAGIC 0xEF53
-#define EXT4_SUPERBLOCK_SIZE 1024
-#define EXT4_SUPERBLOCK_OFFSET 1024
-
-#define EXT4_SUPERBLOCK_OS_LINUX 0
-#define EXT4_SUPERBLOCK_OS_HURD 1
-
-/*
- * Misc. filesystem flags
- */
-#define EXT4_SUPERBLOCK_FLAGS_SIGNED_HASH 0x0001 /* Signed dirhash in use */
-#define EXT4_SUPERBLOCK_FLAGS_UNSIGNED_HASH 0x0002 /* Unsigned dirhash in use */
-#define EXT4_SUPERBLOCK_FLAGS_TEST_FILESYS 0x0004 /* to test development code */
-
-/*
- * Filesystem states
- */
-#define EXT4_SUPERBLOCK_STATE_VALID_FS 0x0001 /* Unmounted cleanly */
-#define EXT4_SUPERBLOCK_STATE_ERROR_FS 0x0002 /* Errors detected */
-#define EXT4_SUPERBLOCK_STATE_ORPHAN_FS 0x0004 /* Orphans being recovered */
-
-/*
- * Behaviour when errors detected
- */
-#define EXT4_SUPERBLOCK_ERRORS_CONTINUE 1 /* Continue execution */
-#define EXT4_SUPERBLOCK_ERRORS_RO 2 /* Remount fs read-only */
-#define EXT4_SUPERBLOCK_ERRORS_PANIC 3 /* Panic */
-#define EXT4_SUPERBLOCK_ERRORS_DEFAULT EXT4_ERRORS_CONTINUE
-
-/*
- * Compatible features
- */
-#define EXT4_FEATURE_COMPAT_DIR_PREALLOC 0x0001
-#define EXT4_FEATURE_COMPAT_IMAGIC_INODES 0x0002
-#define EXT4_FEATURE_COMPAT_HAS_JOURNAL 0x0004
-#define EXT4_FEATURE_COMPAT_EXT_ATTR 0x0008
-#define EXT4_FEATURE_COMPAT_RESIZE_INODE 0x0010
-#define EXT4_FEATURE_COMPAT_DIR_INDEX 0x0020
-
-/*
- * Read-only compatible features
- */
-#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
-#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
-#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
-#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008
-#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
-#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
-#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
-
-/*
- * Incompatible features
- */
-#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001
-#define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002
-#define EXT4_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
-#define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
-#define EXT4_FEATURE_INCOMPAT_META_BG 0x0010
-#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */
-#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
-#define EXT4_FEATURE_INCOMPAT_MMP 0x0100
-#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
-#define EXT4_FEATURE_INCOMPAT_EA_INODE 0x0400 /* EA in inode */
-#define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000 /* data in dirent */
-
-#define EXT4_FEATURE_COMPAT_SUPP (EXT4_FEATURE_COMPAT_DIR_INDEX)
-
-#define EXT4_FEATURE_INCOMPAT_SUPP \
- (EXT4_FEATURE_INCOMPAT_FILETYPE | \
- EXT4_FEATURE_INCOMPAT_EXTENTS | \
- EXT4_FEATURE_INCOMPAT_64BIT)
-
-#define EXT4_FEATURE_RO_COMPAT_SUPP \
- (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER | \
- EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \
- EXT4_FEATURE_RO_COMPAT_HUGE_FILE | \
- EXT4_FEATURE_RO_COMPAT_LARGE_FILE | \
- EXT4_FEATURE_RO_COMPAT_GDT_CSUM | \
- EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)
-
-struct ext4_fs {
- struct ext4_blockdev *bdev;
- struct ext4_sblock sb;
-
- uint64_t inode_block_limits[4];
- uint64_t inode_blocks_per_level[4];
-};
-
-
-#define EXT4_BLOCK_GROUP_INODE_UNINIT 0x0001 /* Inode table/bitmap not in use */
-#define EXT4_BLOCK_GROUP_BLOCK_UNINIT 0x0002 /* Block bitmap not in use */
-#define EXT4_BLOCK_GROUP_ITABLE_ZEROED 0x0004 /* On-disk itable initialized to zero */
-
-/*
- * Structure of a blocks group descriptor
- */
-struct ext4_bgroup {
- uint32_t block_bitmap_lo; /* Blocks bitmap block */
- uint32_t inode_bitmap_lo; /* Inodes bitmap block */
- uint32_t inode_table_first_block_lo; /* Inodes table block */
- uint16_t free_blocks_count_lo; /* Free blocks count */
- uint16_t free_inodes_count_lo; /* Free inodes count */
- uint16_t used_dirs_count_lo; /* Directories count */
- uint16_t flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */
- uint32_t reserved[2]; /* Likely block/inode bitmap checksum */
- uint16_t itable_unused_lo; /* Unused inodes count */
- uint16_t checksum; /* crc16(sb_uuid+group+desc) */
-
- uint32_t block_bitmap_hi; /* Blocks bitmap block MSB */
- uint32_t inode_bitmap_hi; /* I-nodes bitmap block MSB */
- uint32_t inode_table_first_block_hi; /* I-nodes table block MSB */
- uint16_t free_blocks_count_hi; /* Free blocks count MSB */
- uint16_t free_inodes_count_hi; /* Free i-nodes count MSB */
- uint16_t used_dirs_count_hi; /* Directories count MSB */
- uint16_t itable_unused_hi; /* Unused inodes count MSB */
- uint32_t reserved2[3]; /* Padding */
-} ;
-
-struct ext4_block_group_ref {
- struct ext4_block block;
- struct ext4_bgroup *block_group;
- struct ext4_fs *fs;
- uint32_t index;
- bool dirty;
-};
-
-#define EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE 32
-#define EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE 64
-
-#define EXT4_MIN_BLOCK_SIZE 1024 /* 1 KiB */
-#define EXT4_MAX_BLOCK_SIZE 65536 /* 64 KiB */
-#define EXT4_REV0_INODE_SIZE 128
-
-#define EXT4_INODE_BLOCK_SIZE 512
-
-#define EXT4_INODE_DIRECT_BLOCK_COUNT 12
-#define EXT4_INODE_INDIRECT_BLOCK EXT4_INODE_DIRECT_BLOCK_COUNT
-#define EXT4_INODE_DOUBLE_INDIRECT_BLOCK (EXT4_INODE_INDIRECT_BLOCK + 1)
-#define EXT4_INODE_TRIPPLE_INDIRECT_BLOCK (EXT4_INODE_DOUBLE_INDIRECT_BLOCK + 1)
-#define EXT4_INODE_BLOCKS (EXT4_INODE_TRIPPLE_INDIRECT_BLOCK + 1)
-#define EXT4_INODE_INDIRECT_BLOCK_COUNT (EXT4_INODE_BLOCKS - EXT4_INODE_DIRECT_BLOCK_COUNT)
-
-/*
- * Structure of an inode on the disk
- */
-struct ext4_inode {
- uint16_t mode; /* File mode */
- uint16_t uid; /* Low 16 bits of owner uid */
- uint32_t size_lo; /* Size in bytes */
- uint32_t access_time; /* Access time */
- uint32_t change_inode_time; /* I-node change time */
- uint32_t modification_time; /* Modification time */
- uint32_t deletion_time; /* Deletion time */
- uint16_t gid; /* Low 16 bits of group id */
- uint16_t links_count; /* Links count */
- uint32_t blocks_count_lo; /* Blocks count */
- uint32_t flags; /* File flags */
- uint32_t unused_osd1; /* OS dependent - not used in HelenOS */
- uint32_t blocks[EXT4_INODE_BLOCKS]; /* Pointers to blocks */
- uint32_t generation; /* File version (for NFS) */
- uint32_t file_acl_lo; /* File ACL */
- uint32_t size_hi;
- uint32_t obso_faddr; /* Obsoleted fragment address */
-
- union {
- struct {
- uint16_t blocks_high;
- uint16_t file_acl_high;
- uint16_t uid_high;
- uint16_t gid_high;
- uint32_t reserved2;
- } linux2;
- struct {
- uint16_t reserved1;
- uint16_t mode_high;
- uint16_t uid_high;
- uint16_t gid_high;
- uint32_t author;
- } hurd2;
- } __attribute__ ((packed)) osd2;
-
- uint16_t extra_isize;
- uint16_t pad1;
- uint32_t ctime_extra; /* Extra change time (nsec << 2 | epoch) */
- uint32_t mtime_extra; /* Extra Modification time (nsec << 2 | epoch) */
- uint32_t atime_extra; /* Extra Access time (nsec << 2 | epoch) */
- uint32_t crtime; /* File creation time */
- uint32_t crtime_extra; /* Extra file creation time (nsec << 2 | epoch) */
- uint32_t version_hi; /* High 32 bits for 64-bit version */
-} __attribute__ ((packed)) ;
-
-#define EXT4_INODE_MODE_FIFO 0x1000
-#define EXT4_INODE_MODE_CHARDEV 0x2000
-#define EXT4_INODE_MODE_DIRECTORY 0x4000
-#define EXT4_INODE_MODE_BLOCKDEV 0x6000
-#define EXT4_INODE_MODE_FILE 0x8000
-#define EXT4_INODE_MODE_SOFTLINK 0xA000
-#define EXT4_INODE_MODE_SOCKET 0xC000
-#define EXT4_INODE_MODE_TYPE_MASK 0xF000
-
-/*
- * Inode flags
- */
-#define EXT4_INODE_FLAG_SECRM 0x00000001 /* Secure deletion */
-#define EXT4_INODE_FLAG_UNRM 0x00000002 /* Undelete */
-#define EXT4_INODE_FLAG_COMPR 0x00000004 /* Compress file */
-#define EXT4_INODE_FLAG_SYNC 0x00000008 /* Synchronous updates */
-#define EXT4_INODE_FLAG_IMMUTABLE 0x00000010 /* Immutable file */
-#define EXT4_INODE_FLAG_APPEND 0x00000020 /* writes to file may only append */
-#define EXT4_INODE_FLAG_NODUMP 0x00000040 /* do not dump file */
-#define EXT4_INODE_FLAG_NOATIME 0x00000080 /* do not update atime */
-
-/* Compression flags */
-#define EXT4_INODE_FLAG_DIRTY 0x00000100
-#define EXT4_INODE_FLAG_COMPRBLK 0x00000200 /* One or more compressed clusters */
-#define EXT4_INODE_FLAG_NOCOMPR 0x00000400 /* Don't compress */
-#define EXT4_INODE_FLAG_ECOMPR 0x00000800 /* Compression error */
-
-#define EXT4_INODE_FLAG_INDEX 0x00001000 /* hash-indexed directory */
-#define EXT4_INODE_FLAG_IMAGIC 0x00002000 /* AFS directory */
-#define EXT4_INODE_FLAG_JOURNAL_DATA 0x00004000 /* File data should be journaled */
-#define EXT4_INODE_FLAG_NOTAIL 0x00008000 /* File tail should not be merged */
-#define EXT4_INODE_FLAG_DIRSYNC 0x00010000 /* Dirsync behaviour (directories only) */
-#define EXT4_INODE_FLAG_TOPDIR 0x00020000 /* Top of directory hierarchies */
-#define EXT4_INODE_FLAG_HUGE_FILE 0x00040000 /* Set to each huge file */
-#define EXT4_INODE_FLAG_EXTENTS 0x00080000 /* Inode uses extents */
-#define EXT4_INODE_FLAG_EA_INODE 0x00200000 /* Inode used for large EA */
-#define EXT4_INODE_FLAG_EOFBLOCKS 0x00400000 /* Blocks allocated beyond EOF */
-#define EXT4_INODE_FLAG_RESERVED 0x80000000 /* reserved for ext4 lib */
-
-#define EXT4_INODE_ROOT_INDEX 2
-
-struct ext4_inode_ref {
- struct ext4_block block;
- struct ext4_inode *inode;
- struct ext4_fs *fs;
- uint32_t index;
- bool dirty;
-} ;
-
-
-#define EXT4_DIRECTORY_FILENAME_LEN 255
-
-#define EXT4_DIRECTORY_FILETYPE_UNKNOWN 0
-#define EXT4_DIRECTORY_FILETYPE_REG_FILE 1
-#define EXT4_DIRECTORY_FILETYPE_DIR 2
-#define EXT4_DIRECTORY_FILETYPE_CHRDEV 3
-#define EXT4_DIRECTORY_FILETYPE_BLKDEV 4
-#define EXT4_DIRECTORY_FILETYPE_FIFO 5
-#define EXT4_DIRECTORY_FILETYPE_SOCK 6
-#define EXT4_DIRECTORY_FILETYPE_SYMLINK 7
-
-/**
- * Linked list directory entry structure
- */
-struct ext4_directory_entry_ll {
- uint32_t inode; /* I-node for the entry */
- uint16_t entry_length; /* Distance to the next directory entry */
- uint8_t name_length; /* Lower 8 bits of name length */
-
- union {
- uint8_t name_length_high; /* Higher 8 bits of name length */
- uint8_t inode_type; /* Type of referenced inode (in rev >= 0.5) */
- } __attribute__ ((packed));
-
- uint8_t name[EXT4_DIRECTORY_FILENAME_LEN]; /* Entry name */
-} __attribute__((packed)) ;
-
-struct ext4_directory_iterator {
- struct ext4_inode_ref *inode_ref;
- struct ext4_block current_block;
- uint64_t current_offset;
- struct ext4_directory_entry_ll *current;
-};
-
-struct ext4_directory_search_result {
- struct ext4_block block;
- struct ext4_directory_entry_ll *dentry;
-};
-
-/* Structures for indexed directory */
-
-struct ext4_directory_dx_countlimit {
- uint16_t limit;
- uint16_t count;
-} ;
-
-struct ext4_directory_dx_dot_entry {
- uint32_t inode;
- uint16_t entry_length;
- uint8_t name_length;
- uint8_t inode_type;
- uint8_t name[4];
-} ;
-
-struct ext4_directory_dx_root_info {
- uint32_t reserved_zero;
- uint8_t hash_version;
- uint8_t info_length;
- uint8_t indirect_levels;
- uint8_t unused_flags;
-} ;
-
-struct ext4_directory_dx_entry {
- uint32_t hash;
- uint32_t block;
-} ;
-
-struct ext4_directory_dx_root {
- struct ext4_directory_dx_dot_entry dots[2];
- struct ext4_directory_dx_root_info info;
- struct ext4_directory_dx_entry entries[0];
-};
-
-struct ext4_fake_directory_entry {
- uint32_t inode;
- uint16_t entry_length;
- uint8_t name_length;
- uint8_t inode_type;
-};
-
-struct ext4_directory_dx_node {
- struct ext4_fake_directory_entry fake;
- struct ext4_directory_dx_entry entries[0];
-};
-
-struct ext4_directory_dx_block {
- struct ext4_block block;
- struct ext4_directory_dx_entry *entries;
- struct ext4_directory_dx_entry *position;
-} ;
-
-#define EXT4_ERR_BAD_DX_DIR (-75000)
-
-
-/*
- * This is the extent on-disk structure.
- * It's used at the bottom of the tree.
- */
-struct ext4_extent {
- uint32_t first_block; /* First logical block extent covers */
- uint16_t block_count; /* Number of blocks covered by extent */
- uint16_t start_hi; /* High 16 bits of physical block */
- uint32_t start_lo; /* Low 32 bits of physical block */
-} ;
-
-/*
- * This is index on-disk structure.
- * It's used at all the levels except the bottom.
- */
-struct ext4_extent_index {
- uint32_t first_block; /* Index covers logical blocks from 'block' */
-
- /**
- * Pointer to the physical block of the next
- * level. leaf or next index could be there
- * high 16 bits of physical block
- */
- uint32_t leaf_lo;
- uint16_t leaf_hi;
- uint16_t padding;
-} ;
-
-/*
- * Each block (leaves and indexes), even inode-stored has header.
- */
-struct ext4_extent_header {
- uint16_t magic;
- uint16_t entries_count; /* Number of valid entries */
- uint16_t max_entries_count; /* Capacity of store in entries */
- uint16_t depth; /* Has tree real underlying blocks? */
- uint32_t generation; /* generation of the tree */
-} ;
-
-struct ext4_extent_path {
- struct ext4_block block;
- uint16_t depth;
- struct ext4_extent_header *header;
- struct ext4_extent_index *index;
- struct ext4_extent *extent;
-} ;
-
-#define EXT4_EXTENT_MAGIC 0xF30A
-
-#define EXT4_EXTENT_FIRST(header) \
- ((struct ext4_extent *) (((void *) (header)) + sizeof(struct ext4_extent_header)))
-
-#define EXT4_EXTENT_FIRST_INDEX(header) \
- ((struct ext4_extent_index *) (((void *) (header)) + sizeof(struct ext4_extent_header)))
-
-
-/* EXT3 HTree directory indexing */
-#define EXT2_HTREE_LEGACY 0
-#define EXT2_HTREE_HALF_MD4 1
-#define EXT2_HTREE_TEA 2
-#define EXT2_HTREE_LEGACY_UNSIGNED 3
-#define EXT2_HTREE_HALF_MD4_UNSIGNED 4
-#define EXT2_HTREE_TEA_UNSIGNED 5
-
-#define EXT2_HTREE_EOF 0x7FFFFFFF
-
-
-struct ext4_hash_info {
- uint32_t hash;
- uint32_t minor_hash;
- uint32_t hash_version;
- const uint32_t *seed;
-};
-
-/*****************************************************************************/
-
-
-#ifdef CONFIG_BIG_ENDIAN
-static inline uint64_t to_le64(uint64_t n)
-{
- return ((n & 0xff) << 56) |
- ((n & 0xff00) << 40) |
- ((n & 0xff0000) << 24) |
- ((n & 0xff000000LL) << 8) |
- ((n & 0xff00000000LL) >> 8) |
- ((n & 0xff0000000000LL) >> 24) |
- ((n & 0xff000000000000LL) >> 40) |
- ((n & 0xff00000000000000LL) >> 56);
-}
-
-static inline uint32_t to_le32(uint32_t n)
-{
- return ((n & 0xff) << 24) |
- ((n & 0xff00) << 8) |
- ((n & 0xff0000) >> 8) |
- ((n & 0xff000000) >> 24);
-}
-
-static inline uint16_t to_le16(uint16_t n)
-{
- return ((n & 0xff) << 8) |
- ((n & 0xff00) >> 8);
-}
-
-
-#else
-#define to_le64(_n) _n
-#define to_le32(_n) _n
-#define to_le16(_n) _n
-#endif
-
-/****************************Access macros to ext4 structures*****************/
-
-#define ext4_get32(s, f) to_le32((s)->f)
-#define ext4_get16(s, f) to_le16((s)->f)
-#define ext4_get8(s, f) (s)->f
-
-
-#define ext4_set32(s, f, v) do { (s)->f = to_le32(v); }while(0)
-#define ext4_set16(s, f, v) do { (s)->f = to_le16(v); }while(0)
-#define ext4_set8 (s, f, v) do { (s)->f = (v); }while(0)
-
-#endif /* EXT4_TYPES_H_ */
-
-/**
- * @}
- */
--- a/src/toolchain/bf518.cmake
+++ /dev/null
@@ -1,22 +1,0 @@
-# Name of the target
-SET(CMAKE_SYSTEM_NAME Generic)
-set(CMAKE_SYSTEM_PROCESSOR bf518)
-
-# Toolchain settings
-set(CMAKE_C_COMPILER bfin-elf-gcc)
-set(CMAKE_CXX_COMPILER bfin-elf-g++)
-set(AS bfin-elf--gcc)
-set(AR bfin-elf-ar)
-set(OBJCOPY bfin-elf-objcopy)
-set(OBJDUMP bfin-elf-objdump)
-set(SIZE bfin-elf-size)
-
-set(CMAKE_C_FLAGS "-mcpu=bf518 -Wall -std=gnu99 -fdata-sections -ffunction-sections" CACHE INTERNAL "c compiler flags")
-set(CMAKE_CXX_FLAGS "-mcpu=bf518 -fno-builtin -Wall -fdata-sections -ffunction-sections" CACHE INTERNAL "cxx compiler flags")
-set(CMAKE_ASM_FLAGS "-mcpu=bf518 -x assembler-with-cpp" CACHE INTERNAL "asm compiler flags")
-set(CMAKE_EXE_LINKER_FLAGS "-nostartfiles -Wl,--gc-sections -mcpu=bf592" CACHE INTERNAL "exe link flags")
-
-
-
-
-
\ No newline at end of file
--- a/src/toolchain/cortex-m3.cmake
+++ /dev/null
@@ -1,18 +1,0 @@
-# Name of the target
-SET(CMAKE_SYSTEM_NAME Generic)
-set(CMAKE_SYSTEM_PROCESSOR cortex-m3)
-
-# Toolchain settings
-set(CMAKE_C_COMPILER arm-none-eabi-gcc)
-set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
-set(AS arm-none-eabi-as)
-set(AR arm-none-eabi-ar)
-set(OBJCOPY arm-none-eabi-objcopy)
-set(OBJDUMP arm-none-eabi-objdump)
-set(SIZE arm-none-eabi-size)
-
-set(CMAKE_C_FLAGS "-mthumb -mcpu=cortex-m3 -fno-builtin -Wall -std=gnu99 -fdata-sections -ffunction-sections" CACHE INTERNAL "c compiler flags")
-set(CMAKE_CXX_FLAGS "-mthumb -mcpu=cortex-m3 -fno-builtin -Wall -fdata-sections -ffunction-sections" CACHE INTERNAL "cxx compiler flags")
-set(CMAKE_ASM_FLAGS "-mthumb -mcpu=cortex-m3" CACHE INTERNAL "asm compiler flags")
-set(CMAKE_EXE_LINKER_FLAGS "-nostartfiles -Wl,--gc-sections -mthumb -mcpu=cortex-m3" CACHE INTERNAL "exe link flags")
-
--- a/src/toolchain/cortex-m4.cmake
+++ /dev/null
@@ -1,18 +1,0 @@
-# Name of the target
-SET(CMAKE_SYSTEM_NAME Generic)
-set(CMAKE_SYSTEM_PROCESSOR cortex-m4)
-
-# Toolchain settings
-set(CMAKE_C_COMPILER arm-none-eabi-gcc)
-set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
-set(AS arm-none-eabi-as)
-set(AR arm-none-eabi-ar)
-set(OBJCOPY arm-none-eabi-objcopy)
-set(OBJDUMP arm-none-eabi-objdump)
-set(SIZE arm-none-eabi-size)
-
-set(CMAKE_C_FLAGS "-mthumb -mcpu=cortex-m4 -fno-builtin -Wall -std=gnu99 -fdata-sections -ffunction-sections" CACHE INTERNAL "c compiler flags")
-set(CMAKE_CXX_FLAGS "-mthumb -mcpu=cortex-m4 -fno-builtin -Wall -fdata-sections -ffunction-sections" CACHE INTERNAL "cxx compiler flags")
-set(CMAKE_ASM_FLAGS "-mthumb -mcpu=cortex-m4" CACHE INTERNAL "asm compiler flags")
-set(CMAKE_EXE_LINKER_FLAGS "-nostartfiles -Wl,--gc-sections -mthumb -mcpu=cortex-m4" CACHE INTERNAL "exe link flags")
-
--- /dev/null
+++ b/toolchain/bf518.cmake
@@ -1,0 +1,22 @@
+# Name of the target
+SET(CMAKE_SYSTEM_NAME Generic)
+set(CMAKE_SYSTEM_PROCESSOR bf518)
+
+# Toolchain settings
+set(CMAKE_C_COMPILER bfin-elf-gcc)
+set(CMAKE_CXX_COMPILER bfin-elf-g++)
+set(AS bfin-elf--gcc)
+set(AR bfin-elf-ar)
+set(OBJCOPY bfin-elf-objcopy)
+set(OBJDUMP bfin-elf-objdump)
+set(SIZE bfin-elf-size)
+
+set(CMAKE_C_FLAGS "-mcpu=bf518 -Wall -std=gnu99 -fdata-sections -ffunction-sections" CACHE INTERNAL "c compiler flags")
+set(CMAKE_CXX_FLAGS "-mcpu=bf518 -fno-builtin -Wall -fdata-sections -ffunction-sections" CACHE INTERNAL "cxx compiler flags")
+set(CMAKE_ASM_FLAGS "-mcpu=bf518 -x assembler-with-cpp" CACHE INTERNAL "asm compiler flags")
+set(CMAKE_EXE_LINKER_FLAGS "-nostartfiles -Wl,--gc-sections -mcpu=bf592" CACHE INTERNAL "exe link flags")
+
+
+
+
+
\ No newline at end of file
--- /dev/null
+++ b/toolchain/cortex-m3.cmake
@@ -1,0 +1,18 @@
+# Name of the target
+SET(CMAKE_SYSTEM_NAME Generic)
+set(CMAKE_SYSTEM_PROCESSOR cortex-m3)
+
+# Toolchain settings
+set(CMAKE_C_COMPILER arm-none-eabi-gcc)
+set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
+set(AS arm-none-eabi-as)
+set(AR arm-none-eabi-ar)
+set(OBJCOPY arm-none-eabi-objcopy)
+set(OBJDUMP arm-none-eabi-objdump)
+set(SIZE arm-none-eabi-size)
+
+set(CMAKE_C_FLAGS "-mthumb -mcpu=cortex-m3 -fno-builtin -Wall -std=gnu99 -fdata-sections -ffunction-sections" CACHE INTERNAL "c compiler flags")
+set(CMAKE_CXX_FLAGS "-mthumb -mcpu=cortex-m3 -fno-builtin -Wall -fdata-sections -ffunction-sections" CACHE INTERNAL "cxx compiler flags")
+set(CMAKE_ASM_FLAGS "-mthumb -mcpu=cortex-m3" CACHE INTERNAL "asm compiler flags")
+set(CMAKE_EXE_LINKER_FLAGS "-nostartfiles -Wl,--gc-sections -mthumb -mcpu=cortex-m3" CACHE INTERNAL "exe link flags")
+
--- /dev/null
+++ b/toolchain/cortex-m4.cmake
@@ -1,0 +1,18 @@
+# Name of the target
+SET(CMAKE_SYSTEM_NAME Generic)
+set(CMAKE_SYSTEM_PROCESSOR cortex-m4)
+
+# Toolchain settings
+set(CMAKE_C_COMPILER arm-none-eabi-gcc)
+set(CMAKE_CXX_COMPILER arm-none-eabi-g++)
+set(AS arm-none-eabi-as)
+set(AR arm-none-eabi-ar)
+set(OBJCOPY arm-none-eabi-objcopy)
+set(OBJDUMP arm-none-eabi-objdump)
+set(SIZE arm-none-eabi-size)
+
+set(CMAKE_C_FLAGS "-mthumb -mcpu=cortex-m4 -fno-builtin -Wall -std=gnu99 -fdata-sections -ffunction-sections" CACHE INTERNAL "c compiler flags")
+set(CMAKE_CXX_FLAGS "-mthumb -mcpu=cortex-m4 -fno-builtin -Wall -fdata-sections -ffunction-sections" CACHE INTERNAL "cxx compiler flags")
+set(CMAKE_ASM_FLAGS "-mthumb -mcpu=cortex-m4" CACHE INTERNAL "asm compiler flags")
+set(CMAKE_EXE_LINKER_FLAGS "-nostartfiles -Wl,--gc-sections -mthumb -mcpu=cortex-m4" CACHE INTERNAL "exe link flags")
+