X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=tar-tree.c;h=d313c80565824824f2e954510d5bbbc65b8e116b;hb=902d960b382a0cd424618ff4e1316da40e4be2f6;hp=277c882acc4f487bfc90dee76b00dc88f99f3da3;hpb=71058b1f2be17bde78f8cf5832a3e03952fa4aac;p=git.git diff --git a/tar-tree.c b/tar-tree.c index 277c882a..d313c805 100644 --- a/tar-tree.c +++ b/tar-tree.c @@ -1,3 +1,6 @@ +/* + * Copyright (c) 2005 Rene Scharfe + */ #include #include "cache.h" @@ -6,10 +9,14 @@ #define TYPEFLAG_AUTO '\0' #define TYPEFLAG_REG '0' +#define TYPEFLAG_LNK '2' #define TYPEFLAG_DIR '5' #define TYPEFLAG_GLOBAL_HEADER 'g' #define TYPEFLAG_EXT_HEADER 'x' +#define EXT_HEADER_PATH 1 +#define EXT_HEADER_LINKPATH 2 + static const char *tar_tree_usage = "tar-tree [basedir]"; static char block[BLOCKSIZE]; @@ -199,28 +206,36 @@ static void append_extended_header(char **p, const char *keyword, } static void write_header(const char *, char, const char *, struct path_prefix *, - const char *, unsigned int, unsigned long); + const char *, unsigned int, void *, unsigned long); /* stores a pax extended header directly in the block buffer */ static void write_extended_header(const char *headerfilename, int is_dir, - const char *basepath, + unsigned int flags, const char *basepath, struct path_prefix *prefix, - const char *path, unsigned int namelen) + const char *path, unsigned int namelen, + void *content, unsigned int contentsize) { - char *p; - unsigned int pathlen, size; + char *buffer, *p; + unsigned int pathlen, size, linkpathlen = 0; size = pathlen = extended_header_len("path", namelen); - if (size > RECORDSIZE) - die("tar-tree: extended header too big, wtf?"); + if (flags & EXT_HEADER_LINKPATH) { + linkpathlen = extended_header_len("linkpath", contentsize); + size += linkpathlen; + } write_header(NULL, TYPEFLAG_EXT_HEADER, NULL, NULL, headerfilename, - 0100600, size); + 0100600, NULL, size); - p = get_record(); + buffer = p = malloc(size); + if (!buffer) + die("git-tar-tree: %s", strerror(errno)); append_extended_header_prefix(&p, pathlen, "path"); append_path(&p, is_dir, basepath, prefix, path); append_char(&p, '\n'); - write_if_needed(); + if (flags & EXT_HEADER_LINKPATH) + append_extended_header(&p, "linkpath", content, contentsize); + write_blocked(buffer, size); + free(buffer); } static void write_global_extended_header(const char *sha1) @@ -230,7 +245,7 @@ static void write_global_extended_header(const char *sha1) size = extended_header_len("comment", 40); write_header(NULL, TYPEFLAG_GLOBAL_HEADER, NULL, NULL, - "pax_global_header", 0100600, size); + "pax_global_header", 0100600, NULL, size); p = get_record(); append_extended_header(&p, "comment", sha1_to_hex(sha1), 40); @@ -240,40 +255,61 @@ static void write_global_extended_header(const char *sha1) /* stores a ustar header directly in the block buffer */ static void write_header(const char *sha1, char typeflag, const char *basepath, struct path_prefix *prefix, const char *path, - unsigned int mode, unsigned long size) + unsigned int mode, void *buffer, unsigned long size) { unsigned int namelen; - char *p, *header = NULL; + char *header = NULL; unsigned int checksum = 0; int i; + unsigned int ext_header = 0; if (typeflag == TYPEFLAG_AUTO) { if (S_ISDIR(mode)) typeflag = TYPEFLAG_DIR; + else if (S_ISLNK(mode)) + typeflag = TYPEFLAG_LNK; else typeflag = TYPEFLAG_REG; } namelen = path_len(S_ISDIR(mode), basepath, prefix, path); - if (namelen > 500) { - die("tar-tree: name too log of object %s\n", sha1_to_hex(sha1)); - } else if (namelen > 100) { - char *sha1_hex = sha1_to_hex(sha1); + if (namelen > 100) + ext_header |= EXT_HEADER_PATH; + if (typeflag == TYPEFLAG_LNK && size > 100) + ext_header |= EXT_HEADER_LINKPATH; + + /* the extended header must be written before the normal one */ + if (ext_header) { char headerfilename[51]; - sprintf(headerfilename, "%s.paxheader", sha1_hex); - /* the extended header must be written before the normal one */ - write_extended_header(headerfilename, S_ISDIR(mode), basepath, - prefix, path, namelen); + sprintf(headerfilename, "%s.paxheader", sha1_to_hex(sha1)); + write_extended_header(headerfilename, S_ISDIR(mode), + ext_header, basepath, prefix, path, + namelen, buffer, size); + } + + header = get_record(); - header = get_record(); - sprintf(header, "%s.data", sha1_hex); + if (ext_header) { + sprintf(header, "%s.data", sha1_to_hex(sha1)); } else { - p = header = get_record(); + char *p = header; append_path(&p, S_ISDIR(mode), basepath, prefix, path); } + if (typeflag == TYPEFLAG_LNK) { + if (ext_header & EXT_HEADER_LINKPATH) { + sprintf(&header[157], "see %s.paxheader", + sha1_to_hex(sha1)); + } else { + if (buffer) + strncpy(&header[157], buffer, size); + } + } + if (S_ISDIR(mode)) mode |= 0755; /* GIT doesn't store permissions of dirs */ + if (S_ISLNK(mode)) + mode |= 0777; /* ... nor of symlinks */ sprintf(&header[100], "%07o", mode & 07777); /* XXX: should we provide more meaningful info here? */ @@ -282,7 +318,9 @@ static void write_header(const char *sha1, char typeflag, const char *basepath, strncpy(&header[265], "git", 31); /* uname */ strncpy(&header[297], "git", 31); /* gname */ - sprintf(&header[124], "%011lo", S_ISDIR(mode) ? 0 : size); + if (S_ISDIR(mode) || S_ISLNK(mode)) + size = 0; + sprintf(&header[124], "%011lo", size); sprintf(&header[136], "%011lo", archive_time); header[156] = typeflag; @@ -325,11 +363,11 @@ static void traverse_tree(void *buffer, unsigned long size, if (!eltbuf) die("cannot read %s", sha1_to_hex(sha1)); write_header(sha1, TYPEFLAG_AUTO, basedir, prefix, path, - mode, eltsize); + mode, eltbuf, eltsize); if (!strcmp(elttype, "tree")) { this_prefix.name = path; traverse_tree(eltbuf, eltsize, &this_prefix); - } else if (!strcmp(elttype, "blob")) { + } else if (!strcmp(elttype, "blob") && !S_ISLNK(mode)) { write_blocked(eltbuf, eltsize); } free(eltbuf); @@ -382,10 +420,6 @@ int main(int argc, char **argv) usage(tar_tree_usage); } - sha1_file_directory = getenv(DB_ENVIRONMENT); - if (!sha1_file_directory) - sha1_file_directory = DEFAULT_DB_ENVIRONMENT; - buffer = read_object_with_reference(sha1, "commit", &size, commit_sha1); if (buffer) { write_global_extended_header(commit_sha1); @@ -399,7 +433,8 @@ int main(int argc, char **argv) if (!archive_time) archive_time = time(NULL); if (basedir) - write_header("0", TYPEFLAG_DIR, NULL, NULL, basedir, 040755, 0); + write_header("0", TYPEFLAG_DIR, NULL, NULL, basedir, 040755, + NULL, 0); traverse_tree(buffer, size, NULL); free(buffer); write_trailer();