{"thread":{"id":"514","subject":"[PATCH 5/5] git-tar-tree: add symlink support","startedAt":"2005-05-06T20:56:16Z","lastAt":"2005-05-06T20:56:16Z","messageCount":1,"participants":["Rene Scharfe"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"2707","messageId":"20050506205616.GF19518@lsrfire.ath.cx","threadId":"514","inReplyTo":null,"subject":"[PATCH 5/5] git-tar-tree: add symlink support","fromName":"Rene Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2005-05-06T20:56:16Z","receivedAt":"2005-05-06T20:56:16Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Add symlink support to git-tar-tree.\n\n---\ncommit 7cc9bcd638b69e7cb7fed5b9aa8887e71f88c6c7\ntree 8326e0ed584a22abfe510f7cf71a5a569157920d\nparent 2da87ce547b59294d4d1cf527009395fbec7bf91\nauthor Rene Scharfe <rene.scharfe@lsrfire.ath.cx> 1115312885 +0200\ncommitter Rene Scharfe <rene.scharfe@lsrfire.ath.cx> 1115312885 +0200\n\nIndex: tar-tree.c\n===================================================================\n--- 9eedd772d20dd5a66735f49efe80e17ced40f258/tar-tree.c  (mode:100644 sha1:e99adc7dd781cf46efbed82221bf62975a4a3996)\n+++ 8326e0ed584a22abfe510f7cf71a5a569157920d/tar-tree.c  (mode:100644 sha1:a09cb416595094e493a52dd7f45d943c81c0310a)\n@@ -6,10 +6,14 @@\n \n #define TYPEFLAG_AUTO\t\t'\\0'\n #define TYPEFLAG_REG\t\t'0'\n+#define TYPEFLAG_LNK\t\t'2'\n #define TYPEFLAG_DIR\t\t'5'\n #define TYPEFLAG_GLOBAL_HEADER\t'g'\n #define TYPEFLAG_EXT_HEADER\t'x'\n \n+#define EXT_HEADER_PATH\t\t1\n+#define EXT_HEADER_LINKPATH\t2\n+\n static const char *tar_tree_usage = \"tar-tree <key> [basedir]\";\n \n static char block[BLOCKSIZE];\n@@ -209,9 +213,13 @@\n                                   void *content, unsigned int contentsize)\n {\n \tchar *p;\n-\tunsigned int pathlen, size;\n+\tunsigned int pathlen, size, linkpathlen = 0;\n \n \tsize = pathlen = extended_header_len(\"path\", namelen);\n+\tif (flags & EXT_HEADER_LINKPATH) {\n+\t\tlinkpathlen = extended_header_len(\"linkpath\", contentsize);\n+\t\tsize += linkpathlen;\n+\t}\n \tif (size > RECORDSIZE)\n \t\tdie(\"tar-tree: extended header too big, wtf?\");\n \twrite_header(NULL, TYPEFLAG_EXT_HEADER, NULL, NULL, headerfilename,\n@@ -221,6 +229,8 @@\n \tappend_extended_header_prefix(&p, pathlen, \"path\");\n \tappend_path(&p, is_dir, basepath, prefix, path);\n \tappend_char(&p, '\\n');\n+\tif (flags & EXT_HEADER_LINKPATH)\n+\t\tappend_extended_header(&p, \"linkpath\", content, contentsize);\n \twrite_if_needed();\n }\n \n@@ -244,38 +254,60 @@\n                          unsigned int mode, void *buffer, unsigned long size)\n {\n \tunsigned int namelen; \n-\tchar *p, *header = NULL;\n+\tchar *header = NULL;\n \tunsigned int checksum = 0;\n \tint i;\n+\tunsigned int ext_header = 0;\n \n \tif (typeflag == TYPEFLAG_AUTO) {\n \t\tif (S_ISDIR(mode))\n \t\t\ttypeflag = TYPEFLAG_DIR;\n+\t\telse if (S_ISLNK(mode))\n+\t\t\ttypeflag = TYPEFLAG_LNK;\n \t\telse\n \t\t\ttypeflag = TYPEFLAG_REG;\n \t}\n \n \tnamelen = path_len(S_ISDIR(mode), basepath, prefix, path);\n-\tif (namelen > 500) {\n+\tif (namelen > 500)\n \t\tdie(\"tar-tree: name too log of object %s\\n\", sha1_to_hex(sha1));\n-\t} else if (namelen > 100) {\n-\t\tchar *sha1_hex = sha1_to_hex(sha1);\n+\telse if (namelen > 100)\n+\t\text_header |= EXT_HEADER_PATH;\n+\tif (typeflag == TYPEFLAG_LNK && size > 100)\n+\t\text_header |= EXT_HEADER_LINKPATH;\n+\n+\t/* the extended header must be written before the normal one */\n+\tif (ext_header) {\n \t\tchar headerfilename[51];\n-\t\tsprintf(headerfilename, \"%s.paxheader\", sha1_hex);\n-\t\t/* the extended header must be written before the normal one */\n+\t\tsprintf(headerfilename, \"%s.paxheader\", sha1_to_hex(sha1));\n \t\twrite_extended_header(headerfilename, S_ISDIR(mode),\n-\t\t                      0, basepath, prefix, path,\n+\t\t                      ext_header, basepath, prefix, path,\n \t\t                      namelen, buffer, size);\n+\t}\n \n-\t\theader = get_record();\n-\t\tsprintf(header, \"%s.data\", sha1_hex);\n+\theader = get_record();\n+\n+\tif (ext_header) {\n+\t\tsprintf(header, \"%s.data\", sha1_to_hex(sha1));\n \t} else {\n-\t\tp = header = get_record();\n+\t\tchar *p = header;\n \t\tappend_path(&p, S_ISDIR(mode), basepath, prefix, path);\n \t}\n \n+\tif (typeflag == TYPEFLAG_LNK) {\n+\t\tif (ext_header & EXT_HEADER_LINKPATH) {\n+\t\t\tsprintf(&header[157], \"see %s.paxheader\",\n+\t\t\t        sha1_to_hex(sha1));\n+\t\t} else {\n+\t\t\tif (buffer)\n+\t\t\t\tstrncpy(&header[157], buffer, size);\n+\t\t}\n+\t}\n+\n \tif (S_ISDIR(mode))\n \t\tmode |= 0755;\t/* GIT doesn't store permissions of dirs */\n+\tif (S_ISLNK(mode))\n+\t\tmode |= 0777;   /* ... nor of symlinks */\n \tsprintf(&header[100], \"%07o\", mode & 07777);\n \n \t/* XXX: should we provide more meaningful info here? */\n@@ -284,7 +316,9 @@\n \tstrncpy(&header[265], \"git\", 31);\t/* uname */\n \tstrncpy(&header[297], \"git\", 31);\t/* gname */\n \n-\tsprintf(&header[124], \"%011lo\", S_ISDIR(mode) ? 0 : size);\n+\tif (S_ISDIR(mode) || S_ISLNK(mode))\n+\t\tsize = 0;\n+\tsprintf(&header[124], \"%011lo\", size);\n \tsprintf(&header[136], \"%011lo\", archive_time);\n \n \theader[156] = typeflag;\n@@ -331,7 +365,7 @@\n \t\tif (!strcmp(elttype, \"tree\")) {\n \t\t\tthis_prefix.name = path;\n \t\t\ttraverse_tree(eltbuf, eltsize, &this_prefix);\n-\t\t} else if (!strcmp(elttype, \"blob\")) {\n+\t\t} else if (!strcmp(elttype, \"blob\") && !S_ISLNK(mode)) {\n \t\t\twrite_blocked(eltbuf, eltsize);\n \t\t}\n \t\tfree(eltbuf);\n\n\n\f\n!-------------------------------------------------------------flip-\n\n\n"}]}