Rewrite realpath without memory allocation.
This commit is contained in:
+12
-16
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 = ¤t->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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user