Accept dates before 2000/01/01 when specified as seconds since the epoch
[gitweb.git] / entry.c
diff --git a/entry.c b/entry.c
index b2ea0efa82e1a0511fe5aa798618c23827b59bab..82bf7259a7d1d34a92a9bf214bccd9771748c582 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -1,9 +1,7 @@
-#include <sys/types.h>
-#include <dirent.h>
 #include "cache.h"
 #include "blob.h"
 
-static void create_directories(const char *path, struct checkout *state)
+static void create_directories(const char *path, const struct checkout *state)
 {
        int len = strlen(path);
        char *buf = xmalloc(len + 1);
@@ -35,7 +33,7 @@ static void remove_subtree(const char *path)
        char *name;
        
        if (!dir)
-               die("cannot opendir %s", path);
+               die("cannot opendir %s (%s)", path, strerror(errno));
        strcpy(pathbuf, path);
        name = pathbuf + strlen(path);
        *name++ = '/';
@@ -47,15 +45,15 @@ static void remove_subtree(const char *path)
                        continue;
                strcpy(name, de->d_name);
                if (lstat(pathbuf, &st))
-                       die("cannot lstat %s", pathbuf);
+                       die("cannot lstat %s (%s)", pathbuf, strerror(errno));
                if (S_ISDIR(st.st_mode))
                        remove_subtree(pathbuf);
                else if (unlink(pathbuf))
-                       die("cannot unlink %s", pathbuf);
+                       die("cannot unlink %s (%s)", pathbuf, strerror(errno));
        }
        closedir(dir);
        if (rmdir(path))
-               die("cannot rmdir %s", path);
+               die("cannot rmdir %s (%s)", path, strerror(errno));
 }
 
 static int create_file(const char *path, unsigned int mode)
@@ -64,23 +62,33 @@ static int create_file(const char *path, unsigned int mode)
        return open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
 }
 
-static int write_entry(struct cache_entry *ce, char *path, struct checkout *state, int to_tempfile)
+static void *read_blob_entry(struct cache_entry *ce, const char *path, unsigned long *size)
+{
+       enum object_type type;
+       void *new = read_sha1_file(ce->sha1, &type, size);
+
+       if (new) {
+               if (type == OBJ_BLOB)
+                       return new;
+               free(new);
+       }
+       return NULL;
+}
+
+static int write_entry(struct cache_entry *ce, char *path, const struct checkout *state, int to_tempfile)
 {
        int fd;
-       void *new;
-       unsigned long size;
        long wrote;
-       char type[20];
 
-       new = read_sha1_file(ce->sha1, type, &size);
-       if (!new || strcmp(type, blob_type)) {
-               if (new)
-                       free(new);
-               return error("git-checkout-index: unable to read sha1 file of %s (%s)",
-                       path, sha1_to_hex(ce->sha1));
-       }
        switch (ntohl(ce->ce_mode) & S_IFMT) {
+               char *buf, *new;
+               unsigned long size;
+
        case S_IFREG:
+               new = read_blob_entry(ce, path, &size);
+               if (!new)
+                       return error("git-checkout-index: unable to read sha1 file of %s (%s)",
+                               path, sha1_to_hex(ce->sha1));
                if (to_tempfile) {
                        strcpy(path, ".merge_file_XXXXXX");
                        fd = mkstemp(path);
@@ -91,22 +99,39 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat
                        return error("git-checkout-index: unable to create file %s (%s)",
                                path, strerror(errno));
                }
-               wrote = write(fd, new, size);
+
+               /*
+                * Convert from git internal format to working tree format
+                */
+               buf = convert_to_working_tree(ce->name, new, &size);
+               if (buf) {
+                       free(new);
+                       new = buf;
+               }
+
+               wrote = write_in_full(fd, new, size);
                close(fd);
                free(new);
                if (wrote != size)
                        return error("git-checkout-index: unable to write file %s", path);
                break;
        case S_IFLNK:
-               if (to_tempfile) {
-                       strcpy(path, ".merge_link_XXXXXX");
-                       fd = mkstemp(path);
+               new = read_blob_entry(ce, path, &size);
+               if (!new)
+                       return error("git-checkout-index: unable to read sha1 file of %s (%s)",
+                               path, sha1_to_hex(ce->sha1));
+               if (to_tempfile || !has_symlinks) {
+                       if (to_tempfile) {
+                               strcpy(path, ".merge_link_XXXXXX");
+                               fd = mkstemp(path);
+                       } else
+                               fd = create_file(path, 0666);
                        if (fd < 0) {
                                free(new);
                                return error("git-checkout-index: unable to create "
                                                 "file %s (%s)", path, strerror(errno));
                        }
-                       wrote = write(fd, new, size);
+                       wrote = write_in_full(fd, new, size);
                        close(fd);
                        free(new);
                        if (wrote != size)
@@ -120,8 +145,13 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat
                                                 "symlink %s (%s)", path, strerror(errno));
                }
                break;
+       case S_IFDIRLNK:
+               if (to_tempfile)
+                       return error("git-checkout-index: cannot create temporary subproject %s", path);
+               if (mkdir(path, 0777) < 0)
+                       return error("git-checkout-index: cannot create subproject directory %s", path);
+               break;
        default:
-               free(new);
                return error("git-checkout-index: unknown file mode for %s", path);
        }
 
@@ -133,7 +163,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat
        return 0;
 }
 
-int checkout_entry(struct cache_entry *ce, struct checkout *state, char *topath)
+int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath)
 {
        static char path[PATH_MAX + 1];
        struct stat st;
@@ -163,6 +193,9 @@ int checkout_entry(struct cache_entry *ce, struct checkout *state, char *topath)
                 */
                unlink(path);
                if (S_ISDIR(st.st_mode)) {
+                       /* If it is a gitlink, leave it alone! */
+                       if (S_ISDIRLNK(ntohl(ce->ce_mode)))
+                               return 0;
                        if (!state->force)
                                return error("%s is a directory", path);
                        remove_subtree(path);