Merge branch 'lt/readlink'

* lt/readlink:
  combine-diff.c: use strbuf_readlink()
  builtin-blame.c: use strbuf_readlink()
  make_absolute_path(): check bounds when seeing an overlong symlink
  Make 'prepare_temp_file()' ignore st_size for symlinks
  Make 'diff_populate_filespec()' use the new 'strbuf_readlink()'
  Make 'index_path()' use 'strbuf_readlink()'
  Make 'ce_compare_link()' use the new 'strbuf_readlink()'
  Add generic 'strbuf_readlink()' helper function
This commit is contained in:
Junio C Hamano
2008-12-17 22:28:03 -08:00
9 changed files with 62 additions and 50 deletions

View File

@ -64,6 +64,8 @@ const char *make_absolute_path(const char *path)
len = readlink(buf, next_buf, PATH_MAX); len = readlink(buf, next_buf, PATH_MAX);
if (len < 0) if (len < 0)
die ("Invalid symlink: %s", buf); die ("Invalid symlink: %s", buf);
if (PATH_MAX <= len)
die("symbolic link too long: %s", buf);
next_buf[len] = '\0'; next_buf[len] = '\0';
buf = next_buf; buf = next_buf;
buf_index = 1 - buf_index; buf_index = 1 - buf_index;

View File

