mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-04 19:50:19 +00:00
odb: Proper symlink hashing
This commit is contained in:
parent
18e5b8547d
commit
f19e3ca288
57
src/blob.c
57
src/blob.c
@ -68,10 +68,7 @@ int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *b
|
||||
int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path)
|
||||
{
|
||||
int error = GIT_SUCCESS;
|
||||
int islnk = 0;
|
||||
int fd = 0;
|
||||
git_buf full_path = GIT_BUF_INIT;
|
||||
char buffer[2048];
|
||||
git_off_t size;
|
||||
git_odb_stream *stream = NULL;
|
||||
struct stat st;
|
||||
@ -92,34 +89,51 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
islnk = S_ISLNK(st.st_mode);
|
||||
size = st.st_size;
|
||||
|
||||
error = git_repository_odb__weakptr(&odb, repo);
|
||||
if (error < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
if (!islnk) {
|
||||
if ((fd = p_open(full_path.ptr, O_RDONLY)) < 0) {
|
||||
error = git__throw(GIT_ENOTFOUND, "Failed to create blob. Could not open '%s'", full_path.ptr
|
||||
);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if ((error = git_odb_open_wstream(&stream, odb, (size_t)size, GIT_OBJ_BLOB)) < GIT_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
while (size > 0) {
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
char *link_data;
|
||||
ssize_t read_len;
|
||||
|
||||
if (!islnk)
|
||||
read_len = p_read(fd, buffer, sizeof(buffer));
|
||||
else
|
||||
read_len = p_readlink(full_path.ptr, buffer, sizeof(buffer));
|
||||
link_data = git__malloc(size);
|
||||
if (!link_data) {
|
||||
error = GIT_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
read_len = p_readlink(full_path.ptr, link_data, size);
|
||||
|
||||
if (read_len != (ssize_t)size) {
|
||||
error = git__throw(GIT_EOSERR, "Failed to create blob. Can't read symlink");
|
||||
free(link_data);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
stream->write(stream, link_data, size);
|
||||
free(link_data);
|
||||
|
||||
} else {
|
||||
int fd;
|
||||
char buffer[2048];
|
||||
|
||||
if ((fd = p_open(full_path.ptr, O_RDONLY)) < 0) {
|
||||
error = git__throw(GIT_ENOTFOUND, "Failed to create blob. Could not open '%s'", full_path.ptr);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
while (size > 0) {
|
||||
ssize_t read_len = p_read(fd, buffer, sizeof(buffer));
|
||||
|
||||
if (read_len < 0) {
|
||||
error = git__throw(GIT_EOSERR, "Failed to create blob. Can't read full file");
|
||||
p_close(fd);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@ -127,16 +141,17 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat
|
||||
size -= read_len;
|
||||
}
|
||||
|
||||
p_close(fd);
|
||||
}
|
||||
|
||||
error = stream->finalize_write(oid, stream);
|
||||
|
||||
cleanup:
|
||||
if (stream)
|
||||
stream->free(stream);
|
||||
if (!islnk && fd)
|
||||
p_close(fd);
|
||||
|
||||
git_buf_free(&full_path);
|
||||
|
||||
return error == GIT_SUCCESS ? GIT_SUCCESS :
|
||||
git__rethrow(error, "Failed to create blob");
|
||||
return error;
|
||||
}
|
||||
|
||||
|
42
src/odb.c
42
src/odb.c
@ -145,6 +145,48 @@ int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_otype type)
|
||||
return GIT_SUCCESS;
|
||||
}
|
||||
|
||||
int git_odb__hashlink(git_oid *out, const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
int error;
|
||||
git_off_t size;
|
||||
|
||||
error = p_lstat(path, &st);
|
||||
if (error < 0)
|
||||
return git__throw(GIT_EOSERR, "Failed to stat blob. %s", strerror(errno));
|
||||
|
||||
size = st.st_size;
|
||||
|
||||
if (!git__is_sizet(size))
|
||||
return git__throw(GIT_EOSERR, "File size overflow for 32-bit systems");
|
||||
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
char *link_data;
|
||||
ssize_t read_len;
|
||||
|
||||
link_data = git__malloc(size);
|
||||
if (link_data == NULL)
|
||||
return GIT_ENOMEM;
|
||||
|
||||
read_len = p_readlink(path, link_data, size + 1);
|
||||
if (read_len != (ssize_t)size)
|
||||
return git__throw(GIT_EOSERR, "Failed to read symlink data");
|
||||
|
||||
error = git_odb_hash(out, link_data, (size_t)size, GIT_OBJ_BLOB);
|
||||
free(link_data);
|
||||
} else {
|
||||
int fd;
|
||||
|
||||
if ((fd = p_open(path, O_RDONLY)) < 0)
|
||||
return git__throw(GIT_ENOTFOUND, "Could not open '%s'", path);
|
||||
|
||||
error = git_odb__hashfd(out, fd, (size_t)size, GIT_OBJ_BLOB);
|
||||
p_close(fd);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_odb_hashfile(git_oid *out, const char *path, git_otype type)
|
||||
{
|
||||
int fd, error;
|
||||
|
25
src/odb.h
25
src/odb.h
@ -39,7 +39,32 @@ struct git_odb {
|
||||
git_cache cache;
|
||||
};
|
||||
|
||||
/*
|
||||
* Hash a git_rawobj internally.
|
||||
* The `git_rawobj` is supposed to be previously initialized
|
||||
*/
|
||||
int git_odb__hashobj(git_oid *id, git_rawobj *obj);
|
||||
|
||||
/*
|
||||
* Hash an open file descriptor.
|
||||
* This is a performance call when the contents of a fd need to be hashed,
|
||||
* but the fd is already open and we have the size of the contents.
|
||||
*
|
||||
* Saves us some `stat` calls.
|
||||
*
|
||||
* The fd is never closed, not even on error. It must be opened and closed
|
||||
* by the caller
|
||||
*/
|
||||
int git_odb__hashfd(git_oid *out, git_file fd, size_t size, git_otype type);
|
||||
|
||||
/*
|
||||
* Hash a `path`, assuming it could be a POSIX symlink: if the path is a symlink,
|
||||
* then the raw contents of the symlink will be hashed. Otherwise, this will
|
||||
* fallback to `git_odb__hashfd`.
|
||||
*
|
||||
* The hash type for this call is always `GIT_OBJ_BLOB` because symlinks may only
|
||||
* point to blobs.
|
||||
*/
|
||||
int git_odb__hashlink(git_oid *out, const char *path);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user