diff options
-rw-r--r-- | builtin-apply.c | 6 | ||||
-rw-r--r-- | strbuf.c | 27 | ||||
-rw-r--r-- | strbuf.h | 1 |
3 files changed, 30 insertions, 4 deletions
diff --git a/builtin-apply.c b/builtin-apply.c index 4c4d1e177..07244b073 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -1559,10 +1559,8 @@ static int read_old_data(struct stat *st, const char *path, struct strbuf *buf) { switch (st->st_mode & S_IFMT) { case S_IFLNK: - strbuf_grow(buf, st->st_size); - if (readlink(path, buf->buf, st->st_size) != st->st_size) - return -1; - strbuf_setlen(buf, st->st_size); + if (strbuf_readlink(buf, path, st->st_size) < 0) + return error("unable to read symlink %s", path); return 0; case S_IFREG: if (strbuf_read_file(buf, path, st->st_size) != st->st_size) @@ -288,6 +288,33 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint) return sb->len - oldlen; } +#define STRBUF_MAXLINK (2*PATH_MAX) + +int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint) +{ + if (hint < 32) + hint = 32; + + while (hint < STRBUF_MAXLINK) { + int len; + + strbuf_grow(sb, hint); + len = readlink(path, sb->buf, hint); + if (len < 0) { + if (errno != ERANGE) + break; + } else if (len < hint) { + strbuf_setlen(sb, len); + return 0; + } + + /* .. the buffer was too small - try again */ + hint *= 2; + } + strbuf_release(sb); + return -1; +} + int strbuf_getline(struct strbuf *sb, FILE *fp, int term) { int ch; @@ -124,6 +124,7 @@ extern size_t strbuf_fread(struct strbuf *, size_t, FILE *); /* XXX: if read fails, any partial read is undone */ extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint); extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint); +extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint); extern int strbuf_getline(struct strbuf *, FILE *, int); |