From a64119e3963fcd358ba914c9e1a81a890666d15a Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 25 Nov 2014 18:13:00 -0500 Subject: [PATCH] checkout: disallow bad paths on win32 Disallow: 1. paths with trailing dot 2. paths with trailing space 3. paths with trailing colon 4. paths that are 8.3 short names of .git folders ("GIT~1") 5. paths that are reserved path names (COM1, LPT1, etc). 6. paths with reserved DOS characters (colons, asterisks, etc) These paths would (without \\?\ syntax) be elided to other paths - for example, ".git." would be written as ".git". As a result, writing these paths literally (using \\?\ syntax) makes them hard to operate with from the shell, Windows Explorer or other tools. Disallow these. --- src/checkout.c | 28 +- src/index.c | 119 +++------ src/path.c | 148 +++++++++++ src/path.h | 38 +++ src/refdb_fs.c | 10 + src/repository.c | 25 ++ src/repository.h | 20 +- src/util.c | 15 ++ src/util.h | 1 + src/win32/path_w32.c | 36 +++ src/win32/path_w32.h | 15 ++ tests/checkout/nasty.c | 251 ++++++++++++++++++ tests/path/core.c | 194 ++++++++++++++ tests/path/win32.c | 24 ++ tests/resources/nasty/.gitted/HEAD | Bin 0 -> 23 bytes tests/resources/nasty/.gitted/index | Bin 0 -> 120 bytes .../02/28b21d477f67b9f7720565da9e760b84c8b85b | Bin 0 -> 133 bytes .../04/18f28a75dc0c4951c01842e0d794843a88178a | Bin 0 -> 46 bytes .../05/1229bf9d30ec923052ff42db8069ccdc17159d | Bin 0 -> 53 bytes .../09/9ed86cb8501ae483b1855c351fe1a506ac9631 | Bin 0 -> 133 bytes .../0a/78e40e54cc471c0415ca0680550f242e7843e2 | Bin 0 -> 51 bytes .../0d/45fb57852c2229346a800bd3fc58e32527a21c | Bin 0 -> 45 bytes .../12/12c12915820e1ad523b6305c0dcdefea8b7e97 | Bin 0 -> 133 bytes .../13/e5f8be09e8b7db074fb39b96e08215cc4a36f1 | Bin 0 -> 56 bytes .../16/a701796bc3670e5c2fdaeccb7f1280c60b373f | Bin 0 -> 62 bytes .../1b/31d55e0c53efbea6c670ece9057b76b5822eea | Bin 0 -> 132 bytes .../1e/3c845808fa5883aa4bcf2f882172edb72a7a32 | Bin 0 -> 134 bytes .../24/676d5e93f9fa7b568f38d7bce01772908e982b | Bin 0 -> 47 bytes .../26/b665c162f67acae67779445f3c7b9782b0a6d7 | Bin 0 -> 133 bytes .../27/db66b046536a0e4f64c4f8c3a490641c3fa5e5 | Bin 0 -> 44 bytes .../39/fb3af508440cf970b92767f6d081c811574d2a | Bin 0 -> 131 bytes .../44/14ac920acabc3eb00e3cf9375eeb0cb6859c15 | Bin 0 -> 135 bytes .../4a/a347c8bb0456230f43f34833c97b9f52c40f62 | Bin 0 -> 133 bytes .../53/41a7b545d71198b076b8ba3374a75c9a290640 | Bin 0 -> 133 bytes .../5d/1ee4f24f66dcd62a30248588d33804656b2073 | Bin 0 -> 46 bytes .../65/94bdbad86bbc8d3ed0806a23827203fbab56c6 | Bin 0 -> 132 bytes .../68/e8bce48725490c376d57ebc60f0170605951a5 | Bin 0 -> 58 bytes .../69/7dc3d723a018538eb819d5db2035c15109af73 | Bin 0 -> 132 bytes .../6c/1f5f6fec515d33036b44c596bfae28fc460cba | Bin 0 -> 47 bytes .../7d/4e382485ace068fb83b768ba1a1c674afbdc1d | Bin 0 -> 62 bytes .../7f/924ca37670afa06c7a481a2487b728b2c0185a | Bin 0 -> 47 bytes .../80/a8fe4f10626c50b3a4fd065a4604bafc9f30fa | Bin 0 -> 23 bytes .../82/482ad2e683edfc14f7de359e4f9a5e88909c51 | Bin 0 -> 45 bytes .../89/9ff28744bed5bece69c78ba752c7dc3e954629 | Bin 0 -> 136 bytes .../8b/cbb6e0c0f9554efd5401e1ec14a4b2595eb3bf | Bin 0 -> 134 bytes .../8c/e7a3ef59c3d602a0296321eb964218f3d52fae | Bin 0 -> 56 bytes .../8f/1dcd43aa0164eb6ec319c3ec8879ca5cf62c1e | Bin 0 -> 132 bytes .../91/602c85bb50dd834205edd30435b77d5bb9ccf0 | Bin 0 -> 131 bytes .../94/f37c29173c8fa45a232b17e745c82132b2fafd | Bin 0 -> 132 bytes .../96/3fdf003bf7261b9155c5748dc0945349b69e68 | Bin 0 -> 44 bytes .../9e/683cdaf9ea2727c891b4cf8f7f11e9e28a67ca | Bin 0 -> 50 bytes .../af/45aa1eb7edf804ed10f70efb96fd178527c17c | Bin 0 -> 58 bytes .../b8/3795b1e0eb54f22f7056119db132500d0cdc05 | Bin 0 -> 56 bytes .../bf/7ab4723fcc57ecc7fceccf591d6c4773491569 | Bin 0 -> 133 bytes .../c4/89e70ed6d9f6331770eae21a77d15afd11cd99 | Bin 0 -> 56 bytes .../c6/72414d4d08111145ef8202f21c95fa7e688aee | Bin 0 -> 56 bytes .../cc/bbfdb796f9b03298f5c7225e8f830784e1a3b1 | Bin 0 -> 136 bytes .../cd/44b4ea1066b3fa1d4b3baad8dc1531aec287a6 | Bin 0 -> 47 bytes .../d2/eb26d4938550487de59a017a7bfee8ca46b5f4 | Bin 0 -> 132 bytes .../dc/37c5f1521fb76fe1c1ac7b13187f9396a59247 | Bin 0 -> 58 bytes .../de/bdc4a004fda6141a17d9c297617be70d40248f | Bin 0 -> 133 bytes .../e2/377bdbc93b30a34ed5deefedded89b947ff8f4 | Bin 0 -> 132 bytes .../e3/99c4fc4c07cb7947d2f3d966bc374df6ccc691 | Bin 0 -> 131 bytes .../e4/edb361e51932b5ccedbc7ee41b4d3a4289aece | Bin 0 -> 50 bytes .../e8/7caf56c91ab8d14e4ee8eb56308533503d1885 | Bin 0 -> 133 bytes .../ed/4bc023f61dc345ff0084b922b229d24de206e7 | Bin 0 -> 47 bytes .../ef/6ed8a2b15f95795aed82a974b995cace02dbfe | Bin 0 -> 43 bytes .../fa/9cfdbeaaf3a91ff4b84d74412cd59d9b16a615 | Bin 0 -> 136 bytes .../fd/7a37d92197267e55e1fc0cc4f283a815bd79b8 | Bin 0 -> 43 bytes .../heads/dot_backslash_dotcapitalgit_path | Bin 0 -> 41 bytes .../.gitted/refs/heads/dot_dotcapitalgit_path | Bin 0 -> 41 bytes .../nasty/.gitted/refs/heads/dot_dotgit_path | Bin 0 -> 41 bytes .../nasty/.gitted/refs/heads/dot_dotgit_tree | Bin 0 -> 41 bytes .../nasty/.gitted/refs/heads/dot_git_colon | Bin 0 -> 41 bytes .../.gitted/refs/heads/dot_git_colon_stuff | Bin 0 -> 41 bytes .../nasty/.gitted/refs/heads/dot_git_dot | Bin 0 -> 41 bytes .../nasty/.gitted/refs/heads/dot_path | Bin 0 -> 41 bytes .../nasty/.gitted/refs/heads/dot_path_two | Bin 0 -> 41 bytes .../nasty/.gitted/refs/heads/dot_tree | Bin 0 -> 41 bytes .../refs/heads/dotcapitalgit_backslash_path | Bin 0 -> 41 bytes .../.gitted/refs/heads/dotcapitalgit_path | Bin 0 -> 41 bytes .../.gitted/refs/heads/dotcapitalgit_tree | Bin 0 -> 41 bytes .../refs/heads/dotdot_dotcapitalgit_path | Bin 0 -> 41 bytes .../.gitted/refs/heads/dotdot_dotgit_path | Bin 0 -> 41 bytes .../.gitted/refs/heads/dotdot_dotgit_tree | Bin 0 -> 41 bytes .../nasty/.gitted/refs/heads/dotdot_path | Bin 0 -> 41 bytes .../nasty/.gitted/refs/heads/dotdot_tree | Bin 0 -> 41 bytes .../.gitted/refs/heads/dotgit_backslash_path | Bin 0 -> 41 bytes .../nasty/.gitted/refs/heads/dotgit_path | Bin 0 -> 41 bytes .../nasty/.gitted/refs/heads/dotgit_tree | Bin 0 -> 41 bytes .../nasty/.gitted/refs/heads/git_tilde1 | Bin 0 -> 41 bytes .../nasty/.gitted/refs/heads/git_tilde2 | Bin 0 -> 41 bytes .../nasty/.gitted/refs/heads/git_tilde3 | Bin 0 -> 41 bytes .../resources/nasty/.gitted/refs/heads/master | Bin 0 -> 41 bytes 94 files changed, 834 insertions(+), 90 deletions(-) create mode 100644 tests/checkout/nasty.c create mode 100644 tests/resources/nasty/.gitted/HEAD create mode 100644 tests/resources/nasty/.gitted/index create mode 100644 tests/resources/nasty/.gitted/objects/02/28b21d477f67b9f7720565da9e760b84c8b85b create mode 100644 tests/resources/nasty/.gitted/objects/04/18f28a75dc0c4951c01842e0d794843a88178a create mode 100644 tests/resources/nasty/.gitted/objects/05/1229bf9d30ec923052ff42db8069ccdc17159d create mode 100644 tests/resources/nasty/.gitted/objects/09/9ed86cb8501ae483b1855c351fe1a506ac9631 create mode 100644 tests/resources/nasty/.gitted/objects/0a/78e40e54cc471c0415ca0680550f242e7843e2 create mode 100644 tests/resources/nasty/.gitted/objects/0d/45fb57852c2229346a800bd3fc58e32527a21c create mode 100644 tests/resources/nasty/.gitted/objects/12/12c12915820e1ad523b6305c0dcdefea8b7e97 create mode 100644 tests/resources/nasty/.gitted/objects/13/e5f8be09e8b7db074fb39b96e08215cc4a36f1 create mode 100644 tests/resources/nasty/.gitted/objects/16/a701796bc3670e5c2fdaeccb7f1280c60b373f create mode 100644 tests/resources/nasty/.gitted/objects/1b/31d55e0c53efbea6c670ece9057b76b5822eea create mode 100644 tests/resources/nasty/.gitted/objects/1e/3c845808fa5883aa4bcf2f882172edb72a7a32 create mode 100644 tests/resources/nasty/.gitted/objects/24/676d5e93f9fa7b568f38d7bce01772908e982b create mode 100644 tests/resources/nasty/.gitted/objects/26/b665c162f67acae67779445f3c7b9782b0a6d7 create mode 100644 tests/resources/nasty/.gitted/objects/27/db66b046536a0e4f64c4f8c3a490641c3fa5e5 create mode 100644 tests/resources/nasty/.gitted/objects/39/fb3af508440cf970b92767f6d081c811574d2a create mode 100644 tests/resources/nasty/.gitted/objects/44/14ac920acabc3eb00e3cf9375eeb0cb6859c15 create mode 100644 tests/resources/nasty/.gitted/objects/4a/a347c8bb0456230f43f34833c97b9f52c40f62 create mode 100644 tests/resources/nasty/.gitted/objects/53/41a7b545d71198b076b8ba3374a75c9a290640 create mode 100644 tests/resources/nasty/.gitted/objects/5d/1ee4f24f66dcd62a30248588d33804656b2073 create mode 100644 tests/resources/nasty/.gitted/objects/65/94bdbad86bbc8d3ed0806a23827203fbab56c6 create mode 100644 tests/resources/nasty/.gitted/objects/68/e8bce48725490c376d57ebc60f0170605951a5 create mode 100644 tests/resources/nasty/.gitted/objects/69/7dc3d723a018538eb819d5db2035c15109af73 create mode 100644 tests/resources/nasty/.gitted/objects/6c/1f5f6fec515d33036b44c596bfae28fc460cba create mode 100644 tests/resources/nasty/.gitted/objects/7d/4e382485ace068fb83b768ba1a1c674afbdc1d create mode 100644 tests/resources/nasty/.gitted/objects/7f/924ca37670afa06c7a481a2487b728b2c0185a create mode 100644 tests/resources/nasty/.gitted/objects/80/a8fe4f10626c50b3a4fd065a4604bafc9f30fa create mode 100644 tests/resources/nasty/.gitted/objects/82/482ad2e683edfc14f7de359e4f9a5e88909c51 create mode 100644 tests/resources/nasty/.gitted/objects/89/9ff28744bed5bece69c78ba752c7dc3e954629 create mode 100644 tests/resources/nasty/.gitted/objects/8b/cbb6e0c0f9554efd5401e1ec14a4b2595eb3bf create mode 100644 tests/resources/nasty/.gitted/objects/8c/e7a3ef59c3d602a0296321eb964218f3d52fae create mode 100644 tests/resources/nasty/.gitted/objects/8f/1dcd43aa0164eb6ec319c3ec8879ca5cf62c1e create mode 100644 tests/resources/nasty/.gitted/objects/91/602c85bb50dd834205edd30435b77d5bb9ccf0 create mode 100644 tests/resources/nasty/.gitted/objects/94/f37c29173c8fa45a232b17e745c82132b2fafd create mode 100644 tests/resources/nasty/.gitted/objects/96/3fdf003bf7261b9155c5748dc0945349b69e68 create mode 100644 tests/resources/nasty/.gitted/objects/9e/683cdaf9ea2727c891b4cf8f7f11e9e28a67ca create mode 100644 tests/resources/nasty/.gitted/objects/af/45aa1eb7edf804ed10f70efb96fd178527c17c create mode 100644 tests/resources/nasty/.gitted/objects/b8/3795b1e0eb54f22f7056119db132500d0cdc05 create mode 100644 tests/resources/nasty/.gitted/objects/bf/7ab4723fcc57ecc7fceccf591d6c4773491569 create mode 100644 tests/resources/nasty/.gitted/objects/c4/89e70ed6d9f6331770eae21a77d15afd11cd99 create mode 100644 tests/resources/nasty/.gitted/objects/c6/72414d4d08111145ef8202f21c95fa7e688aee create mode 100644 tests/resources/nasty/.gitted/objects/cc/bbfdb796f9b03298f5c7225e8f830784e1a3b1 create mode 100644 tests/resources/nasty/.gitted/objects/cd/44b4ea1066b3fa1d4b3baad8dc1531aec287a6 create mode 100644 tests/resources/nasty/.gitted/objects/d2/eb26d4938550487de59a017a7bfee8ca46b5f4 create mode 100644 tests/resources/nasty/.gitted/objects/dc/37c5f1521fb76fe1c1ac7b13187f9396a59247 create mode 100644 tests/resources/nasty/.gitted/objects/de/bdc4a004fda6141a17d9c297617be70d40248f create mode 100644 tests/resources/nasty/.gitted/objects/e2/377bdbc93b30a34ed5deefedded89b947ff8f4 create mode 100644 tests/resources/nasty/.gitted/objects/e3/99c4fc4c07cb7947d2f3d966bc374df6ccc691 create mode 100644 tests/resources/nasty/.gitted/objects/e4/edb361e51932b5ccedbc7ee41b4d3a4289aece create mode 100644 tests/resources/nasty/.gitted/objects/e8/7caf56c91ab8d14e4ee8eb56308533503d1885 create mode 100644 tests/resources/nasty/.gitted/objects/ed/4bc023f61dc345ff0084b922b229d24de206e7 create mode 100644 tests/resources/nasty/.gitted/objects/ef/6ed8a2b15f95795aed82a974b995cace02dbfe create mode 100644 tests/resources/nasty/.gitted/objects/fa/9cfdbeaaf3a91ff4b84d74412cd59d9b16a615 create mode 100644 tests/resources/nasty/.gitted/objects/fd/7a37d92197267e55e1fc0cc4f283a815bd79b8 create mode 100644 tests/resources/nasty/.gitted/refs/heads/dot_backslash_dotcapitalgit_path create mode 100644 tests/resources/nasty/.gitted/refs/heads/dot_dotcapitalgit_path create mode 100644 tests/resources/nasty/.gitted/refs/heads/dot_dotgit_path create mode 100644 tests/resources/nasty/.gitted/refs/heads/dot_dotgit_tree create mode 100644 tests/resources/nasty/.gitted/refs/heads/dot_git_colon create mode 100644 tests/resources/nasty/.gitted/refs/heads/dot_git_colon_stuff create mode 100644 tests/resources/nasty/.gitted/refs/heads/dot_git_dot create mode 100644 tests/resources/nasty/.gitted/refs/heads/dot_path create mode 100644 tests/resources/nasty/.gitted/refs/heads/dot_path_two create mode 100644 tests/resources/nasty/.gitted/refs/heads/dot_tree create mode 100644 tests/resources/nasty/.gitted/refs/heads/dotcapitalgit_backslash_path create mode 100644 tests/resources/nasty/.gitted/refs/heads/dotcapitalgit_path create mode 100644 tests/resources/nasty/.gitted/refs/heads/dotcapitalgit_tree create mode 100644 tests/resources/nasty/.gitted/refs/heads/dotdot_dotcapitalgit_path create mode 100644 tests/resources/nasty/.gitted/refs/heads/dotdot_dotgit_path create mode 100644 tests/resources/nasty/.gitted/refs/heads/dotdot_dotgit_tree create mode 100644 tests/resources/nasty/.gitted/refs/heads/dotdot_path create mode 100644 tests/resources/nasty/.gitted/refs/heads/dotdot_tree create mode 100644 tests/resources/nasty/.gitted/refs/heads/dotgit_backslash_path create mode 100644 tests/resources/nasty/.gitted/refs/heads/dotgit_path create mode 100644 tests/resources/nasty/.gitted/refs/heads/dotgit_tree create mode 100644 tests/resources/nasty/.gitted/refs/heads/git_tilde1 create mode 100644 tests/resources/nasty/.gitted/refs/heads/git_tilde2 create mode 100644 tests/resources/nasty/.gitted/refs/heads/git_tilde3 create mode 100644 tests/resources/nasty/.gitted/refs/heads/master diff --git a/src/checkout.c b/src/checkout.c index 4e879e36f..a3a46011e 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -1172,6 +1172,30 @@ static int checkout_get_remove_conflicts( return checkout_conflicts_foreach(data, data->index, workdir, pathspec, checkout_conflict_append_remove, data); } +static int checkout_verify_paths( + git_repository *repo, + int action, + git_diff_delta *delta) +{ + unsigned int flags = GIT_PATH_REJECT_DEFAULTS | GIT_PATH_REJECT_DOT_GIT; + + if (action & CHECKOUT_ACTION__REMOVE) { + if (!git_path_isvalid(repo, delta->old_file.path, flags)) { + giterr_set(GITERR_CHECKOUT, "Cannot remove invalid path '%s'", delta->old_file.path); + return -1; + } + } + + if (action & ~CHECKOUT_ACTION__REMOVE) { + if (!git_path_isvalid(repo, delta->new_file.path, flags)) { + giterr_set(GITERR_CHECKOUT, "Cannot checkout to invalid path '%s'", delta->old_file.path); + return -1; + } + } + + return 0; +} + static int checkout_get_actions( uint32_t **actions_ptr, size_t **counts_ptr, @@ -1205,7 +1229,9 @@ static int checkout_get_actions( } git_vector_foreach(deltas, i, delta) { - error = checkout_action(&act, data, delta, workdir, &wditem, &pathspec); + if ((error = checkout_action(&act, data, delta, workdir, &wditem, &pathspec)) == 0) + error = checkout_verify_paths(data->repo, act, delta); + if (error != 0) goto fail; diff --git a/src/index.c b/src/index.c index 644f0c8a7..2db7c8ea5 100644 --- a/src/index.c +++ b/src/index.c @@ -762,86 +762,19 @@ void git_index_entry__init_from_stat( entry->file_size = st->st_size; } -/* - * We fundamentally don't like some paths: we don't want - * dot or dot-dot anywhere, and for obvious reasons don't - * want to recurse into ".git" either. - * - * Also, we don't want double slashes or slashes at the - * end that can make pathnames ambiguous. - */ -static int verify_dotfile(const char *rest) -{ - /* - * The first character was '.', but that - * has already been discarded, we now test - * the rest. - */ - - /* "." is not allowed */ - if (*rest == '\0' || *rest == '/') - return -1; - - switch (*rest) { - /* - * ".git" followed by NUL or slash is bad. This - * shares the path end test with the ".." case. - */ - case 'g': - case 'G': - if (rest[1] != 'i' && rest[1] != 'I') - break; - if (rest[2] != 't' && rest[2] != 'T') - break; - rest += 2; - /* fallthrough */ - case '.': - if (rest[1] == '\0' || rest[1] == '/') - return -1; - } - return 0; -} - -static int verify_component(char c, const char *rest) -{ - if ((c == '.' && verify_dotfile(rest)) < 0 || c == '/' || c == '\0') { - giterr_set(GITERR_INDEX, "Invalid path component in index: '%c%s'", c, rest); - return -1; - } - return 0; -} - -static int verify_path(const char *path) -{ - char c; - - /* TODO: should we check this? */ - /* - if (has_dos_drive_prefix(path)) - return -1; - */ - - c = *path++; - if (verify_component(c, path) < 0) - return -1; - - while ((c = *path++) != '\0') { - if (c == '/') { - c = *path++; - if (verify_component(c, path) < 0) - return -1; - } - } - return 0; -} - -static int index_entry_create(git_index_entry **out, const char *path) +static int index_entry_create( + git_index_entry **out, + git_repository *repo, + const char *path) { size_t pathlen = strlen(path); struct entry_internal *entry; - if (verify_path(path) < 0) + if (!git_path_isvalid(repo, path, + GIT_PATH_REJECT_DEFAULTS | GIT_PATH_REJECT_DOT_GIT)) { + giterr_set(GITERR_INDEX, "Invalid path: '%s'", path); return -1; + } entry = git__calloc(sizeof(struct entry_internal) + pathlen + 1, 1); GITERR_CHECK_ALLOC(entry); @@ -855,7 +788,9 @@ static int index_entry_create(git_index_entry **out, const char *path) } static int index_entry_init( - git_index_entry **entry_out, git_index *index, const char *rel_path) + git_index_entry **entry_out, + git_index *index, + const char *rel_path) { int error = 0; git_index_entry *entry = NULL; @@ -867,7 +802,7 @@ static int index_entry_init( "Could not initialize index entry. " "Index is not backed up by an existing repository."); - if (index_entry_create(&entry, rel_path) < 0) + if (index_entry_create(&entry, INDEX_OWNER(index), rel_path) < 0) return -1; /* write the blob to disk and get the oid and stat info */ @@ -933,7 +868,10 @@ static void index_entry_cpy(git_index_entry *tgt, const git_index_entry *src) tgt->path = tgt_path; /* reset to existing path data */ } -static int index_entry_dup(git_index_entry **out, const git_index_entry *src) +static int index_entry_dup( + git_index_entry **out, + git_repository *repo, + const git_index_entry *src) { git_index_entry *entry; @@ -942,7 +880,7 @@ static int index_entry_dup(git_index_entry **out, const git_index_entry *src) return 0; } - if (index_entry_create(&entry, src->path) < 0) + if (index_entry_create(&entry, repo, src->path) < 0) return -1; index_entry_cpy(entry, src); @@ -1211,7 +1149,7 @@ int git_index_add(git_index *index, const git_index_entry *source_entry) return -1; } - if ((ret = index_entry_dup(&entry, source_entry)) < 0 || + if ((ret = index_entry_dup(&entry, INDEX_OWNER(index), source_entry)) < 0 || (ret = index_insert(index, &entry, 1)) < 0) return ret; @@ -1331,9 +1269,9 @@ int git_index_conflict_add(git_index *index, assert (index); - if ((ret = index_entry_dup(&entries[0], ancestor_entry)) < 0 || - (ret = index_entry_dup(&entries[1], our_entry)) < 0 || - (ret = index_entry_dup(&entries[2], their_entry)) < 0) + if ((ret = index_entry_dup(&entries[0], INDEX_OWNER(index), ancestor_entry)) < 0 || + (ret = index_entry_dup(&entries[1], INDEX_OWNER(index), our_entry)) < 0 || + (ret = index_entry_dup(&entries[2], INDEX_OWNER(index), their_entry)) < 0) goto on_error; for (i = 0; i < 3; i++) { @@ -1850,7 +1788,10 @@ static int read_conflict_names(git_index *index, const char *buffer, size_t size } static size_t read_entry( - git_index_entry **out, const void *buffer, size_t buffer_size) + git_index_entry **out, + git_index *index, + const void *buffer, + size_t buffer_size) { size_t path_length, entry_size; const char *path_ptr; @@ -1914,7 +1855,7 @@ static size_t read_entry( entry.path = (char *)path_ptr; - if (index_entry_dup(out, &entry) < 0) + if (index_entry_dup(out, INDEX_OWNER(index), &entry) < 0) return 0; return entry_size; @@ -2015,7 +1956,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) /* Parse all the entries */ for (i = 0; i < header.entry_count && buffer_size > INDEX_FOOTER_SIZE; ++i) { git_index_entry *entry; - size_t entry_size = read_entry(&entry, buffer, buffer_size); + size_t entry_size = read_entry(&entry, index, buffer, buffer_size); /* 0 bytes read means an object corruption */ if (entry_size == 0) { @@ -2376,6 +2317,7 @@ int git_index_entry_stage(const git_index_entry *entry) } typedef struct read_tree_data { + git_index *index; git_vector *old_entries; git_vector *new_entries; git_vector_cmp entry_cmp; @@ -2396,7 +2338,7 @@ static int read_tree_cb( if (git_buf_joinpath(&path, root, tentry->filename) < 0) return -1; - if (index_entry_create(&entry, path.ptr) < 0) + if (index_entry_create(&entry, INDEX_OWNER(data->index), path.ptr) < 0) return -1; entry->mode = tentry->attr; @@ -2437,6 +2379,7 @@ int git_index_read_tree(git_index *index, const git_tree *tree) git_vector_set_cmp(&entries, index->entries._cmp); /* match sort */ + data.index = index; data.old_entries = &index->entries; data.new_entries = &entries; data.entry_cmp = index->entries_search; @@ -2556,7 +2499,7 @@ int git_index_add_all( break; /* make the new entry to insert */ - if ((error = index_entry_dup(&entry, wd)) < 0) + if ((error = index_entry_dup(&entry, INDEX_OWNER(index), wd)) < 0) break; entry->id = blobid; diff --git a/src/path.c b/src/path.c index effe2fff1..dbe193acb 100644 --- a/src/path.c +++ b/src/path.c @@ -7,6 +7,7 @@ #include "common.h" #include "path.h" #include "posix.h" +#include "repository.h" #ifdef GIT_WIN32 #include "win32/posix.h" #include "win32/w32_util.h" @@ -1238,3 +1239,150 @@ int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or_path) else return git_buf_sets(local_path_out, url_or_path); } + +GIT_INLINE(bool) verify_shortname( + git_repository *repo, + const char *component, + size_t len) +{ + const char *shortname_repo; + + if (len == git_repository__8dot3_default_len && + strncasecmp(git_repository__8dot3_default, component, len) == 0) + return false; + + if (repo && + (shortname_repo = git_repository__8dot3_name(repo)) && + shortname_repo != git_repository__8dot3_default && + git__prefixncmp_icase(component, len, shortname_repo) == 0) + return false; + + return true; +} + +/* Reject paths like AUX or COM1, or those versions that end in a dot or + * colon. ("AUX." or "AUX:") + */ +GIT_INLINE(bool) verify_dospath( + const char *component, + size_t len, + const char dospath[3], + bool trailing_num) +{ + size_t last = trailing_num ? 4 : 3; + + if (len < last || git__strncasecmp(component, dospath, 3) != 0) + return true; + + if (trailing_num && !git__isdigit(component[3])) + return true; + + return (len > last && + component[last] != '.' && + component[last] != ':'); +} + +GIT_INLINE(bool) verify_char(unsigned char c, unsigned int flags) +{ + if ((flags & GIT_PATH_REJECT_BACKSLASH) && c == '\\') + return false; + + if (flags & GIT_PATH_REJECT_NT_CHARS) { + if (c < 32) + return false; + + switch (c) { + case '<': + case '>': + case ':': + case '"': + case '|': + case '?': + case '*': + return false; + } + } + + return true; +} + +/* + * We fundamentally don't like some paths when dealing with user-inputted + * strings (in checkout or ref names): we don't want dot or dot-dot + * anywhere, we want to avoid writing weird paths on Windows that can't + * be handled by tools that use the non-\\?\ APIs, we don't want slashes + * or double slashes at the end of paths that can make them ambiguous. + * + * For checkout, we don't want to recurse into ".git" either. + */ +static bool verify_component( + git_repository *repo, + const char *component, + size_t len, + unsigned int flags) +{ + if (len == 0) + return false; + + if ((flags & GIT_PATH_REJECT_TRAVERSAL) && + len == 1 && component[0] == '.') + return false; + + if ((flags & GIT_PATH_REJECT_TRAVERSAL) && + len == 2 && component[0] == '.' && component[1] == '.') + return false; + + if ((flags & GIT_PATH_REJECT_DOT_GIT) && len == 4 && + component[0] == '.' && + (component[1] == 'g' || component[1] == 'G') && + (component[2] == 'i' || component[2] == 'I') && + (component[3] == 't' || component[3] == 'T')) + return false; + + if ((flags & GIT_PATH_REJECT_TRAILING_DOT) && component[len-1] == '.') + return false; + + if ((flags & GIT_PATH_REJECT_TRAILING_SPACE) && component[len-1] == ' ') + return false; + + if ((flags & GIT_PATH_REJECT_TRAILING_COLON) && component[len-1] == ':') + return false; + + if ((flags & GIT_PATH_REJECT_DOS_GIT_SHORTNAME) && + !verify_shortname(repo, component, len)) + return false; + + if (flags & GIT_PATH_REJECT_DOS_PATHS) { + if (!verify_dospath(component, len, "CON", false) || + !verify_dospath(component, len, "PRN", false) || + !verify_dospath(component, len, "AUX", false) || + !verify_dospath(component, len, "NUL", false) || + !verify_dospath(component, len, "COM", true) || + !verify_dospath(component, len, "LPT", true)) + return false; + } + + return true; +} + +bool git_path_isvalid( + git_repository *repo, + const char *path, + unsigned int flags) +{ + const char *start, *c; + + for (start = c = path; *c; c++) { + if (!verify_char(*c, flags)) + return false; + + if (*c == '/') { + if (!verify_component(repo, start, (c - start), flags)) + return false; + + start = c+1; + } + } + + return verify_component(repo, start, (c - start), flags); +} diff --git a/src/path.h b/src/path.h index 23d7c2ddb..a97668a98 100644 --- a/src/path.h +++ b/src/path.h @@ -462,4 +462,42 @@ extern bool git_path_does_fs_decompose_unicode(const char *root); extern bool git_path_is_local_file_url(const char *file_url); extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or_path); +/* Flags to determine path validity in `git_path_isvalid` */ +#define GIT_PATH_REJECT_TRAVERSAL (1 << 0) +#define GIT_PATH_REJECT_DOT_GIT (1 << 1) +#define GIT_PATH_REJECT_BACKSLASH (1 << 2) +#define GIT_PATH_REJECT_TRAILING_DOT (1 << 3) +#define GIT_PATH_REJECT_TRAILING_SPACE (1 << 4) +#define GIT_PATH_REJECT_TRAILING_COLON (1 << 5) +#define GIT_PATH_REJECT_DOS_GIT_SHORTNAME (1 << 6) +#define GIT_PATH_REJECT_DOS_PATHS (1 << 7) +#define GIT_PATH_REJECT_NT_CHARS (1 << 8) + +#ifdef GIT_WIN32 +# define GIT_PATH_REJECT_DEFAULTS \ + GIT_PATH_REJECT_TRAVERSAL | \ + GIT_PATH_REJECT_BACKSLASH | \ + GIT_PATH_REJECT_TRAILING_DOT | \ + GIT_PATH_REJECT_TRAILING_SPACE | \ + GIT_PATH_REJECT_TRAILING_COLON | \ + GIT_PATH_REJECT_DOS_GIT_SHORTNAME | \ + GIT_PATH_REJECT_DOS_PATHS | \ + GIT_PATH_REJECT_NT_CHARS +#else +# define GIT_PATH_REJECT_DEFAULTS GIT_PATH_REJECT_TRAVERSAL +#endif + +/* + * Determine whether a path is a valid git path or not - this must not contain + * a '.' or '..' component, or a component that is ".git" (in any case). + * + * `repo` is optional. If specified, it will be used to determine the short + * path name to reject (if `GIT_PATH_REJECT_DOS_SHORTNAME` is specified), + * in addition to the default of "git~1". + */ +extern bool git_path_isvalid( + git_repository *repo, + const char *path, + unsigned int flags); + #endif diff --git a/src/refdb_fs.c b/src/refdb_fs.c index f39ba4f9c..61d1cd56e 100644 --- a/src/refdb_fs.c +++ b/src/refdb_fs.c @@ -712,6 +712,11 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char * assert(file && backend && name); + if (!git_path_isvalid(backend->repo, name, GIT_PATH_REJECT_DEFAULTS)) { + giterr_set(GITERR_INVALID, "Invalid reference name '%s'.", name); + return GIT_EINVALIDSPEC; + } + /* Remove a possibly existing empty directory hierarchy * which name would collide with the reference name */ @@ -1653,6 +1658,11 @@ static int lock_reflog(git_filebuf *file, refdb_fs_backend *backend, const char repo = backend->repo; + if (!git_path_isvalid(backend->repo, refname, GIT_PATH_REJECT_DEFAULTS)) { + giterr_set(GITERR_INVALID, "Invalid reference name '%s'.", refname); + return GIT_EINVALIDSPEC; + } + if (retrieve_reflog_path(&log_path, repo, refname) < 0) return -1; diff --git a/src/repository.c b/src/repository.c index 2bab52919..74a966ef3 100644 --- a/src/repository.c +++ b/src/repository.c @@ -37,6 +37,9 @@ #define GIT_REPO_VERSION 0 +const char *git_repository__8dot3_default = "GIT~1"; +size_t git_repository__8dot3_default_len = 5; + static void set_odb(git_repository *repo, git_odb *odb) { if (odb) { @@ -120,6 +123,7 @@ void git_repository_free(git_repository *repo) git__free(repo->path_repository); git__free(repo->workdir); git__free(repo->namespace); + git__free(repo->name_8dot3); git__memzero(repo, sizeof(*repo)); git__free(repo); @@ -791,6 +795,27 @@ const char *git_repository_get_namespace(git_repository *repo) return repo->namespace; } +const char *git_repository__8dot3_name(git_repository *repo) +{ + if (!repo->has_8dot3) { + repo->has_8dot3 = 1; + +#ifdef GIT_WIN32 + if (!repo->is_bare) { + repo->name_8dot3 = git_win32_path_8dot3_name(repo->path_repository); + + /* We anticipate the 8.3 name is "GIT~1", so use a static for + * easy testing in the common case */ + if (strcasecmp(repo->name_8dot3, git_repository__8dot3_default) == 0) + repo->has_8dot3_default = 1; + } +#endif + } + + return repo->has_8dot3_default ? + git_repository__8dot3_default : repo->name_8dot3; +} + static int check_repositoryformatversion(git_config *config) { int version; diff --git a/src/repository.h b/src/repository.h index 40e54c1ca..d9b950aac 100644 --- a/src/repository.h +++ b/src/repository.h @@ -120,8 +120,11 @@ struct git_repository { char *path_repository; char *workdir; char *namespace; + char *name_8dot3; - unsigned is_bare:1; + unsigned is_bare:1, + has_8dot3:1, + has_8dot3_default:1; unsigned int lru_counter; git_cvar_value cvar_cache[GIT_CVAR_CACHE_MAX]; @@ -174,4 +177,19 @@ int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head int git_repository__cleanup_files(git_repository *repo, const char *files[], size_t files_len); +/* + * Gets the DOS-compatible 8.3 "short name". This will return only the + * short name for the repository directory (ie, "git~1" for ".git"). This + * will always return a pointer to `git_repository__8dot3_default` when + * "GIT~1" is the short name. This will return NULL for bare repositories, + * and systems that do not have a short name. + */ +const char *git_repository__8dot3_name(git_repository *repo); + +/* The default DOS-compatible 8.3 "short name" for a git repository, + * "GIT~1". + */ +extern const char *git_repository__8dot3_default; +extern size_t git_repository__8dot3_default_len; + #endif diff --git a/src/util.c b/src/util.c index 5c305950f..6b0efbea5 100644 --- a/src/util.c +++ b/src/util.c @@ -250,6 +250,21 @@ int git__prefixcmp_icase(const char *str, const char *prefix) return strncasecmp(str, prefix, strlen(prefix)); } +int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix) +{ + int s, p; + + while(str_n--) { + s = (unsigned char)tolower(*str++); + p = (unsigned char)tolower(*prefix++); + + if (s != p) + return s - p; + } + + return (0 - *prefix); +} + int git__suffixcmp(const char *str, const char *suffix) { size_t a = strlen(str); diff --git a/src/util.h b/src/util.h index 6e57ad8c3..17cc08987 100644 --- a/src/util.h +++ b/src/util.h @@ -106,6 +106,7 @@ GIT_INLINE(void) git__free(void *ptr) extern int git__prefixcmp(const char *str, const char *prefix); extern int git__prefixcmp_icase(const char *str, const char *prefix); +extern int git__prefixncmp_icase(const char *str, size_t str_n, const char *prefix); extern int git__suffixcmp(const char *str, const char *suffix); GIT_INLINE(int) git__signum(int val) diff --git a/src/win32/path_w32.c b/src/win32/path_w32.c index f0eacaa63..d66969c4d 100644 --- a/src/win32/path_w32.c +++ b/src/win32/path_w32.c @@ -267,3 +267,39 @@ int git_win32_path_to_utf8(git_win32_utf8_path dest, const wchar_t *src) return len; } + +char *git_win32_path_8dot3_name(const char *path) +{ + git_win32_path longpath, shortpath; + wchar_t *start; + char *shortname; + int len, namelen = 1; + + if (git_win32_path_from_utf8(longpath, path) < 0) + return NULL; + + len = GetShortPathNameW(longpath, shortpath, GIT_WIN_PATH_UTF16); + + while (len && shortpath[len-1] == L'\\') + shortpath[--len] = L'\0'; + + if (len == 0 || len >= GIT_WIN_PATH_UTF16) + return NULL; + + for (start = shortpath + (len - 1); + start > shortpath && *(start-1) != '/' && *(start-1) != '\\'; + start--) + namelen++; + + /* We may not have actually been given a short name. But if we have, + * it will be in the ASCII byte range, so we don't need to worry about + * multi-byte sequences and can allocate naively. + */ + if (namelen > 12 || (shortname = git__malloc(namelen + 1)) == NULL) + return NULL; + + if ((len = git__utf16_to_8(shortname, namelen + 1, start)) < 0) + return NULL; + + return shortname; +} diff --git a/src/win32/path_w32.h b/src/win32/path_w32.h index dc7a68e59..1d10166e8 100644 --- a/src/win32/path_w32.h +++ b/src/win32/path_w32.h @@ -26,6 +26,11 @@ */ #define GIT_WIN_PATH_UTF8 (259 * 3 + 1) +/* + * The length of a Windows "shortname", for 8.3 compatibility. + */ +#define GIT_WIN_PATH_SHORTNAME 13 + /* Win32 path types */ typedef wchar_t git_win32_path[GIT_WIN_PATH_UTF16]; typedef char git_win32_utf8_path[GIT_WIN_PATH_UTF8]; @@ -62,4 +67,14 @@ extern int git_win32_path_canonicalize(git_win32_path path); */ extern int git_win32_path_to_utf8(git_win32_utf8_path dest, const wchar_t *src); +/** + * Get the short name for the terminal path component in the given path. + * For example, given "C:\Foo\Bar\Asdf.txt", this will return the short name + * for the file "Asdf.txt". + * + * @param path The given path in UTF-8 + * @return The name of the shortname for the given path + */ +extern char *git_win32_path_8dot3_name(const char *path); + #endif diff --git a/tests/checkout/nasty.c b/tests/checkout/nasty.c new file mode 100644 index 000000000..8bc98f3d6 --- /dev/null +++ b/tests/checkout/nasty.c @@ -0,0 +1,251 @@ +#include "clar_libgit2.h" +#include "checkout_helpers.h" + +#include "git2/checkout.h" +#include "repository.h" +#include "buffer.h" +#include "fileops.h" + +static const char *repo_name = "nasty"; +static git_repository *repo; +static git_checkout_options checkout_opts; + +void test_checkout_nasty__initialize(void) +{ + repo = cl_git_sandbox_init(repo_name); + + GIT_INIT_STRUCTURE(&checkout_opts, GIT_CHECKOUT_OPTIONS_VERSION); + checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE; +} + +void test_checkout_nasty__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_checkout_fails(const char *refname, const char *filename) +{ + git_oid commit_id; + git_commit *commit; + git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; + git_buf path = GIT_BUF_INIT; + + cl_git_pass(git_buf_joinpath(&path, repo_name, filename)); + + cl_git_pass(git_reference_name_to_id(&commit_id, repo, refname)); + cl_git_pass(git_commit_lookup(&commit, repo, &commit_id)); + + opts.checkout_strategy = GIT_CHECKOUT_FORCE; + + cl_git_fail(git_checkout_tree(repo, (const git_object *)commit, &opts)); + cl_assert(!git_path_exists(path.ptr)); + + git_commit_free(commit); + git_buf_free(&path); +} + +/* A tree that contains ".git" as a tree, with a blob inside + * (".git/foobar"). + */ +void test_checkout_nasty__dotgit_tree(void) +{ + test_checkout_fails("refs/heads/dotgit_tree", ".git/foobar"); +} + +/* A tree that contains ".GIT" as a tree, with a blob inside + * (".GIT/foobar"). + */ +void test_checkout_nasty__dotcapitalgit_tree(void) +{ + test_checkout_fails("refs/heads/dotcapitalgit_tree", ".GIT/foobar"); +} + +/* A tree that contains a tree ".", with a blob inside ("./foobar"). + */ +void test_checkout_nasty__dot_tree(void) +{ + test_checkout_fails("refs/heads/dot_tree", "foobar"); +} + +/* A tree that contains a tree ".", with a tree ".git", with a blob + * inside ("./.git/foobar"). + */ +void test_checkout_nasty__dot_dotgit_tree(void) +{ + test_checkout_fails("refs/heads/dot_dotgit_tree", ".git/foobar"); +} + +/* A tree that contains a tree, with a tree "..", with a tree ".git", with a + * blob inside ("foo/../.git/foobar"). + */ +void test_checkout_nasty__dotdot_dotgit_tree(void) +{ + test_checkout_fails("refs/heads/dotdot_dotgit_tree", ".git/foobar"); +} + +/* A tree that contains a tree, with a tree "..", with a blob inside + * ("foo/../foobar"). + */ +void test_checkout_nasty__dotdot_tree(void) +{ + test_checkout_fails("refs/heads/dotdot_tree", "foobar"); +} + +/* A tree that contains a blob with the rogue name ".git/foobar" */ +void test_checkout_nasty__dotgit_path(void) +{ + test_checkout_fails("refs/heads/dotgit_path", ".git/foobar"); +} + +/* A tree that contains a blob with the rogue name ".GIT/foobar" */ +void test_checkout_nasty__dotcapitalgit_path(void) +{ + test_checkout_fails("refs/heads/dotcapitalgit_path", ".GIT/foobar"); +} + +/* A tree that contains a blob with the rogue name "./.git/foobar" */ +void test_checkout_nasty__dot_dotgit_path(void) +{ + test_checkout_fails("refs/heads/dot_dotgit_path", ".git/foobar"); +} + +/* A tree that contains a blob with the rogue name "./.GIT/foobar" */ +void test_checkout_nasty__dot_dotcapitalgit_path(void) +{ + test_checkout_fails("refs/heads/dot_dotcapitalgit_path", ".GIT/foobar"); +} + +/* A tree that contains a blob with the rogue name "foo/../.git/foobar" */ +void test_checkout_nasty__dotdot_dotgit_path(void) +{ + test_checkout_fails("refs/heads/dotdot_dotgit_path", ".git/foobar"); +} + +/* A tree that contains a blob with the rogue name "foo/../.GIT/foobar" */ +void test_checkout_nasty__dotdot_dotcapitalgit_path(void) +{ + test_checkout_fails("refs/heads/dotdot_dotcapitalgit_path", ".GIT/foobar"); +} + +/* A tree that contains a blob with the rogue name "foo/." */ +void test_checkout_nasty__dot_path(void) +{ + test_checkout_fails("refs/heads/dot_path", "./foobar"); +} + +/* A tree that contains a blob with the rogue name "foo/." */ +void test_checkout_nasty__dot_path_two(void) +{ + test_checkout_fails("refs/heads/dot_path_two", "foo/."); +} + +/* A tree that contains a blob with the rogue name "foo/../foobar" */ +void test_checkout_nasty__dotdot_path(void) +{ + test_checkout_fails("refs/heads/dotdot_path", "foobar"); +} + +/* A tree that contains an entry with a backslash ".git\foobar" */ +void test_checkout_nasty__dotgit_backslash_path(void) +{ +#ifdef GIT_WIN32 + test_checkout_fails("refs/heads/dotgit_backslash_path", ".git/foobar"); +#endif +} + +/* A tree that contains an entry with a backslash ".GIT\foobar" */ +void test_checkout_nasty__dotcapitalgit_backslash_path(void) +{ +#ifdef GIT_WIN32 + test_checkout_fails("refs/heads/dotcapitalgit_backslash_path", ".GIT/foobar"); +#endif +} + +/* A tree that contains an entry with a backslash ".\.GIT\foobar" */ +void test_checkout_nasty__dot_backslash_dotcapitalgit_path(void) +{ +#ifdef GIT_WIN32 + test_checkout_fails("refs/heads/dot_backslash_dotcapitalgit_path", ".GIT/foobar"); +#endif +} + +/* A tree that contains an entry ".git.", because Win32 APIs will drop the + * trailing slash. + */ +void test_checkout_nasty__dot_git_dot(void) +{ +#ifdef GIT_WIN32 + test_checkout_fails("refs/heads/dot_git_dot", ".git/foobar"); +#endif +} + +/* A tree that contains an entry "git~1", because that is typically the + * short name for ".git". + */ +void test_checkout_nasty__git_tilde1(void) +{ +#ifdef GIT_WIN32 + test_checkout_fails("refs/heads/git_tilde1", ".git/foobar"); +#endif +} + +/* A tree that contains an entry "git~2", when we have forced the short + * name for ".git" into "GIT~2". + */ +void test_checkout_nasty__git_custom_shortname(void) +{ +#ifdef GIT_WIN32 + cl_must_pass(p_rename("nasty/.git", "nasty/_temp")); + cl_git_write2file("nasty/git~1", "", 0, O_RDWR|O_CREAT, 0666); + cl_must_pass(p_rename("nasty/_temp", "nasty/.git")); + test_checkout_fails("refs/heads/git_tilde2", ".git/foobar"); +#endif +} + +/* A tree that contains an entry "git~3", which should be allowed, since + * it is not the typical short name ("GIT~1") or the actual short name + * ("GIT~2") for ".git". + */ +void test_checkout_nasty__only_looks_like_a_git_shortname(void) +{ +#ifdef GIT_WIN32 + git_oid commit_id; + git_commit *commit; + git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; + + cl_must_pass(p_rename("nasty/.git", "nasty/_temp")); + cl_git_write2file("nasty/git~1", "", 0, O_RDWR|O_CREAT, 0666); + cl_must_pass(p_rename("nasty/_temp", "nasty/.git")); + + cl_git_pass(git_reference_name_to_id(&commit_id, repo, "refs/heads/git_tilde3")); + cl_git_pass(git_commit_lookup(&commit, repo, &commit_id)); + + opts.checkout_strategy = GIT_CHECKOUT_FORCE; + + cl_git_pass(git_checkout_tree(repo, (const git_object *)commit, &opts)); + cl_assert(git_path_exists("nasty/git~3/foobar")); + + git_commit_free(commit); +#endif +} + +/* A tree that contains an entry "git:", because Win32 APIs will reject + * that as looking too similar to a drive letter. + */ +void test_checkout_nasty__dot_git_colon(void) +{ +#ifdef GIT_WIN32 + test_checkout_fails("refs/heads/dot_git_colon", ".git/foobar"); +#endif +} + +/* A tree that contains an entry "git:foo", because Win32 APIs will turn + * that into ".git". + */ +void test_checkout_nasty__dot_git_colon_stuff(void) +{ +#ifdef GIT_WIN32 + test_checkout_fails("refs/heads/dot_git_colon_stuff", ".git/foobar"); +#endif +} + diff --git a/tests/path/core.c b/tests/path/core.c index 45f54df29..7cc111800 100644 --- a/tests/path/core.c +++ b/tests/path/core.c @@ -51,3 +51,197 @@ void test_path_core__make_relative(void) test_make_relative("/path", "/path", "pathtofoo", GIT_ENOTFOUND); test_make_relative("path", "path", "pathtofoo", GIT_ENOTFOUND); } + +void test_path_core__isvalid_standard(void) +{ + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/file.txt", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/.file", 0)); +} + +void test_path_core__isvalid_empty_dir_component(void) +{ + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo//bar", 0)); + + /* leading slash */ + cl_assert_equal_b(false, git_path_isvalid(NULL, "/", 0)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "/foo", 0)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "/foo/bar", 0)); + + /* trailing slash */ + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/", 0)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar/", 0)); +} + +void test_path_core__isvalid_dot_and_dotdot(void) +{ + cl_assert_equal_b(true, git_path_isvalid(NULL, ".", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "./foo", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "./foo", 0)); + + cl_assert_equal_b(true, git_path_isvalid(NULL, "..", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "../foo", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/..", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "../foo", 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, ".", GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "./foo", GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.", GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "./foo", GIT_PATH_REJECT_TRAVERSAL)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "..", GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "../foo", GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/..", GIT_PATH_REJECT_TRAVERSAL)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "../foo", GIT_PATH_REJECT_TRAVERSAL)); +} + +void test_path_core__isvalid_dot_git(void) +{ + cl_assert_equal_b(true, git_path_isvalid(NULL, ".git", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".git/foo", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.git", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.git/bar", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.GIT/bar", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar/.Git", 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", GIT_PATH_REJECT_DOT_GIT)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ".git/foo", GIT_PATH_REJECT_DOT_GIT)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git", GIT_PATH_REJECT_DOT_GIT)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.git/bar", GIT_PATH_REJECT_DOT_GIT)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/.GIT/bar", GIT_PATH_REJECT_DOT_GIT)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar/.Git", GIT_PATH_REJECT_DOT_GIT)); + + cl_assert_equal_b(true, git_path_isvalid(NULL, "!git", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/!git", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "!git/bar", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".tig", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/.tig", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ".tig/bar", 0)); +} + +void test_path_core__isvalid_backslash(void) +{ + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo\\file.txt", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar\\file.txt", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar\\", 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo\\file.txt", GIT_PATH_REJECT_BACKSLASH)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar\\file.txt", GIT_PATH_REJECT_BACKSLASH)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar\\", GIT_PATH_REJECT_BACKSLASH)); +} + +void test_path_core__isvalid_trailing_dot(void) +{ + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo.", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo...", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar.", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo./bar", 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo.", GIT_PATH_REJECT_TRAILING_DOT)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo...", GIT_PATH_REJECT_TRAILING_DOT)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar.", GIT_PATH_REJECT_TRAILING_DOT)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo./bar", GIT_PATH_REJECT_TRAILING_DOT)); +} + +void test_path_core__isvalid_trailing_space(void) +{ + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo ", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo ", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar ", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, " ", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo /bar", 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo ", GIT_PATH_REJECT_TRAILING_SPACE)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo ", GIT_PATH_REJECT_TRAILING_SPACE)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar ", GIT_PATH_REJECT_TRAILING_SPACE)); + cl_assert_equal_b(false, git_path_isvalid(NULL, " ", GIT_PATH_REJECT_TRAILING_SPACE)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo /bar", GIT_PATH_REJECT_TRAILING_SPACE)); +} + +void test_path_core__isvalid_trailing_colon(void) +{ + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo:", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo/bar:", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, ":", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "foo:/bar", 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo:", GIT_PATH_REJECT_TRAILING_COLON)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo/bar:", GIT_PATH_REJECT_TRAILING_COLON)); + cl_assert_equal_b(false, git_path_isvalid(NULL, ":", GIT_PATH_REJECT_TRAILING_COLON)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "foo:/bar", GIT_PATH_REJECT_TRAILING_COLON)); +} + +void test_path_core__isvalid_dos_git_shortname(void) +{ + cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1", 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1", GIT_PATH_REJECT_DOS_GIT_SHORTNAME)); +} + +void test_path_core__isvalid_dos_paths(void) +{ + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux:", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.asdf", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux.asdf\\zippy", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux:asdf\\foobar", 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "aux", GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "aux.", GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "aux:", GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "aux.asdf", GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "aux.asdf\\zippy", GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "aux:asdf\\foobar", GIT_PATH_REJECT_DOS_PATHS)); + + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux1", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux1", GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "auxn", GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "aux\\foo", GIT_PATH_REJECT_DOS_PATHS)); +} + +void test_path_core__isvalid_dos_paths_withnum(void) +{ + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1:", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.asdf", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1.asdf\\zippy", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1:asdf\\foobar", 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1", GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1.", GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1:", GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1.asdf", GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1.asdf\\zippy", GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "com1:asdf\\foobar", GIT_PATH_REJECT_DOS_PATHS)); + + cl_assert_equal_b(true, git_path_isvalid(NULL, "com10", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com10", GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "comn", GIT_PATH_REJECT_DOS_PATHS)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "com1\\foo", GIT_PATH_REJECT_DOS_PATHS)); +} + +void test_core_path__isvalid_nt_chars(void) +{ + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf\001foo", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf\037bar", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdffoo", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf:foo", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf\"bar", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf|foo", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf?bar", 0)); + cl_assert_equal_b(true, git_path_isvalid(NULL, "asdf*bar", 0)); + + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf\001foo", GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf\037bar", GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdffoo", GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf:foo", GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf\"bar", GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf|foo", GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf?bar", GIT_PATH_REJECT_NT_CHARS)); + cl_assert_equal_b(false, git_path_isvalid(NULL, "asdf*bar", GIT_PATH_REJECT_NT_CHARS)); +} diff --git a/tests/path/win32.c b/tests/path/win32.c index ef0b5d2f2..22742f82d 100644 --- a/tests/path/win32.c +++ b/tests/path/win32.c @@ -188,3 +188,27 @@ void test_path_win32__canonicalize(void) test_canonicalize(L"\\\\server\\..\\..\\share\\.\\foo", L"\\\\server\\share\\foo"); #endif } + +void test_path_win32__8dot3_name(void) +{ +#ifdef GIT_WIN32 + char *shortname; + + /* Some guaranteed short names */ + cl_assert_equal_s("PROGRA~1", (shortname = git_win32_path_8dot3_name("C:\\Program Files"))); + git__free(shortname); + + cl_assert_equal_s("WINDOWS", (shortname = git_win32_path_8dot3_name("C:\\WINDOWS"))); + git__free(shortname); + + /* Create some predictible short names */ + cl_must_pass(p_mkdir(".foo", 0777)); + cl_assert_equal_s("FOO~1", (shortname = git_win32_path_8dot3_name(".foo"))); + git__free(shortname); + + cl_git_write2file("bar~1", "foobar\n", 7, O_RDWR|O_CREAT, 0666); + cl_must_pass(p_mkdir(".bar", 0777)); + cl_assert_equal_s("BAR~2", (shortname = git_win32_path_8dot3_name(".bar"))); + git__free(shortname); +#endif +} diff --git a/tests/resources/nasty/.gitted/HEAD b/tests/resources/nasty/.gitted/HEAD new file mode 100644 index 0000000000000000000000000000000000000000..cb089cd89a7d7686d284d8761201649346b5aa1c GIT binary patch literal 23 ecmXR)O|w!cN=+-)&qz&7Db~+TEG|hc;sO9;xClW2 literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/index b/tests/resources/nasty/.gitted/index new file mode 100644 index 0000000000000000000000000000000000000000..782a50d0a8a2df69bda7abb381350bb366e11cb6 GIT binary patch literal 120 zcmZ?q402{*U|<4bhL9jvS0EL@V5nfo)#Rad=~?sJKO*1nna=Z{71uFgPGDMoK3Hy= z{e1@O?`qN$Lywm99+(pBxouvCo*q!jfQzf*317$=cNrGZQ)~^P{3?1C&W~RFJrV6^ Tqu_LRtD)6HX4~A=uCiGG7NjaL literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/02/28b21d477f67b9f7720565da9e760b84c8b85b b/tests/resources/nasty/.gitted/objects/02/28b21d477f67b9f7720565da9e760b84c8b85b new file mode 100644 index 0000000000000000000000000000000000000000..e7cd63a28060e09aeef4f9b6ca5f950eebf2f5fb GIT binary patch literal 133 zcmV;00DAv;0i}&y3IZV%g?n}tcLNPxe@BSur4`f$9KB+YBREF1`z+c)Z|8g;oD*s( zw+`s!t~VlxLE4}bYJq97CJ_eo!7eCqw#i9nymmra<{v%R2Iu(nEy6X|vegw1H0URt n=qrA03bh;o6&k0+Y!vLd=9~>W&O7}%!!CEf<=6BE^^!pKl+QeJ literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/04/18f28a75dc0c4951c01842e0d794843a88178a b/tests/resources/nasty/.gitted/objects/04/18f28a75dc0c4951c01842e0d794843a88178a new file mode 100644 index 0000000000000000000000000000000000000000..7f8722e78fa65496a07231a18d8213f150244085 GIT binary patch literal 46 zcmbPA<=i?PL)e}BX+Mg4cr?dOt8S@{k J3})>D^#B9<6#f7J literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/09/9ed86cb8501ae483b1855c351fe1a506ac9631 b/tests/resources/nasty/.gitted/objects/09/9ed86cb8501ae483b1855c351fe1a506ac9631 new file mode 100644 index 0000000000000000000000000000000000000000..7738fc85d6f2322a3e51b1db4a99da20eeb7a13c GIT binary patch literal 133 zcmV;00DAv;0i}&g3IZ_@L|x|;eF2AbeojEdjVI6xv`L2uW&)XrczdIG19w&LK~<=w z+&ZAwo8FjV4!k4H$@-w9lZvGBPAlZAcShlybhIiF3wrci8=T^kT7*lkWvvVBdC*Tf n@>l%Y6lysD8g$;^j1IQaN+|{%=bitY5$8Lt`8B-(1lB4V=y!@Ff%bxNXyUH*VEJ2bN39<2eOkAix?VK{PPz`$_d!K U%`G2xeA<6e&uJL!>!bB~?-woKAjbW36Wv{@HVFaE>qEB3yGVYkk0x2mQE( mzr`<2p_UUMp>d?h5$vUwQVcrIJO4Q&E_c7?ZF&Q^89=!Oy*lgw literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/1e/3c845808fa5883aa4bcf2f882172edb72a7a32 b/tests/resources/nasty/.gitted/objects/1e/3c845808fa5883aa4bcf2f882172edb72a7a32 new file mode 100644 index 0000000000000000000000000000000000000000..e25f153f4c17e66a0d6ad16c70e2a6a6431cd5e4 GIT binary patch literal 134 zcmV;10D1p-0i}&m4#FT1ME&LzdjXqeVQEQ>@y8SB1t`#9A|;_13L}ZmVZbF=cT0Bot5!2{Mdf^@|l?vzZbTz;=mAsV|4zbfu oI>oQ}wZWHs1gWL5S{aM5M@AH#_VX71oDrA1+tO=z1Djkxd~;1eaR2}S literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/24/676d5e93f9fa7b568f38d7bce01772908e982b b/tests/resources/nasty/.gitted/objects/24/676d5e93f9fa7b568f38d7bce01772908e982b new file mode 100644 index 0000000000000000000000000000000000000000..fc11c20d5f9f26ef56d54e610a92a2e20c74b2d7 GIT binary patch literal 47 zcmbL=5ib54O)5VqnO?#A<8HCf4a6yR^K*hMC{P!ghz<(xa=K_i!_unaa}+01tHy A+5i9m literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/39/fb3af508440cf970b92767f6d081c811574d2a b/tests/resources/nasty/.gitted/objects/39/fb3af508440cf970b92767f6d081c811574d2a new file mode 100644 index 0000000000000000000000000000000000000000..3854748c9f3aab8554e72fa01f23493cc2fc2ce6 GIT binary patch literal 131 zcmV-}0DS*=0i}&S3PLdugspRm?FGrtCaxf2BVzw95VQMu7I7g)yuMMqfm6+V12aWy zy>)OqT=gabk(~(69_N&}aPm1=j}(bG1hSZ7x_Y|}CO`Y44Nm;ZjbU1}KJ*TI8T8|h l@-2R8Q?wqyp-V*8qKCB|GJ}ruE`QD#)(+>(WZurCKkovEJ{JH0 literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/44/14ac920acabc3eb00e3cf9375eeb0cb6859c15 b/tests/resources/nasty/.gitted/objects/44/14ac920acabc3eb00e3cf9375eeb0cb6859c15 new file mode 100644 index 0000000000000000000000000000000000000000..4eaaa0cd7485dc7c1a43e7338a61d74f2771f3f0 GIT binary patch literal 135 zcmV;20C@j+0i{n%3c@fHbe&VYy-@OR6%jYyzze**yx1<%KpOG-rs55p)qG%vp_22` zKudjSl^Hy#9(uB?T1tYICV@k8i9I9&^cCS>eLn-Pw)5 p!A}iT@)eX-<7h`USvblL(cM1Y_|Fc;Ox`l?vzZbTz;=mAsV|4&3P{ no%kz$ZSW-@fh1`=X^A83Q6Y*>`+4I(XT;_1w)7g_ioHS2YimJT literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/53/41a7b545d71198b076b8ba3374a75c9a290640 b/tests/resources/nasty/.gitted/objects/53/41a7b545d71198b076b8ba3374a75c9a290640 new file mode 100644 index 0000000000000000000000000000000000000000..fdfe6eb374957fa35e5b1dfa8d74e7ea6a944f69 GIT binary patch literal 133 zcmV;00DAv;0i}&y3c@fDgniB__5zmOq-hfn@x>G91@f~cf@vU)h_^S2H}Gxd8~7%a zoNo=ts$Hwh;EkHC_Qc3ukBgMcjCvxn(UX!IF=B`TwQ!G?N`-TLx*Fk{O5Vx}2k!Kf nPW&ByZ3rbFfkv9F(ncECV^@hz`+4I(HR5u2TY3#|w`M@8Bpg9{ literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/5d/1ee4f24f66dcd62a30248588d33804656b2073 b/tests/resources/nasty/.gitted/objects/5d/1ee4f24f66dcd62a30248588d33804656b2073 new file mode 100644 index 0000000000000000000000000000000000000000..ffd9bfd3619b9858286ed58ac02da4b464bb594c GIT binary patch literal 46 zcmb4 literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/65/94bdbad86bbc8d3ed0806a23827203fbab56c6 b/tests/resources/nasty/.gitted/objects/65/94bdbad86bbc8d3ed0806a23827203fbab56c6 new file mode 100644 index 0000000000000000000000000000000000000000..fa990d4084cc27cd6c0c50b0b3be8a6717ecaf40 GIT binary patch literal 132 zcmV-~0DJ#<0i}&m3PK?eMf-LYvw(N_OL~Zs0JP9UH+U=r(0O_YkC81n?OH^8$NXa literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/68/e8bce48725490c376d57ebc60f0170605951a5 b/tests/resources/nasty/.gitted/objects/68/e8bce48725490c376d57ebc60f0170605951a5 new file mode 100644 index 0000000000000000000000000000000000000000..c23f81597f2701fd30861cfbe6ed3ad1af8d9229 GIT binary patch literal 58 zcmV-A0LA}!0V^p=O;s>4WH2-^Ff%bx(9_p*_YBcb%g;|rEMjO_@y}l%DJNj_lD}+G QZY;b0%s2Q20B-3Kyp>uQ@Bjb+ literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/69/7dc3d723a018538eb819d5db2035c15109af73 b/tests/resources/nasty/.gitted/objects/69/7dc3d723a018538eb819d5db2035c15109af73 new file mode 100644 index 0000000000000000000000000000000000000000..6d7d9f5007a1c29cd55fc1343cfb48c943fca01f GIT binary patch literal 132 zcmV-~0DJ#<0i}&g3IZ_@L|x|;eF29glaCD|Zajfrpp$fnU<}Me#M>Li8@Q|Y3aVnO z_1ZzN literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/6c/1f5f6fec515d33036b44c596bfae28fc460cba b/tests/resources/nasty/.gitted/objects/6c/1f5f6fec515d33036b44c596bfae28fc460cba new file mode 100644 index 0000000000000000000000000000000000000000..8172b7f0a10cc26a4b05d5a61d6a9a5e890b48a7 GIT binary patch literal 47 zcmbL=5ib54OKd DYXK1< literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/7d/4e382485ace068fb83b768ba1a1c674afbdc1d b/tests/resources/nasty/.gitted/objects/7d/4e382485ace068fb83b768ba1a1c674afbdc1d new file mode 100644 index 0000000000000000000000000000000000000000..f7be9ab39c6fe4d95b63d3eb2e64855b5c3050e0 GIT binary patch literal 62 zcmV-E0Kxxw0V^p=O;s>4V=y!@Ff%bxNXyUH*VEJ2OV2FP2eOkAix?VK{PPz`$_d!K UL=5ib54OUJuxA|~c`igTboK=oDL;V#sX0^t literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/8b/cbb6e0c0f9554efd5401e1ec14a4b2595eb3bf b/tests/resources/nasty/.gitted/objects/8b/cbb6e0c0f9554efd5401e1ec14a4b2595eb3bf new file mode 100644 index 0000000000000000000000000000000000000000..bba2035da7164a2bcafa8dc5fb8c2a5173791dd7 GIT binary patch literal 134 zcmV;10D1p-0i}&y3IZV%g?n}tcLNPxe@2CfURptIz|kuPIf7$EyU(H>^mfko!8xIp za_fLj?s_AF6pfcAI)ToJ*^t(RDew?f5>|SPdWps@mib4|wZS<)eT#6-wQO~T0}c8~ oC;EzCn?fx|K!vkYQYr&`t~qCej`L1`&alhfZ}~O70S|*gDTd!Y3IG5A literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/8c/e7a3ef59c3d602a0296321eb964218f3d52fae b/tests/resources/nasty/.gitted/objects/8c/e7a3ef59c3d602a0296321eb964218f3d52fae new file mode 100644 index 0000000000000000000000000000000000000000..6f3484c1ae520cbb98c6625cf622beb31a102b47 GIT binary patch literal 56 zcmV-80LTA$0V^p=O;s?qWH2-^Ff%bx&`ZxOiAl@PPf9FeXjt*jUmz(bVDpl{Y*B73 OyZ+2K_yquL{t@$0lNXl& literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/8f/1dcd43aa0164eb6ec319c3ec8879ca5cf62c1e b/tests/resources/nasty/.gitted/objects/8f/1dcd43aa0164eb6ec319c3ec8879ca5cf62c1e new file mode 100644 index 0000000000000000000000000000000000000000..f802e5af7eea5a9ae7d67da7d15f8b4044147bfd GIT binary patch literal 132 zcmV-~0DJ#<0i}&g3IZ_@L|x|;eF2AjI%7A8xbXyffsk~FU<}Me#M>Li8@Q`_52|9T z_1eL(+w?^Q$RgR0tjy#jU;}pc};H^20<@BB|yCZ literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/91/602c85bb50dd834205edd30435b77d5bb9ccf0 b/tests/resources/nasty/.gitted/objects/91/602c85bb50dd834205edd30435b77d5bb9ccf0 new file mode 100644 index 0000000000000000000000000000000000000000..d7147fb1c0bd783d457b251cce9567e20d260ab7 GIT binary patch literal 131 zcmV-}0DS*=0i}&m3IZ_eD z=W7EBcGIdV#Az4Qql%NTIBUswU>%9Q7n*qyq9`F4eza67oaD(>;F3yS%N_RG?I#`e lTl{EHu`1@h?-!5GLy#M>Li8@Q`_1+PLa z<=R17wdsu+IBFk|R9a*VO3x`F?zFc=p2$YhkqH+z!aaJf4NmdtT7*lkWvzGE^Prz} mf(tQcE+`Xb`qIBZ@)CdFMYh;(T*!eob%rI6&s&yFCg3 literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/96/3fdf003bf7261b9155c5748dc0945349b69e68 b/tests/resources/nasty/.gitted/objects/96/3fdf003bf7261b9155c5748dc0945349b69e68 new file mode 100644 index 0000000000000000000000000000000000000000..ff1d33e5cc4aecbb998f62863ebf782f13eb0878 GIT binary patch literal 44 zcmb)5VqnO?#A<8HwysOPMlt2CtPDKy G{O$nMpA)tK literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/af/45aa1eb7edf804ed10f70efb96fd178527c17c b/tests/resources/nasty/.gitted/objects/af/45aa1eb7edf804ed10f70efb96fd178527c17c new file mode 100644 index 0000000000000000000000000000000000000000..9e270bfbc9eeeed975756efcb5aac58b4b8540df GIT binary patch literal 58 zcmV-A0LA}!0V^p=O;s>4WH2-^Ff%bx(9_pT&n(eT%g;|rEMjO_@y}l%DJNj_lD}+G QZY;b0%s2Q20D37B9E)@pZ2$lO literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/b8/3795b1e0eb54f22f7056119db132500d0cdc05 b/tests/resources/nasty/.gitted/objects/b8/3795b1e0eb54f22f7056119db132500d0cdc05 new file mode 100644 index 0000000000000000000000000000000000000000..6cee4f9d823d3ff9160feaa143681c6d564f3c69 GIT binary patch literal 56 zcmV-80LTA$0V^p=O;s?qWH2-^Ff%bx&`ZxO(ND|IPf9FeXjt*jUmz(bVDpl{Y*B73 OyZ+2K_yquH5)sB(HWtVL literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/bf/7ab4723fcc57ecc7fceccf591d6c4773491569 b/tests/resources/nasty/.gitted/objects/bf/7ab4723fcc57ecc7fceccf591d6c4773491569 new file mode 100644 index 0000000000000000000000000000000000000000..af02c6b9b67d7189022a8e79c1dcbc031ec6f080 GIT binary patch literal 133 zcmV;00DAv;0i}&g3IZ_@L|x|;eF2B=d>jKJZajfrV5U1Ef|)=jBHrF8-oRbedr-wC z=UW5vX47g2fR42GbM#^`u-68ij?rqF_qg-S!ZeceqNYbnrNUXBQx&+TlGn1pA$0ml nr|=cOHgL&DAWI{X)5gLU9ir;ApSSSmjJn*XHNA#6)ptP056DAD literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/c4/89e70ed6d9f6331770eae21a77d15afd11cd99 b/tests/resources/nasty/.gitted/objects/c4/89e70ed6d9f6331770eae21a77d15afd11cd99 new file mode 100644 index 0000000000000000000000000000000000000000..1d763482f01fb9ba80823f8708df898a0c334a9f GIT binary patch literal 56 zcmV-80LTA$0V^p=O;s>4WH2-^Ff%bxNXyUH*VEGnQb~zL3=J#(`3ofF1Z-aNmo3VT OW!Ini2EPD&SrQycd=_K? literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/c6/72414d4d08111145ef8202f21c95fa7e688aee b/tests/resources/nasty/.gitted/objects/c6/72414d4d08111145ef8202f21c95fa7e688aee new file mode 100644 index 0000000000000000000000000000000000000000..1b79b342c36e06fc2ca5638bd5a84e0b9cbea7fc GIT binary patch literal 56 zcmV-80LTA$0V^p=O;s?qWH2-^Ff%bx&~x_;iAl@PPf9FeXjt*jUmz(bVDpl{Y*B73 OyZ+2K_yquAz7dmGe-|78 literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/cc/bbfdb796f9b03298f5c7225e8f830784e1a3b1 b/tests/resources/nasty/.gitted/objects/cc/bbfdb796f9b03298f5c7225e8f830784e1a3b1 new file mode 100644 index 0000000000000000000000000000000000000000..732474aefdf129bcab450d44bf357a34a52be156 GIT binary patch literal 136 zcmV;30C)d*0i{n#3IZ_@^qg1pT^O=-j3Xjm{DB|nB&{=tOhYE(_sxhuuuio=6_uov zxq;Pw*D5nGa*pm`*qhPW=u_%C1!go6vm>;}kvOrUSDU25Ex)N|xKC16S>Vjw-Po1C q!A}iI$^{IX5HMJcu-6@`yM4UzpEYWD&h7LN0a}4z`=LJGn?x-Rt^#q>L=5ib54OfK~jkhSRGl7(`$eQL9Jrf0+_(#vR!8tyCi*U`gtaX6{5Bf4WH2-^Ff%bx(2LP?_Y8?i%g;|rEMjO_@y}l%DJNj_lD}+G QZY;b0%s2Q20C}Pk7JWY#a{vGU literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/de/bdc4a004fda6141a17d9c297617be70d40248f b/tests/resources/nasty/.gitted/objects/de/bdc4a004fda6141a17d9c297617be70d40248f new file mode 100644 index 0000000000000000000000000000000000000000..de34bd4305ef86f32ab42e7cca56eda0427cb12b GIT binary patch literal 133 zcmV;00DAv;0i}&g3IZ_@L|x|;eF2AbW+opHapMW}0&S?Ji&zt-?qfR$km)GzHZO}oaNn<+< literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/e2/377bdbc93b30a34ed5deefedded89b947ff8f4 b/tests/resources/nasty/.gitted/objects/e2/377bdbc93b30a34ed5deefedded89b947ff8f4 new file mode 100644 index 0000000000000000000000000000000000000000..f365908e0f3df2e46ab8ce03383781a4b588c4da GIT binary patch literal 132 zcmV-~0DJ#<0i}&g3IZ_@L|x|;eF2B=$sa`AcmlmZCTWRa3}hnW?Tz9M+*Q2?Rk4bBw>phQ4BiHJO4Q&PPee;*YpOE(Lh&e20u^$ literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/e3/99c4fc4c07cb7947d2f3d966bc374df6ccc691 b/tests/resources/nasty/.gitted/objects/e3/99c4fc4c07cb7947d2f3d966bc374df6ccc691 new file mode 100644 index 0000000000000000000000000000000000000000..d8c2379461f2fecb2ba973f1a942c7a8c465d1b5 GIT binary patch literal 131 zcmV-}0DS*=0i}&m3IZ_;x3?bc(H8N2Oia$_-LtAI4;jv7dWSq*K&thJN=}C le#Ng1Qt}>%$s>gc8Mf#UO{e|5>7O&^bc<_x4R3pxKsb}+K;{4d literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/e4/edb361e51932b5ccedbc7ee41b4d3a4289aece b/tests/resources/nasty/.gitted/objects/e4/edb361e51932b5ccedbc7ee41b4d3a4289aece new file mode 100644 index 0000000000000000000000000000000000000000..a9b181815a9e29bb5000680fac07fc49e1ae4688 GIT binary patch literal 50 zcmbL=5ib54O)5U|`6=#A?g7u1mc}G5tLp)W+k5y8MR|-ARA3E6QtJC z0ThO??5$ra+g%9zYZT literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/objects/fd/7a37d92197267e55e1fc0cc4f283a815bd79b8 b/tests/resources/nasty/.gitted/objects/fd/7a37d92197267e55e1fc0cc4f283a815bd79b8 new file mode 100644 index 0000000000000000000000000000000000000000..c8d38ca46c6e7471571bd7154436210c82f3e126 GIT binary patch literal 43 zcmb)5U|`6=#A?eX*6AO+w7kNGncu_0c8A^4qpO_va5Efb<%s|Q0-+4k literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/refs/heads/dot_backslash_dotcapitalgit_path b/tests/resources/nasty/.gitted/refs/heads/dot_backslash_dotcapitalgit_path new file mode 100644 index 0000000000000000000000000000000000000000..06132bc80f2dcdb2067cf9f3390bc0772c0e1710 GIT binary patch literal 41 ucmV~$!4Uu;2m`Rc(;x>F#<3#%k6#<5uTAHn3X$So`D1Va4~=5m$C4NfG)#U3C0>I<;| literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/refs/heads/dot_git_colon b/tests/resources/nasty/.gitted/refs/heads/dot_git_colon new file mode 100644 index 0000000000000000000000000000000000000000..39052d99a592f17279df233ee8d33ae5e9be4b00 GIT binary patch literal 41 ucmXppF*Hd`wlp$GOioNnHcm}4Fi15{PO~&NH%$d{l9S9VOf8cQO}PN}stbAm literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/refs/heads/dot_git_colon_stuff b/tests/resources/nasty/.gitted/refs/heads/dot_git_colon_stuff new file mode 100644 index 0000000000000000000000000000000000000000..a3bc39f66f069a26304e10049b7e39aaaf80ec4b GIT binary patch literal 41 vcmV~$NdW*L2n4{tX*fh6j*HMgf-_aXJb0c-kV?i_xrlX4D0%GWtKjtk{(TEN literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/refs/heads/dot_git_dot b/tests/resources/nasty/.gitted/refs/heads/dot_git_dot new file mode 100644 index 0000000000000000000000000000000000000000..b20a1e0acf4539fcb5a90e84602e31153b538bc9 GIT binary patch literal 41 ucmV~$K>+|D2m`>sX%u0TIDpbWf_H)htQMrfsCXdhs@A)h&LcSkm*WHC@(Qy6 literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/refs/heads/dot_path b/tests/resources/nasty/.gitted/refs/heads/dot_path new file mode 100644 index 0000000000000000000000000000000000000000..b3c7ab682ae122c52d845267fa4455ba2513c1a9 GIT binary patch literal 41 ucmYdFGfzx1F*hs?3r{pPM=-JW%SdjHl5{D~9SjL8^g9KW9P0z=y9)jQ literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/refs/heads/dotdot_path b/tests/resources/nasty/.gitted/refs/heads/dotdot_path new file mode 100644 index 0000000000000000000000000000000000000000..185e13b11d9970cda1eebc756a720c26a8eda260 GIT binary patch literal 41 vcmcCCG&3+twlGafGBrp^u`o6+|D2m`>sX+#hq4$jd(f_KsK@Jy?wxbZrnl29VzBx<95K{!79RSUcT literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/refs/heads/dotgit_backslash_path b/tests/resources/nasty/.gitted/refs/heads/dotgit_backslash_path new file mode 100644 index 0000000000000000000000000000000000000000..6e4344dd6f24ab919b13c76a45d92ebc2d934951 GIT binary patch literal 41 ucmV~$!4Uu;2m`Rc)6m0mWgJA@e*_cDoU7;~8fv!uKx8}d21SeN49EKB7YdvJ literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/refs/heads/dotgit_path b/tests/resources/nasty/.gitted/refs/heads/dotgit_path new file mode 100644 index 0000000000000000000000000000000000000000..dd71efaa4859bd96448a6680857cadb10877be57 GIT binary patch literal 41 tcmV~$K>+|D2m`>sX+Sn6aX|ZL@Qwj*4Z$b(I%CQ?(-A_8w|bW)Y<<^#3JL%K literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/refs/heads/dotgit_tree b/tests/resources/nasty/.gitted/refs/heads/dotgit_tree new file mode 100644 index 0000000000000000000000000000000000000000..3b7a08d7ced193fb2b4ba234cc9c3d3d0fa5630d GIT binary patch literal 41 ucmV~$!4Uu;2m`Rc({P}*jzdBBAHf9cOtrEJsn~JbXh;wGc8jOfLScOOa|>1g literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/refs/heads/git_tilde1 b/tests/resources/nasty/.gitted/refs/heads/git_tilde1 new file mode 100644 index 0000000000000000000000000000000000000000..d48a185304c03a5199ad0f06978b600abc0ff303 GIT binary patch literal 41 ucmcCCNi#N2HnKD{H%_)lOEfV}G%_|yGBi&$H!)4NFfs&kjM5U*Qn&!$xeChw literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/refs/heads/git_tilde2 b/tests/resources/nasty/.gitted/refs/heads/git_tilde2 new file mode 100644 index 0000000000000000000000000000000000000000..77082e153322919b5078a735698428159f91a6ab GIT binary patch literal 41 tcmV~$$pHW$2m`Rc;~-Evj$HeXU=rl61XOd{a%!A~$On@`*BzR=@O<~Z3s(RD literal 0 HcmV?d00001 diff --git a/tests/resources/nasty/.gitted/refs/heads/git_tilde3 b/tests/resources/nasty/.gitted/refs/heads/git_tilde3 new file mode 100644 index 0000000000000000000000000000000000000000..73022aad6833621762a0ac2aa388b882f1aa619f GIT binary patch literal 41 ucmV~$K>+|D2m`>sZKj|SXMpP;!8