summaryrefslogtreecommitdiff
path: root/src/io.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/io.c')
-rw-r--r--src/io.c56
1 files changed, 50 insertions, 6 deletions
diff --git a/src/io.c b/src/io.c
index 9199d03..b9041e0 100644
--- a/src/io.c
+++ b/src/io.c
@@ -351,12 +351,17 @@ EXPORT_SYMBOL int HX_readlink(hxmc_t **target, const char *path)
size_t linkbuf_size;
if (allocate) {
- linkbuf_size = 32;
- *target = HXmc_meminit(NULL, 32);
+ linkbuf_size = 128;
+ *target = HXmc_meminit(nullptr, 128);
if (*target == NULL)
return -errno;
} else {
linkbuf_size = HXmc_length(*target);
+ if (linkbuf_size < 128) {
+ linkbuf_size = 128;
+ if (HXmc_setlen(target, 128) == nullptr)
+ return -errno;
+ }
}
while (true) {
ssize_t ret = readlink(path, *target, linkbuf_size);
@@ -453,6 +458,45 @@ HX_realpath_symres(struct HX_realpath_state *state, const char *path)
return 1;
}
+EXPORT_SYMBOL int HX_getcwd(hxmc_t **target)
+{
+ bool allocate = *target == nullptr;
+ size_t linkbuf_size;
+
+ if (allocate) {
+ linkbuf_size = 128;
+ *target = HXmc_meminit(nullptr, linkbuf_size);
+ if (*target == nullptr)
+ return -errno;
+ } else {
+ linkbuf_size = HXmc_length(*target);
+ if (linkbuf_size < 128) {
+ linkbuf_size = 128;
+ if (HXmc_setlen(target, linkbuf_size) == nullptr)
+ return -errno;
+ }
+ }
+ while (true) {
+ const char *ret = getcwd(*target, linkbuf_size);
+ if (ret != nullptr) {
+ HXmc_setlen(target, strlen(ret)); /* shrink to fit */
+ return 1;
+ }
+ if (errno == ERANGE) {
+ if (HXmc_setlen(target, linkbuf_size *= 2) != nullptr)
+ continue;
+ /* errno already set by realloc, fall into next if block */
+ }
+ int saved_errno = errno;
+ if (allocate) {
+ HXmc_free(*target);
+ *target = nullptr;
+ }
+ return -(errno = saved_errno);
+ }
+ return -EINVAL;
+}
+
EXPORT_SYMBOL int HX_realpath(hxmc_t **dest_pptr, const char *path,
unsigned int flags)
{
@@ -462,7 +506,7 @@ EXPORT_SYMBOL int HX_realpath(hxmc_t **dest_pptr, const char *path,
int ret = 0;
if (dnull) {
- state.dest = HXmc_meminit(NULL, PATH_MAX);
+ state.dest = HXmc_meminit(NULL, 256);
if (state.dest == NULL)
goto err;
}
@@ -470,11 +514,9 @@ EXPORT_SYMBOL int HX_realpath(hxmc_t **dest_pptr, const char *path,
if (*path == '/') {
rq_slash = true;
} else if (flags & HX_REALPATH_ABSOLUTE) {
- if (getcwd(state.dest, PATH_MAX) == NULL)
+ if (HX_getcwd(&state.dest) < 0)
goto err;
rq_slash = true;
- if (HXmc_setlen(&state.dest, strlen(state.dest)) == NULL)
- goto err;
}
while (*path != '\0') {
@@ -541,6 +583,8 @@ EXPORT_SYMBOL int HX_realpath(hxmc_t **dest_pptr, const char *path,
/* If caller supplied a buffer, do not take it away. */
HXmc_free(state.dest);
*dest_pptr = NULL;
+ } else {
+ *dest_pptr = state.dest;
}
HXmc_free(state.link_target);
HXmc_free(state.new_path);