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 __FBSDID("$FreeBSD: src/usr.bin/tar/test/test_copy.c,v 1.2 2008/05/26 17:10:10 kientzle Exp $"); 27 28 static void 29 create_tree(void) 30 { 31 char buff[260]; 32 char buff2[260]; 33 int i; 34 int fd; 35 36 assertEqualInt(0, mkdir("original", 0775)); 37 chdir("original"); 38 assertEqualInt(0, mkdir("f", 0775)); 39 assertEqualInt(0, mkdir("l", 0775)); 40 assertEqualInt(0, mkdir("m", 0775)); 41 assertEqualInt(0, mkdir("s", 0775)); 42 assertEqualInt(0, mkdir("d", 0775)); 43 44 for (i = 0; i < 200; i++) { 45 buff[0] = 'f'; 46 buff[1] = '/'; 47 /* Create a file named "f/abcdef..." */ 48 buff[i + 2] = 'a' + (i % 26); 49 buff[i + 3] = '\0'; 50 fd = open(buff, O_CREAT | O_WRONLY, 0644); 51 assert(fd >= 0); 52 assertEqualInt(i + 3, write(fd, buff, strlen(buff))); 53 close(fd); 54 55 /* Create a link named "l/abcdef..." to the above. */ 56 strcpy(buff2, buff); 57 buff2[0] = 'l'; 58 assertEqualInt(0, link(buff, buff2)); 59 60 /* Create a link named "m/abcdef..." to the above. */ 61 strcpy(buff2, buff); 62 buff2[0] = 'm'; 63 assertEqualInt(0, link(buff, buff2)); 64 65 /* Create a symlink named "s/abcdef..." to the above. */ 66 strcpy(buff2 + 3, buff); 67 buff[0] = 's'; 68 buff2[0] = '.'; 69 buff2[1] = '.'; 70 buff2[2] = '/'; 71 assertEqualInt(0, symlink(buff2, buff)); 72 73 /* Create a dir named "d/abcdef...". */ 74 buff[0] = 'd'; 75 assertEqualInt(0, mkdir(buff, 0775)); 76 } 77 78 chdir(".."); 79 } 80 81 #define LIMIT_NONE 0 82 #define LIMIT_USTAR 1 83 84 static void 85 verify_tree(int limit) 86 { 87 struct stat st, st2; 88 char filename[260]; 89 char name1[260]; 90 char name2[260]; 91 char contents[260]; 92 int i, j, r; 93 int fd; 94 int len; 95 const char *p, *dp; 96 DIR *d; 97 struct dirent *de; 98 99 /* Generate the names we know should be there and verify them. */ 100 for (i = 1; i < 200; i++) { 101 /* Generate a base name of the correct length. */ 102 for (j = 0; j < i; ++j) 103 filename[j] = 'a' + (j % 26); 104 #if 0 105 for (n = i; n > 0; n /= 10) 106 filename[--j] = '0' + (n % 10); 107 #endif 108 filename[i] = '\0'; 109 110 /* Verify a file named "f/abcdef..." */ 111 strcpy(name1, "f/"); 112 strcat(name1, filename); 113 if (limit != LIMIT_USTAR || strlen(filename) <= 100) { 114 fd = open(name1, O_RDONLY); 115 failure("Couldn't open \"%s\": %s", 116 name1, strerror(errno)); 117 if (assert(fd >= 0)) { 118 len = read(fd, contents, i + 10); 119 close(fd); 120 assertEqualInt(len, i + 2); 121 /* Verify contents of 'contents' */ 122 contents[len] = '\0'; 123 failure("Each test file contains its own name"); 124 assertEqualString(name1, contents); 125 /* stat() for dev/ino for next check */ 126 assertEqualInt(0, lstat(name1, &st)); 127 } 128 } 129 130 /* 131 * ustar allows 100 chars for links, and we have 132 * "original/" as part of the name, so the link 133 * names here can't exceed 91 chars. 134 */ 135 strcpy(name2, "l/"); 136 strcat(name2, filename); 137 if (limit != LIMIT_USTAR || strlen(name2) <= 100) { 138 /* Verify hardlink "l/abcdef..." */ 139 assertEqualInt(0, (r = lstat(name2, &st2))); 140 if (r == 0) { 141 assertEqualInt(st2.st_dev, st.st_dev); 142 assertEqualInt(st2.st_ino, st.st_ino); 143 } 144 145 /* Verify hardlink "m_abcdef..." */ 146 name2[0] = 'm'; 147 assertEqualInt(0, (r = lstat(name2, &st2))); 148 if (r == 0) { 149 assertEqualInt(st2.st_dev, st.st_dev); 150 assertEqualInt(st2.st_ino, st.st_ino); 151 } 152 } 153 154 /* 155 * Symlink text doesn't include the 'original/' prefix, 156 * so the limit here is 100 characters. 157 */ 158 /* Verify symlink "s/abcdef..." */ 159 strcpy(name2, "../s/"); 160 strcat(name2, filename); 161 if (limit != LIMIT_USTAR || strlen(name2) <= 100) { 162 /* This is a symlink. */ 163 failure("Couldn't stat %s (length %d)", 164 filename, strlen(filename)); 165 if (assertEqualInt(0, lstat(name2 + 3, &st2))) { 166 assert(S_ISLNK(st2.st_mode)); 167 /* This is a symlink to the file above. */ 168 failure("Couldn't stat %s", name2 + 3); 169 if (assertEqualInt(0, stat(name2 + 3, &st2))) { 170 assertEqualInt(st2.st_dev, st.st_dev); 171 assertEqualInt(st2.st_ino, st.st_ino); 172 } 173 } 174 } 175 176 /* Verify dir "d/abcdef...". */ 177 strcpy(name1, "d/"); 178 strcat(name1, filename); 179 if (limit != LIMIT_USTAR || strlen(filename) < 100) { 180 /* This is a dir. */ 181 failure("Couldn't stat %s (length %d)", 182 name1, strlen(filename)); 183 if (assertEqualInt(0, lstat(name1, &st2))) { 184 if (assert(S_ISDIR(st2.st_mode))) { 185 /* TODO: opendir/readdir this 186 * directory and make sure 187 * it's empty. 188 */ 189 } 190 } 191 } 192 } 193 194 /* Now make sure nothing is there that shouldn't be. */ 195 for (dp = "dflms"; *dp != '\0'; ++dp) { 196 char dir[2]; 197 dir[0] = *dp; dir[1] = '\0'; 198 d = opendir(dir); 199 while ((de = readdir(d)) != NULL) { 200 p = de->d_name; 201 switch(dp[0]) { 202 case 'l': case 'm': 203 if (limit == LIMIT_USTAR) { 204 failure("strlen(p) = %d", strlen(p)); 205 assert(strlen(p) <= 100); 206 } 207 case 'd': 208 if (limit == LIMIT_USTAR) { 209 failure("strlen(p)=%d", strlen(p)); 210 assert(strlen(p) < 100); 211 } 212 case 'f': case 's': 213 if (limit == LIMIT_USTAR) { 214 failure("strlen(p)=%d", strlen(p)); 215 assert(strlen(p) < 101); 216 } 217 /* Our files have very particular filename patterns. */ 218 if (p[0] != '.' || (p[1] != '.' && p[1] != '\0')) { 219 for (i = 0; p[i] != '\0' && i < 200; i++) { 220 failure("i=%d, p[i]='%c' 'a'+(i%%26)='%c'", i, p[i], 'a' + (i % 26)); 221 assertEqualInt(p[i], 'a' + (i % 26)); 222 } 223 assert(p[i] == '\0'); 224 } 225 break; 226 case '.': 227 assert(p[1] == '\0' || (p[1] == '.' && p[2] == '\0')); 228 break; 229 default: 230 failure("File %s shouldn't be here", p); 231 assert(0); 232 } 233 } 234 closedir(d); 235 } 236 } 237 238 static void 239 copy_basic(void) 240 { 241 int r; 242 243 assertEqualInt(0, mkdir("plain", 0775)); 244 assertEqualInt(0, chdir("plain")); 245 246 /* 247 * Use the tar program to create an archive. 248 */ 249 r = systemf("%s cf archive -C ../original f d l m s >pack.out 2>pack.err", 250 testprog); 251 failure("Error invoking \"%s cf\"", testprog); 252 assertEqualInt(r, 0); 253 254 /* Verify that nothing went to stdout or stderr. */ 255 assertEmptyFile("pack.err"); 256 assertEmptyFile("pack.out"); 257 258 /* 259 * Use tar to unpack the archive into another directory. 260 */ 261 r = systemf("%s xf archive >unpack.out 2>unpack.err", testprog); 262 failure("Error invoking %s xf archive", testprog); 263 assertEqualInt(r, 0); 264 265 /* Verify that nothing went to stdout or stderr. */ 266 assertEmptyFile("unpack.err"); 267 assertEmptyFile("unpack.out"); 268 269 verify_tree(LIMIT_NONE); 270 assertEqualInt(0, chdir("..")); 271 } 272 273 static void 274 copy_ustar(void) 275 { 276 const char *target = "ustar"; 277 int r; 278 279 assertEqualInt(0, mkdir(target, 0775)); 280 assertEqualInt(0, chdir(target)); 281 282 /* 283 * Use the tar program to create an archive. 284 */ 285 r = systemf("%s cf archive --format=ustar -C ../original f d l m s >pack.out 2>pack.err", 286 testprog); 287 failure("Error invoking \"%s cf archive --format=ustar\"", testprog); 288 assertEqualInt(r, 0); 289 290 /* Verify that nothing went to stdout. */ 291 assertEmptyFile("pack.out"); 292 /* Stderr is non-empty, since there are a bunch of files 293 * with filenames too long to archive. */ 294 295 /* 296 * Use tar to unpack the archive into another directory. 297 */ 298 r = systemf("%s xf archive >unpack.out 2>unpack.err", testprog); 299 failure("Error invoking %s xf archive", testprog); 300 assertEqualInt(r, 0); 301 302 /* Verify that nothing went to stdout or stderr. */ 303 assertEmptyFile("unpack.err"); 304 assertEmptyFile("unpack.out"); 305 306 chdir("original"); 307 verify_tree(LIMIT_USTAR); 308 chdir("../.."); 309 } 310 311 DEFINE_TEST(test_copy) 312 { 313 int oldumask; 314 315 oldumask = umask(0); 316 317 create_tree(); /* Create sample files in "original" dir. */ 318 319 /* Test simple "tar -c | tar -x" pipeline copy. */ 320 copy_basic(); 321 322 /* Same, but constrain to ustar format. */ 323 copy_ustar(); 324 325 umask(oldumask); 326 } 327