Commit 3a12891f53cd5c349c0eed2ace7a9a900432aa5e

Vicent Martí 2011-06-07T07:07:45

Merge pull request #243 from jpfender/symlinks2 Symlinks NEW

diff --git a/src/blob.c b/src/blob.c
index 6ab58d6..12f468e 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -80,37 +80,52 @@ 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, fd;
+	int error, islnk;
+	int fd = 0;
 	char full_path[GIT_PATH_MAX];
 	char buffer[2048];
 	git_off_t size;
 	git_odb_stream *stream;
+	struct stat st;
+
+	gitfo_lstat(path, &st);
+
+	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 +136,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/fileops.c b/src/fileops.c
index 8292843..2e5717e 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -175,6 +175,14 @@ int gitfo_exists(const char *path)
 	return access(path, F_OK);
 }
 
+int gitfo_shallow_exists(const char *path)
+{
+	assert(path);
+
+	struct stat st;
+	return gitfo_lstat(path, &st);
+}
+
 git_off_t gitfo_size(git_file fd)
 {
 	struct stat sb;
diff --git a/src/fileops.h b/src/fileops.h
index c114508..e20ce6f 100644
--- a/src/fileops.h
+++ b/src/fileops.h
@@ -65,6 +65,7 @@ typedef struct {  /* file io buffer  */
 } gitfo_buf;
 
 extern int gitfo_exists(const char *path);
+extern int gitfo_shallow_exists(const char *path);
 extern int gitfo_open(const char *path, int flags);
 extern int gitfo_creat(const char *path, int mode);
 extern int gitfo_creat_force(const char *path, int mode);
@@ -94,6 +95,7 @@ extern int gitfo_mv_force(const char *from, const char *to);
 
 #define gitfo_stat(p,b) stat(p, b)
 #define gitfo_fstat(f,b) fstat(f, b)
+#define gitfo_lstat(p,b) lstat(p,b)
 
 #define gitfo_unlink(p) unlink(p)
 #define gitfo_rmdir(p) rmdir(p)
diff --git a/src/index.c b/src/index.c
index e25c899..798d9e9 100644
--- a/src/index.c
+++ b/src/index.c
@@ -138,6 +138,15 @@ int unmerged_cmp(const void *a, const void *b)
 	return strcmp(info_a->path, info_b->path);
 }
 
+unsigned int index_create_mode(unsigned int mode)
+{
+	if (S_ISLNK(mode))
+		return S_IFLNK;
+	if (S_ISDIR(mode) || (mode & S_IFMT) == 0160000)
+		return 0160000;
+	return S_IFREG | ((mode & 0100) ? 0755 : 0644);
+}
+
 static int index_initialize(git_index **index_out, git_repository *owner, const char *index_path)
 {
 	git_index *index;
@@ -402,10 +411,10 @@ static int index_init_entry(git_index_entry *entry, git_index *index, const char
 
 	git__joinpath(full_path, index->repository->path_workdir, rel_path);
 
-	if (gitfo_exists(full_path) < 0)
+	if (gitfo_shallow_exists(full_path) < 0)
 		return git__throw(GIT_ENOTFOUND, "Failed to initialize entry. %s does not exist", full_path);
 
-	if (gitfo_stat(full_path, &st) < 0)
+	if (gitfo_lstat(full_path, &st) < 0)
 		return git__throw(GIT_EOSERR, "Failed to initialize entry. %s appears to be corrupted", full_path);
 
 	if (stage < 0 || stage > 3)
@@ -419,7 +428,7 @@ static int index_init_entry(git_index_entry *entry, git_index *index, const char
 	/* entry.ctime.nanoseconds = st.st_ctimensec; */
 	entry->dev= st.st_rdev;
 	entry->ino = st.st_ino;
-	entry->mode = st.st_mode;
+	entry->mode = index_create_mode(st.st_mode);
 	entry->uid = st.st_uid;
 	entry->gid = st.st_gid;
 	entry->file_size = st.st_size;