Introduce crealpath
crealpath (for "custom realpath") is a custom implementation of realpath(3) that aims to work similarly to GNU's realpath(1). This implementation is provided due to the following reasons: - Future commits will require extracting an absolute path from a relative path, and/or process relative components from a path, such as ".." or ".". - realpath(3) is defined by POSIX.1-2008 as a XSI extension, and extensions are generally avoided in this repository whenever possible. - Additionally, realpath(3) requires the file or directory pointed to by the path to exist, which might not always be the case for slcl. - auth.c uses its own implementation to extract a dynamically allocated string by repeatedly calling getcwd(3). Future commits will also require this future, so it makes sense to keep it on a separate component.
This commit is contained in:
parent
8bcf0bf855
commit
08a991d60c
|
@ -4,6 +4,7 @@ add_executable(${PROJECT_NAME}
|
|||
auth.c
|
||||
base64.c
|
||||
cftw.c
|
||||
crealpath.c
|
||||
hex.c
|
||||
jwt.c
|
||||
main.c
|
||||
|
|
1
configure
vendored
1
configure
vendored
|
@ -96,6 +96,7 @@ OBJECTS = \
|
|||
auth.o \
|
||||
base64.o \
|
||||
cftw.o \
|
||||
crealpath.o \
|
||||
hex.o \
|
||||
jwt.o \
|
||||
main.o \
|
||||
|
|
174
crealpath.c
Normal file
174
crealpath.c
Normal file
|
@ -0,0 +1,174 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
|
||||
#include "crealpath.h"
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static char *alloc_cwd(void)
|
||||
{
|
||||
size_t len = 1;
|
||||
char *p = NULL;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char *const pp = realloc(p, len);
|
||||
|
||||
if (!pp)
|
||||
{
|
||||
fprintf(stderr, "%s: realloc(3): %s\n", __func__, strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
p = pp;
|
||||
|
||||
if (!getcwd(pp, len))
|
||||
{
|
||||
if (errno != ERANGE)
|
||||
{
|
||||
fprintf(stderr, "%s: getcwd(3): %s\n",
|
||||
__func__, strerror(errno));
|
||||
break;
|
||||
}
|
||||
else
|
||||
len++;
|
||||
}
|
||||
else
|
||||
return p;
|
||||
}
|
||||
|
||||
free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *get_parent(char *p)
|
||||
{
|
||||
char *last;
|
||||
size_t len;
|
||||
|
||||
if (!p || !(last = strrchr(p, '/')) || strlen(last) < strlen("/a"))
|
||||
{
|
||||
fprintf(stderr, "%s: parent folder expected\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = last == p ? strlen("/") : last - p;
|
||||
|
||||
if (!(p = realloc(p, len + 1)))
|
||||
{
|
||||
fprintf(stderr, "%s: realloc(3): %s\n", __func__, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p[len] = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *get_component(const char **const path)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
while (**path == '/')
|
||||
(*path)++;
|
||||
|
||||
const char *const next = strchr(*path, '/');
|
||||
const size_t len = next ? next - *path : strlen(*path);
|
||||
|
||||
if (!(ret = malloc(len + 1)))
|
||||
{
|
||||
fprintf(stderr, "%s: malloc(3): %s\n", __func__, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(ret, *path, len);
|
||||
ret[len] = '\0';
|
||||
*path += len;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *resolve_component(const char **const path, char *p)
|
||||
{
|
||||
char *const c = get_component(path);
|
||||
|
||||
if (!*c)
|
||||
{
|
||||
if (!p && !(p = strdup("/")))
|
||||
{
|
||||
fprintf(stderr, "%s: strdup(3): %s\n", __func__, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
|
||||
goto end;
|
||||
}
|
||||
else if (!strcmp(c, "..") && !(p = get_parent(p)))
|
||||
{
|
||||
fprintf(stderr, "%s: get_parent failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (strcmp(c, "."))
|
||||
{
|
||||
const size_t len = p ? strlen(p) : 0, clen = strlen(c);
|
||||
|
||||
if (!(p = realloc(p, len + strlen("/") + clen + 1)))
|
||||
{
|
||||
fprintf(stderr, "%s: realloc(3): %s\n",
|
||||
__func__, strerror(errno));
|
||||
goto end;
|
||||
}
|
||||
else
|
||||
{
|
||||
p[len] = '/';
|
||||
memcpy(&p[len + 1], c, clen);
|
||||
p[len + 1 + clen] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
free(c);
|
||||
return p;
|
||||
}
|
||||
|
||||
static char *resolve(const char *path, char *p)
|
||||
{
|
||||
while (*path)
|
||||
if (!(p = resolve_component(&path, p)))
|
||||
{
|
||||
fprintf(stderr, "%s: resolve_component failed\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
char *crealpath(const char *const path)
|
||||
{
|
||||
char *p = NULL, *ret = NULL;
|
||||
|
||||
if (!*path)
|
||||
{
|
||||
fprintf(stderr, "%s: expected non-empty path\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (*path != '/' && !(p = alloc_cwd()))
|
||||
{
|
||||
fprintf(stderr, "%s: alloc_cwd failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
else if (!(p = resolve(path, p)))
|
||||
{
|
||||
fprintf(stderr, "%s: resolve failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = p;
|
||||
|
||||
end:
|
||||
if (!ret)
|
||||
free(p);
|
||||
|
||||
return ret;
|
||||
}
|
8
crealpath.h
Normal file
8
crealpath.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef CREALPATH_H
|
||||
#define CREALPATH_H
|
||||
|
||||
/* Custom implementation of a GNU's realpath(1)-like function that
|
||||
* does not require GNU extensions. */
|
||||
char *crealpath(const char *path);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user