diff options
author | Jakob Pfender <jpfender@elegosoft.com> | 2011-05-25 16:04:29 +0200 |
---|---|---|
committer | Jakob Pfender <jpfender@elegosoft.com> | 2011-06-07 12:54:36 +0200 |
commit | 4d7905c579a4a89a4894ec1cea1f593338d1042f (patch) | |
tree | 7c3ad55850747990c2fd4c6bb3c9ad8d40f635d1 | |
parent | 340fc0d40ac03680d6f7964bc47f8c8d7fbbc57c (diff) | |
download | libgit2-4d7905c579a4a89a4894ec1cea1f593338d1042f.tar.gz |
blob: Require stat information for git_blob_create_fromfile()
In order to be able to write symlinks with git_blob_create_fromfile(),
we need to check whether the file to be written is a symbolic link or
not. Since the calling function of git_blob_create_fromfile() is likely to have
stated the file before calling, we make it pass the stat.
The reason for this is that writing symbolic link blobs is significantly
different from writing ordinary files - we do not want to open the link
destination but instead want to write the link itself, regardless of
whether it exists or not.
Previously, index_init_entry() used to error out if the file to be added
was a symlink that pointed to a nonexistent file. Fix this behaviour to
add the file regardless of whether it exists. This mimics git.git's
behaviour.
-rw-r--r-- | include/git2/blob.h | 2 | ||||
-rw-r--r-- | src/blob.c | 35 | ||||
-rw-r--r-- | src/index.c | 2 |
3 files changed, 26 insertions, 13 deletions
diff --git a/include/git2/blob.h b/include/git2/blob.h index e366ce880..1cfff841d 100644 --- a/include/git2/blob.h +++ b/include/git2/blob.h @@ -119,7 +119,7 @@ GIT_EXTERN(int) git_blob_rawsize(git_blob *blob); * relative to the repository's working dir * @return 0 on success; error code otherwise */ -GIT_EXTERN(int) git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path); +GIT_EXTERN(int) git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path, struct stat st); /** diff --git a/src/blob.c b/src/blob.c index 6ab58d6b2..b00fc25af 100644 --- a/src/blob.c +++ b/src/blob.c @@ -78,39 +78,51 @@ int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *b return GIT_SUCCESS; } -int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path) +int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path, struct stat st) { - int error, fd; + int error, islnk; + int fd = 0; char full_path[GIT_PATH_MAX]; char buffer[2048]; git_off_t size; git_odb_stream *stream; + islnk = S_ISLNK(st.st_mode); + if (repo->path_workdir == NULL) return git__throw(GIT_ENOTFOUND, "Failed to create blob. (No working directory found)"); git__joinpath(full_path, repo->path_workdir, path); - if ((fd = gitfo_open(full_path, O_RDONLY)) < 0) - return git__throw(GIT_ENOTFOUND, "Failed to create blob. Could not open '%s'", full_path); + if (!islnk) { + if ((fd = gitfo_open(full_path, O_RDONLY)) < 0) + return git__throw(GIT_ENOTFOUND, "Failed to create blob. Could not open '%s'", full_path); - if ((size = gitfo_size(fd)) < 0 || !git__is_sizet(size)) { - gitfo_close(fd); - return git__throw(GIT_EOSERR, "Failed to create blob. '%s' appears to be corrupted", full_path); + if ((size = gitfo_size(fd)) < 0 || !git__is_sizet(size)) { + gitfo_close(fd); + return git__throw(GIT_EOSERR, "Failed to create blob. '%s' appears to be corrupted", full_path); + } + } else { + size = st.st_size; } if ((error = git_odb_open_wstream(&stream, repo->db, (size_t)size, GIT_OBJ_BLOB)) < GIT_SUCCESS) { - gitfo_close(fd); + if (!islnk) + gitfo_close(fd); return git__rethrow(error, "Failed to create blob"); } while (size > 0) { ssize_t read_len; - read_len = read(fd, buffer, sizeof(buffer)); + if (!islnk) + read_len = read(fd, buffer, sizeof(buffer)); + else + read_len = readlink(full_path, buffer, sizeof(buffer)); if (read_len < 0) { - gitfo_close(fd); + if (!islnk) + gitfo_close(fd); stream->free(stream); return git__throw(GIT_EOSERR, "Failed to create blob. Can't read full file"); } @@ -121,7 +133,8 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat error = stream->finalize_write(oid, stream); stream->free(stream); - gitfo_close(fd); + if (!islnk) + gitfo_close(fd); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to create blob"); diff --git a/src/index.c b/src/index.c index e25c899a3..6aefe4432 100644 --- a/src/index.c +++ b/src/index.c @@ -425,7 +425,7 @@ static int index_init_entry(git_index_entry *entry, git_index *index, const char entry->file_size = st.st_size; /* write the blob to disk and get the oid */ - if ((error = git_blob_create_fromfile(&entry->oid, index->repository, rel_path)) < GIT_SUCCESS) + if ((error = git_blob_create_fromfile(&entry->oid, index->repository, rel_path, st)) < GIT_SUCCESS) return git__rethrow(error, "Failed to initialize index entry"); entry->flags |= (stage << GIT_IDXENTRY_STAGESHIFT); |