rename test: Add comments.
[gnulib.git] / tests / test-rename.h
1 /* Test of rename() function.
2    Copyright (C) 2009, 2010 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 /* This file is designed to test both rename(a,b) and
18    renameat(AT_FDCWD,a,AT_FDCWD,b).  FUNC is the function to test.
19    Assumes that BASE and ASSERT are already defined, and that
20    appropriate headers are already included.  If PRINT, warn before
21    skipping symlink tests with status 77.  */
22
23 static int
24 test_rename (int (*func) (char const *, char const *), bool print)
25 {
26   /* Setup.  */
27   struct stat st;
28   int fd = creat (BASE "file", 0600);
29   ASSERT (0 <= fd);
30   ASSERT (write (fd, "hi", 2) == 2);
31   ASSERT (close (fd) == 0);
32   ASSERT (mkdir (BASE "dir", 0700) == 0);
33
34   /* Files present here:
35        {BASE}file
36        {BASE}dir/
37    */
38
39   /* Obvious errors.  */
40
41   { /* Missing source.  */
42     {
43       errno = 0;
44       ASSERT (func (BASE "missing", BASE "missing") == -1);
45       ASSERT (errno == ENOENT);
46     }
47     {
48       errno = 0;
49       ASSERT (func (BASE "missing/", BASE "missing") == -1);
50       ASSERT (errno == ENOENT);
51     }
52     {
53       errno = 0;
54       ASSERT (func (BASE "missing", BASE "missing/") == -1);
55       ASSERT (errno == ENOENT);
56     }
57   }
58   { /* Empty operand.  */
59     {
60       errno = 0;
61       ASSERT (func ("", BASE "missing") == -1);
62       ASSERT (errno == ENOENT);
63     }
64     {
65       errno = 0;
66       ASSERT (func (BASE "file", "") == -1);
67       ASSERT (errno == ENOENT);
68     }
69     {
70       errno = 0;
71       ASSERT (func (BASE "", "") == -1);
72       ASSERT (errno == ENOENT);
73     }
74   }
75
76   /* Files.  */
77
78   { /* Trailing slash.  */
79     {
80       errno = 0;
81       ASSERT (func (BASE "file", BASE "file2/") == -1);
82       ASSERT (errno == ENOENT || errno == ENOTDIR);
83     }
84     {
85       errno = 0;
86       ASSERT (func (BASE "file/", BASE "file2") == -1);
87       ASSERT (errno == ENOTDIR);
88     }
89     {
90       errno = 0;
91       ASSERT (stat (BASE "file2", &st) == -1);
92       ASSERT (errno == ENOENT);
93     }
94   }
95   { /* Simple rename.  */
96     ASSERT (func (BASE "file", BASE "file2") == 0);
97     errno = 0;
98     ASSERT (stat (BASE "file", &st) == -1);
99     ASSERT (errno == ENOENT);
100     memset (&st, 0, sizeof st);
101     ASSERT (stat (BASE "file2", &st) == 0);
102     ASSERT (st.st_size == 2);
103   }
104   /* Files present here:
105        {BASE}file2
106        {BASE}dir/
107    */
108   { /* Overwrite.  */
109     ASSERT (close (creat (BASE "file", 0600)) == 0);
110     errno = 0;
111     ASSERT (func (BASE "file2", BASE "file/") == -1);
112     ASSERT (errno == ENOTDIR);
113     ASSERT (func (BASE "file2", BASE "file") == 0);
114     memset (&st, 0, sizeof st);
115     ASSERT (stat (BASE "file", &st) == 0);
116     ASSERT (st.st_size == 2);
117     errno = 0;
118     ASSERT (stat (BASE "file2", &st) == -1);
119     ASSERT (errno == ENOENT);
120   }
121   /* Files present here:
122        {BASE}file
123        {BASE}dir/
124    */
125
126   /* Directories.  */
127
128   { /* Simple rename.  */
129     {
130       ASSERT (func (BASE "dir", BASE "dir2/") == 0);
131       errno = 0;
132       ASSERT (stat (BASE "dir", &st) == -1);
133       ASSERT (errno == ENOENT);
134       ASSERT (stat (BASE "dir2", &st) == 0);
135     }
136     /* Files present here:
137          {BASE}file
138          {BASE}dir2/
139      */
140     {
141       ASSERT (func (BASE "dir2/", BASE "dir") == 0);
142       ASSERT (stat (BASE "dir", &st) == 0);
143       errno = 0;
144       ASSERT (stat (BASE "dir2", &st) == -1);
145       ASSERT (errno == ENOENT);
146     }
147     /* Files present here:
148          {BASE}file
149          {BASE}dir/
150      */
151     {
152       ASSERT (func (BASE "dir", BASE "dir2") == 0);
153       errno = 0;
154       ASSERT (stat (BASE "dir", &st) == -1);
155       ASSERT (errno == ENOENT);
156       ASSERT (stat (BASE "dir2", &st) == 0);
157     }
158     /* Files present here:
159          {BASE}file
160          {BASE}dir2/
161      */
162     { /* Empty onto empty.  */
163       ASSERT (mkdir (BASE "dir", 0700) == 0);
164       /* Files present here:
165            {BASE}file
166            {BASE}dir/
167            {BASE}dir2/
168        */
169       ASSERT (func (BASE "dir2", BASE "dir") == 0);
170       /* Files present here:
171            {BASE}file
172            {BASE}dir/
173        */
174       ASSERT (mkdir (BASE "dir2", 0700) == 0);
175       /* Files present here:
176            {BASE}file
177            {BASE}dir/
178            {BASE}dir2/
179        */
180       ASSERT (func (BASE "dir2", BASE "dir/") == 0);
181       /* Files present here:
182            {BASE}file
183            {BASE}dir/
184        */
185       ASSERT (mkdir (BASE "dir2", 0700) == 0);
186       /* Files present here:
187            {BASE}file
188            {BASE}dir/
189            {BASE}dir2/
190        */
191       ASSERT (func (BASE "dir2/", BASE "dir") == 0);
192       /* Files present here:
193            {BASE}file
194            {BASE}dir/
195        */
196       ASSERT (mkdir (BASE "dir2", 0700) == 0);
197     }
198     /* Files present here:
199          {BASE}file
200          {BASE}dir/
201          {BASE}dir2/
202      */
203     { /* Empty onto full.  */
204       ASSERT (close (creat (BASE "dir/file", 0600)) == 0);
205       /* Files present here:
206            {BASE}file
207            {BASE}dir/
208            {BASE}dir/file
209            {BASE}dir2/
210        */
211       {
212         errno = 0;
213         ASSERT (func (BASE "dir2", BASE "dir") == -1);
214         ASSERT (errno == EEXIST || errno == ENOTEMPTY);
215       }
216       {
217         errno = 0;
218         ASSERT (func (BASE "dir2/", BASE "dir") == -1);
219         ASSERT (errno == EEXIST || errno == ENOTEMPTY);
220       }
221       {
222         errno = 0;
223         ASSERT (func (BASE "dir2", BASE "dir/") == -1);
224         ASSERT (errno == EEXIST || errno == ENOTEMPTY);
225       }
226     }
227     { /* Full onto empty.  */
228       ASSERT (func (BASE "dir", BASE "dir2") == 0);
229       errno = 0;
230       ASSERT (stat (BASE "dir", &st) == -1);
231       ASSERT (errno == ENOENT);
232       ASSERT (stat (BASE "dir2/file", &st) == 0);
233       /* Files present here:
234            {BASE}file
235            {BASE}dir2/
236            {BASE}dir2/file
237        */
238       ASSERT (mkdir (BASE "dir", 0700) == 0);
239       /* Files present here:
240            {BASE}file
241            {BASE}dir/
242            {BASE}dir2/
243            {BASE}dir2/file
244        */
245       {
246         ASSERT (func (BASE "dir2/", BASE "dir") == 0);
247         ASSERT (stat (BASE "dir/file", &st) == 0);
248         errno = 0;
249         ASSERT (stat (BASE "dir2", &st) == -1);
250         ASSERT (errno == ENOENT);
251       }
252       /* Files present here:
253            {BASE}file
254            {BASE}dir/
255            {BASE}dir/file
256        */
257       ASSERT (mkdir (BASE "dir2", 0700) == 0);
258       /* Files present here:
259            {BASE}file
260            {BASE}dir/
261            {BASE}dir/file
262            {BASE}dir2/
263        */
264       {
265         ASSERT (func (BASE "dir", BASE "dir2/") == 0);
266         errno = 0;
267         ASSERT (stat (BASE "dir", &st) == -1);
268         ASSERT (errno == ENOENT);
269         ASSERT (stat (BASE "dir2/file", &st) == 0);
270       }
271       /* Files present here:
272            {BASE}file
273            {BASE}dir2/
274            {BASE}dir2/file
275        */
276       ASSERT (unlink (BASE "dir2/file") == 0);
277     }
278     /* Files present here:
279          {BASE}file
280          {BASE}dir2/
281      */
282     { /* Reject trailing dot.  */
283       {
284         errno = 0;
285         ASSERT (func (BASE "dir2", BASE "dir/.") == -1);
286         ASSERT (errno == EINVAL || errno == ENOENT);
287       }
288       ASSERT (mkdir (BASE "dir", 0700) == 0);
289       /* Files present here:
290            {BASE}file
291            {BASE}dir/
292            {BASE}dir2/
293        */
294       {
295         errno = 0;
296         ASSERT (func (BASE "dir2", BASE "dir/.") == -1);
297         ASSERT (errno == EINVAL || errno == EBUSY || errno == EISDIR
298                 || errno == ENOTEMPTY);
299       }
300       {
301         errno = 0;
302         ASSERT (func (BASE "dir2/.", BASE "dir") == -1);
303         ASSERT (errno == EINVAL || errno == EBUSY);
304       }
305       ASSERT (rmdir (BASE "dir") == 0);
306       /* Files present here:
307            {BASE}file
308            {BASE}dir2/
309        */
310       {
311         errno = 0;
312         ASSERT (func (BASE "dir2", BASE "dir/.//") == -1);
313         ASSERT (errno == EINVAL || errno == ENOENT);
314       }
315       ASSERT (mkdir (BASE "dir", 0700) == 0);
316       /* Files present here:
317            {BASE}file
318            {BASE}dir/
319            {BASE}dir2/
320        */
321       {
322         errno = 0;
323         ASSERT (func (BASE "dir2", BASE "dir/.//") == -1);
324         ASSERT (errno == EINVAL || errno == EBUSY || errno == EISDIR
325                 || errno == ENOTEMPTY);
326       }
327       {
328         errno = 0;
329         ASSERT (func (BASE "dir2/.//", BASE "dir") == -1);
330         ASSERT (errno == EINVAL || errno == EBUSY);
331       }
332       ASSERT (rmdir (BASE "dir2") == 0);
333       /* Files present here:
334            {BASE}file
335            {BASE}dir/
336        */
337     }
338     { /* Move into subdir.  */
339       {
340         errno = 0;
341         ASSERT (func (BASE "dir", BASE "dir/sub") == -1);
342         ASSERT (errno == EINVAL || errno == EACCES);
343       }
344       {
345         errno = 0;
346         ASSERT (stat (BASE "dir/sub", &st) == -1);
347         ASSERT (errno == ENOENT);
348       }
349       ASSERT (mkdir (BASE "dir/sub", 0700) == 0);
350       /* Files present here:
351            {BASE}file
352            {BASE}dir/
353            {BASE}dir/sub/
354        */
355       {
356         errno = 0;
357         ASSERT (func (BASE "dir", BASE "dir/sub") == -1);
358         ASSERT (errno == EINVAL);
359         ASSERT (stat (BASE "dir/sub", &st) == 0);
360       }
361       ASSERT (rmdir (BASE "dir/sub") == 0);
362     }
363   }
364   /* Files present here:
365        {BASE}file
366        {BASE}dir/
367    */
368
369   /* Mixing file and directory.  */
370
371   {
372     { /* File onto dir.  */
373       {
374         errno = 0;
375         ASSERT (func (BASE "file", BASE "dir") == -1);
376         ASSERT (errno == EISDIR || errno == ENOTDIR);
377       }
378       {
379         errno = 0;
380         ASSERT (func (BASE "file", BASE "dir/") == -1);
381         ASSERT (errno == EISDIR || errno == ENOTDIR);
382       }
383     }
384     { /* Dir onto file.  */
385       {
386         errno = 0;
387         ASSERT (func (BASE "dir", BASE "file") == -1);
388         ASSERT (errno == ENOTDIR);
389       }
390       {
391         errno = 0;
392         ASSERT (func (BASE "dir/", BASE "file") == -1);
393         ASSERT (errno == ENOTDIR);
394       }
395     }
396   }
397
398   /* Hard links.  */
399
400   { /* File onto self.  */
401     ASSERT (func (BASE "file", BASE "file") == 0);
402     memset (&st, 0, sizeof st);
403     ASSERT (stat (BASE "file", &st) == 0);
404     ASSERT (st.st_size == 2);
405   }
406   /* Files present here:
407        {BASE}file
408        {BASE}dir/
409    */
410   { /* Empty dir onto self.  */
411     ASSERT (func (BASE "dir", BASE "dir") == 0);
412     ASSERT (stat (BASE "dir", &st) == 0);
413   }
414   /* Files present here:
415        {BASE}file
416        {BASE}dir/
417    */
418   ASSERT (close (creat (BASE "dir/file", 0600)) == 0);
419   /* Files present here:
420        {BASE}file
421        {BASE}dir/
422        {BASE}dir/file
423    */
424   { /* Full dir onto self.  */
425     ASSERT (func (BASE "dir", BASE "dir") == 0);
426   }
427   ASSERT (unlink (BASE "dir/file") == 0);
428   /* Files present here:
429        {BASE}file
430        {BASE}dir/
431    */
432   {
433     /*  Not all file systems support link.  Mingw doesn't have
434         reliable st_nlink on hard links, but our implementation does
435         fail with EPERM on poor file systems, and we can detect the
436         inferior stat() via st_ino.  Cygwin 1.5.x copies rather than
437         links files on those file systems, but there, st_nlink and
438         st_ino are reliable.  */
439     int ret = link (BASE "file", BASE "file2");
440     if (!ret)
441       {
442         memset (&st, 0, sizeof st);
443         ASSERT (stat (BASE "file2", &st) == 0);
444         if (st.st_ino && st.st_nlink != 2)
445           {
446             ASSERT (unlink (BASE "file2") == 0);
447             errno = EPERM;
448             ret = -1;
449           }
450       }
451     if (ret == -1)
452       {
453         /* If the device does not support hard links, errno is
454            EPERM on Linux, EOPNOTSUPP on FreeBSD.  */
455         switch (errno)
456           {
457           case EPERM:
458           case EOPNOTSUPP:
459             if (print)
460               fputs ("skipping test: "
461                      "hard links not supported on this file system\n",
462                      stderr);
463             ASSERT (unlink (BASE "file") == 0);
464             ASSERT (rmdir (BASE "dir") == 0);
465             return 77;
466           default:
467             perror ("link");
468             return 1;
469           }
470       }
471     ASSERT (ret == 0);
472   }
473   /* Files present here:
474        {BASE}file
475        {BASE}file2       (hard link to file)
476        {BASE}dir/
477    */
478   { /* File onto hard link.  */
479     ASSERT (func (BASE "file", BASE "file2") == 0);
480     memset (&st, 0, sizeof st);
481     ASSERT (stat (BASE "file", &st) == 0);
482     ASSERT (st.st_size == 2);
483     memset (&st, 0, sizeof st);
484     ASSERT (stat (BASE "file2", &st) == 0);
485     ASSERT (st.st_size == 2);
486   }
487   /* Files present here:
488        {BASE}file
489        {BASE}file2
490        {BASE}dir/
491    */
492   ASSERT (unlink (BASE "file2") == 0);
493   /* Files present here:
494        {BASE}file
495        {BASE}dir/
496    */
497
498   /* Symlinks.  */
499
500   if (symlink (BASE "file", BASE "link1"))
501     {
502       if (print)
503         fputs ("skipping test: symlinks not supported on this file system\n",
504                stderr);
505       ASSERT (unlink (BASE "file") == 0);
506       ASSERT (rmdir (BASE "dir") == 0);
507       return 77;
508     }
509   /* Files present here:
510        {BASE}file
511        {BASE}link1 -> {BASE}file
512        {BASE}dir/
513    */
514   { /* Simple rename.  */
515     ASSERT (func (BASE "link1", BASE "link2") == 0);
516     ASSERT (stat (BASE "file", &st) == 0);
517     errno = 0;
518     ASSERT (lstat (BASE "link1", &st) == -1);
519     ASSERT (errno == ENOENT);
520     memset (&st, 0, sizeof st);
521     ASSERT (lstat (BASE "link2", &st) == 0);
522     ASSERT (S_ISLNK (st.st_mode));
523   }
524   /* Files present here:
525        {BASE}file
526        {BASE}link2 -> {BASE}file
527        {BASE}dir/
528    */
529   { /* Overwrite.  */
530     ASSERT (symlink (BASE "nowhere", BASE "link1") == 0);
531     /* Files present here:
532          {BASE}file
533          {BASE}link1 -> {BASE}nowhere
534          {BASE}link2 -> {BASE}file
535          {BASE}dir/
536      */
537     {
538       ASSERT (func (BASE "link2", BASE "link1") == 0);
539       memset (&st, 0, sizeof st);
540       ASSERT (stat (BASE "link1", &st) == 0);
541       ASSERT (st.st_size == 2);
542       errno = 0;
543       ASSERT (lstat (BASE "link2", &st) == -1);
544       ASSERT (errno == ENOENT);
545     }
546   }
547   /* Files present here:
548        {BASE}file
549        {BASE}link1 -> {BASE}file
550        {BASE}dir/
551    */
552   { /* Symlink loop.  */
553     ASSERT (symlink (BASE "link2", BASE "link2") == 0);
554     /* Files present here:
555          {BASE}file
556          {BASE}link1 -> {BASE}file
557          {BASE}link2 -> {BASE}link2
558          {BASE}dir/
559      */
560     {
561       ASSERT (func (BASE "link2", BASE "link2") == 0);
562     }
563     {
564       errno = 0;
565       ASSERT (func (BASE "link2/", BASE "link2") == -1);
566       ASSERT (errno == ELOOP || errno == ENOTDIR);
567     }
568     ASSERT (func (BASE "link2", BASE "link3") == 0);
569     /* Files present here:
570          {BASE}file
571          {BASE}link1 -> {BASE}file
572          {BASE}link3 -> {BASE}link2
573          {BASE}dir/
574      */
575     ASSERT (unlink (BASE "link3") == 0);
576   }
577   /* Files present here:
578        {BASE}file
579        {BASE}link1 -> {BASE}file
580        {BASE}dir/
581    */
582   { /* Dangling link.  */
583     ASSERT (symlink (BASE "nowhere", BASE "link2") == 0);
584     /* Files present here:
585          {BASE}file
586          {BASE}link1 -> {BASE}file
587          {BASE}link2 -> {BASE}nowhere
588          {BASE}dir/
589      */
590     {
591       ASSERT (func (BASE "link2", BASE "link3") == 0);
592       errno = 0;
593       ASSERT (lstat (BASE "link2", &st) == -1);
594       ASSERT (errno == ENOENT);
595       memset (&st, 0, sizeof st);
596       ASSERT (lstat (BASE "link3", &st) == 0);
597     }
598   }
599   /* Files present here:
600        {BASE}file
601        {BASE}link1 -> {BASE}file
602        {BASE}link3 -> {BASE}nowhere
603        {BASE}dir/
604    */
605   { /* Trailing slash on dangling.  */
606     {
607       errno = 0;
608       ASSERT (func (BASE "link3/", BASE "link2") == -1);
609       ASSERT (errno == ENOENT || errno == ENOTDIR);
610     }
611     {
612       errno = 0;
613       ASSERT (func (BASE "link3", BASE "link2/") == -1);
614       ASSERT (errno == ENOENT || errno == ENOTDIR);
615     }
616     {
617       errno = 0;
618       ASSERT (lstat (BASE "link2", &st) == -1);
619       ASSERT (errno == ENOENT);
620     }
621     memset (&st, 0, sizeof st);
622     ASSERT (lstat (BASE "link3", &st) == 0);
623   }
624   /* Files present here:
625        {BASE}file
626        {BASE}link1 -> {BASE}file
627        {BASE}link3 -> {BASE}nowhere
628        {BASE}dir/
629    */
630   { /* Trailing slash on link to file.  */
631     {
632       errno = 0;
633       ASSERT (func (BASE "link1/", BASE "link2") == -1);
634       ASSERT (errno == ENOTDIR);
635     }
636     {
637       errno = 0;
638       ASSERT (func (BASE "link1", BASE "link3/") == -1);
639       ASSERT (errno == ENOENT || errno == ENOTDIR);
640     }
641   }
642   /* Files present here:
643        {BASE}file
644        {BASE}link1 -> {BASE}file
645        {BASE}link3 -> {BASE}nowhere
646        {BASE}dir/
647    */
648
649   /* Mixing symlink and file.  */
650
651   { /* File onto link.  */
652     ASSERT (close (creat (BASE "file2", 0600)) == 0);
653     /* Files present here:
654          {BASE}file
655          {BASE}file2
656          {BASE}link1 -> {BASE}file
657          {BASE}link3 -> {BASE}nowhere
658          {BASE}dir/
659      */
660     {
661       ASSERT (func (BASE "file2", BASE "link3") == 0);
662       errno = 0;
663       ASSERT (stat (BASE "file2", &st) == -1);
664       ASSERT (errno == ENOENT);
665       memset (&st, 0, sizeof st);
666       ASSERT (lstat (BASE "link3", &st) == 0);
667       ASSERT (S_ISREG (st.st_mode));
668     }
669     /* Files present here:
670          {BASE}file
671          {BASE}link1 -> {BASE}file
672          {BASE}link3
673          {BASE}dir/
674      */
675     ASSERT (unlink (BASE "link3") == 0);
676   }
677   /* Files present here:
678        {BASE}file
679        {BASE}link1 -> {BASE}file
680        {BASE}dir/
681    */
682   { /* Link onto file.  */
683     ASSERT (symlink (BASE "nowhere", BASE "link2") == 0);
684     /* Files present here:
685          {BASE}file
686          {BASE}link1 -> {BASE}file
687          {BASE}link2 -> {BASE}nowhere
688          {BASE}dir/
689      */
690     ASSERT (close (creat (BASE "file2", 0600)) == 0);
691     /* Files present here:
692          {BASE}file
693          {BASE}file2
694          {BASE}link1 -> {BASE}file
695          {BASE}link2 -> {BASE}nowhere
696          {BASE}dir/
697      */
698     {
699       ASSERT (func (BASE "link2", BASE "file2") == 0);
700       errno = 0;
701       ASSERT (lstat (BASE "link2", &st) == -1);
702       ASSERT (errno == ENOENT);
703       memset (&st, 0, sizeof st);
704       ASSERT (lstat (BASE "file2", &st) == 0);
705       ASSERT (S_ISLNK (st.st_mode));
706     }
707     /* Files present here:
708          {BASE}file
709          {BASE}file2 -> {BASE}nowhere
710          {BASE}link1 -> {BASE}file
711          {BASE}dir/
712      */
713     ASSERT (unlink (BASE "file2") == 0);
714   }
715   /* Files present here:
716        {BASE}file
717        {BASE}link1 -> {BASE}file
718        {BASE}dir/
719    */
720   { /* Trailing slash.  */
721     {
722       errno = 0;
723       ASSERT (func (BASE "file/", BASE "link1") == -1);
724       ASSERT (errno == ENOTDIR);
725     }
726     {
727       errno = 0;
728       ASSERT (func (BASE "file", BASE "link1/") == -1);
729       ASSERT (errno == ENOTDIR || errno == ENOENT);
730     }
731     {
732       errno = 0;
733       ASSERT (func (BASE "link1/", BASE "file") == -1);
734       ASSERT (errno == ENOTDIR);
735     }
736     {
737       errno = 0;
738       ASSERT (func (BASE "link1", BASE "file/") == -1);
739       ASSERT (errno == ENOTDIR || errno == ENOENT);
740       memset (&st, 0, sizeof st);
741       ASSERT (lstat (BASE "file", &st) == 0);
742       ASSERT (S_ISREG (st.st_mode));
743       memset (&st, 0, sizeof st);
744       ASSERT (lstat (BASE "link1", &st) == 0);
745       ASSERT (S_ISLNK (st.st_mode));
746     }
747   /* Files present here:
748        {BASE}file
749        {BASE}link1 -> {BASE}file
750        {BASE}dir/
751    */
752
753   /* Mixing symlink and directory.  */
754
755   { /* Directory onto link.  */
756     {
757       errno = 0;
758       ASSERT (func (BASE "dir", BASE "link1") == -1);
759       ASSERT (errno == ENOTDIR);
760     }
761     {
762       errno = 0;
763       ASSERT (func (BASE "dir/", BASE "link1") == -1);
764       ASSERT (errno == ENOTDIR);
765     }
766     {
767       errno = 0;
768       ASSERT (func (BASE "dir", BASE "link1/") == -1);
769       ASSERT (errno == ENOTDIR);
770     }
771   }
772   { /* Link onto directory.  */
773     {
774       errno = 0;
775       ASSERT (func (BASE "link1", BASE "dir") == -1);
776       ASSERT (errno == EISDIR || errno == ENOTDIR);
777     }
778     {
779       errno = 0;
780       ASSERT (func (BASE "link1", BASE "dir/") == -1);
781       ASSERT (errno == EISDIR || errno == ENOTDIR);
782     }
783     {
784       errno = 0;
785       ASSERT (func (BASE "link1/", BASE "dir") == -1);
786       ASSERT (errno == ENOTDIR);
787       memset (&st, 0, sizeof st);
788       ASSERT (lstat (BASE "link1", &st) == 0);
789       ASSERT (S_ISLNK (st.st_mode));
790       memset (&st, 0, sizeof st);
791       ASSERT (lstat (BASE "dir", &st) == 0);
792       ASSERT (S_ISDIR (st.st_mode));
793     }
794   }
795   /* Files present here:
796        {BASE}file
797        {BASE}link1 -> {BASE}file
798        {BASE}dir/
799    */
800
801   /* POSIX requires rename("link-to-dir/","other") to rename "dir" and
802      leave "link-to-dir" dangling, but GNU rejects this.  POSIX
803      requires rename("dir","dangling/") to create the directory so
804      that "dangling/" now resolves, but GNU rejects this.  While we
805      prefer GNU behavior, we don't enforce it.  However, we do test
806      that the system either follows POSIX in both cases, or follows
807      GNU.  */
808   {
809     int result;
810     ASSERT (symlink (BASE "dir2", BASE "link2") == 0);
811     /* Files present here:
812          {BASE}file
813          {BASE}link1 -> {BASE}file
814          {BASE}link2 -> {BASE}dir2
815          {BASE}dir/
816      */
817     errno = 0;
818     result = func (BASE "dir", BASE "link2/");
819     if (result == 0)
820       {
821         /* POSIX.  */
822         errno = 0;
823         ASSERT (lstat (BASE "dir", &st) == -1);
824         ASSERT (errno == ENOENT);
825         memset (&st, 0, sizeof st);
826         ASSERT (lstat (BASE "dir2", &st) == 0);
827         ASSERT (S_ISDIR (st.st_mode));
828         memset (&st, 0, sizeof st);
829         ASSERT (lstat (BASE "link2", &st) == 0);
830         ASSERT (S_ISLNK (st.st_mode));
831         /* Files present here:
832              {BASE}file
833              {BASE}link1 -> {BASE}file
834              {BASE}link2 -> {BASE}dir2
835              {BASE}dir2/
836          */
837         {
838           ASSERT (func (BASE "link2/", BASE "dir") == 0);
839           memset (&st, 0, sizeof st);
840           ASSERT (lstat (BASE "dir", &st) == 0);
841           ASSERT (S_ISDIR (st.st_mode));
842           errno = 0;
843           ASSERT (lstat (BASE "dir2", &st) == -1);
844           ASSERT (errno == ENOENT);
845           memset (&st, 0, sizeof st);
846           ASSERT (lstat (BASE "link2", &st) == 0);
847           ASSERT (S_ISLNK (st.st_mode));
848         }
849       }
850     else
851       {
852         /* GNU.  */
853         ASSERT (result == -1);
854         ASSERT (errno == ENOTDIR);
855         memset (&st, 0, sizeof st);
856         ASSERT (lstat (BASE "dir", &st) == 0);
857         ASSERT (S_ISDIR (st.st_mode));
858         errno = 0;
859         ASSERT (lstat (BASE "dir2", &st) == -1);
860         ASSERT (errno == ENOENT);
861         memset (&st, 0, sizeof st);
862         ASSERT (lstat (BASE "link2", &st) == 0);
863         ASSERT (S_ISLNK (st.st_mode));
864         ASSERT (unlink (BASE "link2") == 0);
865         ASSERT (symlink (BASE "dir", BASE "link2") == 0);
866         /* Files present here:
867              {BASE}file
868              {BASE}link1 -> {BASE}file
869              {BASE}link2 -> {BASE}dir
870              {BASE}dir/
871          */
872         errno = 0; /* OpenBSD notices that link2/ and dir are the same.  */
873         result = func (BASE "link2/", BASE "dir");
874         if (result) /* GNU/Linux rejects attempts to use link2/.  */
875           {
876             ASSERT (result == -1);
877             ASSERT (errno == ENOTDIR);
878           }
879         memset (&st, 0, sizeof st);
880         ASSERT (lstat (BASE "dir", &st) == 0);
881         ASSERT (S_ISDIR (st.st_mode));
882         errno = 0;
883         ASSERT (lstat (BASE "dir2", &st) == -1);
884         ASSERT (errno == ENOENT);
885         memset (&st, 0, sizeof st);
886         ASSERT (lstat (BASE "link2", &st) == 0);
887         ASSERT (S_ISLNK (st.st_mode));
888       }
889   }
890   /* Files present here:
891        {BASE}file
892        {BASE}link1 -> {BASE}file
893        {BASE}link2 -> {BASE}dir or {BASE}dir2
894        {BASE}dir/
895    */
896
897   /* Clean up.  */
898   ASSERT (unlink (BASE "file") == 0);
899   ASSERT (rmdir (BASE "dir") == 0);
900   ASSERT (unlink (BASE "link1") == 0);
901   ASSERT (unlink (BASE "link2") == 0);
902
903   return 0;
904 }