1 /* test28: mkdir() rmdir() Author: Jan-Mark Wams (jms@cs.vu.nl) */ 2 3 /* 4 ** Not tested readonly file systems (EROFS.) 5 ** Not tested fs full (ENOSPC.) 6 ** Not really tested EBUSY. 7 ** Not tested unlinking busy directories. 8 */ 9 10 #include <sys/types.h> 11 #include <sys/stat.h> 12 #include <sys/wait.h> 13 #include <string.h> 14 #include <stdlib.h> 15 #include <unistd.h> 16 #include <fcntl.h> 17 #include <errno.h> 18 #include <dirent.h> 19 #include <limits.h> 20 #include <time.h> 21 #include <stdio.h> 22 23 int max_error = 4; 24 #include "common.h" 25 26 #define ITERATIONS 2 27 28 29 #define DIRENT0 ((struct dirent *) NULL) 30 31 #define System(cmd) if (system(cmd) != 0) printf("``%s'' failed\n", cmd) 32 #define Chdir(dir) if (chdir(dir) != 0) printf("Can't goto %s\n", dir) 33 34 int subtest = 1; 35 int superuser; 36 char *MaxName; /* Name of maximum length */ 37 char MaxPath[PATH_MAX]; 38 char *ToLongName; /* Name of maximum +1 length */ 39 char ToLongPath[PATH_MAX + 1]; 40 41 void test28a(void); 42 void test28c(void); 43 void test28b(void); 44 void makelongnames(void); 45 46 int main(int argc, char *argv[]) 47 { 48 int i, m = 0xFFFF; 49 50 sync(); 51 if (argc == 2) m = atoi(argv[1]); 52 start(28); 53 superuser = (getuid() == 0); 54 makelongnames(); 55 umask(0000); /* no umask */ 56 57 for (i = 0; i < ITERATIONS; i++) { 58 if (m & 0001) test28a(); 59 if (m & 0002) test28b(); 60 if (m & 0004) test28c(); 61 } 62 quit(); 63 64 return(-1); /* Unreachable */ 65 } 66 67 void test28a() 68 { 69 int mode; /* used in for loop */ 70 struct stat st; 71 time_t time1, time2; 72 DIR *dirp; 73 struct dirent *dep; 74 int dot = 0, dotdot = 0; 75 76 subtest = 1; 77 78 System("rm -rf foo /tmp/foo");/* clean up junk */ 79 80 /* Check relative path names */ 81 if (mkdir("./foo", 0777) != 0) e(1); /* make a dir foo */ 82 if (mkdir("./foo/bar", 0777) != 0) e(2); /* make foo/bar */ 83 if (rmdir("foo/bar") != 0) e(3); /* delete bar */ 84 if (mkdir("foo/../foo/bar", 0777) != 0) e(4); /* make bar again */ 85 if (rmdir("./foo/bar") != 0) e(5); /* and remove again */ 86 87 /* Foo should be empty (ie. contain only "." and ".." */ 88 if ((dirp = opendir("foo")) == (DIR *) NULL) e(6); /* open foo */ 89 if ((dep = readdir(dirp)) == DIRENT0) e(7); /* get first entry */ 90 if (strcmp(dep->d_name, ".") == 0) dot += 1; /* record what it is */ 91 if (strcmp(dep->d_name, "..") == 0) dotdot += 1; 92 if ((dep = readdir(dirp)) == DIRENT0) e(8); /* get second entry */ 93 if (strcmp(dep->d_name, ".") == 0) dot += 1; /* record again */ 94 if (strcmp(dep->d_name, "..") == 0) dotdot += 1; 95 if ((dep = readdir(dirp)) != DIRENT0) e(9); /* no 3d entry */ 96 if (dot == 1 && dotdot != 1) e(10); /* only . and .. */ 97 if (closedir(dirp) != 0) e(11); /* close foo */ 98 if (rmdir("./foo") != 0) e(12); /* remove dir foo */ 99 100 /* Check absolute path names */ 101 if (mkdir("/tmp/foo", 0777) != 0) e(13); 102 if (mkdir("/tmp/foo/bar", 0777) != 0) e(14); 103 if (rmdir("/tmp/foo/bar") != 0) e(15); /* make some dirs */ 104 if (rmdir("/tmp/foo") != 0) e(16); 105 106 /* Check the mode arument for mkdir() */ 107 for (mode = 0; mode <= 0777; mode++) { 108 if (mkdir("foo", mode) != 0) e(17); /* make foo */ 109 if (stat("foo", &st) != 0) e(18); 110 if ((st.st_mode & 0777) != mode) e(19); /* check it's mode */ 111 if (rmdir("foo") != 0) e(20); /* and remove it */ 112 } 113 114 /* Check the stat */ 115 time(&time1); 116 while (time1 >= time((time_t *)0)) 117 ; 118 if (mkdir("foo", 0765) != 0) e(21); /* make foo */ 119 if (stat("foo", &st) != 0) e(22); 120 time(&time2); 121 while (time2 >= time((time_t *)0)) 122 ; 123 time(&time2); 124 if (st.st_nlink != 2) e(23); 125 if (st.st_uid != geteuid()) e(24); 126 if (st.st_gid != getegid()) e(25); 127 if (st.st_size < 0) e(26); 128 if ((st.st_mode & 0777) != 0765) e(27); 129 if (st.st_atime <= time1) e(28); 130 if (st.st_atime >= time2) e(29); 131 if (st.st_ctime <= time1) e(30); 132 if (st.st_ctime >= time2) e(31); 133 if (st.st_mtime <= time1) e(32); 134 if (st.st_mtime >= time2) e(33); 135 136 /* Check if parent is updated */ 137 if (stat(".", &st) != 0) e(34); 138 time(&time2); 139 while (time2 >= time((time_t *)0)) 140 ; 141 time(&time2); 142 if (st.st_ctime <= time1) e(35); 143 if (st.st_ctime >= time2) e(36); 144 if (st.st_mtime <= time1) e(37); 145 if (st.st_mtime >= time2) e(38); 146 time(&time1); 147 while (time1 >= time((time_t *)0)) 148 ; 149 if (rmdir("foo") != 0) e(39); 150 if (stat(".", &st) != 0) e(40); 151 time(&time2); 152 while (time2 >= time((time_t *)0)) 153 ; 154 time(&time2); 155 if (st.st_ctime <= time1) e(41); 156 if (st.st_ctime >= time2) e(42); 157 if (st.st_mtime <= time1) e(43); 158 if (st.st_mtime >= time2) e(44); 159 } 160 161 void test28b() 162 { /* Test critical values. */ 163 struct stat st; 164 DIR *dirp; 165 struct dirent *dep; 166 int fd; /* file descriptor */ 167 int other = 0, dot = 0, dotdot = 0; /* dirent counters */ 168 int r; /* Intermediate result */ 169 int rmdir_result; /* tmp var */ 170 int stat_loc, does_truncate; 171 172 subtest = 2; 173 174 System("rm -rf ../DIR_28/*"); 175 176 /* Check funny but valid path names */ 177 if (mkdir("/../../..////.//../tmp/foo/", 0777) != 0) e(1); 178 if (mkdir("/tmp/foo//////..//foo//../foo/bar/", 0777) != 0) e(2); 179 if (rmdir("///tmp/..//tmp/foo/bar//../..//foo/bar") != 0) e(3); 180 if (mkdir("///tmp/foo/foobar//", 0777) != 0) e(4); 181 if (rmdir("/tmp/foo/foobar//") != 0) e(5); 182 if (rmdir("/.././/././/tmp/foo///////////////") != 0) e(6); 183 if (rmdir("/tmp/foo") != -1) e(7); /* try again */ 184 185 /* Test max path ed. */ 186 if (mkdir(MaxName, 0777) != 0) e(9); /* make dir MaxName */ 187 if (rmdir(MaxName) != 0) e(10); /* and remove it */ 188 MaxPath[strlen(MaxPath) - 2] = '/'; /* convert MaxPath */ 189 MaxPath[strlen(MaxPath) - 1] = 'a'; /* to ././.../a */ 190 if (mkdir(MaxPath, 0777) != 0) e(11); /* it should be */ 191 if (rmdir(MaxPath) != 0) e(12); /* ok */ 192 193 /* Test too long path ed. */ 194 does_truncate = does_fs_truncate(); 195 r = mkdir(ToLongName, 0777); 196 if (does_truncate ) { 197 /* FS truncates names, mkdir should've worked */ 198 if (r != 0) e(13); /* Try ToLongName */ 199 if (rmdir(ToLongName) != 0) e(14); /* and remove it */ 200 } else { 201 /* Too long, should've failed with ENAMETOOLONG */ 202 if (r == 0) e(15); 203 if (errno != ENAMETOOLONG) e(16); 204 } 205 ToLongPath[strlen(ToLongPath) - 2] = '/'; /* make ToLongPath */ 206 ToLongPath[strlen(ToLongPath) - 1] = 'a'; /* contain ././.../a */ 207 if (mkdir(ToLongPath, 0777) != -1) e(17); /* it should */ 208 if (errno != ENAMETOOLONG) e(18); /* not be ok */ 209 if (rmdir(ToLongPath) != -1) e(19); 210 if (errno != ENAMETOOLONG) e(20); 211 212 if (mkdir("foo", 0777) != 0) e(21); 213 System("touch foo/xyzzy"); 214 215 /* Test if rmdir removes only empty dirs */ 216 if (rmdir("foo") != -1) e(29);/* not empty */ 217 if (errno != EEXIST && errno != ENOTEMPTY) e(30); 218 /* Test if rmdir removes a dir with an empty file (it shouldn't.) */ 219 System("rm -rf foo"); /* cleanup */ 220 if (mkdir("foo", 0777) != 0) e(31); 221 System("> foo/empty"); /* > empty */ 222 if (rmdir("foo") != -1) e(32);/* not empty */ 223 if (errno != EEXIST && errno != ENOTEMPTY) e(33); 224 if (unlink("foo/empty") != 0) e(34); /* rm empty */ 225 226 /* See what happens if foo is linked. */ 227 #if 0 228 if (superuser) { 229 if (link("foo", "footoo") != 0) e(35); /* foo still */ 230 if (rmdir("footoo") != 0) e(36); /* exist */ 231 if (chdir("footoo") != -1) e(37); /* footoo */ 232 if (errno != ENOENT) e(38); /* is gone */ 233 } 234 #endif 235 #if defined(__minix) && defined(_NETBSD_SOURCE) 236 /* Some implementations might allow users to link directories. */ 237 if (!superuser) { 238 if (link("foo", "footoo") != -1) e(39); 239 if (errno != EPERM) e(40); 240 if (unlink("foo") != -1) e(41); 241 if (errno != EPERM) e(42); 242 } 243 #endif 244 245 /* See if ".." and "." are removed from the dir, and if it is 246 * unwriteable 247 * Note, we can not remove any files in the PARENT 248 * process, because this 249 * will make readdir unpredicatble. (see 250 * 1003.1 page 84 line 30.) However 251 * removal of the directory is 252 * not specified in the standard. 253 */ 254 System("rm -rf /tmp/sema[12].07"); 255 switch (fork()) { 256 case -1: printf("Can't fork\n"); break; 257 258 case 0: 259 alarm(20); 260 if ((fd = open("foo", O_RDONLY)) <= 2) e(43); /* open */ 261 if ((dirp = opendir("foo")) == (DIR *) NULL) e(44); /* opendir */ 262 /* UpA downB */ 263 system(">/tmp/sema1.07; while test -f /tmp/sema1.07; do sleep 1;done"); 264 while ((dep = readdir(dirp)) != DIRENT0) { 265 if (strcmp(dep->d_name, "..") == 0) 266 dotdot += 1; 267 else if (strcmp(dep->d_name, ".") == 0) 268 dot += 1; 269 else 270 other += 1; 271 } 272 if (dotdot != 0) e(45); /* no entrys */ 273 if (dot != 0) e(46); /* shoul be */ 274 if (other != 0) e(47); /* left or */ 275 276 /* No new files (entrys) are allowed on foo */ 277 if (creat("foo/nono", 0777) != -1) e(48); /* makeable */ 278 if (closedir(dirp) != 0) e(49); /* close foo */ 279 system("while test ! -f /tmp/sema2.07; do sleep 1; done"); /* downA */ 280 System("rm -f /tmp/sema2.07"); /* clean up */ 281 282 /* Foo still exist, so we should be able to get a fstat */ 283 if (fstat(fd, &st) != 0) e(50); 284 if (st.st_nlink != (nlink_t) 0) e(51); /* 0 left */ 285 if (close(fd) != 0) e(52); /* last one */ 286 exit(0); 287 288 default: 289 system("while test ! -f /tmp/sema1.07; do sleep 1; done"); /* downA */ 290 if (rmdir("foo") != 0) e(53); /* cleanerup */ 291 System("rm -f /tmp/sema1.07"); /* upB */ 292 if (chdir("foo") != -1) e(54); /* it should */ 293 if (errno != ENOENT) e(55); /* be gone */ 294 System("> /tmp/sema2.07"); /* upA */ 295 if (wait(&stat_loc) == -1) e(56); 296 if (stat_loc != 0) e(57); 297 } 298 299 /* See if foo isn't accessible any more */ 300 if (chdir("foo") != -1) e(58); 301 if (errno != ENOENT) e(59); 302 303 /* Let's see if we can get a EBUSSY..... */ 304 if (mkdir("foo", 0777) != 0) e(60); /* mkdir foo */ 305 System("rm -f /tmp/sema.07"); /* unness */ 306 switch (fork()) { 307 case -1: printf("Can't fork\n"); break; 308 case 0: 309 alarm(20); 310 if (chdir("foo") != 0) e(61); /* child goes */ 311 System("> /tmp/sema.07"); /* upA */ 312 system("while test -f /tmp/sema.07; do sleep 1; done"); /* downB */ 313 sleep(1); 314 exit(0); 315 default: 316 system("while test ! -f /tmp/sema.07; do sleep 1; done"); /* downA */ 317 rmdir_result = rmdir("foo"); /* try remove */ 318 if (rmdir_result == -1) { /* if it failed */ 319 if (errno != EBUSY) e(62); /* foo is busy */ 320 } else { 321 if (rmdir_result != 0) e(63); 322 if (rmdir("foo") != -1) e(64); /* not removable */ 323 if (errno != ENOENT) e(65); /* again. */ 324 if (chdir("foo") != -1) e(66); /* we can't go */ 325 if (errno != ENOENT) e(67); /* there any more */ 326 if (mkdir("foo", 0777) != 0) e(68); /* we can remake foo */ 327 } 328 System("rm -f /tmp/sema.07"); /* upB */ 329 if (wait(&stat_loc) == -1) e(69); 330 if (stat_loc != 0) e(70); 331 } 332 if (rmdir("foo") != 0) e(71); /* clean up */ 333 } 334 335 void test28c() 336 { /* Test error handeling. */ 337 subtest = 3; 338 339 System("rm -rf ../DIR_28/*"); 340 System("rm -rf foo /tmp/foo");/* clean up junk */ 341 342 /* Test common errors */ 343 if (mkdir("foo", 0777) != 0) e(1); /* mkdir shouldn't fail */ 344 if (mkdir("foo", 0777) != -1) e(2); /* should fail the 2d time */ 345 if (errno != EEXIST) e(3); /* because it exists already */ 346 if (rmdir("foo") != 0) e(4); /* rmdir shouldn't fail */ 347 if (rmdir("foo") != -1) e(5); /* but it should now because */ 348 if (errno != ENOENT) e(6); /* it's gone the 1st time */ 349 /* Test on access etc. */ 350 if (mkdir("foo", 0777) != 0) e(7); 351 if (mkdir("foo/bar", 0777) != 0) e(8); 352 if (!superuser) { 353 System("chmod 677 foo");/* make foo inaccesable */ 354 if (mkdir("foo/foo", 0777) != -1) e(9); 355 if (errno != EACCES) e(10); 356 if (rmdir("foo/bar") != -1) e(11); 357 if (errno != EACCES) e(12); 358 System("chmod 577 foo");/* make foo unwritable */ 359 if (mkdir("foo/foo", 0777) != -1) e(13); 360 if (errno != EACCES) e(14); 361 if (rmdir("foo/bar") != -1) e(15); 362 if (errno != EACCES) e(16); 363 System("chmod 777 foo");/* make foo full accessable */ 364 } 365 if (rmdir("foo/bar") != 0) e(17); /* bar should be removable */ 366 if (mkdir("foo/no/foo", 0777) != -1) e(18); /* Note: "no" doesn't exist */ 367 if (errno != ENOENT) e(19); 368 if (mkdir("", 0777) != -1) e(20); /* empty string isn't ok */ 369 if (errno != ENOENT) e(21); 370 if (rmdir("") != -1) e(22); /* empty string isn't ok */ 371 if (errno != ENOENT) e(23); 372 System("> foo/no"); /* make a file "no" */ 373 if (mkdir("foo/no/foo", 0777) != -1) e(24); 374 if (errno != ENOTDIR) e(25); /* note: "no" is not a a dir */ 375 if (rmdir("foo/no/foo") != -1) e(26); 376 if (errno != ENOTDIR) e(27); 377 System("rm -rf foo"); /* clean up */ 378 } 379 380 void makelongnames() 381 { 382 register int i; 383 int max_name_length; 384 385 max_name_length = name_max("."); /* Aka NAME_MAX, but not every FS supports 386 * the same length, hence runtime check */ 387 MaxName = malloc(max_name_length + 1); 388 ToLongName = malloc(max_name_length + 1 + 1); /* Name of maximum +1 length */ 389 memset(MaxName, 'a', max_name_length); 390 MaxName[max_name_length] = '\0'; 391 392 for (i = 0; i < PATH_MAX - 1; i++) { /* idem path */ 393 MaxPath[i++] = '.'; 394 MaxPath[i] = '/'; 395 } 396 MaxPath[PATH_MAX - 1] = '\0'; 397 398 strcpy(ToLongName, MaxName); /* copy them Max to ToLong */ 399 strcpy(ToLongPath, MaxPath); 400 401 ToLongName[max_name_length] = 'a'; 402 ToLongName[max_name_length+1] = '\0';/* extend ToLongName by one too many */ 403 ToLongPath[PATH_MAX - 1] = '/'; 404 ToLongPath[PATH_MAX] = '\0'; /* inc ToLongPath by one */ 405 } 406