Support XiZi_AIoT
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
SRC_DIR := fs
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,17 @@
|
||||
toolchain ?= arm-none-eabi-
|
||||
cc = ${toolchain}gcc
|
||||
ld = ${toolchain}g++
|
||||
objdump = ${toolchain}objdump
|
||||
user_ldflags = -N -Ttext 0
|
||||
|
||||
cflags = -march=armv7-a -mtune=cortex-a9 -nostdlib -nodefaultlibs -mfloat-abi=soft -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -ggdb -Wno-unused -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pie -no-pie
|
||||
c_useropts = -O0
|
||||
|
||||
INC_DIR = -I$(KERNEL_ROOT)/services/fs/include -I$(KERNEL_ROOT)/services/lib/ipc -I$(KERNEL_ROOT)/services/boards/imx6q-sabrelite
|
||||
|
||||
fs_server: fs_server.o fs_service.o fs.o block_io.o
|
||||
@mv $^ ../../boards/imx6q-sabrelite
|
||||
|
||||
%.o: %.c
|
||||
@echo "cc $^"
|
||||
@${cc} ${cflags} ${c_useropts} ${INC_DIR} -o $@ -c $^
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "block_io.h"
|
||||
#include "libserial.h"
|
||||
#include "fs.h"
|
||||
#include "list.h"
|
||||
|
||||
static void Error(char* s)
|
||||
{
|
||||
printf("Error: %s\n", s);
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
|
||||
// Locate the data block using block_num
|
||||
uint8_t* BlockRead(int block_num)
|
||||
{
|
||||
uint8_t* data = (uint8_t*)MemFsRange.memfs_start + block_num * BLOCK_SIZE;
|
||||
return data;
|
||||
}
|
||||
|
||||
// Zero a block.
|
||||
static void BlockClear(int block_num)
|
||||
{
|
||||
uint8_t* data = BlockRead(block_num);
|
||||
memset(data, 0, BLOCK_SIZE);
|
||||
}
|
||||
|
||||
// Allocate a zeroed disk block.
|
||||
uint32_t BlockAlloc()
|
||||
{
|
||||
int bit_index, block_index, bit_mark;
|
||||
|
||||
struct SuperBlock sb;
|
||||
|
||||
ReadSuperBlock(&sb);
|
||||
|
||||
for (bit_index = 0; bit_index < sb.size; bit_index += BITMAP_SIZE) {
|
||||
|
||||
uint8_t* data = BlockRead(BLOCK_BIT_INDEX(bit_index, sb.ninodes));
|
||||
|
||||
for (block_index = 0; block_index < BITMAP_SIZE && bit_index + block_index < sb.size; block_index++) {
|
||||
bit_mark = 1 << (block_index % 8);
|
||||
|
||||
if ((data[block_index / 8] & bit_mark) == 0) {
|
||||
data[block_index / 8] |= bit_mark;
|
||||
|
||||
BlockClear(bit_index + block_index);
|
||||
return bit_index + block_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Error("BlockAlloc: out of blocks");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Free a disk block.
|
||||
void BlockFree(int block_num)
|
||||
{
|
||||
struct SuperBlock sb;
|
||||
int block_index, bit_mark;
|
||||
|
||||
ReadSuperBlock(&sb);
|
||||
|
||||
uint8_t* data = BlockRead(BLOCK_BIT_INDEX(block_num, sb.ninodes));
|
||||
|
||||
block_index = block_num % BITMAP_SIZE;
|
||||
bit_mark = 1 << (block_index % 8);
|
||||
|
||||
if ((data[block_index / 8] & bit_mark) == 0) {
|
||||
Error("freeing free block");
|
||||
}
|
||||
|
||||
data[block_index / 8] &= ~bit_mark;
|
||||
}
|
||||
@@ -0,0 +1,482 @@
|
||||
// Copyright (c) 2006-2018 Frans Kaashoek, Robert Morris, Russ Cox, Massachusetts Institute of Technology
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
/**
|
||||
* @file fs.c
|
||||
* @brief support read and write the fs.img
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2024-01-25
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: fs.c
|
||||
Description: support read and write the fs.img
|
||||
Others: take ARM_XV6 kernel/fs.c for references
|
||||
https://github.com/KingofHamyang/ARM_xv6
|
||||
History:
|
||||
1. Date: 2024-01-25
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. support inode create and delete
|
||||
3. remove inode lock and unlock
|
||||
4. remove inode cache
|
||||
*************************************************/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "block_io.h"
|
||||
#include "libserial.h"
|
||||
#include "fs.h"
|
||||
|
||||
static void Error(char* s)
|
||||
{
|
||||
printf("Error: %s\n", s);
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
static int DirInodeAddEntry(struct Inode* dp, char* name, uint32_t inum);
|
||||
static struct Inode* DirInodeLookup(struct Inode* dp, char* name, uint32_t* poff);
|
||||
static struct Inode* InodeAlloc(short type);
|
||||
static int InodeFree(struct Inode* ip);
|
||||
static int InodeFreeRecursive(struct Inode* dp);
|
||||
static char* PathElementExtract(char* path, char* name);
|
||||
static uint32_t InodeBlockMapping(struct Inode* ip, uint32_t block_num);
|
||||
|
||||
#define MAX_SUPPORT_FD 1024
|
||||
static struct FileDescriptor fd_table[MAX_SUPPORT_FD];
|
||||
|
||||
struct MemFsRange MemFsRange;
|
||||
|
||||
/// @brief Using syscall to get fs.img real location in the memory
|
||||
void MemFsInit(uintptr_t _binary_fs_img_start, uint32_t fs_img_len)
|
||||
{
|
||||
MemFsRange.memfs_start = _binary_fs_img_start;
|
||||
MemFsRange.memfs_nr_blocks = fs_img_len / BLOCK_SIZE;
|
||||
}
|
||||
|
||||
/// @brief Read the super block.
|
||||
void ReadSuperBlock(struct SuperBlock* sb)
|
||||
{
|
||||
uint8_t* data = BlockRead(ROOT_INUM);
|
||||
memmove(sb, data, sizeof(*sb));
|
||||
}
|
||||
|
||||
/// @brief Get a existed Inode by inum
|
||||
struct Inode* InodeGet(uint32_t inum)
|
||||
{
|
||||
struct Inode* ip;
|
||||
uint8_t* data = BlockRead(BLOCK_INDEX(inum));
|
||||
ip = (struct Inode*)data + INODE_INDEX(inum);
|
||||
return ip;
|
||||
}
|
||||
|
||||
/// @brief Alloc a new Inode using type
|
||||
static struct Inode* InodeAlloc(short type)
|
||||
{
|
||||
int inum;
|
||||
struct Inode* ip;
|
||||
struct SuperBlock sb;
|
||||
|
||||
ReadSuperBlock(&sb);
|
||||
for (inum = 1; inum < sb.ninodes; inum++) {
|
||||
uint8_t* data = BlockRead(BLOCK_INDEX(inum));
|
||||
ip = (struct Inode*)data + INODE_INDEX(inum);
|
||||
if (ip->type == 0) {
|
||||
memset(ip, 0, sizeof(*ip));
|
||||
ip->inum = inum;
|
||||
ip->type = type;
|
||||
ip->nlink = 1;
|
||||
ip->size = 0;
|
||||
return ip;
|
||||
}
|
||||
}
|
||||
|
||||
Error("InodeAlloc: no inodes");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// @brief Free the existed Inode
|
||||
static int InodeFree(struct Inode* ip)
|
||||
{
|
||||
uint8_t* data = BlockRead(BLOCK_INDEX(ip->inum));
|
||||
struct Inode* dip = (struct Inode*)data + INODE_INDEX(ip->inum);
|
||||
dip->type = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief Delete the dir and all files or dirs under the dir.
|
||||
static int InodeFreeRecursive(struct Inode* dp)
|
||||
{
|
||||
uint32_t off;
|
||||
struct Inode* ip;
|
||||
struct DirectEntry de;
|
||||
|
||||
for (off = 0; off < dp->size; off += sizeof(de)) {
|
||||
if (InodeRead(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
|
||||
Error("inode_delete_dir failed: read directory entry failed");
|
||||
}
|
||||
|
||||
// unlink dir
|
||||
if (de.inum == 0 || strcmp(de.name, "..") == 0 || strcmp(de.name, ".") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ip = InodeGet(de.inum);
|
||||
if (ip->type == T_DIR) {
|
||||
if (InodeFreeRecursive(ip) < 0) {
|
||||
return -1;
|
||||
}
|
||||
} else if (ip->type == T_FILE) {
|
||||
InodeFree(ip);
|
||||
}
|
||||
|
||||
// delete the dir entry
|
||||
de.inum = 0;
|
||||
if (InodeWrite(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
|
||||
printf("InodeDelete failed: clear directory entry failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief Delete a file Inode or a dir Inode
|
||||
int InodeDelete(struct Inode* dp, char* name)
|
||||
{
|
||||
uint32_t off;
|
||||
struct Inode* ip;
|
||||
struct DirectEntry de;
|
||||
|
||||
if ((ip = DirInodeLookup(dp, name, &off)) == 0) {
|
||||
Error("Inode delete failed, file not exsit");
|
||||
return -1;
|
||||
}
|
||||
|
||||
InodeFree(ip);
|
||||
if (ip->type == T_DIR) {
|
||||
// recursive free alloced Inode
|
||||
if (InodeFreeRecursive(ip) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// delete the dir entry
|
||||
de.inum = 0;
|
||||
if (InodeWrite(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
|
||||
printf("InodeDelete failed: clear directory entry failed");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief Create a new Inode under the parent Inode
|
||||
struct Inode* InodeCreate(struct Inode* dp, char* name, short type, short major, short minor)
|
||||
{
|
||||
uint32_t off;
|
||||
struct Inode* ip;
|
||||
|
||||
if ((ip = DirInodeLookup(dp, name, &off)) != 0) {
|
||||
if (type == T_FILE && ip->type == T_FILE) {
|
||||
return ip;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((ip = InodeAlloc(type)) == 0) {
|
||||
Error("InodeCreate: create Inode failed\n");
|
||||
}
|
||||
|
||||
if (type == T_DIR) {
|
||||
dp->nlink++;
|
||||
if (DirInodeAddEntry(ip, ".", ip->inum) < 0 || DirInodeAddEntry(ip, "..", dp->inum) < 0) {
|
||||
Error("InodeCreate: create dots");
|
||||
}
|
||||
}
|
||||
|
||||
if (DirInodeAddEntry(dp, name, ip->inum) < 0) {
|
||||
Error("InodeCreate: DirInodeAddEntry failed");
|
||||
}
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
||||
/// @brief Mapping the direct block addrs or indirect block addrs of the Inode using the block_num
|
||||
static uint32_t InodeBlockMapping(struct Inode* ip, uint32_t block_num)
|
||||
{
|
||||
uint32_t addr;
|
||||
// block is in range of direct mapping
|
||||
if (block_num < NR_DIRECT_BLOCKS) {
|
||||
if ((addr = ip->addrs[block_num]) == 0) {
|
||||
ip->addrs[block_num] = addr = BlockAlloc();
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
// alloc a new indirect indexing block
|
||||
block_num -= NR_DIRECT_BLOCKS;
|
||||
int indirect_block_id = block_num / MAX_INDIRECT_BLOCKS;
|
||||
if (indirect_block_id < NR_INDIRECT_BLOCKS) {
|
||||
if ((addr = ip->addrs[NR_DIRECT_BLOCKS + indirect_block_id]) == 0) {
|
||||
ip->addrs[NR_DIRECT_BLOCKS + indirect_block_id] = addr = BlockAlloc();
|
||||
}
|
||||
block_num -= indirect_block_id * MAX_INDIRECT_BLOCKS;
|
||||
} else {
|
||||
Error("InodeBlockMapping: out of range");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// alloc a new indirect block
|
||||
uint32_t* indirect_block = (uint32_t*)BlockRead(addr);
|
||||
if ((addr = indirect_block[block_num]) == 0) {
|
||||
indirect_block[block_num] = addr = BlockAlloc();
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
/// @brief Look up the directory Inode for searching the target Inode
|
||||
static struct Inode* DirInodeLookup(struct Inode* dp, char* name, uint32_t* poff)
|
||||
{
|
||||
uint32_t off, inum;
|
||||
struct DirectEntry de;
|
||||
|
||||
if (dp->type != T_DIR) {
|
||||
Error("DirInodeLookup not DIR");
|
||||
}
|
||||
|
||||
for (off = 0; off < dp->size; off += sizeof(de)) {
|
||||
if (InodeRead(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
|
||||
Error("DirInodeAddEntry read");
|
||||
}
|
||||
|
||||
if (de.inum == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp((const char*)name, (const char*)de.name, DIR_NAME_SIZE) == 0) {
|
||||
if (poff) {
|
||||
*poff = off;
|
||||
}
|
||||
inum = de.inum;
|
||||
return InodeGet(inum);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @brief Add a new directory entry for dir Inode
|
||||
static int DirInodeAddEntry(struct Inode* dp, char* name, uint32_t inum)
|
||||
{
|
||||
int off;
|
||||
struct DirectEntry de;
|
||||
struct Inode* ip;
|
||||
|
||||
// Check that direct entry is existed.
|
||||
if ((ip = DirInodeLookup(dp, name, 0)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Look for an empty dir entry.
|
||||
for (off = 0; off < dp->size; off += sizeof(de)) {
|
||||
if (InodeRead(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
|
||||
Error("DirInodeAddEntry: read failed");
|
||||
}
|
||||
|
||||
if (de.inum == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// build a new direct entry.
|
||||
strncpy(de.name, name, DIR_NAME_SIZE);
|
||||
de.inum = inum;
|
||||
if (InodeWrite(dp, (char*)&de, off, sizeof(de)) != sizeof(de)) {
|
||||
Error("DirInodeAddEntry: write failed");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct Inode* Seek(struct Inode* ip, char* path, int nameiparent, char* name)
|
||||
{
|
||||
if (ip->size == 0) {
|
||||
Error("Inode is not sync\n");
|
||||
}
|
||||
|
||||
struct Inode* next;
|
||||
while ((path = PathElementExtract(path, name)) != 0) {
|
||||
if (ip->type != T_DIR) {
|
||||
return NULL;
|
||||
}
|
||||
if (nameiparent && *path == '\0') {
|
||||
return ip;
|
||||
}
|
||||
if ((next = DirInodeLookup(ip, name, 0)) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
ip = next;
|
||||
}
|
||||
|
||||
if (nameiparent) {
|
||||
return NULL;
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
/// @brief Find target Inode from source Inode
|
||||
struct Inode* InodeSeek(struct Inode* source, char* path)
|
||||
{
|
||||
char name[DIR_NAME_SIZE] = { 0 };
|
||||
return Seek(source, path, 0, name);
|
||||
}
|
||||
|
||||
/// @brief Find target parent Inode from source Inode
|
||||
struct Inode* InodeParentSeek(struct Inode* source, char* path, char* name)
|
||||
{
|
||||
return Seek(source, path, 1, name);
|
||||
}
|
||||
|
||||
/// @brief Copy State information from Inode.
|
||||
void InodeStateGet(struct Inode* ip, struct State* st)
|
||||
{
|
||||
st->ino = ip->inum;
|
||||
st->type = ip->type;
|
||||
st->nlink = ip->nlink;
|
||||
st->size = ip->size;
|
||||
}
|
||||
|
||||
/// @brief Read data from the Inode to the dst buffer.
|
||||
int InodeRead(struct Inode* ip, char* dst, int off, int n)
|
||||
{
|
||||
uint32_t tot, m;
|
||||
|
||||
if (off > ip->size || off + n < off) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (off + n > ip->size) {
|
||||
n = ip->size - off;
|
||||
}
|
||||
|
||||
for (tot = 0; tot < n; tot += m, off += m, dst += m) {
|
||||
uint8_t* data = BlockRead(InodeBlockMapping(ip, off / BLOCK_SIZE));
|
||||
m = min(n - tot, BLOCK_SIZE - off % BLOCK_SIZE);
|
||||
memmove(dst, data + off % BLOCK_SIZE, m);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/// @brief Write data from src buffer to the Inode, then increase the Inode size if neccessary.
|
||||
int InodeWrite(struct Inode* ip, char* src, uint32_t off, uint32_t n)
|
||||
{
|
||||
uint32_t tot, m;
|
||||
|
||||
if (off > ip->size || off + n < off) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (off + n > MAX_FILE_SIZE * BLOCK_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (tot = 0; tot < n; tot += m, off += m, src += m) {
|
||||
uint8_t* data = BlockRead(InodeBlockMapping(ip, off / BLOCK_SIZE));
|
||||
m = min(n - tot, BLOCK_SIZE - off % BLOCK_SIZE);
|
||||
memmove(data + off % BLOCK_SIZE, src, m);
|
||||
}
|
||||
|
||||
if (n > 0 && off > ip->size) {
|
||||
ip->size = off;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
// Paths process
|
||||
static char* PathElementExtract(char* path, char* name)
|
||||
{
|
||||
// Skip leading slashes
|
||||
while (*path == '/')
|
||||
path++;
|
||||
|
||||
// Check for end of path
|
||||
if (*path == 0)
|
||||
return NULL;
|
||||
|
||||
// Extract element
|
||||
char* start = path;
|
||||
while (*path != '/' && *path != 0)
|
||||
path++;
|
||||
|
||||
// Calculate length and copy to 'name'
|
||||
int len = path - start;
|
||||
if (len >= DIR_NAME_SIZE)
|
||||
len = DIR_NAME_SIZE - 1;
|
||||
strncpy(name, start, len);
|
||||
name[len] = 0;
|
||||
|
||||
// Skip trailing slashes
|
||||
while (*path == '/')
|
||||
path++;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
struct FileDescriptor* GetFileDescriptor(int fd)
|
||||
{
|
||||
if (fd < 0 || fd > MAX_SUPPORT_FD) {
|
||||
printf("fd invlid.\n");
|
||||
return NULL;
|
||||
}
|
||||
return &fd_table[fd];
|
||||
}
|
||||
|
||||
void FreeFileDescriptor(int fd)
|
||||
{
|
||||
if (fd < 0 || fd > MAX_SUPPORT_FD) {
|
||||
printf("fd invlid.\n");
|
||||
return;
|
||||
}
|
||||
fd_table[fd].data = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int AllocFileDescriptor(void)
|
||||
{
|
||||
int free_idx = -1;
|
||||
for (int i = 0; i < MAX_SUPPORT_FD; i++) {
|
||||
// found free fd
|
||||
if (free_idx == -1 && fd_table[i].data == 0) {
|
||||
free_idx = i;
|
||||
}
|
||||
}
|
||||
if (free_idx == -1) {
|
||||
return -1;
|
||||
}
|
||||
return free_idx;
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "block_io.h"
|
||||
#include "fs.h"
|
||||
#include "fs_service.h"
|
||||
#include "libserial.h"
|
||||
#include "usyscall.h"
|
||||
|
||||
struct CwdPair {
|
||||
int session_id;
|
||||
struct Inode* Inode;
|
||||
};
|
||||
|
||||
#define MAX_SUPPORT_SESSION 1024
|
||||
static struct CwdPair session_cwd[MAX_SUPPORT_SESSION];
|
||||
|
||||
static struct CwdPair* get_session_cwd(void)
|
||||
{
|
||||
int free_idx = -1;
|
||||
for (int i = 0; i < MAX_SUPPORT_SESSION; i++) {
|
||||
// found session cwd
|
||||
if (session_cwd[i].session_id == cur_session_id()) {
|
||||
return &session_cwd[i];
|
||||
}
|
||||
if (free_idx == -1 && session_cwd[i].session_id == 0) {
|
||||
free_idx = i;
|
||||
}
|
||||
}
|
||||
// new a cwd pair for session
|
||||
if (free_idx == -1) {
|
||||
printf("Connect Session reaches max value.\n");
|
||||
return NULL;
|
||||
}
|
||||
session_cwd[free_idx].session_id = cur_session_id();
|
||||
session_cwd[free_idx].Inode = InodeGet(ROOT_INUM);
|
||||
return &session_cwd[free_idx];
|
||||
}
|
||||
|
||||
int IPC_DO_SERVE_FUNC(Ipc_ls)(char* path)
|
||||
{
|
||||
struct Inode *dp, *ip;
|
||||
if (*path == '/') {
|
||||
dp = InodeGet(ROOT_INUM);
|
||||
} else {
|
||||
struct CwdPair* cwd = get_session_cwd();
|
||||
if (!cwd) {
|
||||
printf("ls:find current work dir failed\n");
|
||||
return -1;
|
||||
}
|
||||
dp = cwd->Inode;
|
||||
}
|
||||
|
||||
if (!(ip = InodeSeek(dp, path))) {
|
||||
printf("ls:find target Inode failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (ip->type != T_DIR) {
|
||||
printf("ls:not a dir\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t off;
|
||||
struct DirectEntry de;
|
||||
for (off = 0; off < ip->size; off += sizeof(de)) {
|
||||
if (InodeRead(ip, (char*)&de, off, sizeof(de)) != sizeof(de)) {
|
||||
printf("ls:read dir entry failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (de.inum == 0) {
|
||||
continue;
|
||||
}
|
||||
printf("%s\n", de.name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IPC_DO_SERVE_FUNC(Ipc_cd)(char* path)
|
||||
{
|
||||
struct CwdPair* cwd;
|
||||
struct Inode *dp, *ip;
|
||||
|
||||
cwd = get_session_cwd();
|
||||
if (!cwd) {
|
||||
printf("cd:find current work dir failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*path == '/') {
|
||||
dp = InodeGet(ROOT_INUM);
|
||||
} else {
|
||||
dp = cwd->Inode;
|
||||
}
|
||||
|
||||
if (!(ip = InodeSeek(dp, path))) {
|
||||
/// @todo Is need to create the Inode when the dir is node existed?
|
||||
printf("cd:find target Inode failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ip->type != T_DIR) {
|
||||
printf("cd:not a dir\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cwd->Inode = ip;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IPC_DO_SERVE_FUNC(Ipc_mkdir)(char* path)
|
||||
{
|
||||
// printf("Create a new directory: %s\n", path);
|
||||
struct Inode *dp, *ip;
|
||||
if (*path == '/') {
|
||||
dp = InodeGet(ROOT_INUM);
|
||||
} else {
|
||||
struct CwdPair* cwd = get_session_cwd();
|
||||
if (!cwd) {
|
||||
printf("find current work dir failed\n");
|
||||
return -1;
|
||||
}
|
||||
dp = cwd->Inode;
|
||||
}
|
||||
|
||||
if ((ip = InodeSeek(dp, path)) != NULL) {
|
||||
/// @todo Is need to return target Inode?
|
||||
printf("target Inode existed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
char name[DIR_NAME_SIZE] = { 0 };
|
||||
if (!(ip = InodeParentSeek(dp, path, name))) {
|
||||
/// @todo Is need to return target Inode?
|
||||
printf("target parent Inode is not existed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (InodeCreate(ip, name, T_DIR, 0, 0) == 0) {
|
||||
printf("create target Inode %s failed\n", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IPC_DO_SERVE_FUNC(Ipc_delete)(char* path)
|
||||
{
|
||||
struct Inode *dp, *ip;
|
||||
if (*path == '/') {
|
||||
dp = InodeGet(ROOT_INUM);
|
||||
} else {
|
||||
struct CwdPair* cwd = get_session_cwd();
|
||||
if (!cwd) {
|
||||
printf("delete:find current work dir failed\n");
|
||||
return -1;
|
||||
}
|
||||
dp = cwd->Inode;
|
||||
}
|
||||
|
||||
char name[DIR_NAME_SIZE] = { 0 };
|
||||
if (!(ip = InodeParentSeek(dp, path, name))) {
|
||||
printf("delete:target file parent not existed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (InodeDelete(ip, name) < 0) {
|
||||
printf("delete:target file not existed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @todo Support malloc for user
|
||||
int IPC_DO_SERVE_FUNC(Ipc_cat)(char* path)
|
||||
{
|
||||
static char buffer[BLOCK_SIZE + 1] = { 0 };
|
||||
buffer[BLOCK_SIZE] = '\0';
|
||||
|
||||
struct Inode *dp, *ip;
|
||||
if (*path == '/') {
|
||||
dp = InodeGet(ROOT_INUM);
|
||||
} else {
|
||||
struct CwdPair* cwd = get_session_cwd();
|
||||
if (!cwd) {
|
||||
printf("delete:find current work dir failed\n");
|
||||
return -1;
|
||||
}
|
||||
dp = cwd->Inode;
|
||||
}
|
||||
|
||||
if (!(ip = InodeSeek(dp, path))) {
|
||||
printf("delete:target file not existed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ip->type != T_FILE) {
|
||||
printf("cat: %s Is not a file\n", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t off;
|
||||
for (off = 0; off < ip->size; off += BLOCK_SIZE) {
|
||||
if (InodeRead(ip, buffer, off, BLOCK_SIZE) < 0) {
|
||||
printf("cat: read file data failed\n");
|
||||
break;
|
||||
}
|
||||
printf("%s", buffer);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IPC_DO_SERVE_FUNC(Ipc_open)(char* path)
|
||||
{
|
||||
// printf("Ipc_open: %s\n", path);
|
||||
int fd;
|
||||
struct FileDescriptor* fdp;
|
||||
fd = AllocFileDescriptor();
|
||||
if (fd < 0) {
|
||||
printf("open: alloc a new fd failed\n");
|
||||
return -1;
|
||||
}
|
||||
fdp = GetFileDescriptor(fd);
|
||||
|
||||
struct Inode *dp, *ip;
|
||||
if (*path == '/') {
|
||||
dp = InodeGet(ROOT_INUM);
|
||||
} else {
|
||||
struct CwdPair* cwd = get_session_cwd();
|
||||
if (!cwd) {
|
||||
printf("ls:find current work dir failed\n");
|
||||
return -1;
|
||||
}
|
||||
dp = cwd->Inode;
|
||||
}
|
||||
if ((ip = InodeSeek(dp, path)) == NULL) {
|
||||
printf("open: find target Inode failed, path is %s\n", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// @todo record absolute path
|
||||
strncpy(fdp->path, path, strlen(path) + 1);
|
||||
ip->nlink++;
|
||||
fdp->data = ip;
|
||||
InodeStateGet(ip, &fdp->st);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int IPC_DO_SERVE_FUNC(Ipc_close)(int* fd)
|
||||
{
|
||||
struct FileDescriptor* fdp = GetFileDescriptor(*fd);
|
||||
if (!fdp) {
|
||||
printf("read: fd invalid\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct Inode* ip = fdp->data;
|
||||
ip->nlink--;
|
||||
|
||||
FreeFileDescriptor(*fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IPC_DO_SERVE_FUNC(Ipc_read)(int* fd, char* dst, int* offset, int* len)
|
||||
{
|
||||
// printf("Ipc_read, fd is %d, dst: %x, offset: %d, len: %d\n", *fd, dst, *offset, *len);
|
||||
struct FileDescriptor* fdp = GetFileDescriptor(*fd);
|
||||
if (!fdp) {
|
||||
printf("read: fd invalid\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct Inode* ip = fdp->data;
|
||||
if (ip->type != T_FILE) {
|
||||
printf("read: %s Is not a file\n", fdp->path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cur_read_len = InodeRead(ip, dst, *offset, *len);
|
||||
|
||||
return *len;
|
||||
}
|
||||
|
||||
int IPC_DO_SERVE_FUNC(Ipc_write)(int* fd, char* src, int* offset, int* len)
|
||||
{
|
||||
// printf("Ipc_write, fd is %d\n", *fd);
|
||||
struct FileDescriptor* fdp = GetFileDescriptor(*fd);
|
||||
if (!fdp) {
|
||||
printf("read: fd invalid\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct Inode* ip = fdp->data;
|
||||
if (ip->type != T_FILE) {
|
||||
printf("read: %s Is not a file\n", fdp->path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cur_write_len = InodeWrite(ip, src, *offset, *len);
|
||||
|
||||
return cur_write_len;
|
||||
}
|
||||
|
||||
IPC_SERVER_INTERFACE(Ipc_ls, 1);
|
||||
IPC_SERVER_INTERFACE(Ipc_cd, 1);
|
||||
IPC_SERVER_INTERFACE(Ipc_mkdir, 1);
|
||||
IPC_SERVER_INTERFACE(Ipc_delete, 1);
|
||||
IPC_SERVER_INTERFACE(Ipc_cat, 1);
|
||||
|
||||
IPC_SERVER_INTERFACE(Ipc_open, 1);
|
||||
IPC_SERVER_INTERFACE(Ipc_close, 1);
|
||||
IPC_SERVER_INTERFACE(Ipc_read, 4);
|
||||
IPC_SERVER_INTERFACE(Ipc_write, 4);
|
||||
|
||||
IPC_SERVER_REGISTER_INTERFACES(IpcFsServer, 9, Ipc_ls, Ipc_cd, Ipc_mkdir, Ipc_delete, Ipc_cat,
|
||||
Ipc_open, Ipc_close, Ipc_read, Ipc_write);
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
sys_state_info info;
|
||||
get_memblock_info(&info);
|
||||
|
||||
int len = info.memblock_info.memblock_end - info.memblock_info.memblock_start;
|
||||
mmap(FS_IMG_ADDR, info.memblock_info.memblock_start, len, false);
|
||||
|
||||
MemFsInit((uintptr_t)FS_IMG_ADDR, (uint32_t)len);
|
||||
|
||||
if (register_server("MemFS") < 0) {
|
||||
printf("register server name: %s failed.\n", "SimpleServer");
|
||||
exit();
|
||||
}
|
||||
ipc_server_loop(&IpcFsServer);
|
||||
|
||||
// never reached
|
||||
exit();
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
#include "fs_service.h"
|
||||
#include "fs.h"
|
||||
|
||||
IPC_INTERFACE(Ipc_ls, 1, path, strlen(path) + 1);
|
||||
int ls(struct Session* session, char* path)
|
||||
{
|
||||
return IPC_CALL(Ipc_ls)(session, path);
|
||||
}
|
||||
|
||||
IPC_INTERFACE(Ipc_cd, 1, path, strlen(path) + 1);
|
||||
int cd(struct Session* session, char* path)
|
||||
{
|
||||
return IPC_CALL(Ipc_cd)(session, path);
|
||||
}
|
||||
|
||||
IPC_INTERFACE(Ipc_mkdir, 1, path, strlen(path) + 1);
|
||||
int mkdir(struct Session* session, char* path)
|
||||
{
|
||||
return IPC_CALL(Ipc_mkdir)(session, path);
|
||||
}
|
||||
|
||||
IPC_INTERFACE(Ipc_delete, 1, path, strlen(path) + 1);
|
||||
int rm(struct Session* session, char* path)
|
||||
{
|
||||
return IPC_CALL(Ipc_delete)(session, path);
|
||||
}
|
||||
|
||||
IPC_INTERFACE(Ipc_cat, 1, path, strlen(path) + 1);
|
||||
int cat(struct Session* session, char* path)
|
||||
{
|
||||
return IPC_CALL(Ipc_cat)(session, path);
|
||||
}
|
||||
|
||||
IPC_INTERFACE(Ipc_open, 1, path, strlen(path) + 1);
|
||||
int open(struct Session* session, char* path)
|
||||
{
|
||||
return IPC_CALL(Ipc_open)(session, path);
|
||||
}
|
||||
|
||||
IPC_INTERFACE(Ipc_close, 1, fd, sizeof(int));
|
||||
int close(struct Session* session, int fd)
|
||||
{
|
||||
return IPC_CALL(Ipc_close)(session, &fd);
|
||||
}
|
||||
|
||||
IPC_INTERFACE(Ipc_read, 4, fd, dst, offset, len, sizeof(int), *(int*)len, sizeof(int), sizeof(int));
|
||||
int read(struct Session* session, int fd, char* dst, int offset, int len)
|
||||
{
|
||||
return IPC_CALL(Ipc_read)(session, &fd, dst, &offset, &len);
|
||||
}
|
||||
|
||||
IPC_INTERFACE(Ipc_write, 4, fd, src, offset, len, sizeof(int), *(int*)len, sizeof(int), sizeof(int));
|
||||
int write(struct Session* session, int fd, char* src, int offset, int len)
|
||||
{
|
||||
return IPC_CALL(Ipc_write)(session, &fd, src, &offset, &len);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "fs.h"
|
||||
|
||||
// Block size
|
||||
#define BLOCK_SIZE 512
|
||||
|
||||
// bits size
|
||||
#define BITS 8
|
||||
|
||||
// Bitmap size of one block
|
||||
#define BITMAP_SIZE (BLOCK_SIZE * BITS)
|
||||
|
||||
// Inode size of one block
|
||||
#define INODE_SIZE (BLOCK_SIZE / sizeof(struct Inode))
|
||||
|
||||
// Caculate block bit index
|
||||
#define BLOCK_BIT_INDEX(b, ninodes) ((b / BITMAP_SIZE) + (ninodes / INODE_SIZE) + 3)
|
||||
|
||||
// Caculate block index by inode number
|
||||
#define BLOCK_INDEX(inum) ((inum / INODE_SIZE) + 2)
|
||||
|
||||
// Caculate inode index in the block
|
||||
#define INODE_INDEX(inum) (inum % INODE_SIZE)
|
||||
|
||||
uint8_t* BlockRead(int block_num);
|
||||
void BlockFree(int block_num);
|
||||
uint32_t BlockAlloc();
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "block_io.h"
|
||||
|
||||
// memory file system memlayout.
|
||||
// [ block 0 ] [ block 1 ] [block 2] [...] [ block 28 ] [ ... ]
|
||||
// [ unused ] [super block] [Inode bit map] [block bit map] [data blocks]
|
||||
|
||||
#define NR_DIRECT_BLOCKS 5 // direct block number
|
||||
#define NR_INDIRECT_BLOCKS 8 // indirect block number
|
||||
#define ROOT_INUM 1 // root inode number
|
||||
|
||||
#define MAX_INDIRECT_BLOCKS (BLOCK_SIZE / sizeof(uint32_t)) // Mmaximum number of indirect blocks mapped per block
|
||||
#define MAX_FILE_SIZE (NR_DIRECT_BLOCKS + (NR_INDIRECT_BLOCKS * MAX_INDIRECT_BLOCKS)) // maximum size of a file
|
||||
|
||||
// memory fs range
|
||||
struct MemFsRange {
|
||||
uintptr_t memfs_start;
|
||||
uint32_t memfs_nr_blocks;
|
||||
};
|
||||
|
||||
// current state of the Inode
|
||||
enum INODE_STATE {
|
||||
I_RESERVED = 0,
|
||||
I_BUSY,
|
||||
I_VALID
|
||||
};
|
||||
|
||||
// memfs file type
|
||||
enum FILE_TYPE {
|
||||
T_RESERVED = 0,
|
||||
T_DIR, // Directory
|
||||
T_FILE, // File
|
||||
T_DEV, // Device
|
||||
};
|
||||
|
||||
// File system super block
|
||||
struct SuperBlock {
|
||||
uint32_t size; // Number of total blocks of file system image
|
||||
uint32_t nblocks; // Number of data blocks
|
||||
uint32_t ninodes; // Number of inodes.
|
||||
};
|
||||
|
||||
// state of the Inode
|
||||
struct State {
|
||||
short type; // Type of file
|
||||
int dev; // File system's disk device
|
||||
uint32_t ino; // Inode number
|
||||
short nlink; // Number of links to file
|
||||
uint32_t size; // Size of file in bytes
|
||||
};
|
||||
|
||||
// Inode structure
|
||||
struct Inode {
|
||||
uint32_t inum; // Inode number
|
||||
short type; // File type
|
||||
short nlink; // Number of links to Inode in file system
|
||||
uint32_t size; // Size of file (bytes)
|
||||
uint32_t addrs[NR_DIRECT_BLOCKS + NR_INDIRECT_BLOCKS]; // Data block addresses
|
||||
};
|
||||
|
||||
// directory entry
|
||||
#define DIR_NAME_SIZE 14
|
||||
struct DirectEntry {
|
||||
uint16_t inum;
|
||||
char name[DIR_NAME_SIZE];
|
||||
};
|
||||
|
||||
// file descriptor definition
|
||||
#define MAX_PATH_LEN 128
|
||||
struct FileDescriptor {
|
||||
char path[MAX_PATH_LEN];
|
||||
void* data;
|
||||
struct State st;
|
||||
};
|
||||
|
||||
// range of memory fs
|
||||
extern struct MemFsRange MemFsRange;
|
||||
|
||||
void MemFsInit(uintptr_t _binary_fs_img_start, uint32_t fs_img_len);
|
||||
void ReadSuperBlock(struct SuperBlock*);
|
||||
|
||||
// fs Inode ops
|
||||
struct Inode* InodeGet(uint32_t inum);
|
||||
struct Inode* InodeCreate(struct Inode*, char*, short, short, short);
|
||||
int InodeDelete(struct Inode*, char*);
|
||||
int InodeRead(struct Inode*, char*, int, int);
|
||||
int InodeWrite(struct Inode*, char*, uint32_t, uint32_t);
|
||||
struct Inode* InodeSeek(struct Inode*, char*);
|
||||
struct Inode* InodeParentSeek(struct Inode*, char*, char*);
|
||||
void InodeStateGet(struct Inode*, struct State*);
|
||||
|
||||
// fs fd ops
|
||||
struct FileDescriptor* GetFileDescriptor(int fd);
|
||||
void FreeFileDescriptor(int fd);
|
||||
int AllocFileDescriptor(void);
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fs.h"
|
||||
#include "libipc.h"
|
||||
|
||||
IPC_SERVICES(IpcFsServer, Ipc_ls, Ipc_cd, Ipc_mkdir, Ipc_delete, Ipc_cat,
|
||||
Ipc_open, Ipc_close, Ipc_read, Ipc_write);
|
||||
|
||||
int ls(struct Session* session, char* path);
|
||||
int cd(struct Session* session, char* path);
|
||||
int mkdir(struct Session* session, char* path);
|
||||
int rm(struct Session* session, char* path);
|
||||
int cat(struct Session* session, char* path);
|
||||
|
||||
int open(struct Session* session, char* path);
|
||||
int close(struct Session* session, int fd);
|
||||
int read(struct Session* session, int fd, char* dst, int offset, int len);
|
||||
int write(struct Session* session, int fd, char* src, int offset, int len);
|
||||
|
||||
#define FS_IMG_ADDR 0x60000000
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2020 AIIT XUOS Lab
|
||||
* XiUOS is licensed under Mulan PSL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||
* You may obtain a copy of Mulan PSL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPSL2
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct double_list_node {
|
||||
struct double_list_node* next;
|
||||
struct double_list_node* prev;
|
||||
};
|
||||
|
||||
#define CONTAINER_OF(item, type, member) \
|
||||
((type*)((char*)(item) - (unsigned long)(&((type*)0)->member)))
|
||||
|
||||
#define IS_DOUBLE_LIST_EMPTY(head) \
|
||||
((head)->next == (head))
|
||||
|
||||
/*********************************************
|
||||
*
|
||||
* Double linked list operation functions
|
||||
*
|
||||
*********************************************/
|
||||
#define DOUBLE_LIST_ENTRY(item, type, member) \
|
||||
CONTAINER_OF(item, type, member)
|
||||
|
||||
#define DOUBLE_LIST_FOR_EACH_ENTRY(item, head, member) \
|
||||
for (item = DOUBLE_LIST_ENTRY((head)->next, typeof(*item), member); \
|
||||
&item->member != (head); \
|
||||
item = DOUBLE_LIST_ENTRY(item->member.next, typeof(*item), member))
|
||||
|
||||
#define DOUBLE_LIST_FOR_EACH_ENTRY_REVERSE(item, head, member) \
|
||||
for (item = DOUBLE_LIST_ENTRY((head)->prev, typeof(*item), member); \
|
||||
&item->member != (head); \
|
||||
item = DOUBLE_LIST_ENTRY(item->member.prev, typeof(*item), member))
|
||||
|
||||
__attribute__((always_inline)) static void inline doubleListNodeInit(struct double_list_node* list)
|
||||
{
|
||||
list->next = list;
|
||||
list->prev = list;
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) static void inline _double_list_add(struct double_list_node* new_node, struct double_list_node* prev, struct double_list_node* next)
|
||||
{
|
||||
next->prev = new_node;
|
||||
new_node->next = next;
|
||||
new_node->prev = prev;
|
||||
prev->next = new_node;
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) static void inline _double_list_del(struct double_list_node* prev, struct double_list_node* next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) static void inline doubleListAddOnHead(struct double_list_node* new_node, struct double_list_node* head)
|
||||
{
|
||||
_double_list_add(new_node, head, head->next);
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) static void inline doubleListAddOnBack(struct double_list_node* new_node, struct double_list_node* head)
|
||||
{
|
||||
_double_list_add(new_node, head->prev, head);
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) static void inline doubleListDel(struct double_list_node* entry)
|
||||
{
|
||||
_double_list_del(entry->prev, entry->next);
|
||||
entry->next = entry;
|
||||
entry->prev = entry;
|
||||
}
|
||||
Reference in New Issue
Block a user