diff options
-rw-r--r-- | eval.c | 13 | ||||
-rw-r--r-- | util.c | 30 | ||||
-rw-r--r-- | util.h | 13 |
3 files changed, 44 insertions, 12 deletions
@@ -599,23 +599,12 @@ bool eval_lname(const struct expr *expr, struct eval_state *state) { goto done; } - size_t size = statbuf->st_size + 1; - name = malloc(size); + name = xreadlinkat(ftwbuf->at_fd, ftwbuf->at_path, statbuf->st_size); if (!name) { eval_error(state); goto done; } - ssize_t len = readlinkat(ftwbuf->at_fd, ftwbuf->at_path, name, size); - if (len < 0) { - eval_error(state); - goto done; - } else if (len >= size) { - goto done; - } - - name[len] = '\0'; - ret = fnmatch(expr->sdata, name, expr->idata) == 0; done: @@ -29,6 +29,36 @@ int xreaddir(DIR *dir, struct dirent **de) { } } +char *xreadlinkat(int fd, const char *path, size_t size) { + ++size; // NUL-terminator + ssize_t len; + char *name = NULL; + + while (true) { + char *new_name = realloc(name, size); + if (!new_name) { + goto error; + } + name = new_name; + + len = readlinkat(fd, path, name, size); + if (len < 0) { + goto error; + } else if (len >= size) { + size *= 2; + } else { + break; + } + } + + name[len] = '\0'; + return name; + +error: + free(name); + return NULL; +} + bool isopen(int fd) { return fcntl(fd, F_GETFD) >= 0 || errno != EBADF; } @@ -49,6 +49,19 @@ int xreaddir(DIR *dir, struct dirent **de); /** + * readlinkat() wrapper that dynamically allocates the result. + * + * @param fd + * The base directory descriptor. + * @param path + * The path to the link, relative to fd. + * @param size + * An estimate for the size of the link name (pass 0 if unknown). + * @return The target of the link, allocated with malloc(), or NULL on failure. + */ +char *xreadlinkat(int fd, const char *path, size_t size); + +/** * Check if a file descriptor is open. */ bool isopen(int fd); |