xref: /minix/minix/tests/test32.c (revision 83133719)
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