Compare commits

..

1 Commits

Author SHA1 Message Date
Mathieu Maret
3ecb5b9d66 VFS: design for the name cache system 2024-05-23 00:21:41 +02:00
9 changed files with 60 additions and 411 deletions

View File

@ -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 */

View File

@ -1,27 +1,13 @@
#include "fs.h" #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) int fsInodeUnref(struct inode *inode)
{ {
//TODO
(void)inode; (void)inode;
return 0; return 0;
}; };
int fsInodeRef(struct inode *inode) int fsInodeRef(struct inode *inode)
{ {
//TODO
(void)inode; (void)inode;
return 0; return 0;
}; };

136
core/fs.h
View File

@ -1,139 +1,7 @@
#pragma once #pragma once
#include "fsEntry.h"
#include "process.h"
#include "stdint.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 {
};
struct inode { // inode_operation
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 (*new_opened_file)(struct inode *this, const struct process *owner,
uint32_t open_flags, struct file **result_of);
int (*close_opened_file)(struct inode *this, struct file *of);
void *custom;
struct inode *prev_dirty, *next_dirty;
};
struct file_system_instance_ops { // super_operations
// From the inode location, instantiace a struct inode
int (*getInodeFromDevice)(struct file_system_instance *this, uint64_t storage_location,
struct inode **result);
int (*allocateNewInode)(struct file_system_instance *this, fs_inode_type_t type,
const struct process *creator, uint32_t access_rights,
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 fsEntry *root; // root fsEntry for this fs instance
struct indoe *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; struct inode {//TODO
}; };
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 **mounted_fs);
int (*umount)(struct file_system *this, struct file_system_instance *mounted_fs);
struct file_system *prev, *next;
};
struct file_operations{
};
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 *for_owner,
struct file **result);
void *custom;
};
int fsRegister(struct file_system *fs);
int fsInodeUnref(struct inode *inode); int fsInodeUnref(struct inode *inode);
int fsInodeRef(struct inode *inode); int fsInodeRef(struct inode *inode);

View File

