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