Compare commits
No commits in common. "fat" and "master" have entirely different histories.
@ -17,7 +17,7 @@
|
|||||||
uaddr_t loadElfProg(const char *prog, struct process *proc)
|
uaddr_t loadElfProg(const char *prog, struct process *proc)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
uaddr_t lastUserAddr = 0;
|
uaddr_t lastUserAddr = 0;
|
||||||
struct uAddrSpace *as = processGetAddrSpace(proc);
|
struct uAddrSpace *as = processGetAddrSpace(proc);
|
||||||
|
|
||||||
/* e_ident value */
|
/* e_ident value */
|
||||||
|
27
core/fs.c
27
core/fs.c
@ -1,27 +0,0 @@
|
|||||||
#include "fs.h"
|
|
||||||
#include "list.h"
|
|
||||||
#include "stddef.h"
|
|
||||||
|
|
||||||
// List of all fs supported (e.g. EXT4, FAT32 ...)
|
|
||||||
struct file_system *fsList = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
int fsRegister(struct file_system *fs){
|
|
||||||
list_add_tail(fsList, fs);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fsInodeUnref(struct inode *inode)
|
|
||||||
{
|
|
||||||
//TODO
|
|
||||||
(void)inode;
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
int fsInodeRef(struct inode *inode)
|
|
||||||
{
|
|
||||||
//TODO
|
|
||||||
(void)inode;
|
|
||||||
return 0;
|
|
||||||
};
|
|
167
core/fs.h
167
core/fs.h
@ -1,167 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "ata.h"
|
|
||||||
#include "fsEntry.h"
|
|
||||||
#include "process.h"
|
|
||||||
#include "stdint.h"
|
|
||||||
#include "types.h"
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define FS_NAME_MAXLEN 32
|
|
||||||
|
|
||||||
// Forward declaration
|
|
||||||
struct file_system;
|
|
||||||
struct file_system_instance;
|
|
||||||
struct fs_stat;
|
|
||||||
struct file;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
FS_INODE_REGULAR_FILE = 0x01,
|
|
||||||
FS_INODE_DIRECTORY = 0x02,
|
|
||||||
FS_INODE_SYMLINK = 0x04,
|
|
||||||
FS_INODE_DEVICE_CHAR = 0x08,
|
|
||||||
FS_INODE_DEVICE_BLOCK = 0x10
|
|
||||||
} fs_inode_type_t;
|
|
||||||
|
|
||||||
struct inode_operation {
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represent a file on the disk
|
|
||||||
*/
|
|
||||||
struct inode {
|
|
||||||
struct file_system_instance *fs;
|
|
||||||
|
|
||||||
uint64_t location;
|
|
||||||
size_t onDiskRef;
|
|
||||||
size_t inMemRef;
|
|
||||||
fs_inode_type_t type;
|
|
||||||
|
|
||||||
#define FS_READABLE 00400
|
|
||||||
#define FS_WRITABLE 00200
|
|
||||||
#define FS_EXECUTABLE 00100
|
|
||||||
uint32_t mode;
|
|
||||||
|
|
||||||
bool_t dirty;
|
|
||||||
struct inode_operation *ops;
|
|
||||||
|
|
||||||
union {
|
|
||||||
struct inode_dir_ops *opsDir;
|
|
||||||
struct inode_dir_symlink *opsSymlink;
|
|
||||||
};
|
|
||||||
|
|
||||||
int (*destructor)(struct inode *this);
|
|
||||||
int (*newOpenedFile)(struct inode *this, const struct process *owner, uint32_t openFlags,
|
|
||||||
struct file **result);
|
|
||||||
int (*closeOpenedFile)(struct inode *this, struct file *of);
|
|
||||||
void *custom;
|
|
||||||
|
|
||||||
struct inode *prevDirty, *nextDirty;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct file_system_instance_ops { // super_operations
|
|
||||||
// From the inode location, instantiace a struct inode
|
|
||||||
int (*getInodeFromDevice)(struct file_system_instance *this, uint64_t storageLocation,
|
|
||||||
struct inode **result);
|
|
||||||
|
|
||||||
int (*allocateNewInode)(struct file_system_instance *this, fs_inode_type_t type,
|
|
||||||
const struct process *creator, uint32_t accessRights,
|
|
||||||
uint32_t open_creat_flags, struct inode **result);
|
|
||||||
|
|
||||||
int (*statfs)(struct file_system_instance *this, struct fs_stat *result);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct file_system_instance {
|
|
||||||
|
|
||||||
struct file_system *fsType; // this instance is of this type of file_system
|
|
||||||
struct inode *device; // device (like block one) could have a disk associated
|
|
||||||
|
|
||||||
#define FS_MOUNT_SYNC (1 << 0)
|
|
||||||
#define FS_MOUNT_READONLY (1 << 1)
|
|
||||||
#define FS_MOUNT_NOEXEC (1 << 2)
|
|
||||||
uint32_t flags;
|
|
||||||
|
|
||||||
struct fs_entry *root; // root fs_entry for this fs instance
|
|
||||||
struct inode *dirtyNodes; // list of inodes that are out of sync
|
|
||||||
void *custom; // custom
|
|
||||||
const struct file_system_instance_ops *ops;
|
|
||||||
|
|
||||||
struct file_system_instance *prev, *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum { SEEK_SET, SEEK_CUR, SEEK_END } seek_mode_t;
|
|
||||||
|
|
||||||
struct file_system {
|
|
||||||
char name[FS_NAME_MAXLEN];
|
|
||||||
struct file_system_instance *instances;
|
|
||||||
void *custom;
|
|
||||||
|
|
||||||
int (*mount)(struct file_system *this, struct inode *device, const char *args,
|
|
||||||
struct file_system_instance **mountedFs);
|
|
||||||
|
|
||||||
int (*umount)(struct file_system *this, struct file_system_instance *mountedFs);
|
|
||||||
|
|
||||||
|
|
||||||
//tmp function to implement fs in kernel only as a firts step
|
|
||||||
void *(*open)(struct ata_device *disk, struct ata_partition *path, uint32_t mode);
|
|
||||||
int (*read)(struct ata_device *disk, void *private, uint32_t size, uint32_t nmemb,
|
|
||||||
char *out);
|
|
||||||
int (*resolve)(struct ata_device *disk);
|
|
||||||
|
|
||||||
int (*close)(void *private);
|
|
||||||
|
|
||||||
int (*seek)(void *private, uint32_t offset, seek_mode_t seek_mode);
|
|
||||||
// end tmp
|
|
||||||
|
|
||||||
struct file_system *prev, *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct file_operations {
|
|
||||||
loff_t (*llseek)(struct file *this, loff_t offset, seek_mode_t whence);
|
|
||||||
ssize_t (*read)(struct file *this, char *buf, size_t size, loff_t *offset);
|
|
||||||
ssize_t (*write)(struct file *this, const char *buf, size_t size, loff_t *offset);
|
|
||||||
int (*mmap)(struct file *this, uaddr_t *uaddr, size_t size,
|
|
||||||
int32_t access_rights, int32_t flags, loff_t offset);
|
|
||||||
|
|
||||||
int (*open)(struct inode *, struct file *);
|
|
||||||
int (*flush)(struct file *);
|
|
||||||
int (*release)(struct inode *, struct file *);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A opened file by a process
|
|
||||||
*/
|
|
||||||
struct file {
|
|
||||||
const struct process *owner;
|
|
||||||
|
|
||||||
struct fs_entry *direntry;
|
|
||||||
uint ref;
|
|
||||||
int64_t position;
|
|
||||||
|
|
||||||
#define O_ACCMODE 0003
|
|
||||||
#define O_RDONLY 00
|
|
||||||
#define O_WRONLY 01
|
|
||||||
#define O_RDWR 02
|
|
||||||
|
|
||||||
#define O_CREAT 0100 /* Not fcntl. */
|
|
||||||
#define O_EXCL 0200 /* Not fcntl. */
|
|
||||||
#define O_NOCTTY 0400 /* Not fcntl. */
|
|
||||||
#define O_TRUNC 01000 /* Not fcntl. */
|
|
||||||
#define O_APPEND 02000
|
|
||||||
#define O_DIRECTORY 0200000 /* Must be a directory. */
|
|
||||||
#define O_NOFOLLOW 0400000 /* Do not follow links. */
|
|
||||||
#define O_SYNC 04010000
|
|
||||||
#define O_CLOEXEC 02000000 /* Set close_on_exec. */
|
|
||||||
|
|
||||||
uint32_t flags;
|
|
||||||
const struct file_operations *ops;
|
|
||||||
|
|
||||||
int (*duplicate)(struct file *this, const struct process *owner, struct file **result);
|
|
||||||
|
|
||||||
void *custom;
|
|
||||||
};
|
|
||||||
|
|
||||||
int fsRegister(struct file_system *fs);
|
|
||||||
|
|
||||||
int fsInodeUnref(struct inode *inode);
|
|
||||||
int fsInodeRef(struct inode *inode);
|
|
215
core/fsEntry.c
215
core/fsEntry.c
@ -1,215 +0,0 @@
|
|||||||
#include "alloc.h"
|
|
||||||
#include "assert.h"
|
|
||||||
#include "fsEntry.h"
|
|
||||||
#include "errno.h"
|
|
||||||
#include "list.h"
|
|
||||||
#include "mem.h"
|
|
||||||
|
|
||||||
bool_t pstringSplipPath(struct pstr *path, struct pstr *upper, struct pstr *lower)
|
|
||||||
{
|
|
||||||
typeof(path->name) curPos = path->name;
|
|
||||||
typeof(path->len) curLen = path->len;
|
|
||||||
typeof(path->len) upperLen = 0;
|
|
||||||
|
|
||||||
// Skip leading /
|
|
||||||
while (curLen > 0 && curPos[0] == '/') {
|
|
||||||
curPos++;
|
|
||||||
curLen--;
|
|
||||||
}
|
|
||||||
|
|
||||||
upper->name = curPos;
|
|
||||||
|
|
||||||
// Find first non /
|
|
||||||
while (curLen > 0 && curPos[0] != '/') {
|
|
||||||
upperLen++;
|
|
||||||
curLen--;
|
|
||||||
curPos++;
|
|
||||||
}
|
|
||||||
upper->len = upperLen;
|
|
||||||
|
|
||||||
while (curLen > 0 && curPos[0] == '/') {
|
|
||||||
curPos++;
|
|
||||||
curLen--;
|
|
||||||
}
|
|
||||||
lower->name = curPos;
|
|
||||||
lower->len = path->len - (lower->name - path->name);
|
|
||||||
|
|
||||||
return lower->len > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool_t pstringIsEq(const struct pstr *p1, const struct pstr *p2)
|
|
||||||
{
|
|
||||||
return p1->len == p2->len && (memcmp(p1->name, p2->name, p1->len) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool_t pstringIsStr(const struct pstr *p, char *s)
|
|
||||||
{
|
|
||||||
size_t slen = strlen(s);
|
|
||||||
return p->len == slen && (memcmp(p->name, s, slen) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fsEntryRef(struct fs_entry *entry)
|
|
||||||
{
|
|
||||||
entry->ref++;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fsEntryUnref(struct fs_entry **entry)
|
|
||||||
{
|
|
||||||
struct fs_entry *toDelete = NULL, *entryTmp;
|
|
||||||
|
|
||||||
entryTmp = *entry;
|
|
||||||
|
|
||||||
while (entryTmp) {
|
|
||||||
assert(entryTmp->ref > 0);
|
|
||||||
entryTmp->ref--;
|
|
||||||
|
|
||||||
if (entryTmp->ref > 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (entryTmp == *entry)
|
|
||||||
*entry = NULL;
|
|
||||||
|
|
||||||
if (entryTmp->parent) {
|
|
||||||
struct fs_entry *parent = entryTmp->parent;
|
|
||||||
|
|
||||||
assert(entryTmp->parent->ref >= 1);
|
|
||||||
|
|
||||||
list_delete_named(parent->childs, entryTmp, prevSiblings, nextSiblings);
|
|
||||||
// At next iteration we will decrement parent's ref cnt
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avoid recursivity in kernel by using a list of entry to suppress
|
|
||||||
list_add_tail_named(toDelete, entryTmp, prevSiblings, nextSiblings);
|
|
||||||
|
|
||||||
// now, unref parent
|
|
||||||
entryTmp = entryTmp->parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// free 0 ref entries
|
|
||||||
while (!list_is_empty_named(toDelete, prevSiblings, nextSiblings)) {
|
|
||||||
entryTmp = list_pop_head_named(toDelete, prevSiblings, nextSiblings);
|
|
||||||
fsInodeUnref(entryTmp->node);
|
|
||||||
free(entryTmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fs_entry *fsEntryAlloc(struct fs_entry *parent, const struct pstr *name, struct inode *inode)
|
|
||||||
{
|
|
||||||
struct fs_entry *entry = zalloc(sizeof(struct fs_entry));
|
|
||||||
|
|
||||||
if (!entry)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (name && name->len > 0) {
|
|
||||||
char *allocName = malloc(name->len);
|
|
||||||
|
|
||||||
if (!allocName) {
|
|
||||||
free(entry);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(allocName, name->name, name->len);
|
|
||||||
entry->name.len = name->len;
|
|
||||||
entry->name.name = allocName;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry->ref = 1;
|
|
||||||
entry->node = inode;
|
|
||||||
entry->parent = parent;
|
|
||||||
|
|
||||||
fsInodeRef(inode);
|
|
||||||
|
|
||||||
if (parent) {
|
|
||||||
fsEntryRef(parent);
|
|
||||||
list_add_head_named(parent->childs, entry, prevSiblings, nextSiblings);
|
|
||||||
}
|
|
||||||
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fsEntryLookup(struct fs_entry *entry, const struct pstr *name, const struct fs_entry *root, struct fs_entry **result)
|
|
||||||
{
|
|
||||||
if (pstringIsStr(name, ".")) {
|
|
||||||
*result = entry;
|
|
||||||
} else if (pstringIsStr(name, "..")) {
|
|
||||||
if (entry == root) {
|
|
||||||
*result = entry;
|
|
||||||
} else {
|
|
||||||
// If this entry is mounted, get the mountpoint
|
|
||||||
for (; entry->mountpoint; entry = entry->mountpoint) {
|
|
||||||
// No-op
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(NULL != entry->parent);
|
|
||||||
*result = entry->parent;
|
|
||||||
}
|
|
||||||
fsEntryRef(*result);
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
struct fs_entry *child;
|
|
||||||
int childIdx;
|
|
||||||
list_foreach_forward_named(entry->childs, child, childIdx, prevSiblings, nextSiblings)
|
|
||||||
{
|
|
||||||
if (pstringIsEq(&child->name, name)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!list_foreach_early_break(entry->childs, child, childIdx))
|
|
||||||
return -ENOENT;
|
|
||||||
|
|
||||||
*result = child;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Follow the mount chain
|
|
||||||
for (; (*result)->mountedFs; *result = (*result)->mountedFs)
|
|
||||||
;
|
|
||||||
|
|
||||||
fsEntryRef(*result);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fsEntrySetup(void)
|
|
||||||
{
|
|
||||||
return allocBookSlab(sizeof(struct fs_entry), PAGE_SIZE, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fsEntryMount(struct fs_entry *mountpoint, struct fs_entry *mounted)
|
|
||||||
{
|
|
||||||
if (mountpoint->mountedFs != NULL || mounted->mountpoint != NULL) {
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
mountpoint->mountedFs = mounted;
|
|
||||||
mounted->mountpoint = mountpoint;
|
|
||||||
|
|
||||||
fsEntryRef(mounted);
|
|
||||||
fsEntryRef(mountpoint);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fsEntryUmount(struct fs_entry *mounted)
|
|
||||||
{
|
|
||||||
if (!mounted->mountpoint || !mounted->mountpoint->mountedFs || mounted->mountpoint->mountedFs != mounted)
|
|
||||||
return -ENOENT;
|
|
||||||
|
|
||||||
if (mounted->mountedFs)
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
// self + mounted
|
|
||||||
if (mounted->ref != 2)
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
|
|
||||||
mounted->mountpoint->mountedFs = NULL;
|
|
||||||
fsEntryUnref(&mounted->mountpoint);
|
|
||||||
mounted->mountpoint = NULL;
|
|
||||||
fsEntryUnref(&mounted);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
183
core/fsEntry.h
183
core/fsEntry.h
@ -1,183 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "fs.h"
|
|
||||||
#include "stdint.h"
|
|
||||||
#include "stddef.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Those structures aimes to represent VFS directory entries in memory.
|
|
||||||
* It's the equivalent of the Linux dentry or SimpleOs sos_fs_nscache_node.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Path or Pascal String
|
|
||||||
* */
|
|
||||||
struct pstr {
|
|
||||||
size_t len;
|
|
||||||
const char *name;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define PSTR_INIT(n, l) \
|
|
||||||
{ \
|
|
||||||
.len = l, .name = n \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define PSTR_STATIC_INIT(n) \
|
|
||||||
{ \
|
|
||||||
.len = sizeof(n) - 1, .name = n \
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Structure representing a file system entry.
|
|
||||||
*
|
|
||||||
* This structure holds information about a file system entry,
|
|
||||||
* including its name, associated inode, relationships within
|
|
||||||
* the file system hierarchy, and reference count.
|
|
||||||
*/
|
|
||||||
struct fs_entry {
|
|
||||||
struct pstr name;
|
|
||||||
struct inode *node;
|
|
||||||
|
|
||||||
struct fs_entry *parent; // parent directory
|
|
||||||
struct fs_entry *mountpoint; // if this is a mounted fs, point to mountpoint
|
|
||||||
struct fs_entry *mountedFs; // Fs possibly mounted on this fsEntry
|
|
||||||
|
|
||||||
struct fs_entry *childs; // point to the list of children
|
|
||||||
struct fs_entry *nextSiblings, *prevSiblings; // Sibling at the same level
|
|
||||||
|
|
||||||
uint ref; // reference counter
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Splits a pstr path into upper and lower components.
|
|
||||||
*
|
|
||||||
* This function takes a path and splits it into an upper component
|
|
||||||
* (the first segment of the path) and a lower component (the rest of the path).
|
|
||||||
*
|
|
||||||
* @param path Pointer to the input pstr structure representing the path.
|
|
||||||
* @param upper Pointer to the pstr structure to store the upper component.
|
|
||||||
* @param lower Pointer to the pstr structure to store the lower component.
|
|
||||||
* @return bool_t Returns true if there is a lower component, false otherwise.
|
|
||||||
*/
|
|
||||||
bool_t pstringSplipPath(struct pstr *path, struct pstr *upper, struct pstr *lower);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Compares two pstr structures to check if they are equal.
|
|
||||||
*
|
|
||||||
* This function compares the length and the content of the strings
|
|
||||||
* in the two provided pstr structures.
|
|
||||||
*
|
|
||||||
* @param a Pointer to the first pstr structure.
|
|
||||||
* @param b Pointer to the second pstr structure.
|
|
||||||
* @return int Returns 1 if the structures are equal, 0 otherwise.
|
|
||||||
*/
|
|
||||||
bool_t pstringIsEq(const struct pstr *p1, const struct pstr *p2);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if a pstr structure matches a given C string.
|
|
||||||
*
|
|
||||||
* @param s Pointer to the null-terminated C string to compare.
|
|
||||||
* @return bool_t Returns true if the pstr matches the C string, false otherwise.
|
|
||||||
*/
|
|
||||||
bool_t pstringIsStr(const struct pstr *p, char *s);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Increments the reference count of a file system entry.
|
|
||||||
*
|
|
||||||
* This function increments the reference count of the given file system
|
|
||||||
* entry. It is typically used to manage the lifecycle of file system
|
|
||||||
* entries, ensuring that they are not prematurely deallocated.
|
|
||||||
*
|
|
||||||
* @param entry Pointer to the fsEntry structure whose reference count will be incremented.
|
|
||||||
* @return int Returns 0 on success.
|
|
||||||
*/
|
|
||||||
int fsEntryRef(struct fs_entry *entry);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Decrements the reference count of a file system entry.
|
|
||||||
*
|
|
||||||
* This function decrements the reference count of the given file system
|
|
||||||
* entry. It is typically used to manage the lifecycle of file system
|
|
||||||
* entries, ensuring that they are not prematurely deallocated.
|
|
||||||
*
|
|
||||||
* @param entry Pointer to the fsEntry structure whose reference count will be decremented.
|
|
||||||
* @return int Returns 0 on success.
|
|
||||||
*/
|
|
||||||
int fsEntryUnref(struct fs_entry **entry);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Allocates and initializes a new fsEntry.
|
|
||||||
*
|
|
||||||
* This function allocates memory for a new `fsEntry` structure, initializes
|
|
||||||
* it with the provided name and inode, and adds it to the parent's list of children.
|
|
||||||
*
|
|
||||||
* @param parent Pointer to the parent `fsEntry` structure. Can be NULL if the new entry has no parent.
|
|
||||||
* @param name Pointer to the `pstr` structure representing the name of the new entry. Can be NULL.
|
|
||||||
* @param inode Pointer to the `inode` structure associated with the new entry.
|
|
||||||
*
|
|
||||||
* @return struct fsEntry* Pointer to the newly allocated `fsEntry` structure, or NULL if allocation fails.
|
|
||||||
*
|
|
||||||
* @note The reference count of the new entry is set to 1.
|
|
||||||
* @note If a parent is provided, the new entry is added to the parent's list of children and the parent's reference count is incremented.
|
|
||||||
* @note The inode's reference count is incremented.
|
|
||||||
*/
|
|
||||||
struct fs_entry *fsEntryAlloc(struct fs_entry *parent, const struct pstr *name, struct inode *inode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Looks up an entry in the file system.
|
|
||||||
*
|
|
||||||
* This function searches for a specified entry within the children
|
|
||||||
* of a given directory entry. The search is limited to the entries
|
|
||||||
* that are already in memory. If the entry is not found, it indicates
|
|
||||||
* that the entry must be resolved using disk accesses.
|
|
||||||
*
|
|
||||||
* @param entry The node in which we are looking for the entry.
|
|
||||||
* @param name The name of the entry we are looking for.
|
|
||||||
* @param root The base node beyond which lookup must not go (to
|
|
||||||
* support chroot): a kind of "barrier".
|
|
||||||
* @param result The fsEntry for the given entry (set only when
|
|
||||||
* the return value is 0).
|
|
||||||
*
|
|
||||||
* @return int Returns 0 if the entry is found, otherwise returns a non-zero error code.
|
|
||||||
* -ENOENT if the entry could not be found in the entry directory.
|
|
||||||
*
|
|
||||||
* @note The mountpoints are followed.
|
|
||||||
* @note result is a NEW reference to the node. It should be unreferenced when unused.
|
|
||||||
*/
|
|
||||||
int fsEntryLookup(struct fs_entry *entry, const struct pstr *name,
|
|
||||||
const struct fs_entry *root, struct fs_entry **result);
|
|
||||||
/**
|
|
||||||
* @brief Setup the fsEntry subsystem
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
int fsEntrySetup(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Mounts a file system entry at a specified mount point.
|
|
||||||
*
|
|
||||||
* This function mounts a file system entry (`mounted`) at a specified mount point (`mountpoint`).
|
|
||||||
* It updates the `mountedFs` field of the mount point and the `mountpoint` field of the mounted entry.
|
|
||||||
*
|
|
||||||
* @param mountpoint Pointer to the `fsEntry` structure representing the mount point.
|
|
||||||
* @param mounted Pointer to the `fsEntry` structure representing the file system entry to be mounted.
|
|
||||||
*
|
|
||||||
* @return int Returns 0 on success, or -EBUSY if either the mount point is already occupied or the mounted entry is already mounted.
|
|
||||||
*
|
|
||||||
* @note The reference counts of both the mount point and the mounted entry are incremented.
|
|
||||||
*/
|
|
||||||
int fsEntryMount(struct fs_entry *mountpoint, struct fs_entry *mounted);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Unmounts a file system entry.
|
|
||||||
*
|
|
||||||
* This function unmounts a file system entry (`mounted`) from its mount point.
|
|
||||||
* It updates the `mountedFs` field of the mount point and the `mountpoint` field of the mounted entry.
|
|
||||||
*
|
|
||||||
* @param mounted Pointer to the `fsEntry` structure representing the file system entry to be unmounted.
|
|
||||||
*
|
|
||||||
* @return int Returns 0 on success, -ENOENT if the entry is not mounted, or -EBUSY if the entry is busy.
|
|
||||||
*
|
|
||||||
* @note The unmount operation fails if the mounted entry has children or other references.
|
|
||||||
* @note The reference counts of both the mount point and the mounted entry are decremented.
|
|
||||||
*/
|
|
||||||
int fsEntryUmount(struct fs_entry *mounted);
|
|
@ -171,7 +171,7 @@ void reverse(char s[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* K&R */
|
/* K&R */
|
||||||
size_t strlen(const char s[])
|
int strlen(const char s[])
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (s[i] != '\0')
|
while (s[i] != '\0')
|
||||||
|
@ -26,7 +26,7 @@ __attribute__ ((access (write_only, 1, 3))) void *memset(void *s, int c, size_t
|
|||||||
char *itoa(long long int value, char *str, int base);
|
char *itoa(long long int value, char *str, int base);
|
||||||
int atoi(const char *str);
|
int atoi(const char *str);
|
||||||
void reverse(char s[]);
|
void reverse(char s[]);
|
||||||
size_t strlen(const char s[]);
|
int strlen(const char s[]);
|
||||||
__attribute__ ((access (read_only, 1, 2))) unsigned int strnlen(const char *s, size_t count);
|
__attribute__ ((access (read_only, 1, 2))) unsigned int strnlen(const char *s, size_t count);
|
||||||
int strcmp(const char s1[], const char s2[]);
|
int strcmp(const char s1[], const char s2[]);
|
||||||
__attribute__ ((access (read_only, 2), access (write_only, 1, 3))) char *strzcpy(char *dst, const char *src, int len);
|
__attribute__ ((access (read_only, 2), access (write_only, 1, 3))) char *strzcpy(char *dst, const char *src, int len);
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
#include "ata.h"
|
#include "ata.h"
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
#include "exception.h"
|
#include "exception.h"
|
||||||
#include "fsEntry.h"
|
|
||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
#include "interrupt.h"
|
#include "interrupt.h"
|
||||||
|
#include "io.h"
|
||||||
#include "irq.h"
|
#include "irq.h"
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
#include "keyboard.h"
|
#include "keyboard.h"
|
||||||
@ -19,6 +19,7 @@
|
|||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
#include "stack.h"
|
#include "stack.h"
|
||||||
|
#include "stdarg.h"
|
||||||
#include "swintr.h"
|
#include "swintr.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#ifdef RUN_TEST
|
#ifdef RUN_TEST
|
||||||
@ -40,6 +41,7 @@ void idleThread(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define FILE_HEADER_SIZE 16
|
#define FILE_HEADER_SIZE 16
|
||||||
#define FILE_MAX_SIZE 64 // In nb of sectors
|
#define FILE_MAX_SIZE 64 // In nb of sectors
|
||||||
void loadUserSpace()
|
void loadUserSpace()
|
||||||
@ -51,7 +53,7 @@ void loadUserSpace()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *buf = (char *)malloc(FILE_MAX_SIZE * DISK_SECTOR_SIZE);
|
char *buf = malloc(FILE_MAX_SIZE * DISK_SECTOR_SIZE);
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
printf("ENOMEM\n");
|
printf("ENOMEM\n");
|
||||||
return;
|
return;
|
||||||
@ -257,9 +259,6 @@ void kmain(unsigned long magic, unsigned long addr)
|
|||||||
irqSetRoutine(IRQ_TIMER, pit_handler);
|
irqSetRoutine(IRQ_TIMER, pit_handler);
|
||||||
|
|
||||||
ATAInit();
|
ATAInit();
|
||||||
|
|
||||||
// VFS name caching
|
|
||||||
fsEntrySetup();
|
|
||||||
#ifdef RUN_TEST
|
#ifdef RUN_TEST
|
||||||
run_test();
|
run_test();
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,6 +9,3 @@ typedef unsigned long paddr_t;
|
|||||||
|
|
||||||
// Userspace vaddr
|
// Userspace vaddr
|
||||||
typedef unsigned long uaddr_t;
|
typedef unsigned long uaddr_t;
|
||||||
|
|
||||||
// Offset
|
|
||||||
typedef long long loff_t;
|
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* media organization:
|
|
||||||
* * boot record (1 sector, so could be called boot sector): BPB + Extended Boot Record
|
|
||||||
* * File Allocation Table (FAT)
|
|
||||||
* * data area
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
struct ebr_fat16 { // Extended Boot Record for FAT16
|
|
||||||
uint8_t drive_number;
|
|
||||||
uint8_t flags;
|
|
||||||
uint8_t signature; // Must be 0x29 for FAT16
|
|
||||||
uint8_t vol_id[4];
|
|
||||||
uint8_t vol_label[11];
|
|
||||||
uint8_t sys_id[8]; // Do not trust this!
|
|
||||||
uint8_t bootcode[448];
|
|
||||||
uint16_t bootable_signature; // 0xAA55
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct ebr_fat32 { // Extended Boot Record for FAT32
|
|
||||||
uint32_t fat_size;
|
|
||||||
uint16_t flags;
|
|
||||||
uint16_t fat_version_number;
|
|
||||||
uint32_t root_cluster_nb;
|
|
||||||
uint8_t reserved[12];
|
|
||||||
uint8_t drive_number;
|
|
||||||
uint8_t flags_nt;
|
|
||||||
uint8_t signature;
|
|
||||||
uint8_t vol_id[4];
|
|
||||||
uint8_t vol_label[11];
|
|
||||||
uint8_t sys_id[8]; // Should be always "FAT32"
|
|
||||||
uint8_t bootcode[420];
|
|
||||||
uint16_t bootable_signature; // 0xAA55
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct bpb { // Bios Param Block
|
|
||||||
uint8_t jump_ins[3];
|
|
||||||
uint8_t oem_id[3];
|
|
||||||
uint16_t bytes_per_sector;
|
|
||||||
uint8_t sector_per_cluster;
|
|
||||||
uint16_t reserved_sectors; // boot sectors included
|
|
||||||
uint8_t nb_fat;
|
|
||||||
uint16_t nb_root_dirs;
|
|
||||||
uint16_t nb_sectors;
|
|
||||||
uint8_t media_description_type;
|
|
||||||
uint16_t sectors_per_fat;
|
|
||||||
uint16_t sectors_per_track;
|
|
||||||
uint16_t number_of_heads;
|
|
||||||
uint32_t hidden_sectors;
|
|
||||||
uint32_t nb_large_sectors;
|
|
||||||
union {
|
|
||||||
struct ebr_fat32 fat32;
|
|
||||||
struct ebr_fat16 fat16;
|
|
||||||
};
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
READ_ONLY = 0x01,
|
|
||||||
HIDDEN = 0x02,
|
|
||||||
SYSTEM = 0x04,
|
|
||||||
VOLUME_ID = 0x08,
|
|
||||||
DIRECTORY = 0x10,
|
|
||||||
ARCHIVE = 0x20,
|
|
||||||
LFN = READ_ONLY | HIDDEN | SYSTEM | VOLUME_ID,
|
|
||||||
} __attribute__((__packed__)) directory_entry_type_t;
|
|
||||||
|
|
||||||
struct directory_entry {
|
|
||||||
uint8_t filename[11];
|
|
||||||
directory_entry_type_t type;
|
|
||||||
uint8_t reserved;
|
|
||||||
uint8_t creation_time_hundredths_sec;
|
|
||||||
uint16_t creation_time; // hour[5] min[6] sec[5]
|
|
||||||
uint16_t creation_date; // year[7] month[4] day[5]
|
|
||||||
uint16_t last_access_date; // year[7] month[4] day[5]
|
|
||||||
uint16_t cluster_nb_high;
|
|
||||||
uint16_t modification_time; // hour[5] min[6] sec[5]
|
|
||||||
uint16_t modification_date; // year[7] month[4] day[5]
|
|
||||||
uint16_t cluster_nb_low;
|
|
||||||
uint32_t size; // in bytes
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
190
tests/test.c
190
tests/test.c
@ -3,12 +3,8 @@
|
|||||||
#include "ata.h"
|
#include "ata.h"
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
#include "cpu_context.h"
|
#include "cpu_context.h"
|
||||||
#include "errno.h"
|
|
||||||
#include "fsEntry.h"
|
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
#include "klibc.h"
|
#include "klibc.h"
|
||||||
#include "stddef.h"
|
|
||||||
#include "stdint.h"
|
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
@ -497,194 +493,8 @@ void testRingBuffer()
|
|||||||
ringbufferDestroy(inst);
|
ringbufferDestroy(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void printPstr(struct pstr *str){
|
|
||||||
for(uint i = 0; i < str->len; i++){
|
|
||||||
putc(str->name[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void printPstrln(struct pstr *str){
|
|
||||||
printPstr(str);
|
|
||||||
putc('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
void testFsPstring()
|
|
||||||
{
|
|
||||||
bool_t result;
|
|
||||||
struct pstr path, upper, lower, lower2, lower3;
|
|
||||||
|
|
||||||
// Test 1
|
|
||||||
path.name = "/usr/local/bin";
|
|
||||||
path.len = 14;
|
|
||||||
result = pstringSplipPath(&path, &upper, &lower);
|
|
||||||
printf("Test 1:\n");
|
|
||||||
printPstrln(&path);
|
|
||||||
printPstrln(&upper);
|
|
||||||
printPstrln(&lower);
|
|
||||||
printf("Result: %s\n\n", result ? "true" : "false");
|
|
||||||
|
|
||||||
// Test 2
|
|
||||||
path.name = "/home/user";
|
|
||||||
path.len = 10;
|
|
||||||
result = pstringSplipPath(&path, &upper, &lower);
|
|
||||||
printf("Test 2:\n");
|
|
||||||
printPstrln(&path);
|
|
||||||
printPstrln(&upper);
|
|
||||||
printPstrln(&lower);
|
|
||||||
printf("Result: %s\n\n", result ? "true" : "false");
|
|
||||||
|
|
||||||
// Test 3
|
|
||||||
path.name = "/tmp";
|
|
||||||
path.len = 4;
|
|
||||||
result = pstringSplipPath(&path, &upper, &lower);
|
|
||||||
printf("Test 3:\n");
|
|
||||||
printPstrln(&path);
|
|
||||||
printPstrln(&upper);
|
|
||||||
printPstrln(&lower);
|
|
||||||
printf("Result: %s\n\n", result ? "true" : "false");
|
|
||||||
|
|
||||||
// Test 4
|
|
||||||
path.name = "/var/log/";
|
|
||||||
path.len = 9;
|
|
||||||
result = pstringSplipPath(&path, &upper, &lower);
|
|
||||||
printf("Test 4:\n");
|
|
||||||
printPstrln(&path);
|
|
||||||
printPstrln(&upper);
|
|
||||||
printPstrln(&lower);
|
|
||||||
printf("Result: %s\n\n", result ? "true" : "false");
|
|
||||||
|
|
||||||
// Test 5
|
|
||||||
path.name = "/";
|
|
||||||
path.len = 1;
|
|
||||||
result = pstringSplipPath(&path, &upper, &lower);
|
|
||||||
printf("Test 5:\n");
|
|
||||||
printPstrln(&path);
|
|
||||||
printPstrln(&upper);
|
|
||||||
printPstrln(&lower);
|
|
||||||
printf("Result: %s\n\n", result ? "true" : "false");
|
|
||||||
|
|
||||||
// Test 6
|
|
||||||
const char *tmp = "///home///file/test///";
|
|
||||||
path.name = tmp;
|
|
||||||
path.len = strlen(tmp);
|
|
||||||
struct pstr test = PSTR_STATIC_INIT("test");
|
|
||||||
struct pstr empty = PSTR_INIT("", 0);
|
|
||||||
struct pstr slash = PSTR_INIT("/", 1);
|
|
||||||
struct pstr dot = PSTR_INIT("..", 2);
|
|
||||||
|
|
||||||
printf("Test 6:\n");
|
|
||||||
printPstr(&path);
|
|
||||||
assert(pstringSplipPath(&path, &upper, &lower));
|
|
||||||
printf("\nUpper: ");
|
|
||||||
printPstr(&upper);
|
|
||||||
printf("\nLower: ");
|
|
||||||
printPstr(&lower);
|
|
||||||
printf("\n");
|
|
||||||
assert(pstringSplipPath(&lower, &upper, &lower2));
|
|
||||||
printf("\nUpper: ");
|
|
||||||
printPstr(&upper);
|
|
||||||
printf("\nLower: ");
|
|
||||||
printPstr(&lower2);
|
|
||||||
printf("\n");
|
|
||||||
assert(pstringSplipPath(&lower2, &upper, &lower3) == 0);
|
|
||||||
printf("\nUpper: ");
|
|
||||||
printPstr(&upper);
|
|
||||||
printf("\nLower: ");
|
|
||||||
printPstr(&lower3);
|
|
||||||
printf("\n");
|
|
||||||
assert(pstringIsEq(&upper, &test));
|
|
||||||
assert(pstringSplipPath(&empty, &upper, &lower) == FALSE);
|
|
||||||
assert(pstringSplipPath(&slash, &upper, &lower) == FALSE);
|
|
||||||
assert(pstringIsEq(&empty, &test) == FALSE);
|
|
||||||
assert(pstringIsEq(&dot, &test) == FALSE);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void testFsEntry()
|
|
||||||
{
|
|
||||||
printf("Test fsEntry: create tree\n");
|
|
||||||
|
|
||||||
struct inode inode;
|
|
||||||
struct pstr rootname = PSTR_STATIC_INIT("/");
|
|
||||||
struct pstr homename = PSTR_STATIC_INIT("home");
|
|
||||||
struct pstr usrname = PSTR_STATIC_INIT("usr");
|
|
||||||
struct pstr file1name = PSTR_STATIC_INIT("file1");
|
|
||||||
struct pstr mntname = PSTR_STATIC_INIT("mnt");
|
|
||||||
struct pstr mntfilename = PSTR_STATIC_INIT("file2");
|
|
||||||
struct pstr dot = PSTR_STATIC_INIT(".");
|
|
||||||
struct pstr dot2 = PSTR_STATIC_INIT("..");
|
|
||||||
|
|
||||||
// create fs with /home, /mnt, /usr/file1
|
|
||||||
struct fs_entry *root = fsEntryAlloc(NULL, &rootname, &inode);
|
|
||||||
struct fs_entry *home = fsEntryAlloc(root, &homename, &inode);
|
|
||||||
struct fs_entry *usr = fsEntryAlloc(root, &usrname, &inode);
|
|
||||||
struct fs_entry *mnt = fsEntryAlloc(root, &mntname, &inode);
|
|
||||||
struct fs_entry *file1 = fsEntryAlloc(home, &file1name, &inode);
|
|
||||||
|
|
||||||
// /file2
|
|
||||||
struct fs_entry *rootExt = fsEntryAlloc(NULL, &rootname, &inode);
|
|
||||||
struct fs_entry *mntfile = fsEntryAlloc(rootExt, &mntfilename, &inode);
|
|
||||||
struct fs_entry *res, *res2;
|
|
||||||
|
|
||||||
assert(root && home && usr);
|
|
||||||
|
|
||||||
printf("Test fsEntry: Lookup\n");
|
|
||||||
// find a child
|
|
||||||
assert(fsEntryLookup(root, &homename, NULL, &res) == 0);
|
|
||||||
assert(home == res);
|
|
||||||
fsEntryUnref(&res);
|
|
||||||
|
|
||||||
// cd .
|
|
||||||
assert(fsEntryLookup(home, &dot, NULL, &res) == 0);
|
|
||||||
assert(home == res);
|
|
||||||
fsEntryUnref(&res);
|
|
||||||
|
|
||||||
// cd ..
|
|
||||||
assert(fsEntryLookup(home, &dot2, NULL, &res) == 0);
|
|
||||||
assert(root == res);
|
|
||||||
fsEntryUnref(&res);
|
|
||||||
|
|
||||||
// find a non-child fail
|
|
||||||
assert(fsEntryLookup(home, &usrname, NULL, &res) == -ENOENT);
|
|
||||||
|
|
||||||
// find mnt and mount rootExt
|
|
||||||
assert(fsEntryLookup(root, &mntname, NULL, &res) == 0);
|
|
||||||
assert(res == mnt);
|
|
||||||
assert(fsEntryMount(res, rootExt)==0);
|
|
||||||
fsEntryUnref(&res); //lookup increase ref
|
|
||||||
|
|
||||||
// find on mounted
|
|
||||||
assert(fsEntryLookup(root, &mntname, NULL, &res) == 0);
|
|
||||||
fsEntryUnref(&res); //lookup increase ref
|
|
||||||
assert(fsEntryLookup(res, &mntfilename, NULL, &res2) == 0);
|
|
||||||
fsEntryUnref(&res2); //lookup increase ref
|
|
||||||
|
|
||||||
// Clen rootExt
|
|
||||||
fsEntryUnref(&mntfile);
|
|
||||||
|
|
||||||
// unmount rootExt
|
|
||||||
assert(fsEntryUmount(rootExt) == 0);
|
|
||||||
|
|
||||||
|
|
||||||
printf("Test fsEntry: free tree\n");
|
|
||||||
fsEntryUnref(&usr);
|
|
||||||
assert(root->ref > 0);
|
|
||||||
assert(usr == NULL);
|
|
||||||
fsEntryUnref(&home);
|
|
||||||
assert(home != NULL);
|
|
||||||
fsEntryUnref(&file1);
|
|
||||||
assert(file1 == NULL);
|
|
||||||
fsEntryUnref(&mnt);
|
|
||||||
assert(mnt == NULL);
|
|
||||||
|
|
||||||
fsEntryUnref(&mntfile);
|
|
||||||
fsEntryUnref(&rootExt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void run_test(void)
|
void run_test(void)
|
||||||
{
|
{
|
||||||
testFsPstring();
|
|
||||||
testFsEntry();
|
|
||||||
// Example of checking thx to access attributs
|
// Example of checking thx to access attributs
|
||||||
//int a[4] = {0};
|
//int a[4] = {0};
|
||||||
//int b[3] = {0};
|
//int b[3] = {0};
|
||||||
|
Loading…
Reference in New Issue
Block a user