Rewrite realpath without memory allocation.

This commit is contained in:
Enrico Fraccaroli (Galfurian)
2023-06-23 15:02:17 -04:00
parent 7972ddeac7
commit b7c82d7333
6 changed files with 91 additions and 70 deletions
+12 -16
View File
@@ -7,27 +7,23 @@
/// @brief Extracts the parent directory of the given path and saves it inside
/// the given buffer, e.g., from "/home/user/test.txt" it extracts "/home/user".
/// If the path does not contain a '/', it will return ".".
/// @param path the path we are parsing.
/// @param buffer the buffer where we save the directory name.
/// @param buflen the length of the buffer.
/// @return 1 if succesfull, or 0 if the buffer cannot contain the path.
int dirname(const char *path, char *buffer, size_t buflen);
// TODO: doxygen comment.
/// @brief
/// @param path
/// @result
char *basename(const char *path);
/// @brief Extract the component after the final '/'.
/// @param path the path from which we extract the final component.
/// @return a pointer after the final '/', or path itself it none was found.
const char *basename(const char *path);
/// @brief Return the canonicalized absolute pathname.
/// @param path The path we are canonicalizing.
/// @param resolved The canonicalized path.
/// @return
/// If there is no error, realpath() returns a pointer to the resolved.
/// Otherwise, it returns NULL, the contents of the array resolved
/// are undefined, and errno is set to indicate the error.
/// @details
/// If resolved is NULL, then realpath() uses malloc
/// to allocate a buffer of up to PATH_MAX bytes to hold the
/// resolved pathname, and returns a pointer to this buffer.
char *realpath(const char *path, char *resolved);
/// @param path the path we are canonicalizing.
/// @param buffer where we will store the canonicalized path.
/// @param buflen the size of the buffer.
/// @return If there is no error, realpath() returns a pointer to the buffer.
/// Otherwise, it returns NULL, the contents of the array buffer are undefined,
/// and errno is set to indicate the error.
char *realpath(const char *path, char *buffer, size_t buflen);
+24 -15
View File
@@ -43,18 +43,22 @@ int dirname(const char *path, char *buffer, size_t buflen)
return 1;
}
char *basename(const char *path)
const char *basename(const char *path)
{
char *p = strrchr(path, '/');
return p ? p + 1 : (char *)path;
// Search for the last slash.
const char *last_slash = NULL;
for (const char *it = path; *it; it++) {
if ((*it) == '/') {
last_slash = it;
}
}
return last_slash ? last_slash + 1 : path;
}
char *realpath(const char *path, char *resolved)
char *realpath(const char *path, char *buffer, size_t buflen)
{
assert(path && "Provided null path.");
if (resolved == NULL)
resolved = malloc(sizeof(char) * PATH_MAX);
assert(buffer && "Provided null buffer.");
char abspath[PATH_MAX];
// Initialize the absolute path.
memset(abspath, '\0', PATH_MAX);
@@ -94,22 +98,27 @@ char *realpath(const char *path, char *resolved)
// Go to previous directory if /../ is found
else if (!strncmp("/../", abspath + absidx, 4)) {
// Go to a valid path character (pathidx points to the next one)
if (pathidx)
if (pathidx) {
pathidx--;
while (pathidx && resolved[pathidx] != '/') {
}
while (pathidx && buffer[pathidx] != '/') {
pathidx--;
}
absidx += 3;
} else if (!strncmp("/./", abspath + absidx, 3)) {
absidx += 2;
} else {
resolved[pathidx++] = abspath[absidx++];
if ((pathidx + 1) >= buflen) {
return NULL;
}
buffer[pathidx++] = abspath[absidx++];
}
}
// Remove the last /
if (pathidx > 1)
resolved[pathidx - 1] = '\0';
else
resolved[1] = '\0';
return resolved;
if (pathidx > 1) {
buffer[pathidx - 1] = '\0';
} else {
buffer[1] = '\0';
}
return buffer;
}
+9 -9
View File
@@ -2235,7 +2235,7 @@ static vfs_file_t *ext2_creat(const char *path, mode_t permission)
if (!dirname(path, parent_path, sizeof(parent_path))) {
return NULL;
}
char *file_name = basename(path);
const char *file_name = basename(path);
if (strcmp(parent_path, path) == 0) {
return NULL;
}
@@ -2327,7 +2327,7 @@ static vfs_file_t *ext2_open(const char *path, int flags, mode_t mode)
// Get the absolute path.
char absolute_path[PATH_MAX];
// If the first character is not the '/' then get the absolute path.
if (!realpath(path, absolute_path)) {
if (!realpath(path, absolute_path, sizeof(absolute_path))) {
pr_err("Cannot get the absolute path for path `%s`.\n", path);
return NULL;
}
@@ -2409,12 +2409,12 @@ static int ext2_unlink(const char *path)
// Get the absolute path.
char absolute_path[PATH_MAX];
// If the first character is not the '/' then get the absolute path.
if (!realpath(path, absolute_path)) {
if (!realpath(path, absolute_path, sizeof(absolute_path))) {
pr_err("Cannot get the absolute path for path `%s`.\n", path);
return -ENOENT;
}
// Get the name of the entry we want to unlink.
char *name = basename(absolute_path);
const char *name = basename(absolute_path);
if (name == NULL) {
pr_err("Cannot get the basename from the absolute path `%s`.\n", absolute_path);
return -ENOENT;
@@ -2716,7 +2716,7 @@ static int ext2_mkdir(const char *path, mode_t permission)
// Get the absolute path.
char absolute_path[PATH_MAX];
// If the first character is not the '/' then get the absolute path.
if (!realpath(path, absolute_path)) {
if (!realpath(path, absolute_path, sizeof(absolute_path))) {
pr_err("Cannot get the absolute path for path `%s`.\n", path);
return -ENOENT;
}
@@ -2808,12 +2808,12 @@ static int ext2_rmdir(const char *path)
// Get the absolute path.
char absolute_path[PATH_MAX];
// If the first character is not the '/' then get the absolute path.
if (!realpath(path, absolute_path)) {
if (!realpath(path, absolute_path, sizeof(absolute_path))) {
pr_err("Cannot get the absolute path for path `%s`.\n", path);
return -ENOENT;
}
// Get the name of the entry we want to unlink.
char *name = basename(absolute_path);
const char *name = basename(absolute_path);
if (name == NULL) {
pr_err("Cannot get the basename from the absolute path `%s`.\n", absolute_path);
return -ENOENT;
@@ -2911,7 +2911,7 @@ static int ext2_stat(const char *path, stat_t *stat)
// Get the absolute path.
char absolute_path[PATH_MAX];
// If the first character is not the '/' then get the absolute path.
if (!realpath(path, absolute_path)) {
if (!realpath(path, absolute_path, sizeof(absolute_path))) {
pr_err("Cannot get the absolute path for path `%s`.\n", path);
return -ENOENT;
}
@@ -3100,7 +3100,7 @@ static vfs_file_t *ext2_mount_callback(const char *path, const char *device)
// 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(device, absolute_path)) {
if (!realpath(device, absolute_path, sizeof(absolute_path))) {
pr_err("ext2_mount_callback(%s, %s): Cannot get the absolute path.", path, device);
return NULL;
}
+6 -6
View File
@@ -111,7 +111,7 @@ vfs_file_t *vfs_open(const char *path, int flags, 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)) {
if (!realpath(path, absolute_path, sizeof(absolute_path))) {
pr_err("vfs_open(%s): Cannot get the absolute path!\n", path);
errno = ENODEV;
return NULL;
@@ -213,7 +213,7 @@ int vfs_unlink(const char *path)
// 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)) {
if (!realpath(path, absolute_path, sizeof(absolute_path))) {
pr_err("vfs_unlink(%s): Cannot get the absolute path.", path);
return -ENODEV;
}
@@ -240,7 +240,7 @@ int vfs_mkdir(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)) {
if (!realpath(path, absolute_path, sizeof(absolute_path))) {
pr_err("vfs_mkdir(%s): Cannot get the absolute path.", path);
return -ENODEV;
}
@@ -267,7 +267,7 @@ int vfs_rmdir(const char *path)
// 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)) {
if (!realpath(path, absolute_path, sizeof(absolute_path))) {
pr_err("vfs_rmdir(%s): Cannot get the absolute path.", path);
return -ENODEV;
}
@@ -295,7 +295,7 @@ 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)) {
if (!realpath(path, absolute_path, sizeof(absolute_path))) {
pr_err("vfs_creat(%s): Cannot get the absolute path.", path);
errno = ENODEV;
return NULL;
@@ -336,7 +336,7 @@ int vfs_stat(const char *path, stat_t *buf)
// 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)) {
if (!realpath(path, absolute_path, sizeof(absolute_path))) {
pr_err("vfs_stat(%s): Cannot get the absolute path.", path);
return -ENODEV;
}
+21 -15
View File
@@ -43,18 +43,22 @@ int dirname(const char *path, char *buffer, size_t buflen)
return 1;
}
char *basename(const char *path)
const char *basename(const char *path)
{
char *p = strrchr(path, '/');
return p ? p + 1 : (char *)path;
// Search for the last slash.
const char *last_slash = NULL;
for (const char *it = path; *it; it++) {
if ((*it) == '/') {
last_slash = it;
}
}
return last_slash ? last_slash + 1 : path;
}
char *realpath(const char *path, char *resolved)
char *realpath(const char *path, char *buffer, size_t buflen)
{
assert(path && "Provided null path.");
if (resolved == NULL)
resolved = kmalloc(sizeof(char) * PATH_MAX);
assert(buffer && "Provided null buffer.");
char abspath[PATH_MAX];
// Initialize the absolute path.
memset(abspath, '\0', PATH_MAX);
@@ -94,22 +98,24 @@ char *realpath(const char *path, char *resolved)
// Go to previous directory if /../ is found
else if (!strncmp("/../", abspath + absidx, 4)) {
// Go to a valid path character (pathidx points to the next one)
if (pathidx)
if (pathidx) {
pathidx--;
while (pathidx && resolved[pathidx] != '/') {
}
while (pathidx && buffer[pathidx] != '/') {
pathidx--;
}
absidx += 3;
} else if (!strncmp("/./", abspath + absidx, 3)) {
absidx += 2;
} else {
resolved[pathidx++] = abspath[absidx++];
buffer[pathidx++] = abspath[absidx++];
}
}
// Remove the last /
if (pathidx > 1)
resolved[pathidx - 1] = '\0';
else
resolved[1] = '\0';
return resolved;
if (pathidx > 1) {
buffer[pathidx - 1] = '\0';
} else {
buffer[1] = '\0';
}
return buffer;
}
+19 -9
View File
@@ -4,10 +4,10 @@
/// See LICENSE.md for details.
// Setup the logging for this file (do this before any other include).
#include "sys/kernel_levels.h" // Include kernel log levels.
#define __DEBUG_HEADER__ "[PROC ]" ///< Change header.
#include "sys/kernel_levels.h" // Include kernel log levels.
#define __DEBUG_HEADER__ "[PROC ]" ///< Change header.
#define __DEBUG_LEVEL__ LOGLEVEL_NOTICE ///< Set log level.
#include "io/debug.h" // Include debugging functions.
#include "io/debug.h" // Include debugging functions.
#include "process/process.h"
#include "process/scheduler.h"
@@ -348,10 +348,14 @@ int sys_chdir(char const *path)
{
task_struct *current = scheduler_get_current_process();
assert(current && "There is no running process.");
if (!path)
if (!path) {
return -EFAULT;
}
char absolute_path[PATH_MAX];
realpath(path, absolute_path);
if (!realpath(path, absolute_path, sizeof(absolute_path))) {
pr_err("Cannot get the absolute path for path `%s`.\n", path);
return -ENOENT;
}
// Check that the directory exists.
vfs_file_t *dir = vfs_open(absolute_path, O_RDONLY | O_DIRECTORY, S_IXUSR);
if (dir) {
@@ -368,18 +372,24 @@ int sys_fchdir(int fd)
task_struct *current = scheduler_get_current_process();
assert(current && "There is no running process.");
// Check if it is a valid file descriptor.
if ((fd < 0) || (fd >= current->max_fd))
if ((fd < 0) || (fd >= current->max_fd)) {
return -EBADF;
}
// Get the file descriptor.
vfs_file_descriptor_t *vfd = &current->fd_list[fd];
// Check if the file descriptor file is set.
if (vfd->file_struct == NULL)
if (vfd->file_struct == NULL) {
return -ENOENT;
}
// Check that the path points to a directory.
if (!bitmask_check(vfd->file_struct->flags, DT_DIR))
if (!bitmask_check(vfd->file_struct->flags, DT_DIR)) {
return -ENOTDIR;
}
char absolute_path[PATH_MAX];
realpath(vfd->file_struct->name, absolute_path);
if (!realpath(vfd->file_struct->name, absolute_path, sizeof(absolute_path))) {
pr_err("Cannot get the absolute path for path `%s`.\n", vfd->file_struct->name);
return -ENOENT;
}
strcpy(current->cwd, absolute_path);
return 0;
}