Merge pull request #243 from jpfender/symlinks2 Symlinks NEW
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
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;