summaryrefslogtreecommitdiffstats
path: root/util.c
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2017-01-31 21:01:14 -0500
committerTavian Barnes <tavianator@tavianator.com>2017-01-31 21:01:14 -0500
commit538e4b2054e9802ebc860943e0a43baf2ee46741 (patch)
tree70993ee6abf4d7cc0642bf55a5ea1d7edda4ce05 /util.c
parentab64ca5d29147385b099edb8874d6e101b48c1e0 (diff)
downloadbfs-538e4b2054e9802ebc860943e0a43baf2ee46741.tar.xz
Don't trust st_size when reading symlinks
Linux /proc, for example, reports a st_size of 0 for everything. It's nice to be able to use -lname on them anyway.
Diffstat (limited to 'util.c')
-rw-r--r--util.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/util.c b/util.c
index ce0b458..f3f2c5f 100644
--- a/util.c
+++ b/util.c
@@ -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;
}