1 /*- 2 * Copyright (c) 2003-2007 Tim Kientzle 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 #include "test.h" 26 27 static void test_linkify_tar(void) 28 { 29 struct archive_entry *entry, *e2; 30 struct archive_entry_linkresolver *resolver; 31 32 /* Initialize the resolver. */ 33 assert(NULL != (resolver = archive_entry_linkresolver_new())); 34 archive_entry_linkresolver_set_strategy(resolver, 35 ARCHIVE_FORMAT_TAR_USTAR); 36 37 /* Create an entry with only 1 link and try to linkify it. */ 38 assert(NULL != (entry = archive_entry_new())); 39 archive_entry_set_pathname(entry, "test1"); 40 archive_entry_set_ino(entry, 1); 41 archive_entry_set_dev(entry, 2); 42 archive_entry_set_nlink(entry, 1); 43 archive_entry_set_size(entry, 10); 44 archive_entry_linkify(resolver, &entry, &e2); 45 46 /* Shouldn't have been changed. */ 47 assert(e2 == NULL); 48 assertEqualInt(10, archive_entry_size(entry)); 49 assertEqualString("test1", archive_entry_pathname(entry)); 50 51 /* Now, try again with an entry that has 2 links. */ 52 archive_entry_set_pathname(entry, "test2"); 53 archive_entry_set_nlink(entry, 2); 54 archive_entry_set_ino(entry, 2); 55 archive_entry_linkify(resolver, &entry, &e2); 56 /* Shouldn't be altered, since it wasn't seen before. */ 57 assert(e2 == NULL); 58 assertEqualString("test2", archive_entry_pathname(entry)); 59 assertEqualString(NULL, archive_entry_hardlink(entry)); 60 assertEqualInt(10, archive_entry_size(entry)); 61 62 /* Match again and make sure it does get altered. */ 63 archive_entry_linkify(resolver, &entry, &e2); 64 assert(e2 == NULL); 65 assertEqualString("test2", archive_entry_pathname(entry)); 66 assertEqualString("test2", archive_entry_hardlink(entry)); 67 assertEqualInt(0, archive_entry_size(entry)); 68 69 70 /* Dirs should never be matched as hardlinks, regardless. */ 71 archive_entry_set_pathname(entry, "test3"); 72 archive_entry_set_nlink(entry, 2); 73 archive_entry_set_filetype(entry, AE_IFDIR); 74 archive_entry_set_ino(entry, 3); 75 archive_entry_set_hardlink(entry, NULL); 76 archive_entry_linkify(resolver, &entry, &e2); 77 /* Shouldn't be altered, since it wasn't seen before. */ 78 assert(e2 == NULL); 79 assertEqualString("test3", archive_entry_pathname(entry)); 80 assertEqualString(NULL, archive_entry_hardlink(entry)); 81 82 /* Dir, so it shouldn't get matched. */ 83 archive_entry_linkify(resolver, &entry, &e2); 84 assert(e2 == NULL); 85 assertEqualString("test3", archive_entry_pathname(entry)); 86 assertEqualString(NULL, archive_entry_hardlink(entry)); 87 88 archive_entry_free(entry); 89 archive_entry_linkresolver_free(resolver); 90 } 91 92 static void test_linkify_old_cpio(void) 93 { 94 struct archive_entry *entry, *e2; 95 struct archive_entry_linkresolver *resolver; 96 97 /* Initialize the resolver. */ 98 assert(NULL != (resolver = archive_entry_linkresolver_new())); 99 archive_entry_linkresolver_set_strategy(resolver, 100 ARCHIVE_FORMAT_CPIO_POSIX); 101 102 /* Create an entry with 2 link and try to linkify it. */ 103 assert(NULL != (entry = archive_entry_new())); 104 archive_entry_set_pathname(entry, "test1"); 105 archive_entry_set_ino(entry, 1); 106 archive_entry_set_dev(entry, 2); 107 archive_entry_set_nlink(entry, 2); 108 archive_entry_set_size(entry, 10); 109 archive_entry_linkify(resolver, &entry, &e2); 110 111 /* Shouldn't have been changed. */ 112 assert(e2 == NULL); 113 assertEqualInt(10, archive_entry_size(entry)); 114 assertEqualString("test1", archive_entry_pathname(entry)); 115 116 /* Still shouldn't be matched. */ 117 archive_entry_linkify(resolver, &entry, &e2); 118 assert(e2 == NULL); 119 assertEqualString("test1", archive_entry_pathname(entry)); 120 assertEqualString(NULL, archive_entry_hardlink(entry)); 121 assertEqualInt(10, archive_entry_size(entry)); 122 123 archive_entry_free(entry); 124 archive_entry_linkresolver_free(resolver); 125 } 126 127 static void test_linkify_new_cpio(void) 128 { 129 struct archive_entry *entry, *e2; 130 struct archive_entry_linkresolver *resolver; 131 132 /* Initialize the resolver. */ 133 assert(NULL != (resolver = archive_entry_linkresolver_new())); 134 archive_entry_linkresolver_set_strategy(resolver, 135 ARCHIVE_FORMAT_CPIO_SVR4_NOCRC); 136 137 /* Create an entry with only 1 link and try to linkify it. */ 138 assert(NULL != (entry = archive_entry_new())); 139 archive_entry_set_pathname(entry, "test1"); 140 archive_entry_set_ino(entry, 1); 141 archive_entry_set_dev(entry, 2); 142 archive_entry_set_nlink(entry, 1); 143 archive_entry_set_size(entry, 10); 144 archive_entry_linkify(resolver, &entry, &e2); 145 146 /* Shouldn't have been changed. */ 147 assert(e2 == NULL); 148 assertEqualInt(10, archive_entry_size(entry)); 149 assertEqualString("test1", archive_entry_pathname(entry)); 150 151 /* Now, try again with an entry that has 3 links. */ 152 archive_entry_set_pathname(entry, "test2"); 153 archive_entry_set_nlink(entry, 3); 154 archive_entry_set_ino(entry, 2); 155 archive_entry_linkify(resolver, &entry, &e2); 156 157 /* First time, it just gets swallowed. */ 158 assert(entry == NULL); 159 assert(e2 == NULL); 160 161 /* Match again. */ 162 assert(NULL != (entry = archive_entry_new())); 163 archive_entry_set_pathname(entry, "test3"); 164 archive_entry_set_ino(entry, 2); 165 archive_entry_set_dev(entry, 2); 166 archive_entry_set_nlink(entry, 2); 167 archive_entry_set_size(entry, 10); 168 archive_entry_linkify(resolver, &entry, &e2); 169 170 /* Should get back "test2" and nothing else. */ 171 assertEqualString("test2", archive_entry_pathname(entry)); 172 assertEqualInt(0, archive_entry_size(entry)); 173 archive_entry_free(entry); 174 assert(NULL == e2); 175 archive_entry_free(e2); /* This should be a no-op. */ 176 177 /* Match a third time. */ 178 assert(NULL != (entry = archive_entry_new())); 179 archive_entry_set_pathname(entry, "test4"); 180 archive_entry_set_ino(entry, 2); 181 archive_entry_set_dev(entry, 2); 182 archive_entry_set_nlink(entry, 3); 183 archive_entry_set_size(entry, 10); 184 archive_entry_linkify(resolver, &entry, &e2); 185 186 /* Should get back "test3". */ 187 assertEqualString("test3", archive_entry_pathname(entry)); 188 assertEqualInt(0, archive_entry_size(entry)); 189 190 /* Since "test4" was the last link, should get it back also. */ 191 assertEqualString("test4", archive_entry_pathname(e2)); 192 assertEqualInt(10, archive_entry_size(e2)); 193 194 archive_entry_free(entry); 195 archive_entry_free(e2); 196 archive_entry_linkresolver_free(resolver); 197 } 198 199 DEFINE_TEST(test_link_resolver) 200 { 201 test_linkify_tar(); 202 test_linkify_old_cpio(); 203 test_linkify_new_cpio(); 204 } 205 206 DEFINE_TEST(test_link_resolver_unicode_win) 207 { 208 #if !defined(_WIN32) || defined(__CYGWIN__) 209 skipping("This test is meant to verify unicode string handling" 210 " on Windows with UTF-16 names"); 211 return; 212 #else 213 struct archive_entry *entry, *e2; 214 struct archive_entry_linkresolver *resolver; 215 216 /* Initialize the resolver. */ 217 assert(NULL != (resolver = archive_entry_linkresolver_new())); 218 archive_entry_linkresolver_set_strategy(resolver, 219 ARCHIVE_FORMAT_TAR_USTAR); 220 221 /* Create an entry with a unicode filename and 2 links. */ 222 assert(NULL != (entry = archive_entry_new())); 223 archive_entry_copy_pathname_w(entry, L"\u4f60\u597d.txt"); 224 archive_entry_set_ino(entry, 1); 225 archive_entry_set_dev(entry, 2); 226 archive_entry_set_nlink(entry, 2); 227 archive_entry_set_size(entry, 10); 228 archive_entry_linkify(resolver, &entry, &e2); 229 230 /* Shouldn't be altered, since it wasn't seen before. */ 231 assert(e2 == NULL); 232 assertEqualWString(L"\u4f60\u597d.txt", archive_entry_pathname_w(entry)); 233 assertEqualWString(NULL, archive_entry_hardlink_w(entry)); 234 assertEqualInt(10, archive_entry_size(entry)); 235 236 /* Link to the same file contents, but a new unicode name. */ 237 archive_entry_copy_pathname_w(entry, L"\u518d\u89c1.txt"); 238 archive_entry_linkify(resolver, &entry, &e2); 239 240 /* Size & link path should have changed. */ 241 assert(e2 == NULL); 242 assertEqualWString(L"\u518d\u89c1.txt", archive_entry_pathname_w(entry)); 243 assertEqualWString(L"\u4f60\u597d.txt", archive_entry_hardlink_w(entry)); 244 assertEqualInt(0, archive_entry_size(entry)); 245 246 archive_entry_free(entry); 247 archive_entry_linkresolver_free(resolver); 248 #endif 249 } 250