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