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
commit c0ceb2c32d
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);
if (len < 0)
die ("Invalid symlink: %s", buf);
if (PATH_MAX <= len)
die("symbolic link too long: %s", buf);
next_buf[len] = '\0';
buf = next_buf;
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) {
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)

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)) {
struct stat st;
const char *read_from;
unsigned long fin_size;
if (contents_from) {
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);
read_from = path;
}
fin_size = xsize_t(st.st_size);
mode = canon_mode(st.st_mode);
switch (st.st_mode & S_IFMT) {
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);
break;
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);
buf.len = fin_size;
break;
default:
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;
if (S_ISLNK(st.st_mode)) {
size_t len = xsize_t(st.st_size);
result_size = len;
result = xmalloc(len + 1);
if (result_size != readlink(elem->path, result, len)) {
struct strbuf buf = STRBUF_INIT;
if (strbuf_readlink(&buf, elem->path, st.st_size) < 0) {
error("readlink(%s): %s", elem->path,
strerror(errno));
return;
}
result[len] = 0;
result_size = buf.len;
result = strbuf_detach(&buf, NULL);
elem->mode = canon_mode(st.st_mode);
}
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);
if (!s->size)
goto empty;
if (size_only)
return 0;
if (S_ISLNK(st.st_mode)) {
int ret;
s->data = xmalloc(s->size);
s->should_free = 1;
ret = readlink(s->path, s->data, s->size);
if (ret < 0) {
free(s->data);
struct strbuf sb = STRBUF_INIT;
if (strbuf_readlink(&sb, s->path, s->size))
goto err_empty;
}
s->data = strbuf_detach(&sb, &s->size);
s->should_free = 1;
return 0;
}
if (size_only)
return 0;
fd = open(s->path, O_RDONLY);
if (fd < 0)
goto err_empty;
@ -1883,13 +1881,12 @@ static void prepare_temp_file(const char *name,
if (S_ISLNK(st.st_mode)) {
int ret;
char buf[PATH_MAX + 1]; /* ought to be SYMLINK_MAX */
size_t sz = xsize_t(st.st_size);
if (sizeof(buf) <= st.st_size)
die("symlink too long: %s", name);
ret = readlink(name, buf, sz);
ret = readlink(name, buf, sizeof(buf));
if (ret < 0)
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 : null_sha1),
(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)
{
int match = -1;
char *target;
void *buffer;
unsigned long size;
enum object_type type;
int len;
struct strbuf sb = STRBUF_INIT;
target = xmalloc(expected_size);
len = readlink(ce->name, target, expected_size);
if (len != expected_size) {
free(target);
if (strbuf_readlink(&sb, ce->name, expected_size))
return -1;
}
buffer = read_sha1_file(ce->sha1, &type, &size);
if (!buffer) {
free(target);
return -1;
if (buffer) {
if (size == sb.len)
match = memcmp(buffer, sb.buf, size);
free(buffer);
}
if (size == expected_size)
match = memcmp(buffer, target, size);
free(buffer);
free(target);
strbuf_release(&sb);
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 fd;
char *target;
size_t len;
struct strbuf sb = STRBUF_INIT;
switch (st->st_mode & S_IFMT) {
case S_IFREG:
@ -2537,20 +2536,17 @@ int index_path(unsigned char *sha1, const char *path, struct stat *st, int write
path);
break;
case S_IFLNK:
len = xsize_t(st->st_size);
target = xmalloc(len + 1);
if (readlink(path, target, len + 1) != st->st_size) {
if (strbuf_readlink(&sb, path, st->st_size)) {
char *errstr = strerror(errno);
free(target);
return error("readlink(\"%s\"): %s", path,
errstr);
}
if (!write_object)
hash_sha1_file(target, len, blob_type, sha1);
else if (write_sha1_file(target, len, blob_type, sha1))
hash_sha1_file(sb.buf, sb.len, blob_type, sha1);
else if (write_sha1_file(sb.buf, sb.len, blob_type, sha1))
return error("%s: failed to insert into database",
path);
free(target);
strbuf_release(&sb);
break;
case S_IFDIR:
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;
}
#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;

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 */
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);