@ -4,6 +4,7 @@
#include "errno.h" #include "errno.h"
#include "list.h" #include "list.h"
#include "mem.h" #include "mem.h"
#include "stdint.h"
bool_t pstringSplipPath(struct pstr *path, struct pstr *upper, struct pstr *lower) bool_t pstringSplipPath(struct pstr *path, struct pstr *upper, struct pstr *lower)
{ {
@ -37,28 +38,23 @@ bool_t pstringSplipPath(struct pstr *path, struct pstr *upper, struct pstr *lowe
return lower->len > 0; return lower->len > 0;
} }
bool_t pstringIsEq(const struct pstr *p1, const struct pstr *p2) bool_t pstringIsEq(struct pstr *p1, struct pstr *p2)
{ {
return p1->len == p2->len && (memcmp(p1->name, p2->name, p1->len) == 0); return p1->len == p2->len && (memcmp(p1, p2, p1->len) == 0);
} }
bool_t pstringIsStr(const struct pstr *p, char *s) int fsEntryRef(struct fsEntry *entry)
{
size_t slen = strlen(s);
return p->len == slen && (memcmp(p->name, s, slen) == 0);
}
int fsEntryRef(struct fs_entry *entry)
{ {
entry->ref++; entry->ref++;
return 0; return 0;
} }
int fsEntryUnref(struct fs_entry **entry) int fsEntryUnref(struct fsEntry **entry)
{ {
struct fs_entry *toDelete = NULL, *entryTmp; struct fsEntry *toDelete = NULL, *entryTmp;
entryTmp = *entry; entryTmp = *entry;
*entry = NULL;
while (entryTmp) { while (entryTmp) {
assert(entryTmp->ref > 0); assert(entryTmp->ref > 0);
@ -68,10 +64,10 @@ int fsEntryUnref(struct fs_entry **entry)
break; break;
if (entryTmp == *entry) if (entryTmp == *entry)
*entry = NULL; entry = NULL;
if (entryTmp->parent) { if (entryTmp->parent) {
struct fs_entry *parent = entryTmp->parent; struct fsEntry *parent = entryTmp->parent;
assert(entryTmp->parent->ref >= 1); assert(entryTmp->parent->ref >= 1);
@ -96,19 +92,20 @@ int fsEntryUnref(struct fs_entry **entry)
return 0; return 0;
} }
struct fs_entry *fsEntryAlloc(struct fs_entry *parent, const struct pstr *name, struct inode *inode) int fsEntryNewChild(struct fsEntry *parent, const struct pstr *name, struct inode *inode,
struct fsEntry **result)
{ {
struct fs_entry *entry = zalloc(sizeof(struct fs_entry)); struct fsEntry *entry = malloc(sizeof(struct fsEntry));
if (!entry) if (!entry)
return NULL; return -ENOMEM;
if (name && name->len > 0) { if (name && name->len > 0) {
char *allocName = malloc(name->len); char *allocName = malloc(name->len);
if (!allocName) { if (!allocName) {
free(entry); free(entry);
return NULL; return -ENOMEM;
} }
memcpy(allocName, name->name, name->len); memcpy(allocName, name->name, name->len);
@ -121,95 +118,16 @@ struct fs_entry *fsEntryAlloc(struct fs_entry *parent, const struct pstr *name,
entry->parent = parent; entry->parent = parent;
fsInodeRef(inode); fsInodeRef(inode);
if (parent) { if (parent) {
fsEntryRef(parent); fsEntryRef(parent);
list_add_head_named(parent->childs, entry, prevSiblings, nextSiblings); list_add_head_named(parent->childs, entry, prevSiblings, nextSiblings);
} }
return entry; *result = 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; return 0;
} }
int fsEntrySetup(void) int fsEntrySetup(void){
{ return allocBookSlab(sizeof(struct fsEntry), PAGE_SIZE, 0, 0);
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;
} }

View File

@ -22,10 +22,6 @@ struct pstr {
.len = l, .name = n \ .len = l, .name = n \
} }
#define PSTR_STATIC_INIT(n) \
{ \
.len = sizeof(n) - 1, .name = n \
}
/** /**
* @brief Structure representing a file system entry. * @brief Structure representing a file system entry.
@ -34,16 +30,16 @@ struct pstr {
* including its name, associated inode, relationships within * including its name, associated inode, relationships within
* the file system hierarchy, and reference count. * the file system hierarchy, and reference count.
*/ */
struct fs_entry { struct fsEntry {
struct pstr name; struct pstr name;
struct inode *node; struct inode *node;
struct fs_entry *parent; // parent directory struct fsEntry *parent; // parent directory
struct fs_entry *mountpoint; // if this is a mounted fs, point to mountpoint struct fsEntry *mountpoint; // if this is a mounted fs, point to mountpoint
struct fs_entry *mountedFs; // Fs possibly mounted on this fsEntry struct fsEntry *mountedFs; // Fs possibly mounted on this fsEntry
struct fs_entry *childs; // point to the list of children struct fsEntry *childs; // point to the list of children
struct fs_entry *nextSiblings, *prevSiblings; // Sibling at the same level struct fsEntry *nextSiblings, *prevSiblings; // Sibling at the same level
uint ref; // reference counter uint ref; // reference counter
}; };
@ -71,15 +67,7 @@ bool_t pstringSplipPath(struct pstr *path, struct pstr *upper, struct pstr *lowe
* @param b Pointer to the second pstr structure. * @param b Pointer to the second pstr structure.
* @return int Returns 1 if the structures are equal, 0 otherwise. * @return int Returns 1 if the structures are equal, 0 otherwise.
*/ */
bool_t pstringIsEq(const struct pstr *p1, const struct pstr *p2); bool_t pstringIsEq(struct pstr *p1, 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. * @brief Increments the reference count of a file system entry.
@ -91,7 +79,7 @@ bool_t pstringIsStr(const struct pstr *p, char *s);
* @param entry Pointer to the fsEntry structure whose reference count will be incremented. * @param entry Pointer to the fsEntry structure whose reference count will be incremented.
* @return int Returns 0 on success. * @return int Returns 0 on success.
*/ */
int fsEntryRef(struct fs_entry *entry); int fsEntryRef(struct fsEntry *entry);
/** /**
* @brief Decrements the reference count of a file system entry. * @brief Decrements the reference count of a file system entry.
@ -100,84 +88,31 @@ int fsEntryRef(struct fs_entry *entry);
* entry. It is typically used to manage the lifecycle of file system * entry. It is typically used to manage the lifecycle of file system
* entries, ensuring that they are not prematurely deallocated. * entries, ensuring that they are not prematurely deallocated.
* *
* @param entry Pointer to the fsEntry structure whose reference count will be decremented. * @param entry Pointer to the fsEntry structure whose reference count will be incremented.
* @return int Returns 0 on success. * @return int Returns 0 on success.
*/ */
int fsEntryUnref(struct fs_entry **entry); int fsEntryUnref(struct fsEntry **entry);
/** /**
* @brief Allocates and initializes a new fsEntry. * @brief Creates a new child fsEntry under the specified parent.
* *
* This function allocates memory for a new `fsEntry` structure, initializes * This function allocates and initializes a new fsEntry structure
* it with the provided name and inode, and adds it to the parent's list of children. * representing a file system entry. The new entry is added as a child
* of the specified parent. It also handles reference counting for
* the parent entry and the associated inode.
* *
* @param parent Pointer to the parent `fsEntry` structure. Can be NULL if the new entry has no parent. * @param parent Pointer to the parent fsEntry. 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 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. * @param inode Pointer to the inode associated with the new entry.
* * @param result Pointer to a location where the pointer to the newly created fsEntry will be stored.
* @return struct fsEntry* Pointer to the newly allocated `fsEntry` structure, or NULL if allocation fails. * @return int Returns 0 on success, or a negative error code on failure.
* * -ENOMEM if memory 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); int fsEntryNewChild(struct fsEntry *parent, const struct pstr *name, struct inode *inode,
struct fsEntry **result);
/**
* @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 * @brief Setup the fsEntry subsystem
* *
*/ */
int fsEntrySetup(void); 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);

View File

@ -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')

View File

@ -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);

View File

@ -7,6 +7,7 @@
#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 +20,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 +42,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 +54,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;

View File

@ -3,7 +3,6 @@
#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 "fsEntry.h"
#include "kernel.h" #include "kernel.h"
#include "klibc.h" #include "klibc.h"
@ -564,9 +563,10 @@ void testFsPstring()
// Test 6 // Test 6
const char *tmp = "///home///file/test///"; const char *tmp = "///home///file/test///";
const char *testS = "test";
path.name = tmp; path.name = tmp;
path.len = strlen(tmp); path.len = strlen(tmp);
struct pstr test = PSTR_STATIC_INIT("test"); struct pstr test = PSTR_INIT(testS, strlen(testS));
struct pstr empty = PSTR_INIT("", 0); struct pstr empty = PSTR_INIT("", 0);
struct pstr slash = PSTR_INIT("/", 1); struct pstr slash = PSTR_INIT("/", 1);
struct pstr dot = PSTR_INIT("..", 2); struct pstr dot = PSTR_INIT("..", 2);
@ -603,82 +603,21 @@ void testFsPstring()
void testFsEntry() void testFsEntry()
{ {
printf("Test fsEntry: create tree\n"); printf("Test fsEntry: create tree\n");
struct inode node;
struct inode inode; struct fsEntry *root, *home, *usr;
struct pstr rootname = PSTR_STATIC_INIT("/"); struct pstr rootname = PSTR_INIT("root", 4);
struct pstr homename = PSTR_STATIC_INIT("home"); struct pstr homename = PSTR_INIT("home", 4);
struct pstr usrname = PSTR_STATIC_INIT("usr"); struct pstr usrname = PSTR_INIT("usr", 3);
struct pstr file1name = PSTR_STATIC_INIT("file1"); assert(fsEntryNewChild(NULL, &rootname, &node, &root) == 0);
struct pstr mntname = PSTR_STATIC_INIT("mnt"); assert(fsEntryNewChild(root, &homename, &node, &home) == 0);
struct pstr mntfilename = PSTR_STATIC_INIT("file2"); assert(fsEntryNewChild(root, &usrname, &node, &usr) == 0);
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"); printf("Test fsEntry: free tree\n");
fsEntryUnref(&usr); fsEntryUnref(&usr);
assert(root->ref > 0); assert(root->ref > 0);
assert(usr == NULL); assert(usr == NULL);
fsEntryUnref(&home); fsEntryUnref(&home);
assert(home != NULL); assert(usr == NULL);
fsEntryUnref(&file1);
assert(file1 == NULL);
fsEntryUnref(&mnt);
assert(mnt == NULL);
fsEntryUnref(&mntfile);
fsEntryUnref(&rootExt);
} }
void run_test(void) void run_test(void)