Add creat function call. Fix direntry iteration in EXT2. Fix open of directories in EXT2. Fix re-utilization of unlinked direntries in EXT2.
This commit is contained in:
@@ -15,3 +15,5 @@ int ext2_initialize();
|
||||
/// @brief De-initializes the EXT2 drivers.
|
||||
/// @return 0 on success, 1 on error.
|
||||
int ext2_finalize();
|
||||
|
||||
void ext2_test();
|
||||
@@ -112,6 +112,14 @@ int vfs_mkdir(const char *path, mode_t mode);
|
||||
/// @return Returns a negative value on failure.
|
||||
int vfs_rmdir(const char *path);
|
||||
|
||||
/// @brief Creates a new file or rewrite an existing one.
|
||||
/// @param path path to the file.
|
||||
/// @param mode mode for file creation.
|
||||
/// @return file descriptor number, -1 otherwise and errno is set to indicate the error.
|
||||
/// @details
|
||||
/// It is equivalent to: open(path, O_WRONLY|O_CREAT|O_TRUNC, mode)
|
||||
vfs_file_t *vfs_creat(const char *path, mode_t mode);
|
||||
|
||||
/// @brief Stat the file at the given path.
|
||||
/// @param path Path to the file for which we are retrieving the statistics.
|
||||
/// @param buf Buffer where we are storing the statistics.
|
||||
|
||||
@@ -23,6 +23,8 @@ typedef struct vfs_file_t vfs_file_t;
|
||||
typedef int (*vfs_mkdir_callback)(const char *, mode_t);
|
||||
/// Function used to remove a directory.
|
||||
typedef int (*vfs_rmdir_callback)(const char *);
|
||||
/// Function used to open a file (or directory).
|
||||
typedef vfs_file_t *(*vfs_creat_callback)(const char *, mode_t);
|
||||
/// Function used to read the entries of a directory.
|
||||
typedef int (*vfs_getdents_callback)(vfs_file_t *, dirent_t *, off_t, size_t);
|
||||
/// Function used to open a file (or directory).
|
||||
@@ -62,6 +64,8 @@ typedef struct vfs_sys_operations_t {
|
||||
vfs_rmdir_callback rmdir_f;
|
||||
/// Stat function.
|
||||
vfs_stat_callback stat_f;
|
||||
/// File creation function.
|
||||
vfs_creat_callback creat_f;
|
||||
} vfs_sys_operations_t;
|
||||
|
||||
/// @brief Set of functions used to perform operations on files.
|
||||
|
||||
@@ -208,6 +208,14 @@ int sys_mkdir(const char *path, mode_t mode);
|
||||
/// @return Returns a negative value on failure.
|
||||
int sys_rmdir(const char *path);
|
||||
|
||||
/// @brief Creates a new file or rewrite an existing one.
|
||||
/// @param path path to the file.
|
||||
/// @param mode mode for file creation.
|
||||
/// @return file descriptor number, -1 otherwise and errno is set to indicate the error.
|
||||
/// @details
|
||||
/// It is equivalent to: open(path, O_WRONLY|O_CREAT|O_TRUNC, mode)
|
||||
int sys_creat(const char *path, mode_t mode);
|
||||
|
||||
/// Provide access to the directory entries.
|
||||
/// @param fd The file descriptor of the directory for which we accessing
|
||||
/// the entries.
|
||||
|
||||
+191
-126
@@ -386,6 +386,7 @@ static int ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_t co
|
||||
static int ext2_mkdir(const char *path, mode_t mode);
|
||||
static int ext2_rmdir(const char *path);
|
||||
static int ext2_stat(const char *path, stat_t *stat);
|
||||
static vfs_file_t *ext2_creat(const char *path, mode_t permission);
|
||||
|
||||
static vfs_file_t *ext2_mount(vfs_file_t *block_device, const char *path);
|
||||
|
||||
@@ -397,7 +398,8 @@ static vfs_file_t *ext2_mount(vfs_file_t *block_device, const char *path);
|
||||
static vfs_sys_operations_t ext2_sys_operations = {
|
||||
.mkdir_f = ext2_mkdir,
|
||||
.rmdir_f = ext2_rmdir,
|
||||
.stat_f = ext2_stat
|
||||
.stat_f = ext2_stat,
|
||||
.creat_f = ext2_creat
|
||||
};
|
||||
|
||||
/// Filesystem file operations.
|
||||
@@ -1653,6 +1655,12 @@ static int ext2_allocate_direntry(ext2_filesystem_t *fs, vfs_file_t *parent, con
|
||||
// Iterate the directory entries.
|
||||
ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, &parent_inode);
|
||||
for (; ext2_direntry_iterator_valid(&it); ext2_direntry_iterator_next(&it)) {
|
||||
// If we hit a direntry with an empty inode, that is a free direntry.
|
||||
if (it.direntry->inode == 0) {
|
||||
pr_debug("Found free direntry: %p (%d <= %d)\n", it.direntry, it.direntry->rec_len, rec_len);
|
||||
if (rec_len <= it.direntry->rec_len)
|
||||
break;
|
||||
}
|
||||
// Compute the real rec_len of the entry.
|
||||
uint32_t real_rec_len = ext2_get_rec_len_from_direntry(it.direntry);
|
||||
// If the previous direntry has a wrong rec_len (wrong because it identifies the last).
|
||||
@@ -1670,12 +1678,29 @@ static int ext2_allocate_direntry(ext2_filesystem_t *fs, vfs_file_t *parent, con
|
||||
// Stop here.
|
||||
break;
|
||||
}
|
||||
// If we hit a direntry with an empty inode, that is a free direntry.
|
||||
if (it.direntry->inode == 0)
|
||||
break;
|
||||
}
|
||||
if (it.direntry) {
|
||||
pr_debug("We need to replace the direntry: %p\n", it.direntry);
|
||||
// Clean the previous name.
|
||||
memset(it.direntry->name, 0, it.direntry->name_len);
|
||||
// Set the inode.
|
||||
it.direntry->inode = inode_index;
|
||||
// Set the new name length,
|
||||
it.direntry->name_len = strlen(name);
|
||||
// Set the new name.
|
||||
memcpy(it.direntry->name, name, it.direntry->name_len);
|
||||
// Set the file type.
|
||||
it.direntry->file_type = file_type;
|
||||
|
||||
if (ext2_write_inode_block(fs, &parent_inode, parent->ino, it.block_index, cache) == -1) {
|
||||
pr_err("Failed to update the block of the father directory.\n");
|
||||
// Free the cache.
|
||||
kmem_cache_free(cache);
|
||||
return -1;
|
||||
}
|
||||
// Free the cache.
|
||||
kmem_cache_free(cache);
|
||||
return 0;
|
||||
} else if ((it.block_offset + rec_len) >= fs->block_size) {
|
||||
pr_debug("We need a new direntry, and a new block (%d + %d >= %d).\n", it.block_offset, rec_len, fs->block_size);
|
||||
it.block_index += 1;
|
||||
@@ -1759,12 +1784,15 @@ static int ext2_find_direntry(ext2_filesystem_t *fs, ino_t ino, const char *name
|
||||
memset(cache, 0, fs->block_size);
|
||||
ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, &inode);
|
||||
for (; ext2_direntry_iterator_valid(&it); ext2_direntry_iterator_next(&it)) {
|
||||
// Skip unused inode.
|
||||
if (it.direntry->inode == 0)
|
||||
continue;
|
||||
// Chehck the name.
|
||||
if (!strcmp(it.direntry->name, ".") && !strcmp(name, "/")) {
|
||||
break;
|
||||
}
|
||||
// Check if the entry has the same name.
|
||||
if ((it.direntry->inode != 0) && (strlen(name) == it.direntry->name_len))
|
||||
if (strlen(name) == it.direntry->name_len)
|
||||
if (!strncmp(it.direntry->name, name, it.direntry->name_len))
|
||||
break;
|
||||
}
|
||||
@@ -1936,19 +1964,17 @@ static int ext2_init_vfs_file(
|
||||
const char *name,
|
||||
size_t name_len)
|
||||
{
|
||||
// Information for root dir.
|
||||
file->device = (void *)fs;
|
||||
file->ino = inode_index;
|
||||
// Copy the name
|
||||
memcpy(file->name, name, name_len);
|
||||
file->name[name_len] = 0;
|
||||
// Information from the inode.
|
||||
file->uid = inode->uid;
|
||||
file->gid = inode->gid;
|
||||
file->length = inode->size;
|
||||
file->mask = inode->mode & 0xFFF;
|
||||
file->nlink = inode->links_count;
|
||||
// File flags.
|
||||
// Set the device.
|
||||
file->device = (void *)fs;
|
||||
// Set the mask.
|
||||
file->mask = inode->mode & 0xFFF;
|
||||
// Set UID and GID.
|
||||
file->uid = inode->uid;
|
||||
file->gid = inode->gid;
|
||||
// Set the VFS specific flags.
|
||||
file->flags = 0;
|
||||
if ((inode->mode & EXT2_S_IFREG) == EXT2_S_IFREG) {
|
||||
file->flags |= DT_REG;
|
||||
@@ -1968,15 +1994,29 @@ static int ext2_init_vfs_file(
|
||||
if ((inode->mode & EXT2_S_IFLNK) == EXT2_S_IFLNK) {
|
||||
file->flags |= DT_LNK;
|
||||
}
|
||||
file->atime = inode->atime;
|
||||
file->mtime = inode->mtime;
|
||||
file->ctime = inode->ctime;
|
||||
// Set the inode.
|
||||
file->ino = inode_index;
|
||||
// Set the size of the file.
|
||||
file->length = inode->size;
|
||||
//uint32_t impl;
|
||||
//uint32_t open_flags;
|
||||
// Set the open count.
|
||||
file->count = 0;
|
||||
// Set the timing information.
|
||||
file->atime = inode->atime;
|
||||
file->mtime = inode->mtime;
|
||||
file->ctime = inode->ctime;
|
||||
// Set the FS specific operations.
|
||||
file->sys_operations = &ext2_sys_operations;
|
||||
file->fs_operations = &ext2_fs_operations;
|
||||
// Set the read offest.
|
||||
file->f_pos = 0;
|
||||
// Set the number of links.
|
||||
file->nlink = inode->links_count;
|
||||
// Initialize the list of siblings.
|
||||
list_head_init(&file->siblings);
|
||||
|
||||
pr_debug("ext2_init_vfs_file : [%d] `%s` (%s) (name len : %d)\n", file->ino, file->name, name, strlen(name));
|
||||
// Set the refcount to zero.
|
||||
file->refcount = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2082,24 +2122,41 @@ static int ext2_create_inode(
|
||||
return inode_index;
|
||||
}
|
||||
|
||||
static vfs_file_t *ext2_creat(vfs_file_t *parent, const char *name, mode_t permission)
|
||||
/// @brief Creates a new file or rewrite an existing one.
|
||||
/// @param path path to the file.
|
||||
/// @param mode mode for file creation.
|
||||
/// @return file descriptor number, -1 otherwise and errno is set to indicate the error.
|
||||
/// @details
|
||||
/// It is equivalent to: open(path, O_WRONLY|O_CREAT|O_TRUNC, mode)
|
||||
static vfs_file_t *ext2_creat(const char *path, mode_t permission)
|
||||
{
|
||||
// Get the name of the directory.
|
||||
const char *parent_path = dirname(path), *file_name = basename(path);
|
||||
if (strcmp(parent_path, path) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
// Get the parent VFS node.
|
||||
vfs_file_t *parent = vfs_open(parent_path, O_RDONLY, 0);
|
||||
if (parent == NULL) {
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
// flags = O_WRONLY | O_CREAT | O_TRUNC
|
||||
// Get the filesystem.
|
||||
ext2_filesystem_t *fs = (ext2_filesystem_t *)parent->device;
|
||||
if (fs == NULL) {
|
||||
pr_err("The parent does not belong to an EXT2 filesystem `%s`.\n", parent->name);
|
||||
return NULL;
|
||||
goto close_parent_return_null;
|
||||
}
|
||||
// Prepare the structure for the direntry.
|
||||
ext2_dirent_t direntry;
|
||||
// Prepare an inode, it will come in handy either way.
|
||||
ext2_inode_t inode;
|
||||
// Search if the entry already exists.
|
||||
if (!ext2_find_direntry_simple(fs, parent->ino, name, &direntry)) {
|
||||
if (!ext2_find_direntry_simple(fs, parent->ino, file_name, &direntry)) {
|
||||
if (ext2_read_inode(fs, &inode, direntry.inode) == -1) {
|
||||
pr_err("Failed to read the inode of `%s`.\n", direntry.name);
|
||||
return NULL;
|
||||
goto close_parent_return_null;
|
||||
}
|
||||
vfs_file_t *file = ext2_find_vfs_file_with_inode(fs, direntry.inode);
|
||||
if (file == NULL) {
|
||||
@@ -2107,11 +2164,11 @@ static vfs_file_t *ext2_creat(vfs_file_t *parent, const char *name, mode_t permi
|
||||
file = kmem_cache_alloc(vfs_file_cache, GFP_KERNEL);
|
||||
if (file == NULL) {
|
||||
pr_err("Failed to allocate memory for the EXT2 file.\n");
|
||||
return NULL;
|
||||
goto close_parent_return_null;
|
||||
}
|
||||
if (ext2_init_vfs_file(fs, file, &inode, direntry.inode, direntry.name, direntry.name_len) == -1) {
|
||||
pr_err("Failed to properly set the VFS file.\n");
|
||||
return NULL;
|
||||
goto close_parent_return_null;
|
||||
}
|
||||
// Add the vfs_file to the list of associated files.
|
||||
list_head_add_tail(&file->siblings, &fs->opened_files);
|
||||
@@ -2127,24 +2184,27 @@ static vfs_file_t *ext2_creat(vfs_file_t *parent, const char *name, mode_t permi
|
||||
int inode_index = ext2_create_inode(fs, &inode, mode, group_index);
|
||||
if (inode_index == -1) {
|
||||
pr_err("Failed to create a new inode inside `%s` (group index: %d).\n", parent->name, group_index);
|
||||
return NULL;
|
||||
goto close_parent_return_null;
|
||||
}
|
||||
// Initialize the file.
|
||||
if (ext2_allocate_direntry(fs, parent, name, inode_index, ext2_file_type_regular_file) == -1) {
|
||||
if (ext2_allocate_direntry(fs, parent, file_name, inode_index, ext2_file_type_regular_file) == -1) {
|
||||
pr_err("Failed to allocate a new direntry for the inode.\n");
|
||||
return NULL;
|
||||
goto close_parent_return_null;
|
||||
}
|
||||
// Allocate the memory for the file.
|
||||
vfs_file_t *new_file = kmem_cache_alloc(vfs_file_cache, GFP_KERNEL);
|
||||
if (new_file == NULL) {
|
||||
pr_err("Failed to allocate memory for the EXT2 file.\n");
|
||||
return NULL;
|
||||
goto close_parent_return_null;
|
||||
}
|
||||
if (ext2_init_vfs_file(fs, new_file, &inode, inode_index, name, strlen(name)) == -1) {
|
||||
if (ext2_init_vfs_file(fs, new_file, &inode, inode_index, file_name, strlen(file_name)) == -1) {
|
||||
pr_err("Failed to properly set the VFS file.\n");
|
||||
return NULL;
|
||||
goto close_parent_return_null;
|
||||
}
|
||||
return new_file;
|
||||
close_parent_return_null:
|
||||
vfs_close(parent);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// @brief Open the file at the given path and returns its file descriptor.
|
||||
@@ -2182,31 +2242,16 @@ static vfs_file_t *ext2_open(const char *path, int flags, mode_t mode)
|
||||
// First check, if a file with the given name already exists.
|
||||
if (!ext2_resolve_path(fs->root, absolute_path, &search)) {
|
||||
if (bitmask_check(flags, O_CREAT | O_EXCL)) {
|
||||
pr_err("A file at `%s` already exists (O_CREAT | O_EXCL).\n", absolute_path);
|
||||
pr_err("A file or directory already exists at `%s` (O_CREAT | O_EXCL).\n", absolute_path);
|
||||
return NULL;
|
||||
} else if (bitmask_check(flags, O_DIRECTORY) && (direntry.file_type != ext2_file_type_directory)) {
|
||||
errno = ENOTDIR;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
// If we need to create it, it's ok if it does not exist.
|
||||
if (bitmask_check(flags, O_CREAT)) {
|
||||
// Get the name of the directory.
|
||||
char *parent_path = dirname(path);
|
||||
if (strcmp(parent_path, path)) {
|
||||
// Get the parent VFS node.
|
||||
vfs_file_t *parent = ext2_open(parent_path, O_RDONLY, 0);
|
||||
if (parent) {
|
||||
// Create the file.
|
||||
vfs_file_t *new_file = ext2_creat(parent, basename(path), mode);
|
||||
if (new_file) {
|
||||
// Add the vfs_file to the list of associated files.
|
||||
list_head_add_tail(&new_file->siblings, &fs->opened_files);
|
||||
}
|
||||
// Close the parent directory.
|
||||
ext2_close(parent);
|
||||
// Return the newly created file.
|
||||
return new_file;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return ext2_creat(path, mode);
|
||||
} else {
|
||||
pr_err("The file does not exist `%s`.\n", absolute_path);
|
||||
return NULL;
|
||||
@@ -2522,6 +2567,9 @@ static int ext2_getdents(vfs_file_t *file, dirent_t *dirp, off_t doff, size_t co
|
||||
// Initialize the iterator.
|
||||
ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, &inode);
|
||||
for (; ext2_direntry_iterator_valid(&it) && (written < count); ext2_direntry_iterator_next(&it)) {
|
||||
// Skip unused inode.
|
||||
if (it.direntry->inode == 0)
|
||||
continue;
|
||||
// Skip if already provided.
|
||||
current += sizeof(dirent_t);
|
||||
if (current <= doff)
|
||||
@@ -2566,29 +2614,8 @@ static int ext2_mkdir(const char *path, mode_t permission)
|
||||
ext2_inode_t inode;
|
||||
// Search if the entry already exists.
|
||||
if (!ext2_resolve_path_direntry(fs->root, absolute_path, &direntry)) {
|
||||
// Get the associated inode.
|
||||
if (ext2_read_inode(fs, &inode, direntry.inode) == -1) {
|
||||
pr_err("Failed to read the inode of `%s`.\n", direntry.name);
|
||||
return -ENOENT;
|
||||
}
|
||||
// Create a VFS file.
|
||||
vfs_file_t *file = ext2_find_vfs_file_with_inode(fs, direntry.inode);
|
||||
if (file == NULL) {
|
||||
// Allocate the memory for the file.
|
||||
file = kmem_cache_alloc(vfs_file_cache, GFP_KERNEL);
|
||||
if (file == NULL) {
|
||||
pr_err("Failed to allocate memory for the EXT2 file.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (ext2_init_vfs_file(fs, file, &inode, direntry.inode, direntry.name, direntry.name_len) == -1) {
|
||||
pr_err("Failed to properly set the VFS file.\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
// Add the vfs_file to the list of associated files.
|
||||
list_head_add_tail(&file->siblings, &fs->opened_files);
|
||||
}
|
||||
ext2_close(file);
|
||||
return 0;
|
||||
pr_err("Directory already exists.\n");
|
||||
return -EEXIST;
|
||||
}
|
||||
// Get the parent directory.
|
||||
char *parent_path = dirname(path);
|
||||
@@ -2597,7 +2624,7 @@ static int ext2_mkdir(const char *path, mode_t permission)
|
||||
return -ENOENT;
|
||||
}
|
||||
// Get the parent VFS node.
|
||||
vfs_file_t *parent = ext2_open(parent_path, O_RDONLY, 0);
|
||||
vfs_file_t *parent = vfs_open(parent_path, O_RDONLY, 0);
|
||||
if (parent == NULL) {
|
||||
pr_err("Failed to open parent directory (%s).\n", parent_path);
|
||||
return -ENOENT;
|
||||
@@ -2612,33 +2639,18 @@ static int ext2_mkdir(const char *path, mode_t permission)
|
||||
if (inode_index == -1) {
|
||||
pr_err("Failed to create a new inode inside `%s` (group index: %d).\n", parent->name, group_index);
|
||||
// Close the parent directory.
|
||||
ext2_close(parent);
|
||||
vfs_close(parent);
|
||||
return -ENOENT;
|
||||
}
|
||||
// Initialize the file.
|
||||
if (ext2_allocate_direntry(fs, parent, basename(path), inode_index, ext2_file_type_directory) == -1) {
|
||||
pr_err("Failed to allocate a new direntry for the inode.\n");
|
||||
// Close the parent directory.
|
||||
ext2_close(parent);
|
||||
return -ENOENT;
|
||||
}
|
||||
// Allocate the memory for the file.
|
||||
vfs_file_t *new_file = kmem_cache_alloc(vfs_file_cache, GFP_KERNEL);
|
||||
if (new_file == NULL) {
|
||||
pr_err("Failed to allocate memory for the EXT2 file.\n");
|
||||
// Close the parent directory.
|
||||
ext2_close(parent);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (ext2_init_vfs_file(fs, new_file, &inode, inode_index, basename(path), strlen(basename(path))) == -1) {
|
||||
pr_err("Failed to properly set the VFS file.\n");
|
||||
// Close the parent directory.
|
||||
ext2_close(parent);
|
||||
vfs_close(parent);
|
||||
return -ENOENT;
|
||||
}
|
||||
// Close the parent directory.
|
||||
ext2_close(parent);
|
||||
ext2_close(new_file);
|
||||
vfs_close(parent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3002,6 +3014,7 @@ void dump_dir(vfs_file_t *dir)
|
||||
pr_err("Failed to read the inode (%d).\n", dir->ino);
|
||||
return;
|
||||
}
|
||||
pr_debug("dir: `%-s` inode: `%4d` {\n", dir->name, dir->ino);
|
||||
// Allocate the cache.
|
||||
uint8_t *cache = kmem_cache_alloc(fs->ext2_buffer_cache, GFP_KERNEL);
|
||||
// Clean the cache.
|
||||
@@ -3009,39 +3022,34 @@ void dump_dir(vfs_file_t *dir)
|
||||
// Iterate the directory.
|
||||
ext2_direntry_iterator_t it = ext2_direntry_iterator_begin(fs, cache, &inode);
|
||||
for (; ext2_direntry_iterator_valid(&it); ext2_direntry_iterator_next(&it)) {
|
||||
ext2_inode_t __inode;
|
||||
if (ext2_read_inode(fs, &__inode, it.direntry->inode) == -1) {
|
||||
pr_err("Failed to read the inode (%d).\n", it.direntry->inode);
|
||||
if (it.direntry->inode != 0) {
|
||||
ext2_inode_t __inode;
|
||||
ext2_read_inode(fs, &__inode, it.direntry->inode);
|
||||
pr_debug(" %-16s (inode: %4d, type: %2d, rec_len: %4d, name_len: %2d)[size: %d]\n",
|
||||
it.direntry->name,
|
||||
it.direntry->inode,
|
||||
it.direntry->file_type,
|
||||
it.direntry->rec_len,
|
||||
it.direntry->name_len,
|
||||
__inode.size);
|
||||
} else {
|
||||
pr_debug(" %-16s (inode: %4d, type: %2d, rec_len: %4d, name_len: %2d)\n",
|
||||
it.direntry->name,
|
||||
it.direntry->inode,
|
||||
it.direntry->file_type,
|
||||
it.direntry->rec_len,
|
||||
it.direntry->name_len);
|
||||
}
|
||||
pr_debug("name: %12s inode: %4d file_type: %2d rec_len: %d name_len: %d (realRL: %d, block: %d, total: %d)\n",
|
||||
it.direntry->name,
|
||||
it.direntry->inode,
|
||||
it.direntry->file_type,
|
||||
it.direntry->rec_len,
|
||||
it.direntry->name_len,
|
||||
ext2_get_rec_len_from_direntry(it.direntry),
|
||||
it.block_offset,
|
||||
it.total_offset);
|
||||
ext2_dump_inode(&__inode);
|
||||
pr_debug("\n");
|
||||
//ext2_dump_inode(&__inode);
|
||||
//pr_debug("\n");
|
||||
}
|
||||
pr_debug("}\n");
|
||||
kmem_cache_free(cache);
|
||||
}
|
||||
|
||||
void ext2_test()
|
||||
{
|
||||
vfs_file_t *home = ext2_open("/home", O_RDONLY, 0);
|
||||
assert(home && "Failed to read home.");
|
||||
|
||||
dump_dir(home);
|
||||
|
||||
vfs_file_t *test1 = ext2_creat(home, "test1.txt", EXT2_S_IWUSR | EXT2_S_IRUSR | EXT2_S_IRGRP | EXT2_S_IROTH);
|
||||
assert(test1 && "Failed to create test1.txt.");
|
||||
vfs_file_t *test2 = ext2_creat(home, "test2.txt", EXT2_S_IWUSR | EXT2_S_IRUSR | EXT2_S_IRGRP | EXT2_S_IROTH);
|
||||
assert(test2 && "Failed to create test2.txt.");
|
||||
vfs_file_t *test3 = ext2_creat(home, "test3.txt", EXT2_S_IWUSR | EXT2_S_IRUSR | EXT2_S_IRGRP | EXT2_S_IROTH);
|
||||
assert(test3 && "Failed to create test3.txt.");
|
||||
|
||||
#if 0
|
||||
char buffer[256];
|
||||
memset(buffer, 0, 256);
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
@@ -3049,17 +3057,74 @@ void ext2_test()
|
||||
}
|
||||
buffer[255] = 0;
|
||||
|
||||
vfs_file_t *home, *test1, *test2, *test3;
|
||||
|
||||
assert(home = vfs_open("/home", O_RDONLY, 0));
|
||||
dump_dir(home);
|
||||
|
||||
ext2_write(test1, buffer, 0, 256);
|
||||
ext2_write(test2, buffer, 0, 256);
|
||||
ext2_write(test3, buffer, 0, 256);
|
||||
assert(test1 = vfs_creat("/home/test1.txt", EXT2_S_IWUSR | EXT2_S_IRUSR | EXT2_S_IRGRP | EXT2_S_IROTH));
|
||||
dump_dir(home);
|
||||
|
||||
assert(test2 = vfs_creat("/home/test2.txt", EXT2_S_IWUSR | EXT2_S_IRUSR | EXT2_S_IRGRP | EXT2_S_IROTH));
|
||||
dump_dir(home);
|
||||
|
||||
assert(test3 = vfs_creat("/home/test3.txt", EXT2_S_IWUSR | EXT2_S_IRUSR | EXT2_S_IRGRP | EXT2_S_IROTH));
|
||||
dump_dir(home);
|
||||
|
||||
vfs_write(test1, buffer, 0, 256);
|
||||
vfs_close(test1);
|
||||
dump_dir(home);
|
||||
|
||||
vfs_write(test2, buffer, 0, 256);
|
||||
vfs_close(test2);
|
||||
dump_dir(home);
|
||||
|
||||
vfs_write(test3, buffer, 0, 256);
|
||||
vfs_close(test3);
|
||||
dump_dir(home);
|
||||
|
||||
vfs_mkdir("/home/pippo", EXT2_S_IRWXU | EXT2_S_IRGRP | EXT2_S_IXGRP | EXT2_S_IROTH | EXT2_S_IXOTH);
|
||||
dump_dir(home);
|
||||
|
||||
vfs_rmdir("/home/pippo");
|
||||
dump_dir(home);
|
||||
|
||||
vfs_rmdir("/home");
|
||||
dump_dir(home);
|
||||
|
||||
vfs_close(home);
|
||||
|
||||
vfs_unlink("/home/test1.txt");
|
||||
dump_dir(home);
|
||||
|
||||
vfs_unlink("/home/test2.txt");
|
||||
dump_dir(home);
|
||||
|
||||
vfs_unlink("/home/test3.txt");
|
||||
dump_dir(home);
|
||||
#elif 1
|
||||
vfs_file_t *home, *file;
|
||||
assert(home = vfs_open("/home", O_RDONLY, 0));
|
||||
|
||||
dump_dir(home);
|
||||
|
||||
ext2_mkdir("/home/pippo", EXT2_S_IRWXU | EXT2_S_IRGRP | EXT2_S_IXGRP | EXT2_S_IROTH | EXT2_S_IXOTH);
|
||||
assert(file = vfs_creat("/home/test_file_1.txt", EXT2_S_IWUSR | EXT2_S_IRUSR | EXT2_S_IRGRP | EXT2_S_IROTH));
|
||||
vfs_close(file);
|
||||
|
||||
ext2_rmdir("/home/pippo");
|
||||
assert(file = vfs_creat("/home/test_file_2.txt", EXT2_S_IWUSR | EXT2_S_IRUSR | EXT2_S_IRGRP | EXT2_S_IROTH));
|
||||
vfs_close(file);
|
||||
|
||||
ext2_rmdir("/home");
|
||||
vfs_unlink("/home/test_file_1.txt");
|
||||
vfs_unlink("/home/test_file_2.txt");
|
||||
|
||||
dump_dir(home);
|
||||
|
||||
assert(file = vfs_creat("/home/test_file_4.txt", EXT2_S_IWUSR | EXT2_S_IRUSR | EXT2_S_IRGRP | EXT2_S_IROTH));
|
||||
vfs_close(file);
|
||||
|
||||
dump_dir(home);
|
||||
|
||||
vfs_close(home);
|
||||
while (true) {}
|
||||
#endif
|
||||
}
|
||||
+42
-2
@@ -4,9 +4,10 @@
|
||||
/// @copyright (c) 2014-2021 This file is distributed under the MIT License.
|
||||
/// See LICENSE.md for details.
|
||||
|
||||
#include "sys/errno.h"
|
||||
#include "fs/vfs.h"
|
||||
#include "process/scheduler.h"
|
||||
#include "sys/errno.h"
|
||||
#include "io/debug.h"
|
||||
#include "fs/vfs.h"
|
||||
|
||||
int sys_unlink(const char *path)
|
||||
{
|
||||
@@ -22,3 +23,42 @@ int sys_rmdir(const char *path)
|
||||
{
|
||||
return vfs_rmdir(path);
|
||||
}
|
||||
|
||||
int sys_creat(const char *path, mode_t mode)
|
||||
{
|
||||
// Get the current task.
|
||||
task_struct *task = scheduler_get_current_process();
|
||||
|
||||
// Search for an unused fd.
|
||||
int fd;
|
||||
for (fd = 0; fd < task->max_fd; ++fd) {
|
||||
if (!task->fd_list[fd].file_struct) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there is not fd available.
|
||||
if (fd >= MAX_OPEN_FD) {
|
||||
return -EMFILE;
|
||||
}
|
||||
|
||||
// If fd limit is reached, try to allocate more
|
||||
if (fd == task->max_fd) {
|
||||
if (!vfs_extend_task_fd_list(task)) {
|
||||
pr_err("Failed to extend the file descriptor list.\n");
|
||||
return -EMFILE;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to open the file.
|
||||
vfs_file_t *file = vfs_creat(path, mode);
|
||||
if (file == NULL) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
// Set the file descriptor id.
|
||||
task->fd_list[fd].file_struct = file;
|
||||
|
||||
// Return the file descriptor and increment it.
|
||||
return fd;
|
||||
}
|
||||
+46
-7
@@ -11,7 +11,7 @@
|
||||
// Change the header.
|
||||
#define __DEBUG_HEADER__ "[VFS ]"
|
||||
// Set the log level.
|
||||
#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE
|
||||
#define __DEBUG_LEVEL__ LOGLEVEL_DEBUG
|
||||
|
||||
#include "process/scheduler.h"
|
||||
#include "klib/spinlock.h"
|
||||
@@ -144,22 +144,20 @@ vfs_file_t *vfs_open(const char *path, int flags, mode_t mode)
|
||||
vfs_file_t *file = sb_root->fs_operations->open_f(absolute_path, flags, mode);
|
||||
if (file == NULL) {
|
||||
pr_err("vfs_open(%s): Cannot find the given file (%s)!\n", path, strerror(errno));
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
// Increment file reference counter.
|
||||
++file->count;
|
||||
file->count += 1;
|
||||
// Return the file.
|
||||
return file;
|
||||
}
|
||||
|
||||
int vfs_close(vfs_file_t *file)
|
||||
{
|
||||
// Decrement file reference counter.
|
||||
file->count--;
|
||||
|
||||
pr_debug("vfs_close(ino: %d, file: \"%s\", count: %d)\n", file->ino, file->name, file->count - 1);
|
||||
assert(file->count > 0);
|
||||
// Close file if it's the last reference.
|
||||
if (file->count == 0) {
|
||||
if (--file->count == 0) {
|
||||
// Check if the filesystem has the close function.
|
||||
if (file->fs_operations->close_f == NULL) {
|
||||
return -ENOSYS;
|
||||
@@ -296,6 +294,47 @@ int vfs_rmdir(const char *path)
|
||||
return sb_root->sys_operations->rmdir_f(absolute_path);
|
||||
}
|
||||
|
||||
vfs_file_t *vfs_creat(const char *path, mode_t mode)
|
||||
{
|
||||
// Allocate a variable for the path.
|
||||
char absolute_path[PATH_MAX];
|
||||
// If the first character is not the '/' then get the absolute path.
|
||||
if (!realpath(path, absolute_path)) {
|
||||
pr_err("vfs_creat(%s): Cannot get the absolute path.", path);
|
||||
errno = ENODEV;
|
||||
return NULL;
|
||||
}
|
||||
super_block_t *sb = vfs_get_superblock(absolute_path);
|
||||
if (sb == NULL) {
|
||||
pr_err("vfs_creat(%s): Cannot find the superblock!\n");
|
||||
errno = ENODEV;
|
||||
return NULL;
|
||||
}
|
||||
vfs_file_t *sb_root = sb->root;
|
||||
if (sb_root == NULL) {
|
||||
pr_err("vfs_creat(%s): Cannot find the superblock root.", path);
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
// Check if the function is implemented.
|
||||
if (sb_root->sys_operations->creat_f == NULL) {
|
||||
pr_err("vfs_creat(%s): Function not supported in current filesystem.", path);
|
||||
errno = ENOSYS;
|
||||
return NULL;
|
||||
}
|
||||
// Retrieve the file.
|
||||
vfs_file_t *file = sb_root->sys_operations->creat_f(absolute_path, mode);
|
||||
if (file == NULL) {
|
||||
pr_err("vfs_open(%s): Cannot find the given file (%s)!\n", path, strerror(errno));
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
// Increment file reference counter.
|
||||
file->count += 1;
|
||||
// Return the file.
|
||||
return file;
|
||||
}
|
||||
|
||||
int vfs_stat(const char *path, stat_t *buf)
|
||||
{
|
||||
// Allocate a variable for the path.
|
||||
|
||||
@@ -350,6 +350,8 @@ int kmain(boot_info_t *boot_informations)
|
||||
}
|
||||
print_ok();
|
||||
|
||||
//ext2_test();
|
||||
|
||||
// We have completed the booting procedure.
|
||||
pr_notice("Booting done, jumping into init process.\n");
|
||||
// Print the welcome message.
|
||||
|
||||
@@ -57,6 +57,7 @@ void syscall_init()
|
||||
sys_call_table[__NR_fstat] = (SystemCall)sys_fstat;
|
||||
sys_call_table[__NR_mkdir] = (SystemCall)sys_mkdir;
|
||||
sys_call_table[__NR_rmdir] = (SystemCall)sys_rmdir;
|
||||
sys_call_table[__NR_creat] = (SystemCall)sys_creat;
|
||||
sys_call_table[__NR_unlink] = (SystemCall)sys_unlink;
|
||||
sys_call_table[__NR_getdents] = (SystemCall)sys_getdents;
|
||||
sys_call_table[__NR_lseek] = (SystemCall)sys_lseek;
|
||||
|
||||
Reference in New Issue
Block a user