diff options
Diffstat (limited to 'src/io.c')
-rw-r--r-- | src/io.c | 56 |
1 files changed, 50 insertions, 6 deletions
@@ -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); |