1 /* test32: rename() Author: Jan-Mark Wams (jms@cs.vu.nl) */ 2 3 #include <sys/types.h> 4 #include <sys/stat.h> 5 #include <sys/wait.h> 6 #include <stdlib.h> 7 #include <unistd.h> 8 #include <string.h> 9 #include <fcntl.h> 10 #include <limits.h> 11 #include <errno.h> 12 #include <time.h> 13 #include <stdio.h> 14 15 int max_error = 4; 16 #include "common.h" 17 18 #define ITERATIONS 2 19 20 #define System(cmd) if (system(cmd) != 0) printf("``%s'' failed\n", cmd) 21 #define Chdir(dir) if (chdir(dir) != 0) printf("Can't goto %s\n", dir) 22 #define Stat(a,b) if (stat(a,b) != 0) printf("Can't stat %s\n", a) 23 #define Creat(f) if (close(creat(f,0777))!=0) printf("Can't creat %s\n",f) 24 25 26 int superuser; 27 char *MaxName; /* Name of maximum length */ 28 char MaxPath[PATH_MAX]; /* Same for path */ 29 char *ToLongName; /* Name of maximum +1 length */ 30 char ToLongPath[PATH_MAX + 1]; /* Same for path, both too long */ 31 32 void test32a(void); 33 void test32b(void); 34 void test32c(void); 35 void makelongnames(void); 36 37 int main(int argc, char *argv[]) 38 { 39 int i, m = 0xFFFF; 40 41 start(32); 42 43 if (argc == 2) m = atoi(argv[1]); 44 makelongnames(); 45 superuser = (geteuid() == 0); 46 47 for (i = 0; i < ITERATIONS; i++) { 48 if (m & 0001) test32a(); 49 if (m & 0002) test32b(); 50 if (m & 0004) test32c(); 51 } 52 quit(); 53 54 return(-1); /* Unreachable */ 55 } 56 57 #define BUF_SIZE 1024 58 59 void test32a() 60 { /* Test normal operation. */ 61 struct stat st1, st2; 62 int fd1, fd2; 63 time_t time1, time2, time3; 64 char buf[BUF_SIZE]; 65 66 subtest = 1; 67 System("rm -rf ../DIR_32/*"); 68 69 /* Test normal file renamal. */ 70 System("echo haha > old"); 71 Stat("old", &st1); 72 if (rename("old", "new") != 0) e(1); 73 Stat("new", &st2); 74 75 /* The status of new should be the same as old. */ 76 if (st1.st_dev != st2.st_dev) e(2); 77 if (st1.st_ino != st2.st_ino) e(3); 78 if (st1.st_mode != st2.st_mode) e(4); 79 if (st1.st_nlink != st2.st_nlink) e(5); 80 if (st1.st_uid != st2.st_uid) e(6); 81 if (st1.st_gid != st2.st_gid) e(7); 82 if (st1.st_rdev != st2.st_rdev) e(8); 83 if (st1.st_size != st2.st_size) e(9); 84 if (st1.st_atime != st2.st_atime) e(10); 85 if (st1.st_mtime != st2.st_mtime) e(11); 86 if (st1.st_ctime != st2.st_ctime) e(12); 87 88 /* If new exists, it should be removed. */ 89 System("ln new new2"); 90 System("echo foobar > old"); 91 Stat("old", &st1); 92 if (rename("old", "new") != 0) e(13); 93 Stat("new", &st2); 94 95 /* The status of new should be the same as old. */ 96 if (st1.st_dev != st2.st_dev) e(14); 97 if (st1.st_ino != st2.st_ino) e(15); 98 if (st1.st_mode != st2.st_mode) e(16); 99 if (st1.st_nlink != st2.st_nlink) e(17); 100 if (st1.st_uid != st2.st_uid) e(18); 101 if (st1.st_gid != st2.st_gid) e(19); 102 if (st1.st_rdev != st2.st_rdev) e(20); 103 if (st1.st_size != st2.st_size) e(21); 104 if (st1.st_atime != st2.st_atime) e(22); 105 if (st1.st_mtime != st2.st_mtime) e(23); 106 if (st1.st_ctime != st2.st_ctime) e(24); 107 108 /* The link count on new2 should be one since the old new is removed. */ 109 Stat("new2", &st1); 110 if (st1.st_nlink != 1) e(25); 111 112 /* Check if status for "." is updated. */ 113 System("> OLD"); 114 Stat(".", &st1); 115 time(&time1); 116 while (time1 == time((time_t *)0)) 117 ; 118 time(&time2); 119 rename("OLD", "NEW"); 120 Stat(".", &st2); 121 time(&time3); 122 while (time3 == time((time_t *)0)) 123 ; 124 time(&time3); 125 if (st1.st_ctime >= st2.st_ctime) e(26); 126 if (st1.st_mtime >= st2.st_mtime) e(27); 127 if (st1.st_ctime > time1) e(28); 128 if (st1.st_mtime > time1) e(29); 129 if (st1.st_ctime >= time2) e(30); 130 if (st1.st_mtime >= time2) e(31); 131 if (st2.st_ctime < time2) e(32); 132 if (st2.st_mtime < time2) e(33); 133 if (st2.st_ctime >= time3) e(34); 134 if (st2.st_mtime >= time3) e(35); 135 136 /* If the new file is removed while it's open it should still be 137 * readable. */ 138 System("rm -rf new NEW old OLD"); 139 if ((fd1 = creat("new", 0644)) != 3) e(36); 140 if (write(fd1, "Hi there! I am Sammy the string", 33) != 33) e(37); 141 if (close(fd1) != 0) e(38); 142 if ((fd1 = creat("old", 0644)) != 3) e(39); 143 if (write(fd1, "I need a new name", 18) != 18) e(40); 144 if (close(fd1) != 0) e(41); 145 if ((fd1 = open("new", O_RDONLY)) != 3) e(42); 146 if ((fd2 = open("new", O_RDONLY)) != 4) e(43); 147 if (rename("old", "new") != 0) e(44); 148 if (stat("old", &st1) == 0) e(45); 149 if (close(fd1) != 0) e(46); 150 if ((fd1 = open("new", O_RDONLY)) != 3) e(47); 151 if (read(fd2, buf, BUF_SIZE) != 33) e(48); 152 if (strcmp(buf, "Hi there! I am Sammy the string") != 0) e(49); 153 if (read(fd1, buf, BUF_SIZE) != 18) e(50); 154 if (strcmp(buf, "I need a new name") != 0) e(51); 155 if (close(fd1) != 0) e(52); 156 if (close(fd2) != 0) e(53); 157 } 158 159 void test32b() 160 { 161 char MaxPath2[PATH_MAX]; /* Same for path */ 162 char MaxName2[NAME_MAX + 1]; /* Name of maximum length */ 163 int fd, i; 164 int stat_loc; 165 struct stat st; 166 167 subtest = 2; 168 System("rm -rf ../DIR_32/*"); 169 170 /* Test maximal file name length. */ 171 if ((fd = creat(MaxName, 0777)) != 3) e(1); 172 if (close(fd) != 0) e(2); 173 strcpy(MaxName2, MaxName); 174 MaxName2[strlen(MaxName2) - 1] ^= 1; 175 if (rename(MaxName, MaxName2) != 0) e(3); 176 if (rename(MaxName2, MaxName) != 0) e(4); 177 MaxName2[strlen(MaxName2) - 1] ^= 2; 178 if (rename(MaxName, MaxName2) != 0) e(5); 179 MaxPath[strlen(MaxPath) - 2] = '/'; 180 MaxPath[strlen(MaxPath) - 1] = 'a'; /* make ././.../a */ 181 if ((fd = creat(MaxPath, 0777)) != 3) e(6); 182 if (close(fd) != 0) e(7); 183 strcpy(MaxPath2, MaxPath); 184 MaxPath2[strlen(MaxPath2) - 1] ^= 1; 185 if (rename(MaxPath, MaxPath2) != 0) e(8); 186 if (rename(MaxPath2, MaxPath) != 0) e(9); 187 MaxPath2[strlen(MaxPath2) - 1] ^= 2; 188 if (rename(MaxPath, MaxPath2) != 0) e(10); 189 MaxPath[strlen(MaxPath) - 1] = '/'; /* make ././.../a */ 190 191 /* Test if linked files are renamable. */ 192 System("> foo; ln foo bar"); 193 if (rename("foo", "bar") != 0) e(11); 194 if (rename("bar", "foo") != 0) e(12); 195 System("ln foo foobar"); 196 if (rename("foo", "foobar") != 0) e(13); 197 if (rename("bar", "foobar") != 0) e(14); 198 199 /* Since the same files have the same links.... */ 200 if (rename("bar", "bar") != 0) e(15); 201 if (rename("foo", "foo") != 0) e(16); 202 if (rename("foobar", "foobar") != 0) e(17); 203 204 /* In ``rename(old, new)'' with new existing, there is always an new 205 * entry. */ 206 for (i = 0; i < 5; i++) { 207 System("echo old > old"); 208 System("echo news > new"); 209 switch (fork()) { 210 case -1: printf("Can't fork\n"); break; 211 case 0: 212 alarm(20); 213 sleep(1); 214 rename("old", "new"); 215 exit(0); 216 default: 217 while (stat("old", &st) == 0) 218 if (stat("new", &st) != 0) e(18); 219 wait(&stat_loc); 220 if (stat_loc != 0) e(19); /* Alarm? */ 221 } 222 } 223 224 } 225 226 void test32c() 227 { /* Test behavior under error contitions. */ 228 struct stat st1; 229 int stat_loc; 230 231 subtest = 3; 232 System("rm -rf ../DIR_32/*"); 233 234 /* Test if we have access. */ 235 system("chmod 777 noacc nowrite > /dev/null 2>/dev/null"); 236 system("rm -rf noacc nowrite"); 237 238 System("mkdir noacc nowrite"); 239 System("> noacc/file"); 240 System("> nowrite/file"); 241 System("> file"); 242 System("chmod 677 noacc"); 243 System("chmod 577 nowrite"); 244 if (!superuser) { 245 if (rename("noacc/file", "nono") != -1) e(1); 246 if (errno != EACCES) e(2); 247 if (rename("nowrite/file", "nono") != -1) e(3); 248 if (errno != EACCES) e(4); 249 if (rename("file", "noacc/file") != -1) e(5); 250 if (errno != EACCES) e(6); 251 if (rename("file", "nowrite/file") != -1) e(7); 252 if (errno != EACCES) e(8); 253 } 254 if (superuser) { 255 /* Super user heeft access. */ 256 if (rename("noacc/file", "noacc/yes") != 0) e(9); 257 if (rename("nowrite/file", "nowrite/yes") != 0) e(10); 258 if (rename("file", "yes") != 0) e(11); 259 if (rename("noacc/yes", "noacc/file") != 0) e(12); 260 if (rename("nowrite/yes", "nowrite/file") != 0) e(13); 261 if (rename("yes", "file") != 0) e(14); 262 } 263 System("chmod 777 noacc nowrite"); 264 265 /* If rmdir() doesn't remove a directory, rename() shouldn't eighter. */ 266 System("mkdir newdir olddir"); 267 System("rm -rf /tmp/sema.11[ab]"); 268 switch (fork()) { 269 case -1: printf("Can't fork\n"); break; 270 case 0: 271 alarm(20); 272 switch (fork()) { 273 case -1: printf("Can't fork\n"); break; 274 case 0: 275 /* Child A. */ 276 alarm(20); 277 if (chdir("newdir") != 0) e(15); 278 Creat("/tmp/sema.11a"); 279 while (stat("/tmp/sema.11a", &st1) == 0) sleep(1); 280 exit(0); 281 default: 282 wait(&stat_loc); 283 if (stat_loc != 0) e(16); /* Alarm? */ 284 } 285 286 /* Child B. */ 287 if (chdir("olddir") != 0) e(17); 288 Creat("/tmp/sema.11b"); 289 while (stat("/tmp/sema.11b", &st1) == 0) sleep(1); 290 exit(0); 291 default: 292 /* Wait for child A. It will keep ``newdir'' bussy. */ 293 while (stat("/tmp/sema.11a", &st1) == -1) sleep(1); 294 if (rmdir("newdir") == -1) { 295 if (rename("olddir", "newdir") != -1) e(18); 296 if (errno != EBUSY) e(19); 297 } 298 (void) unlink("/tmp/sema.11a"); 299 300 /* Wait for child B. It will keep ``olddir'' bussy. */ 301 while (stat("/tmp/sema.11b", &st1) == -1) sleep(1); 302 if (rmdir("olddir") == -1) { 303 if (rename("olddir", "newdir") != -1) e(20); 304 if (errno != EBUSY) e(21); 305 } 306 (void) unlink("/tmp/sema.11b"); 307 wait(&stat_loc); 308 if (stat_loc != 0) e(22); /* Alarm? */ 309 } 310 } 311 312 void makelongnames() 313 { 314 register int i; 315 int max_name_length; 316 317 max_name_length = name_max("."); /* Aka NAME_MAX, but not every FS supports 318 * the same length, hence runtime check */ 319 MaxName = malloc(max_name_length + 1); 320 ToLongName = malloc(max_name_length + 1 + 1); /* Name of maximum +1 length */ 321 memset(MaxName, 'a', max_name_length); 322 MaxName[max_name_length] = '\0'; 323 324 for (i = 0; i < PATH_MAX - 1; i++) { /* idem path */ 325 MaxPath[i++] = '.'; 326 MaxPath[i] = '/'; 327 } 328 MaxPath[PATH_MAX - 1] = '\0'; 329 330 strcpy(ToLongName, MaxName); /* copy them Max to ToLong */ 331 strcpy(ToLongPath, MaxPath); 332 333 ToLongName[max_name_length] = 'a'; 334 ToLongName[max_name_length+1] = '\0';/* extend ToLongName by one too many */ 335 ToLongPath[PATH_MAX - 1] = '/'; 336 ToLongPath[PATH_MAX] = '\0'; /* inc ToLongPath by one */ 337 } 338