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;
}