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:
Xavier Del Campo Romero 2023-07-24 23:17:48 +02:00
parent 8bcf0bf855
commit 08a991d60c
Signed by: xavi
GPG Key ID: 84FF3612A9BF43F2
4 changed files with 184 additions and 0 deletions

View File

@ -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
View File

@ -96,6 +96,7 @@ OBJECTS = \
auth.o \
base64.o \
cftw.o \
crealpath.o \
hex.o \
jwt.o \
main.o \

174
crealpath.c Normal file
View 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
View 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