@ -1559,10 +1559,8 @@ static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
{ {
switch (st->st_mode & S_IFMT) { switch (st->st_mode & S_IFMT) {
case S_IFLNK: case S_IFLNK:
strbuf_grow(buf, st->st_size); if (strbuf_readlink(buf, path, st->st_size) < 0)
if (readlink(path, buf->buf, st->st_size) != st->st_size) return error("unable to read symlink %s", path);
return -1;
strbuf_setlen(buf, st->st_size);
return 0; return 0;
case S_IFREG: case S_IFREG:
if (strbuf_read_file(buf, path, st->st_size) != st->st_size) if (strbuf_read_file(buf, path, st->st_size) != st->st_size)

View File

@ -1996,7 +1996,6 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
if (!contents_from || strcmp("-", contents_from)) { if (!contents_from || strcmp("-", contents_from)) {
struct stat st; struct stat st;
const char *read_from; const char *read_from;
unsigned long fin_size;
if (contents_from) { if (contents_from) {
if (stat(contents_from, &st) < 0) if (stat(contents_from, &st) < 0)
@ -2008,7 +2007,6 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
die("Cannot lstat %s", path); die("Cannot lstat %s", path);
read_from = path; read_from = path;
} }
fin_size = xsize_t(st.st_size);
mode = canon_mode(st.st_mode); mode = canon_mode(st.st_mode);
switch (st.st_mode & S_IFMT) { switch (st.st_mode & S_IFMT) {
case S_IFREG: case S_IFREG:
@ -2016,9 +2014,8 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con
die("cannot open or read %s", read_from); die("cannot open or read %s", read_from);
break; break;
case S_IFLNK: case S_IFLNK:
if (readlink(read_from, buf.buf, buf.alloc) != fin_size) if (strbuf_readlink(&buf, read_from, st.st_size) < 0)
die("cannot readlink %s", read_from); die("cannot readlink %s", read_from);
buf.len = fin_size;
break; break;
default: default:
die("unsupported file type %s", read_from); die("unsupported file type %s", read_from);

View File

@ -703,15 +703,15 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
goto deleted_file; goto deleted_file;
if (S_ISLNK(st.st_mode)) { if (S_ISLNK(st.st_mode)) {
size_t len = xsize_t(st.st_size); struct strbuf buf = STRBUF_INIT;
result_size = len;
result = xmalloc(len + 1); if (strbuf_readlink(&buf, elem->path, st.st_size) < 0) {
if (result_size != readlink(elem->path, result, len)) {
error("readlink(%s): %s", elem->path, error("readlink(%s): %s", elem->path,
strerror(errno)); strerror(errno));
return; return;
} }
result[len] = 0; result_size = buf.len;
result = strbuf_detach(&buf, NULL);
elem->mode = canon_mode(st.st_mode); elem->mode = canon_mode(st.st_mode);
} }
else if (0 <= (fd = open(elem->path, O_RDONLY)) && else if (0 <= (fd = open(elem->path, O_RDONLY)) &&

25
diff.c
View File

@ -1773,19 +1773,17 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
s->size = xsize_t(st.st_size); s->size = xsize_t(st.st_size);
if (!s->size) if (!s->size)
goto empty; goto empty;
if (size_only)
return 0;
if (S_ISLNK(st.st_mode)) { if (S_ISLNK(st.st_mode)) {
int ret; struct strbuf sb = STRBUF_INIT;
s->data = xmalloc(s->size);
s->should_free = 1; if (strbuf_readlink(&sb, s->path, s->size))
ret = readlink(s->path, s->data, s->size);
if (ret < 0) {
free(s->data);
goto err_empty; goto err_empty;
} s->data = strbuf_detach(&sb, &s->size);
s->should_free = 1;
return 0; return 0;
} }
if (size_only)
return 0;
fd = open(s->path, O_RDONLY); fd = open(s->path, O_RDONLY);
if (fd < 0) if (fd < 0)
goto err_empty; goto err_empty;
@ -1883,13 +1881,12 @@ static void prepare_temp_file(const char *name,
if (S_ISLNK(st.st_mode)) { if (S_ISLNK(st.st_mode)) {
int ret; int ret;
char buf[PATH_MAX + 1]; /* ought to be SYMLINK_MAX */ char buf[PATH_MAX + 1]; /* ought to be SYMLINK_MAX */
size_t sz = xsize_t(st.st_size); ret = readlink(name, buf, sizeof(buf));
if (sizeof(buf) <= st.st_size)
die("symlink too long: %s", name);
ret = readlink(name, buf, sz);
if (ret < 0) if (ret < 0)
die("readlink(%s)", name); die("readlink(%s)", name);
prep_temp_blob(temp, buf, sz, if (ret == sizeof(buf))
die("symlink too long: %s", name);
prep_temp_blob(temp, buf, ret,
(one->sha1_valid ? (one->sha1_valid ?
one->sha1 : null_sha1), one->sha1 : null_sha1),
(one->sha1_valid ? (one->sha1_valid ?

View File

@ -99,27 +99,21 @@ static int ce_compare_data(struct cache_entry *ce, struct stat *st)
static int ce_compare_link(struct cache_entry *ce, size_t expected_size) static int ce_compare_link(struct cache_entry *ce, size_t expected_size)
{ {
int match = -1; int match = -1;
char *target;
void *buffer; void *buffer;
unsigned long size; unsigned long size;
enum object_type type; enum object_type type;
int len; struct strbuf sb = STRBUF_INIT;
target = xmalloc(expected_size); if (strbuf_readlink(&sb, ce->name, expected_size))
len = readlink(ce->name, target, expected_size);
if (len != expected_size) {
free(target);
return -1; return -1;
}
buffer = read_sha1_file(ce->sha1, &type, &size); buffer = read_sha1_file(ce->sha1, &type, &size);
if (!buffer) { if (buffer) {
free(target); if (size == sb.len)
return -1; match = memcmp(buffer, sb.buf, size);
free(buffer);
} }
if (size == expected_size) strbuf_release(&sb);
match = memcmp(buffer, target, size);
free(buffer);
free(target);
return match; return match;
} }

View File

@ -2523,8 +2523,7 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object) int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object)
{ {
int fd; int fd;
char *target; struct strbuf sb = STRBUF_INIT;
size_t len;
switch (st->st_mode & S_IFMT) { switch (st->st_mode & S_IFMT) {
case S_IFREG: case S_IFREG:
@ -2537,20 +2536,17 @@ int index_path(unsigned char *sha1, const char *path, struct stat *st, int write
path); path);
break; break;
case S_IFLNK: case S_IFLNK:
len = xsize_t(st->st_size); if (strbuf_readlink(&sb, path, st->st_size)) {
target = xmalloc(len + 1);
if (readlink(path, target, len + 1) != st->st_size) {
char *errstr = strerror(errno); char *errstr = strerror(errno);
free(target);
return error("readlink(\"%s\"): %s", path, return error("readlink(\"%s\"): %s", path,
errstr); errstr);
} }
if (!write_object) if (!write_object)
hash_sha1_file(target, len, blob_type, sha1); hash_sha1_file(sb.buf, sb.len, blob_type, sha1);
else if (write_sha1_file(target, len, blob_type, sha1)) else if (write_sha1_file(sb.buf, sb.len, blob_type, sha1))
return error("%s: failed to insert into database", return error("%s: failed to insert into database",
path); path);
free(target); strbuf_release(&sb);
break; break;
case S_IFDIR: case S_IFDIR:
return resolve_gitlink_ref(path, "HEAD", sha1); return resolve_gitlink_ref(path, "HEAD", sha1);

View File

@ -288,6 +288,33 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
return sb->len - oldlen; 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 strbuf_getline(struct strbuf *sb, FILE *fp, int term)
{ {
int ch; int ch;

View File

@ -124,6 +124,7 @@ extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
/* XXX: if read fails, any partial read is undone */ /* XXX: if read fails, any partial read is undone */
extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint); 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_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); extern int strbuf_getline(struct strbuf *, FILE *, int);