diff --git a/test/abspath.2.c b/test/abspath.2.c deleted file mode 100644 index 5e1360c..0000000 --- a/test/abspath.2.c +++ /dev/null @@ -1,109 +0,0 @@ -#include "cache.h" - -/* Test 1 */ -/* We allow "recursive" symbolic links. Only within reason, though. */ -#define MAXDEPTH 5 -#define MAXDEPTH 5 - -const char *make_absolute_path(const char *path) -{ - static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1]; - char cwd[1024] = ""; - int buf_index = 1; - - int depth = MAXDEPTH; - char *last_elem = NULL; - struct stat st; - - if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) - die ("Too long path: %.*s", 60, path); - - while (depth--) { - if (!is_directory(buf)) { - char *last_slash = strrchr(buf, '/'); - if (last_slash) { - *last_slash = '\0'; - last_elem = xstrdup(last_slash + 1); - } else { - last_elem = xstrdup(buf); - *buf = '\0'; - } - } - - if (*buf) { - if (!*cwd && !getcwd(cwd, sizeof(cwd))) - die_errno ("Could not get current working directory"); - - if (chdir(buf)) - die_errno ("Could not switch to '%s'", buf); - } - if (!getcwd(buf, PATH_MAX)) - die_errno ("Could not get current working directory"); - - if (last_elem) { - size_t len = strlen(buf); - if (len + strlen(last_elem) + 2 > PATH_MAX) - die ("Too long path name: '%s/%s'", - buf, last_elem); - if (len && buf[len-1] != '/') - buf[len++] = '/'; - strcpy(buf + len, last_elem); - free(last_elem); - last_elem = NULL; - } - - if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) { - ssize_t len = readlink(buf, next_buf, PATH_MAX); - if (len < 0) - die_errno ("Invalid symlink '%s'", buf); - if (PATH_MAX <= len) - die("symbolic link too long: %s", buf); - next_buf[len] = '\0'; - buf = next_buf; - buf_index = 1 - buf_index; - next_buf = bufs[buf_index]; - } else - break; - } - - if (*cwd && chdir(cwd)) - die_errno ("Could not change back to '%s'", cwd); - - return buf; -} - -static const char *get_pwd_cwd(void) -{ - static char cwd[PATH_MAX + 1]; - char *pwd; - struct stat cwd_stat, pwd_stat; - if (getcwd(cwd, PATH_MAX) == NULL) - return NULL; - pwd = getenv("PWD"); - if (pwd && strcmp(pwd, cwd)) { - stat(cwd, &cwd_stat); - if (!stat(pwd, &pwd_stat) && - pwd_stat.st_dev == cwd_stat.st_dev && - pwd_stat.st_ino == cwd_stat.st_ino) { - strlcpy(cwd, pwd, PATH_MAX); - } - } - return cwd; -} - -const char *make_nonrelative_path(const char *path) -{ - static char buf[PATH_MAX + 1]; - - if (is_absolute_path(path)) { - if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX) - die("Too long path: %.*s", 60, path); - } else { - const char *cwd = get_pwd_cwd(); - if (!cwd) - die_errno("Cannot determine the current working directory"); - if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX) - die("Too long path: %.*s", 60, path); - } - return buf; -} diff --git a/test/advice.c b/test/advice.c index 0be4b5f..5723b6c 100644 --- a/test/advice.c +++ b/test/advice.c @@ -6,7 +6,7 @@ int advice_commit_before_merge = 1; int advice_resolve_conflict = 1; int advice_implicit_identity = 1; int advice_detached_head = 1; - +//////////////////////////////////////////////// static struct { const char *name; int *preference; diff --git a/test/alias.c b/test/alias.c deleted file mode 100644 index 6c8775c..0000000 --- a/test/alias.c +++ /dev/null @@ -1,80 +0,0 @@ -#include "cache.h" - -# my change - -somthing else -static const char *alias_key; -static char *alias_val; - -static int alias_lookup_cb(const char *k, const char *v, void *cb) -{ - if (!prefixcmp(k, "alias.") && !strcmp(k+6, alias_key)) { - if (!v) - return config_error_nonbool(k); - alias_val = xstrdup(v); - return 0; - } - return 0; -} - -char *alias_lookup(const char *alias) -{ - alias_key = alias; - alias_val = NULL; - git_config(alias_lookup_cb, NULL); - return alias_val; -} - -int split_cmdline(char *cmdline, const char ***argv) -{ - int src, dst, count = 0, size = 16; - char quoted = 0; - - *argv = xmalloc(sizeof(char *) * size); - - /* split alias_string */ - (*argv)[count++] = cmdline; - for (src = dst = 0; cmdline[src];) { - char c = cmdline[src]; - if (!quoted && isspace(c)) { - cmdline[dst++] = 0; - while (cmdline[++src] - && isspace(cmdline[src])) - ; /* skip */ - ALLOC_GROW(*argv, count+1, size); - (*argv)[count++] = cmdline + dst; - } else if (!quoted && (c == '\'' || c == '"')) { - quoted = c; - src++; - } else if (c == quoted) { - quoted = 0; - src++; - } else { - if (c == '\\' && quoted != '\'') { - src++; - c = cmdline[src]; - if (!c) { - free(*argv); - *argv = NULL; - return error("cmdline ends with \\"); - } - } - cmdline[dst++] = c; - src++; - } - } - - cmdline[dst] = 0; - - if (quoted) { - free(*argv); - *argv = NULL; - return error("unclosed quote"); - } - - ALLOC_GROW(*argv, count+1, size); - (*argv)[count] = NULL; - - return count; -} - diff --git a/test/alloc.c b/test/alloc.c deleted file mode 100644 index 6ef6753..0000000 --- a/test/alloc.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * alloc.c - specialized allocator for internal objects - * - * Copyright (C) 2006 Linus Torvalds - * - * The standard malloc/free wastes too much space for objects, partly because - * it maintains all the allocation infrastructure (which isn't needed, since - * we never free an object descriptor anyway), but even more because it ends - * up with maximal alignment because it doesn't know what the object alignment - * for the new allocation is. - */ -#include "cache.h" -#include "object.h" -#include "blob.h" -#include "tree.h" -#include "commit.h" -#include "tag.h" - -#define BLOCKING 1024 - -#define DEFINE_ALLOCATOR(name, type) \ -static unsigned int name##_allocs; \ -void *alloc_##name##_node(void) \ -{ \ - static int nr; \ - static type *block; \ - void *ret; \ - \ - if (!nr) { \ - nr = BLOCKING; \ - block = xmalloc(BLOCKING * sizeof(type)); \ - } \ - nr--; \ - name##_allocs++; \ - ret = block++; \ - memset(ret, 0, sizeof(type)); \ - return ret; \ -} - -union any_object { - struct object object; - struct blob blob; - struct tree tree; - struct commit commit; - struct tag tag; -}; - -DEFINE_ALLOCATOR(blob, struct blob) -DEFINE_ALLOCATOR(tree, struct tree) -DEFINE_ALLOCATOR(commit, struct commit) -DEFINE_ALLOCATOR(tag, struct tag) -DEFINE_ALLOCATOR(object, union any_object) - -#ifdef NO_C99_FORMAT -#define SZ_FMT "%u" -#else -#define SZ_FMT "%zu" -#endif - -static void report(const char *name, unsigned int count, size_t size) -{ - fprintf(stderr, "%10s: %8u (" SZ_FMT " kB)\n", name, count, size); -} - -#undef SZ_FMT - -#define REPORT(name) \ - report(#name, name##_allocs, name##_allocs*sizeof(struct name) >> 10) - -void alloc_report(void) -{ - REPORT(blob); - REPORT(tree); - REPORT(commit); - REPORT(tag); -} diff --git a/test/archive-tar.c b/test/archive-tar.c deleted file mode 100644 index cee06ce..0000000 --- a/test/archive-tar.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (c) 2005, 2006 Rene Scharfe - */ -#include "cache.h" -#include "tar.h" -#include "archive.h" - -#define RECORDSIZE (512) -#define BLOCKSIZE (RECORDSIZE * 20) - -static char block[BLOCKSIZE]; -static unsigned long offset; - -static int tar_umask = 002; - -/* writes out the whole block, but only if it is full */ -static void write_if_needed(void) -{ - if (offset == BLOCKSIZE) { - write_or_die(1, block, BLOCKSIZE); - offset = 0; - } -} - -/* - * queues up writes, so that all our write(2) calls write exactly one - * full block; pads writes to RECORDSIZE - */ -static void write_blocked(const void *data, unsigned long size) -{ - const char *buf = data; - unsigned long tail; - - if (offset) { - unsigned long chunk = BLOCKSIZE - offset; - if (size < chunk) - chunk = size; - memcpy(block + offset, buf, chunk); - size -= chunk; - offset += chunk; - buf += chunk; - write_if_needed(); - } - while (size >= BLOCKSIZE) { - write_or_die(1, buf, BLOCKSIZE); - size -= BLOCKSIZE; - buf += BLOCKSIZE; - } - if (size) { - memcpy(block + offset, buf, size); - offset += size; - } - tail = offset % RECORDSIZE; - if (tail) { - memset(block + offset, 0, RECORDSIZE - tail); - offset += RECORDSIZE - tail; - } - write_if_needed(); -} - -/* - * The end of tar archives is marked by 2*512 nul bytes and after that - * follows the rest of the block (if any). - */ -static void write_trailer(void) -{ - int tail = BLOCKSIZE - offset; - memset(block + offset, 0, tail); - write_or_die(1, block, BLOCKSIZE); - if (tail < 2 * RECORDSIZE) { - memset(block, 0, offset); - write_or_die(1, block, BLOCKSIZE); - } -} - -/* - * pax extended header records have the format "%u %s=%s\n". %u contains - * the size of the whole string (including the %u), the first %s is the - * keyword, the second one is the value. This function constructs such a - * string and appends it to a struct strbuf. - */ -static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword, - const char *value, unsigned int valuelen) -{ - int len, tmp; - - /* "%u %s=%s\n" */ - len = 1 + 1 + strlen(keyword) + 1 + valuelen + 1; - for (tmp = len; tmp > 9; tmp /= 10) - len++; - - strbuf_grow(sb, len); - strbuf_addf(sb, "%u %s=", len, keyword); - strbuf_add(sb, value, valuelen); - strbuf_addch(sb, '\n'); -} - -static unsigned int ustar_header_chksum(const struct ustar_header *header) -{ - char *p = (char *)header; - unsigned int chksum = 0; - while (p < header->chksum) - chksum += *p++; - chksum += sizeof(header->chksum) * ' '; - p += sizeof(header->chksum); - while (p < (char *)header + sizeof(struct ustar_header)) - chksum += *p++; - return chksum; -} - -static size_t get_path_prefix(const char *path, size_t pathlen, size_t maxlen) -{ - size_t i = pathlen; - if (i > maxlen) - i = maxlen; - do { - i--; - } while (i > 0 && path[i] != '/'); - return i; -} - -static int write_tar_entry(struct archiver_args *args, - const unsigned char *sha1, const char *path, size_t pathlen, - unsigned int mode, void *buffer, unsigned long size) -{ - struct ustar_header header; - struct strbuf ext_header = STRBUF_INIT; - int err = 0; - - memset(&header, 0, sizeof(header)); - - if (!sha1) { - *header.typeflag = TYPEFLAG_GLOBAL_HEADER; - mode = 0100666; - strcpy(header.name, "pax_global_header"); - } else if (!path) { - *header.typeflag = TYPEFLAG_EXT_HEADER; - mode = 0100666; - sprintf(header.name, "%s.paxheader", sha1_to_hex(sha1)); - } else { - if (S_ISDIR(mode) || S_ISGITLINK(mode)) { - *header.typeflag = TYPEFLAG_DIR; - mode = (mode | 0777) & ~tar_umask; - } else if (S_ISLNK(mode)) { - *header.typeflag = TYPEFLAG_LNK; - mode |= 0777; - } else if (S_ISREG(mode)) { - *header.typeflag = TYPEFLAG_REG; - mode = (mode | ((mode & 0100) ? 0777 : 0666)) & ~tar_umask; - } else { - return error("unsupported file mode: 0%o (SHA1: %s)", - mode, sha1_to_hex(sha1)); - } - if (pathlen > sizeof(header.name)) { - size_t plen = get_path_prefix(path, pathlen, - sizeof(header.prefix)); - size_t rest = pathlen - plen - 1; - if (plen > 0 && rest <= sizeof(header.name)) { - memcpy(header.prefix, path, plen); - memcpy(header.name, path + plen + 1, rest); - } else { - sprintf(header.name, "%s.data", - sha1_to_hex(sha1)); - strbuf_append_ext_header(&ext_header, "path", - path, pathlen); - } - } else - memcpy(header.name, path, pathlen); - } - - if (S_ISLNK(mode) && buffer) { - if (size > sizeof(header.linkname)) { - sprintf(header.linkname, "see %s.paxheader", - sha1_to_hex(sha1)); - strbuf_append_ext_header(&ext_header, "linkpath", - buffer, size); - } else - memcpy(header.linkname, buffer, size); - } - - sprintf(header.mode, "%07o", mode & 07777); - sprintf(header.size, "%011lo", S_ISREG(mode) ? size : 0); - sprintf(header.mtime, "%011lo", (unsigned long) args->time); - - sprintf(header.uid, "%07o", 0); - sprintf(header.gid, "%07o", 0); - strlcpy(header.uname, "root", sizeof(header.uname)); - strlcpy(header.gname, "root", sizeof(header.gname)); - sprintf(header.devmajor, "%07o", 0); - sprintf(header.devminor, "%07o", 0); - - memcpy(header.magic, "ustar", 6); - memcpy(header.version, "00", 2); - - sprintf(header.chksum, "%07o", ustar_header_chksum(&header)); - - if (ext_header.len > 0) { - err = write_tar_entry(args, sha1, NULL, 0, 0, ext_header.buf, - ext_header.len); - if (err) - return err; - } - strbuf_release(&ext_header); - write_blocked(&header, sizeof(header)); - if (S_ISREG(mode) && buffer && size > 0) - write_blocked(buffer, size); - return err; -} - -static int write_global_extended_header(struct archiver_args *args) -{ - const unsigned char *sha1 = args->commit_sha1; - struct strbuf ext_header = STRBUF_INIT; - int err; - - strbuf_append_ext_header(&ext_header, "comment", sha1_to_hex(sha1), 40); - err = write_tar_entry(args, NULL, NULL, 0, 0, ext_header.buf, - ext_header.len); - strbuf_release(&ext_header); - return err; -} - -static int git_tar_config(const char *var, const char *value, void *cb) -{ - if (!strcmp(var, "tar.umask")) { - if (value && !strcmp(value, "user")) { - tar_umask = umask(0); - umask(tar_umask); - } else { - tar_umask = git_config_int(var, value); - } - return 0; - } - return git_default_config(var, value, cb); -} - -int write_tar_archive(struct archiver_args *args) -{ - int err = 0; - - git_config(git_tar_config, NULL); - - if (args->commit_sha1) - err = write_global_extended_header(args); - if (!err) - err = write_archive_entries(args, write_tar_entry); - if (!err) - write_trailer(); - return err; -} diff --git a/test/archive-zip.c b/test/archive-zip.c deleted file mode 100644 index cf28504..0000000 --- a/test/archive-zip.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright (c) 2006 Rene Scharfe - */ -#include "cache.h" -#include "archive.h" - -static int zip_date; -static int zip_time; - -static unsigned char *zip_dir; -static unsigned int zip_dir_size; - -static unsigned int zip_offset; -static unsigned int zip_dir_offset; -static unsigned int zip_dir_entries; - -#define ZIP_DIRECTORY_MIN_SIZE (1024 * 1024) - -struct zip_local_header { - unsigned char magic[4]; - unsigned char version[2]; - unsigned char flags[2]; - unsigned char compression_method[2]; - unsigned char mtime[2]; - unsigned char mdate[2]; - unsigned char crc32[4]; - unsigned char compressed_size[4]; - unsigned char size[4]; - unsigned char filename_length[2]; - unsigned char extra_length[2]; - unsigned char _end[1]; -}; - -struct zip_dir_header { - unsigned char magic[4]; - unsigned char creator_version[2]; - unsigned char version[2]; - unsigned char flags[2]; - unsigned char compression_method[2]; - unsigned char mtime[2]; - unsigned char mdate[2]; - unsigned char crc32[4]; - unsigned char compressed_size[4]; - unsigned char size[4]; - unsigned char filename_length[2]; - unsigned char extra_length[2]; - unsigned char comment_length[2]; - unsigned char disk[2]; - unsigned char attr1[2]; - unsigned char attr2[4]; - unsigned char offset[4]; - unsigned char _end[1]; -}; - -struct zip_dir_trailer { - unsigned char magic[4]; - unsigned char disk[2]; - unsigned char directory_start_disk[2]; - unsigned char entries_on_this_disk[2]; - unsigned char entries[2]; - unsigned char size[4]; - unsigned char offset[4]; - unsigned char comment_length[2]; - unsigned char _end[1]; -}; - -/* - * On ARM, padding is added at the end of the struct, so a simple - * sizeof(struct ...) reports two bytes more than the payload size - * we're interested in. - */ -#define ZIP_LOCAL_HEADER_SIZE offsetof(struct zip_local_header, _end) -#define ZIP_DIR_HEADER_SIZE offsetof(struct zip_dir_header, _end) -#define ZIP_DIR_TRAILER_SIZE offsetof(struct zip_dir_trailer, _end) - -static void copy_le16(unsigned char *dest, unsigned int n) -{ - dest[0] = 0xff & n; - dest[1] = 0xff & (n >> 010); -} - -static void copy_le32(unsigned char *dest, unsigned int n) -{ - dest[0] = 0xff & n; - dest[1] = 0xff & (n >> 010); - dest[2] = 0xff & (n >> 020); - dest[3] = 0xff & (n >> 030); -} - -static void *zlib_deflate(void *data, unsigned long size, - int compression_level, unsigned long *compressed_size) -{ - z_stream stream; - unsigned long maxsize; - void *buffer; - int result; - - memset(&stream, 0, sizeof(stream)); - deflateInit(&stream, compression_level); - maxsize = deflateBound(&stream, size); - buffer = xmalloc(maxsize); - - stream.next_in = data; - stream.avail_in = size; - stream.next_out = buffer; - stream.avail_out = maxsize; - - do { - result = deflate(&stream, Z_FINISH); - } while (result == Z_OK); - - if (result != Z_STREAM_END) { - free(buffer); - return NULL; - } - - deflateEnd(&stream); - *compressed_size = stream.total_out; - - return buffer; -} - -static int write_zip_entry(struct archiver_args *args, - const unsigned char *sha1, const char *path, size_t pathlen, - unsigned int mode, void *buffer, unsigned long size) -{ - struct zip_local_header header; - struct zip_dir_header dirent; - unsigned long attr2; - unsigned long compressed_size; - unsigned long uncompressed_size; - unsigned long crc; - unsigned long direntsize; - int method; - unsigned char *out; - void *deflated = NULL; - - crc = crc32(0, NULL, 0); - - if (pathlen > 0xffff) { - return error("path too long (%d chars, SHA1: %s): %s", - (int)pathlen, sha1_to_hex(sha1), path); - } - - if (S_ISDIR(mode) || S_ISGITLINK(mode)) { - method = 0; - attr2 = 16; - out = NULL; - uncompressed_size = 0; - compressed_size = 0; - } else if (S_ISREG(mode) || S_ISLNK(mode)) { - method = 0; - attr2 = S_ISLNK(mode) ? ((mode | 0777) << 16) : - (mode & 0111) ? ((mode) << 16) : 0; - if (S_ISREG(mode) && args->compression_level != 0) - method = 8; - crc = crc32(crc, buffer, size); - out = buffer; - uncompressed_size = size; - compressed_size = size; - } else { - return error("unsupported file mode: 0%o (SHA1: %s)", mode, - sha1_to_hex(sha1)); - } - - if (method == 8) { - deflated = zlib_deflate(buffer, size, args->compression_level, - &compressed_size); - if (deflated && compressed_size - 6 < size) { - /* ZLIB --> raw compressed data (see RFC 1950) */ - /* CMF and FLG ... */ - out = (unsigned char *)deflated + 2; - compressed_size -= 6; /* ... and ADLER32 */ - } else { - method = 0; - compressed_size = size; - } - } - - /* make sure we have enough free space in the dictionary */ - direntsize = ZIP_DIR_HEADER_SIZE + pathlen; - while (zip_dir_size < zip_dir_offset + direntsize) { - zip_dir_size += ZIP_DIRECTORY_MIN_SIZE; - zip_dir = xrealloc(zip_dir, zip_dir_size); - } - - copy_le32(dirent.magic, 0x02014b50); - copy_le16(dirent.creator_version, - S_ISLNK(mode) || (S_ISREG(mode) && (mode & 0111)) ? 0x0317 : 0); - copy_le16(dirent.version, 10); - copy_le16(dirent.flags, 0); - copy_le16(dirent.compression_method, method); - copy_le16(dirent.mtime, zip_time); - copy_le16(dirent.mdate, zip_date); - copy_le32(dirent.crc32, crc); - copy_le32(dirent.compressed_size, compressed_size); - copy_le32(dirent.size, uncompressed_size); - copy_le16(dirent.filename_length, pathlen); - copy_le16(dirent.extra_length, 0); - copy_le16(dirent.comment_length, 0); - copy_le16(dirent.disk, 0); - copy_le16(dirent.attr1, 0); - copy_le32(dirent.attr2, attr2); - copy_le32(dirent.offset, zip_offset); - memcpy(zip_dir + zip_dir_offset, &dirent, ZIP_DIR_HEADER_SIZE); - zip_dir_offset += ZIP_DIR_HEADER_SIZE; - memcpy(zip_dir + zip_dir_offset, path, pathlen); - zip_dir_offset += pathlen; - zip_dir_entries++; - - copy_le32(header.magic, 0x04034b50); - copy_le16(header.version, 10); - copy_le16(header.flags, 0); - copy_le16(header.compression_method, method); - copy_le16(header.mtime, zip_time); - copy_le16(header.mdate, zip_date); - copy_le32(header.crc32, crc); - copy_le32(header.compressed_size, compressed_size); - copy_le32(header.size, uncompressed_size); - copy_le16(header.filename_length, pathlen); - copy_le16(header.extra_length, 0); - write_or_die(1, &header, ZIP_LOCAL_HEADER_SIZE); - zip_offset += ZIP_LOCAL_HEADER_SIZE; - write_or_die(1, path, pathlen); - zip_offset += pathlen; - if (compressed_size > 0) { - write_or_die(1, out, compressed_size); - zip_offset += compressed_size; - } - - free(deflated); - - return 0; -} - -static void write_zip_trailer(const unsigned char *sha1) -{ - struct zip_dir_trailer trailer; - - copy_le32(trailer.magic, 0x06054b50); - copy_le16(trailer.disk, 0); - copy_le16(trailer.directory_start_disk, 0); - copy_le16(trailer.entries_on_this_disk, zip_dir_entries); - copy_le16(trailer.entries, zip_dir_entries); - copy_le32(trailer.size, zip_dir_offset); - copy_le32(trailer.offset, zip_offset); - copy_le16(trailer.comment_length, sha1 ? 40 : 0); - - write_or_die(1, zip_dir, zip_dir_offset); - write_or_die(1, &trailer, ZIP_DIR_TRAILER_SIZE); - if (sha1) - write_or_die(1, sha1_to_hex(sha1), 40); -} - -static void dos_time(time_t *time, int *dos_date, int *dos_time) -{ - struct tm *t = localtime(time); - - *dos_date = t->tm_mday + (t->tm_mon + 1) * 32 + - (t->tm_year + 1900 - 1980) * 512; - *dos_time = t->tm_sec / 2 + t->tm_min * 32 + t->tm_hour * 2048; -} - -int write_zip_archive(struct archiver_args *args) -{ - int err; - - dos_time(&args->time, &zip_date, &zip_time); - - zip_dir = xmalloc(ZIP_DIRECTORY_MIN_SIZE); - zip_dir_size = ZIP_DIRECTORY_MIN_SIZE; - - err = write_archive_entries(args, write_zip_entry); - if (!err) - write_zip_trailer(args->commit_sha1); - - free(zip_dir); - - return err; -} diff --git a/test/archive.c b/test/archive.c deleted file mode 100644 index d700af3..0000000 --- a/test/archive.c +++ /dev/null @@ -1,396 +0,0 @@ -#include "cache.h" -#include "commit.h" -#include "tree-walk.h" -#include "attr.h" -#include "archive.h" -#include "parse-options.h" -#include "unpack-trees.h" - -static char const * const archive_usage[] = { - "git archive [options] [path...]", - "git archive --list", - "git archive --remote [--exec ] [options] [path...]", - "git archive --remote [--exec ] --list", - NULL -}; - -#define USES_ZLIB_COMPRESSION 1 - -static const struct archiver { - const char *name; - write_archive_fn_t write_archive; - unsigned int flags; -} archivers[] = { - { "tar", write_tar_archive }, - { "zip", write_zip_archive, USES_ZLIB_COMPRESSION }, -}; - -static void format_subst(const struct commit *commit, - const char *src, size_t len, - struct strbuf *buf) -{ - char *to_free = NULL; - struct strbuf fmt = STRBUF_INIT; - struct pretty_print_context ctx = {0}; - ctx.date_mode = DATE_NORMAL; - - if (src == buf->buf) - to_free = strbuf_detach(buf, NULL); - for (;;) { - const char *b, *c; - - b = memmem(src, len, "$Format:", 8); - if (!b) - break; - c = memchr(b + 8, '$', (src + len) - b - 8); - if (!c) - break; - - strbuf_reset(&fmt); - strbuf_add(&fmt, b + 8, c - b - 8); - - strbuf_add(buf, src, b - src); - format_commit_message(commit, fmt.buf, buf, &ctx); - len -= c + 1 - src; - src = c + 1; - } - strbuf_add(buf, src, len); - strbuf_release(&fmt); - free(to_free); -} - -static void *sha1_file_to_archive(const char *path, const unsigned char *sha1, - unsigned int mode, enum object_type *type, - unsigned long *sizep, const struct commit *commit) -{ - void *buffer; - - buffer = read_sha1_file(sha1, type, sizep); - if (buffer && S_ISREG(mode)) { - struct strbuf buf = STRBUF_INIT; - size_t size = 0; - - strbuf_attach(&buf, buffer, *sizep, *sizep + 1); - convert_to_working_tree(path, buf.buf, buf.len, &buf); - if (commit) - format_subst(commit, buf.buf, buf.len, &buf); - buffer = strbuf_detach(&buf, &size); - *sizep = size; - } - - return buffer; -} - -static void setup_archive_check(struct git_attr_check *check) -{ - static struct git_attr *attr_export_ignore; - static struct git_attr *attr_export_subst; - - if (!attr_export_ignore) { - attr_export_ignore = git_attr("export-ignore"); - attr_export_subst = git_attr("export-subst"); - } - check[0].attr = attr_export_ignore; - check[1].attr = attr_export_subst; -} - -struct archiver_context { - struct archiver_args *args; - write_archive_entry_fn_t write_entry; -}; - -static int write_archive_entry(const unsigned char *sha1, const char *base, - int baselen, const char *filename, unsigned mode, int stage, - void *context) -{ - static struct strbuf path = STRBUF_INIT; - struct archiver_context *c = context; - struct archiver_args *args = c->args; - write_archive_entry_fn_t write_entry = c->write_entry; - struct git_attr_check check[2]; - const char *path_without_prefix; - int convert = 0; - int err; - enum object_type type; - unsigned long size; - void *buffer; - - strbuf_reset(&path); - strbuf_grow(&path, PATH_MAX); - strbuf_add(&path, args->base, args->baselen); - strbuf_add(&path, base, baselen); - strbuf_addstr(&path, filename); - path_without_prefix = path.buf + args->baselen; - - setup_archive_check(check); - if (!git_checkattr(path_without_prefix, ARRAY_SIZE(check), check)) { - if (ATTR_TRUE(check[0].value)) - return 0; - convert = ATTR_TRUE(check[1].value); - } - - if (S_ISDIR(mode) || S_ISGITLINK(mode)) { - strbuf_addch(&path, '/'); - if (args->verbose) - fprintf(stderr, "%.*s\n", (int)path.len, path.buf); - err = write_entry(args, sha1, path.buf, path.len, mode, NULL, 0); - if (err) - return err; - return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0); - } - - buffer = sha1_file_to_archive(path_without_prefix, sha1, mode, - &type, &size, convert ? args->commit : NULL); - if (!buffer) - return error("cannot read %s", sha1_to_hex(sha1)); - if (args->verbose) - fprintf(stderr, "%.*s\n", (int)path.len, path.buf); - err = write_entry(args, sha1, path.buf, path.len, mode, buffer, size); - free(buffer); - return err; -} - -int write_archive_entries(struct archiver_args *args, - write_archive_entry_fn_t write_entry) -{ - struct archiver_context context; - struct unpack_trees_options opts; - struct tree_desc t; - int err; - - if (args->baselen > 0 && args->base[args->baselen - 1] == '/') { - size_t len = args->baselen; - - while (len > 1 && args->base[len - 2] == '/') - len--; - if (args->verbose) - fprintf(stderr, "%.*s\n", (int)len, args->base); - err = write_entry(args, args->tree->object.sha1, args->base, - len, 040777, NULL, 0); - if (err) - return err; - } - - context.args = args; - context.write_entry = write_entry; - - /* - * Setup index and instruct attr to read index only - */ - if (!args->worktree_attributes) { - memset(&opts, 0, sizeof(opts)); - opts.index_only = 1; - opts.head_idx = -1; - opts.src_index = &the_index; - opts.dst_index = &the_index; - opts.fn = oneway_merge; - init_tree_desc(&t, args->tree->buffer, args->tree->size); - if (unpack_trees(1, &t, &opts)) - return -1; - git_attr_set_direction(GIT_ATTR_INDEX, &the_index); - } - - err = read_tree_recursive(args->tree, "", 0, 0, args->pathspec, - write_archive_entry, &context); - if (err == READ_TREE_RECURSIVE) - err = 0; - return err; -} - -static const struct archiver *lookup_archiver(const char *name) -{ - int i; - - if (!name) - return NULL; - - for (i = 0; i < ARRAY_SIZE(archivers); i++) { - if (!strcmp(name, archivers[i].name)) - return &archivers[i]; - } - return NULL; -} - -static int reject_entry(const unsigned char *sha1, const char *base, - int baselen, const char *filename, unsigned mode, - int stage, void *context) -{ - return -1; -} - -static int path_exists(struct tree *tree, const char *path) -{ - const char *pathspec[] = { path, NULL }; - - if (read_tree_recursive(tree, "", 0, 0, pathspec, reject_entry, NULL)) - return 1; - return 0; -} - -static void parse_pathspec_arg(const char **pathspec, - struct archiver_args *ar_args) -{ - ar_args->pathspec = pathspec = get_pathspec("", pathspec); - if (pathspec) { - while (*pathspec) { - if (!path_exists(ar_args->tree, *pathspec)) - die("path not found: %s", *pathspec); - pathspec++; - } - } -} - -static void parse_treeish_arg(const char **argv, - struct archiver_args *ar_args, const char *prefix) -{ - const char *name = argv[0]; - const unsigned char *commit_sha1; - time_t archive_time; - struct tree *tree; - const struct commit *commit; - unsigned char sha1[20]; - - if (get_sha1(name, sha1)) - die("Not a valid object name"); - - commit = lookup_commit_reference_gently(sha1, 1); - if (commit) { - commit_sha1 = commit->object.sha1; - archive_time = commit->date; - } else { - commit_sha1 = NULL; - archive_time = time(NULL); - } - - tree = parse_tree_indirect(sha1); - if (tree == NULL) - die("not a tree object"); - - if (prefix) { - unsigned char tree_sha1[20]; - unsigned int mode; - int err; - - err = get_tree_entry(tree->object.sha1, prefix, - tree_sha1, &mode); - if (err || !S_ISDIR(mode)) - die("current working directory is untracked"); - - tree = parse_tree_indirect(tree_sha1); - } - ar_args->tree = tree; - ar_args->commit_sha1 = commit_sha1; - ar_args->commit = commit; - ar_args->time = archive_time; -} - -#define OPT__COMPR(s, v, h, p) \ - { OPTION_SET_INT, (s), NULL, (v), NULL, (h), \ - PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, (p) } -#define OPT__COMPR_HIDDEN(s, v, p) \ - { OPTION_SET_INT, (s), NULL, (v), NULL, "", \ - PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_HIDDEN, NULL, (p) } - -static int parse_archive_args(int argc, const char **argv, - const struct archiver **ar, struct archiver_args *args) -{ - const char *format = "tar"; - const char *base = NULL; - const char *remote = NULL; - const char *exec = NULL; - const char *output = NULL; - int compression_level = -1; - int verbose = 0; - int i; - int list = 0; - int worktree_attributes = 0; - struct option opts[] = { - OPT_GROUP(""), - OPT_STRING(0, "format", &format, "fmt", "archive format"), - OPT_STRING(0, "prefix", &base, "prefix", - "prepend prefix to each pathname in the archive"), - OPT_STRING('o', "output", &output, "file", - "write the archive to this file"), - OPT_BOOLEAN(0, "worktree-attributes", &worktree_attributes, - "read .gitattributes in working directory"), - OPT__VERBOSE(&verbose), - OPT__COMPR('0', &compression_level, "store only", 0), - OPT__COMPR('1', &compression_level, "compress faster", 1), - OPT__COMPR_HIDDEN('2', &compression_level, 2), - OPT__COMPR_HIDDEN('3', &compression_level, 3), - OPT__COMPR_HIDDEN('4', &compression_level, 4), - OPT__COMPR_HIDDEN('5', &compression_level, 5), - OPT__COMPR_HIDDEN('6', &compression_level, 6), - OPT__COMPR_HIDDEN('7', &compression_level, 7), - OPT__COMPR_HIDDEN('8', &compression_level, 8), - OPT__COMPR('9', &compression_level, "compress better", 9), - OPT_GROUP(""), - OPT_BOOLEAN('l', "list", &list, - "list supported archive formats"), - OPT_GROUP(""), - OPT_STRING(0, "remote", &remote, "repo", - "retrieve the archive from remote repository "), - OPT_STRING(0, "exec", &exec, "cmd", - "path to the remote git-upload-archive command"), - OPT_END() - }; - - argc = parse_options(argc, argv, NULL, opts, archive_usage, 0); - - if (remote) - die("Unexpected option --remote"); - if (exec) - die("Option --exec can only be used together with --remote"); - if (output) - die("Unexpected option --output"); - - if (!base) - base = ""; - - if (list) { - for (i = 0; i < ARRAY_SIZE(archivers); i++) - printf("%s\n", archivers[i].name); - exit(0); - } - - /* We need at least one parameter -- tree-ish */ - if (argc < 1) - usage_with_options(archive_usage, opts); - *ar = lookup_archiver(format); - if (!*ar) - die("Unknown archive format '%s'", format); - - args->compression_level = Z_DEFAULT_COMPRESSION; - if (compression_level != -1) { - if ((*ar)->flags & USES_ZLIB_COMPRESSION) - args->compression_level = compression_level; - else { - die("Argument not supported for format '%s': -%d", - format, compression_level); - } - } - args->verbose = verbose; - args->base = base; - args->baselen = strlen(base); - args->worktree_attributes = worktree_attributes; - - return argc; -} - -int write_archive(int argc, const char **argv, const char *prefix, - int setup_prefix) -{ - const struct archiver *ar = NULL; - struct archiver_args args; - - argc = parse_archive_args(argc, argv, &ar, &args); - if (setup_prefix && prefix == NULL) - prefix = setup_git_directory(); - - parse_treeish_arg(argv, &args, prefix); - parse_pathspec_arg(argv + 1, &args); - - git_config(git_default_config, NULL); - - return ar->write_archive(&args); -} diff --git a/test/attr.c b/test/attr.c deleted file mode 100644 index 8ba606c..0000000 --- a/test/attr.c +++ /dev/null @@ -1,703 +0,0 @@ -#define NO_THE_INDEX_COMPATIBILITY_MACROS -#include "cache.h" -#include "attr.h" - -const char git_attr__true[] = "(builtin)true"; -const char git_attr__false[] = "\0(builtin)false"; -static const char git_attr__unknown[] = "(builtin)unknown"; -#define ATTR__TRUE git_attr__true -#define ATTR__FALSE git_attr__false -#define ATTR__UNSET NULL -#define ATTR__UNKNOWN git_attr__unknown - -/* - * The basic design decision here is that we are not going to have - * insanely large number of attributes. - * - * This is a randomly chosen prime. - */ -#define HASHSIZE 257 - -#ifndef DEBUG_ATTR -#define DEBUG_ATTR 0 -#endif - -struct git_attr { - struct git_attr *next; - unsigned h; - int attr_nr; - char name[FLEX_ARRAY]; -}; -static int attr_nr; - -static struct git_attr_check *check_all_attr; -static struct git_attr *(git_attr_hash[HASHSIZE]); - -static unsigned hash_name(const char *name, int namelen) -{ - unsigned val = 0, c; - - while (namelen--) { - c = *name++; - val = ((val << 7) | (val >> 22)) ^ c; - } - return val; -} - -static int invalid_attr_name(const char *name, int namelen) -{ - /* - * Attribute name cannot begin with '-' and from - * [-A-Za-z0-9_.]. We'd specifically exclude '=' for now, - * as we might later want to allow non-binary value for - * attributes, e.g. "*.svg merge=special-merge-program-for-svg" - */ - if (*name == '-') - return -1; - while (namelen--) { - char ch = *name++; - if (! (ch == '-' || ch == '.' || ch == '_' || - ('0' <= ch && ch <= '9') || - ('a' <= ch && ch <= 'z') || - ('A' <= ch && ch <= 'Z')) ) - return -1; - } - return 0; -} - -static struct git_attr *git_attr_internal(const char *name, int len) -{ - unsigned hval = hash_name(name, len); - unsigned pos = hval % HASHSIZE; - struct git_attr *a; - - for (a = git_attr_hash[pos]; a; a = a->next) { - if (a->h == hval && - !memcmp(a->name, name, len) && !a->name[len]) - return a; - } - - if (invalid_attr_name(name, len)) - return NULL; - - a = xmalloc(sizeof(*a) + len + 1); - memcpy(a->name, name, len); - a->name[len] = 0; - a->h = hval; - a->next = git_attr_hash[pos]; - a->attr_nr = attr_nr++; - git_attr_hash[pos] = a; - - check_all_attr = xrealloc(check_all_attr, - sizeof(*check_all_attr) * attr_nr); - check_all_attr[a->attr_nr].attr = a; - check_all_attr[a->attr_nr].value = ATTR__UNKNOWN; - return a; -} - -struct git_attr *git_attr(const char *name) -{ - return git_attr_internal(name, strlen(name)); -} - -/* - * .gitattributes file is one line per record, each of which is - * - * (1) glob pattern. - * (2) whitespace - * (3) whitespace separated list of attribute names, each of which - * could be prefixed with '-' to mean "set to false", '!' to mean - * "unset". - */ - -/* What does a matched pattern decide? */ -struct attr_state { - struct git_attr *attr; - const char *setto; -}; - -struct match_attr { - union { - char *pattern; - struct git_attr *attr; - } u; - char is_macro; - unsigned num_attr; - struct attr_state state[FLEX_ARRAY]; -}; - -static const char blank[] = " \t\r\n"; - -static const char *parse_attr(const char *src, int lineno, const char *cp, - int *num_attr, struct match_attr *res) -{ - const char *ep, *equals; - int len; - - ep = cp + strcspn(cp, blank); - equals = strchr(cp, '='); - if (equals && ep < equals) - equals = NULL; - if (equals) - len = equals - cp; - else - len = ep - cp; - if (!res) { - if (*cp == '-' || *cp == '!') { - cp++; - len--; - } - if (invalid_attr_name(cp, len)) { - fprintf(stderr, - "%.*s is not a valid attribute name: %s:%d\n", - len, cp, src, lineno); - return NULL; - } - } else { - struct attr_state *e; - - e = &(res->state[*num_attr]); - if (*cp == '-' || *cp == '!') { - e->setto = (*cp == '-') ? ATTR__FALSE : ATTR__UNSET; - cp++; - len--; - } - else if (!equals) - e->setto = ATTR__TRUE; - else { - e->setto = xmemdupz(equals + 1, ep - equals - 1); - } - e->attr = git_attr_internal(cp, len); - } - (*num_attr)++; - return ep + strspn(ep, blank); -} - -static struct match_attr *parse_attr_line(const char *line, const char *src, - int lineno, int macro_ok) -{ - int namelen; - int num_attr; - const char *cp, *name; - struct match_attr *res = NULL; - int pass; - int is_macro; - - cp = line + strspn(line, blank); - if (!*cp || *cp == '#') - return NULL; - name = cp; - namelen = strcspn(name, blank); - if (strlen(ATTRIBUTE_MACRO_PREFIX) < namelen && - !prefixcmp(name, ATTRIBUTE_MACRO_PREFIX)) { - if (!macro_ok) { - fprintf(stderr, "%s not allowed: %s:%d\n", - name, src, lineno); - return NULL; - } - is_macro = 1; - name += strlen(ATTRIBUTE_MACRO_PREFIX); - name += strspn(name, blank); - namelen = strcspn(name, blank); - if (invalid_attr_name(name, namelen)) { - fprintf(stderr, - "%.*s is not a valid attribute name: %s:%d\n", - namelen, name, src, lineno); - return NULL; - } - } - else - is_macro = 0; - - for (pass = 0; pass < 2; pass++) { - /* pass 0 counts and allocates, pass 1 fills */ - num_attr = 0; - cp = name + namelen; - cp = cp + strspn(cp, blank); - while (*cp) { - cp = parse_attr(src, lineno, cp, &num_attr, res); - if (!cp) - return NULL; - } - if (pass) - break; - res = xcalloc(1, - sizeof(*res) + - sizeof(struct attr_state) * num_attr + - (is_macro ? 0 : namelen + 1)); - if (is_macro) - res->u.attr = git_attr_internal(name, namelen); - else { - res->u.pattern = (char *)&(res->state[num_attr]); - memcpy(res->u.pattern, name, namelen); - res->u.pattern[namelen] = 0; - } - res->is_macro = is_macro; - res->num_attr = num_attr; - } - return res; -} - -/* - * Like info/exclude and .gitignore, the attribute information can - * come from many places. - * - * (1) .gitattribute file of the same directory; - * (2) .gitattribute file of the parent directory if (1) does not have - * any match; this goes recursively upwards, just like .gitignore. - * (3) $GIT_DIR/info/attributes, which overrides both of the above. - * - * In the same file, later entries override the earlier match, so in the - * global list, we would have entries from info/attributes the earliest - * (reading the file from top to bottom), .gitattribute of the root - * directory (again, reading the file from top to bottom) down to the - * current directory, and then scan the list backwards to find the first match. - * This is exactly the same as what excluded() does in dir.c to deal with - * .gitignore - */ - -static struct attr_stack { - struct attr_stack *prev; - char *origin; - unsigned num_matches; - unsigned alloc; - struct match_attr **attrs; -} *attr_stack; - -static void free_attr_elem(struct attr_stack *e) -{ - int i; - free(e->origin); - for (i = 0; i < e->num_matches; i++) { - struct match_attr *a = e->attrs[i]; - int j; - for (j = 0; j < a->num_attr; j++) { - const char *setto = a->state[j].setto; - if (setto == ATTR__TRUE || - setto == ATTR__FALSE || - setto == ATTR__UNSET || - setto == ATTR__UNKNOWN) - ; - else - free((char *) setto); - } - free(a); - } - free(e); -} - -static const char *builtin_attr[] = { - "[attr]binary -diff -text", - NULL, -}; - -static void handle_attr_line(struct attr_stack *res, - const char *line, - const char *src, - int lineno, - int macro_ok) -{ - struct match_attr *a; - - a = parse_attr_line(line, src, lineno, macro_ok); - if (!a) - return; - if (res->alloc <= res->num_matches) { - res->alloc = alloc_nr(res->num_matches); - res->attrs = xrealloc(res->attrs, - sizeof(struct match_attr *) * - res->alloc); - } - res->attrs[res->num_matches++] = a; -} - -static struct attr_stack *read_attr_from_array(const char **list) -{ - struct attr_stack *res; - const char *line; - int lineno = 0; - - res = xcalloc(1, sizeof(*res)); - while ((line = *(list++)) != NULL) - handle_attr_line(res, line, "[builtin]", ++lineno, 1); - return res; -} - -static enum git_attr_direction direction; -static struct index_state *use_index; - -static struct attr_stack *read_attr_from_file(const char *path, int macro_ok) -{ - FILE *fp = fopen(path, "r"); - struct attr_stack *res; - char buf[2048]; - int lineno = 0; - - if (!fp) - return NULL; - res = xcalloc(1, sizeof(*res)); - while (fgets(buf, sizeof(buf), fp)) - handle_attr_line(res, buf, path, ++lineno, macro_ok); - fclose(fp); - return res; -} - -static void *read_index_data(const char *path) -{ - int pos, len; - unsigned long sz; - enum object_type type; - void *data; - struct index_state *istate = use_index ? use_index : &the_index; - - len = strlen(path); - pos = index_name_pos(istate, path, len); - if (pos < 0) { - /* - * We might be in the middle of a merge, in which - * case we would read stage #2 (ours). - */ - int i; - for (i = -pos - 1; - (pos < 0 && i < istate->cache_nr && - !strcmp(istate->cache[i]->name, path)); - i++) - if (ce_stage(istate->cache[i]) == 2) - pos = i; - } - if (pos < 0) - return NULL; - data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz); - if (!data || type != OBJ_BLOB) { - free(data); - return NULL; - } - return data; -} - -static struct attr_stack *read_attr_from_index(const char *path, int macro_ok) -{ - struct attr_stack *res; - char *buf, *sp; - int lineno = 0; - - buf = read_index_data(path); - if (!buf) - return NULL; - - res = xcalloc(1, sizeof(*res)); - for (sp = buf; *sp; ) { - char *ep; - int more; - for (ep = sp; *ep && *ep != '\n'; ep++) - ; - more = (*ep == '\n'); - *ep = '\0'; - handle_attr_line(res, sp, path, ++lineno, macro_ok); - sp = ep + more; - } - free(buf); - return res; -} - -static struct attr_stack *read_attr(const char *path, int macro_ok) -{ - struct attr_stack *res; - - if (direction == GIT_ATTR_CHECKOUT) { - res = read_attr_from_index(path, macro_ok); - if (!res) - res = read_attr_from_file(path, macro_ok); - } - else if (direction == GIT_ATTR_CHECKIN) { - res = read_attr_from_file(path, macro_ok); - if (!res) - /* - * There is no checked out .gitattributes file there, but - * we might have it in the index. We allow operation in a - * sparsely checked out work tree, so read from it. - */ - res = read_attr_from_index(path, macro_ok); - } - else - res = read_attr_from_index(path, macro_ok); - if (!res) - res = xcalloc(1, sizeof(*res)); - return res; -} - -#if DEBUG_ATTR -static void debug_info(const char *what, struct attr_stack *elem) -{ - fprintf(stderr, "%s: %s\n", what, elem->origin ? elem->origin : "()"); -} -static void debug_set(const char *what, const char *match, struct git_attr *attr, const void *v) -{ - const char *value = v; - - if (ATTR_TRUE(value)) - value = "set"; - else if (ATTR_FALSE(value)) - value = "unset"; - else if (ATTR_UNSET(value)) - value = "unspecified"; - - fprintf(stderr, "%s: %s => %s (%s)\n", - what, attr->name, (char *) value, match); -} -#define debug_push(a) debug_info("push", (a)) -#define debug_pop(a) debug_info("pop", (a)) -#else -#define debug_push(a) do { ; } while (0) -#define debug_pop(a) do { ; } while (0) -#define debug_set(a,b,c,d) do { ; } while (0) -#endif - -static void drop_attr_stack(void) -{ - while (attr_stack) { - struct attr_stack *elem = attr_stack; - attr_stack = elem->prev; - free_attr_elem(elem); - } -} - -static void bootstrap_attr_stack(void) -{ - if (!attr_stack) { - struct attr_stack *elem; - - elem = read_attr_from_array(builtin_attr); - elem->origin = NULL; - elem->prev = attr_stack; - attr_stack = elem; - - if (!is_bare_repository() || direction == GIT_ATTR_INDEX) { - elem = read_attr(GITATTRIBUTES_FILE, 1); - elem->origin = strdup(""); - elem->prev = attr_stack; - attr_stack = elem; - debug_push(elem); - } - - elem = read_attr_from_file(git_path(INFOATTRIBUTES_FILE), 1); - if (!elem) - elem = xcalloc(1, sizeof(*elem)); - elem->origin = NULL; - elem->prev = attr_stack; - attr_stack = elem; - } -} - -static void prepare_attr_stack(const char *path, int dirlen) -{ - struct attr_stack *elem, *info; - int len; - struct strbuf pathbuf; - - strbuf_init(&pathbuf, dirlen+2+strlen(GITATTRIBUTES_FILE)); - - /* - * At the bottom of the attribute stack is the built-in - * set of attribute definitions. Then, contents from - * .gitattribute files from directories closer to the - * root to the ones in deeper directories are pushed - * to the stack. Finally, at the very top of the stack - * we always keep the contents of $GIT_DIR/info/attributes. - * - * When checking, we use entries from near the top of the - * stack, preferring $GIT_DIR/info/attributes, then - * .gitattributes in deeper directories to shallower ones, - * and finally use the built-in set as the default. - */ - if (!attr_stack) - bootstrap_attr_stack(); - - /* - * Pop the "info" one that is always at the top of the stack. - */ - info = attr_stack; - attr_stack = info->prev; - - /* - * Pop the ones from directories that are not the prefix of - * the path we are checking. - */ - while (attr_stack && attr_stack->origin) { - int namelen = strlen(attr_stack->origin); - - elem = attr_stack; - if (namelen <= dirlen && - !strncmp(elem->origin, path, namelen)) - break; - - debug_pop(elem); - attr_stack = elem->prev; - free_attr_elem(elem); - } - - /* - * Read from parent directories and push them down - */ - if (!is_bare_repository() || direction == GIT_ATTR_INDEX) { - while (1) { - char *cp; - - len = strlen(attr_stack->origin); - if (dirlen <= len) - break; - strbuf_reset(&pathbuf); - strbuf_add(&pathbuf, path, dirlen); - strbuf_addch(&pathbuf, '/'); - cp = strchr(pathbuf.buf + len + 1, '/'); - strcpy(cp + 1, GITATTRIBUTES_FILE); - elem = read_attr(pathbuf.buf, 0); - *cp = '\0'; - elem->origin = strdup(pathbuf.buf); - elem->prev = attr_stack; - attr_stack = elem; - debug_push(elem); - } - } - - strbuf_release(&pathbuf); - - /* - * Finally push the "info" one at the top of the stack. - */ - info->prev = attr_stack; - attr_stack = info; -} - -static int path_matches(const char *pathname, int pathlen, - const char *pattern, - const char *base, int baselen) -{ - if (!strchr(pattern, '/')) { - /* match basename */ - const char *basename = strrchr(pathname, '/'); - basename = basename ? basename + 1 : pathname; - return (fnmatch(pattern, basename, 0) == 0); - } - /* - * match with FNM_PATHNAME; the pattern has base implicitly - * in front of it. - */ - if (*pattern == '/') - pattern++; - if (pathlen < baselen || - (baselen && pathname[baselen] != '/') || - strncmp(pathname, base, baselen)) - return 0; - if (baselen != 0) - baselen++; - return fnmatch(pattern, pathname + baselen, FNM_PATHNAME) == 0; -} - -static int macroexpand_one(int attr_nr, int rem); - -static int fill_one(const char *what, struct match_attr *a, int rem) -{ - struct git_attr_check *check = check_all_attr; - int i; - - for (i = a->num_attr - 1; 0 < rem && 0 <= i; i--) { - struct git_attr *attr = a->state[i].attr; - const char **n = &(check[attr->attr_nr].value); - const char *v = a->state[i].setto; - - if (*n == ATTR__UNKNOWN) { - debug_set(what, - a->is_macro ? a->u.attr->name : a->u.pattern, - attr, v); - *n = v; - rem--; - rem = macroexpand_one(attr->attr_nr, rem); - } - } - return rem; -} - -static int fill(const char *path, int pathlen, struct attr_stack *stk, int rem) -{ - int i; - const char *base = stk->origin ? stk->origin : ""; - - for (i = stk->num_matches - 1; 0 < rem && 0 <= i; i--) { - struct match_attr *a = stk->attrs[i]; - if (a->is_macro) - continue; - if (path_matches(path, pathlen, - a->u.pattern, base, strlen(base))) - rem = fill_one("fill", a, rem); - } - return rem; -} - -static int macroexpand_one(int attr_nr, int rem) -{ - struct attr_stack *stk; - struct match_attr *a = NULL; - int i; - - if (check_all_attr[attr_nr].value != ATTR__TRUE) - return rem; - - for (stk = attr_stack; !a && stk; stk = stk->prev) - for (i = stk->num_matches - 1; !a && 0 <= i; i--) { - struct match_attr *ma = stk->attrs[i]; - if (!ma->is_macro) - continue; - if (ma->u.attr->attr_nr == attr_nr) - a = ma; - } - - if (a) - rem = fill_one("expand", a, rem); - - return rem; -} - -int git_checkattr(const char *path, int num, struct git_attr_check *check) -{ - struct attr_stack *stk; - const char *cp; - int dirlen, pathlen, i, rem; - - bootstrap_attr_stack(); - for (i = 0; i < attr_nr; i++) - check_all_attr[i].value = ATTR__UNKNOWN; - - pathlen = strlen(path); - cp = strrchr(path, '/'); - if (!cp) - dirlen = 0; - else - dirlen = cp - path; - prepare_attr_stack(path, dirlen); - rem = attr_nr; - for (stk = attr_stack; 0 < rem && stk; stk = stk->prev) - rem = fill(path, pathlen, stk, rem); - - for (i = 0; i < num; i++) { - const char *value = check_all_attr[check[i].attr->attr_nr].value; - if (value == ATTR__UNKNOWN) - value = ATTR__UNSET; - check[i].value = value; - } - - return 0; -} - -void git_attr_set_direction(enum git_attr_direction new, struct index_state *istate) -{ - enum git_attr_direction old = direction; - - if (is_bare_repository() && new != GIT_ATTR_INDEX) - die("BUG: non-INDEX attr direction in a bare repo"); - - direction = new; - if (new != old) - drop_attr_stack(); - use_index = istate; -}