1 /* Test of rename() function.
2    Copyright (C) 2009-2018 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 <https://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
dentry_exists(const char * filename)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
assert_nonexistent(const char * filename)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
test_rename(int (* func)(char const *,char const *),bool print)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                 || errno == ENOENT /* WSL */);
344       }
345       {
346         errno = 0;
347         ASSERT (func (BASE "dir2/.", BASE "dir") == -1);
348         ASSERT (errno == EINVAL || errno == EBUSY || errno == EEXIST
349                 || errno == ENOENT /* WSL */);
350       }
351       ASSERT (rmdir (BASE "dir") == 0);
352       /* Files present here:
353            {BASE}file
354            {BASE}dir2/
355        */
356       {
357         errno = 0;
358         ASSERT (func (BASE "dir2", BASE "dir/.//") == -1);
359         ASSERT (errno == EINVAL || errno == ENOENT);
360       }
361       ASSERT (mkdir (BASE "dir", 0700) == 0);
362       /* Files present here:
363            {BASE}file
364            {BASE}dir/
365            {BASE}dir2/
366        */
367       {
368         errno = 0;
369         ASSERT (func (BASE "dir2", BASE "dir/.//") == -1);
370         ASSERT (errno == EINVAL || errno == EBUSY || errno == EISDIR
371                 || errno == ENOTEMPTY || errno == EEXIST
372                 || errno == ENOENT /* WSL */);
373       }
374       {
375         errno = 0;
376         ASSERT (func (BASE "dir2/.//", BASE "dir") == -1);
377         ASSERT (errno == EINVAL || errno == EBUSY || errno == EEXIST
378                 || errno == ENOENT /* WSL */);
379       }
380       ASSERT (rmdir (BASE "dir2") == 0);
381       /* Files present here:
382            {BASE}file
383            {BASE}dir/
384        */
385     }
386     { /* Move into subdir.  */
387       {
388         errno = 0;
389         ASSERT (func (BASE "dir", BASE "dir/sub") == -1);
390         ASSERT (errno == EINVAL || errno == EACCES);
391       }
392       {
393         errno = 0;
394         ASSERT (stat (BASE "dir/sub", &st) == -1);
395         ASSERT (errno == ENOENT);
396       }
397       ASSERT (mkdir (BASE "dir/sub", 0700) == 0);
398       /* Files present here:
399            {BASE}file
400            {BASE}dir/
401            {BASE}dir/sub/
402        */
403       {
404         errno = 0;
405         ASSERT (func (BASE "dir", BASE "dir/sub") == -1);
406         ASSERT (errno == EINVAL);
407         ASSERT (stat (BASE "dir/sub", &st) == 0);
408       }
409       ASSERT (rmdir (BASE "dir/sub") == 0);
410     }
411   }
412   /* Files present here:
413        {BASE}file
414        {BASE}dir/
415    */
416 
417   /* Mixing file and directory.  */
418 
419   {
420     { /* File onto dir.  */
421       {
422         errno = 0;
423         ASSERT (func (BASE "file", BASE "dir") == -1);
424         ASSERT (errno == EISDIR || errno == ENOTDIR);
425       }
426       {
427         errno = 0;
428         ASSERT (func (BASE "file", BASE "dir/") == -1);
429         ASSERT (errno == EISDIR || errno == ENOTDIR);
430       }
431     }
432     { /* Dir onto file.  */
433       {
434         errno = 0;
435         ASSERT (func (BASE "dir", BASE "file") == -1);
436         ASSERT (errno == ENOTDIR);
437       }
438       {
439         errno = 0;
440         ASSERT (func (BASE "dir/", BASE "file") == -1);
441         ASSERT (errno == ENOTDIR);
442       }
443     }
444   }
445 
446   /* Hard links.  */
447 
448   { /* File onto self.  */
449     ASSERT (func (BASE "file", BASE "file") == 0);
450     memset (&st, 0, sizeof st);
451     ASSERT (stat (BASE "file", &st) == 0);
452     ASSERT (st.st_size == 2);
453   }
454   /* Files present here:
455        {BASE}file
456        {BASE}dir/
457    */
458   { /* Empty dir onto self.  */
459     ASSERT (func (BASE "dir", BASE "dir") == 0);
460     ASSERT (stat (BASE "dir", &st) == 0);
461   }
462   /* Files present here:
463        {BASE}file
464        {BASE}dir/
465    */
466   ASSERT (close (creat (BASE "dir/file", 0600)) == 0);
467   /* Files present here:
468        {BASE}file
469        {BASE}dir/
470        {BASE}dir/file
471    */
472   { /* Full dir onto self.  */
473     ASSERT (func (BASE "dir", BASE "dir") == 0);
474   }
475   ASSERT (unlink (BASE "dir/file") == 0);
476   /* Files present here:
477        {BASE}file
478        {BASE}dir/
479    */
480   {
481     /*  Not all file systems support link.  Mingw doesn't have
482         reliable st_nlink on hard links, but our implementation does
483         fail with EPERM on poor file systems, and we can detect the
484         inferior stat() via st_ino.  Cygwin 1.5.x copies rather than
485         links files on those file systems, but there, st_nlink and
486         st_ino are reliable.  */
487     int ret = link (BASE "file", BASE "file2");
488     if (!ret)
489       {
490         memset (&st, 0, sizeof st);
491         ASSERT (stat (BASE "file2", &st) == 0);
492         if (st.st_ino && st.st_nlink != 2)
493           {
494             ASSERT (unlink (BASE "file2") == 0);
495             errno = EPERM;
496             ret = -1;
497           }
498       }
499     if (ret == -1)
500       {
501         /* If the device does not support hard links, errno is
502            EPERM on Linux, EOPNOTSUPP on FreeBSD.  */
503         switch (errno)
504           {
505           case EPERM:
506           case EOPNOTSUPP:
507             if (print)
508               fputs ("skipping test: "
509                      "hard links not supported on this file system\n",
510                      stderr);
511             ASSERT (unlink (BASE "file") == 0);
512             ASSERT (rmdir (BASE "dir") == 0);
513             return 77;
514           default:
515             perror ("link");
516             return 1;
517           }
518       }
519     ASSERT (ret == 0);
520   }
521   /* Files present here:
522        {BASE}file
523        {BASE}file2       (hard link to file)
524        {BASE}dir/
525    */
526   { /* File onto hard link.  */
527     ASSERT (func (BASE "file", BASE "file2") == 0);
528     memset (&st, 0, sizeof st);
529     if (stat (BASE "file", &st) != 0)
530       {
531         /* This can happen on NetBSD.  */
532         ASSERT (errno == ENOENT);
533         ASSERT (link (BASE "file2", BASE "file") == 0);
534         ASSERT (stat (BASE "file", &st) == 0);
535       }
536     ASSERT (st.st_size == 2);
537     memset (&st, 0, sizeof st);
538     ASSERT (stat (BASE "file2", &st) == 0);
539     ASSERT (st.st_size == 2);
540   }
541   /* Files present here:
542        {BASE}file
543        {BASE}file2
544        {BASE}dir/
545    */
546   ASSERT (unlink (BASE "file2") == 0);
547   /* Files present here:
548        {BASE}file
549        {BASE}dir/
550    */
551 
552   /* Symlinks.  */
553 
554   if (symlink (BASE "file", BASE "link1"))
555     {
556       if (print)
557         fputs ("skipping test: symlinks not supported on this file system\n",
558                stderr);
559       ASSERT (unlink (BASE "file") == 0);
560       ASSERT (rmdir (BASE "dir") == 0);
561       return 77;
562     }
563   /* Files present here:
564        {BASE}file
565        {BASE}link1 -> {BASE}file
566        {BASE}dir/
567    */
568   { /* Simple rename.  */
569     ASSERT (func (BASE "link1", BASE "link2") == 0);
570     ASSERT (stat (BASE "file", &st) == 0);
571     errno = 0;
572     ASSERT (lstat (BASE "link1", &st) == -1);
573     ASSERT (errno == ENOENT);
574     memset (&st, 0, sizeof st);
575     ASSERT (lstat (BASE "link2", &st) == 0);
576     ASSERT (S_ISLNK (st.st_mode));
577   }
578   /* Files present here:
579        {BASE}file
580        {BASE}link2 -> {BASE}file
581        {BASE}dir/
582    */
583   { /* Overwrite.  */
584     ASSERT (symlink (BASE "nowhere", BASE "link1") == 0);
585     /* Files present here:
586          {BASE}file
587          {BASE}link1 -> {BASE}nowhere
588          {BASE}link2 -> {BASE}file
589          {BASE}dir/
590      */
591     {
592       ASSERT (func (BASE "link2", BASE "link1") == 0);
593       memset (&st, 0, sizeof st);
594       ASSERT (stat (BASE "link1", &st) == 0);
595       ASSERT (st.st_size == 2);
596       errno = 0;
597       ASSERT (lstat (BASE "link2", &st) == -1);
598       ASSERT (errno == ENOENT);
599     }
600   }
601   /* Files present here:
602        {BASE}file
603        {BASE}link1 -> {BASE}file
604        {BASE}dir/
605    */
606   { /* Symlink loop.  */
607     ASSERT (symlink (BASE "link2", BASE "link2") == 0);
608     /* Files present here:
609          {BASE}file
610          {BASE}link1 -> {BASE}file
611          {BASE}link2 -> {BASE}link2
612          {BASE}dir/
613      */
614     {
615       ASSERT (func (BASE "link2", BASE "link2") == 0);
616     }
617     {
618       errno = 0;
619       ASSERT (func (BASE "link2/", BASE "link2") == -1);
620       ASSERT (errno == ELOOP || errno == ENOTDIR);
621     }
622     ASSERT (func (BASE "link2", BASE "link3") == 0);
623     /* Files present here:
624          {BASE}file
625          {BASE}link1 -> {BASE}file
626          {BASE}link3 -> {BASE}link2
627          {BASE}dir/
628      */
629     ASSERT (unlink (BASE "link3") == 0);
630   }
631   /* Files present here:
632        {BASE}file
633        {BASE}link1 -> {BASE}file
634        {BASE}dir/
635    */
636   { /* Dangling link.  */
637     ASSERT (symlink (BASE "nowhere", BASE "link2") == 0);
638     /* Files present here:
639          {BASE}file
640          {BASE}link1 -> {BASE}file
641          {BASE}link2 -> {BASE}nowhere
642          {BASE}dir/
643      */
644     {
645       ASSERT (func (BASE "link2", BASE "link3") == 0);
646       errno = 0;
647       ASSERT (lstat (BASE "link2", &st) == -1);
648       ASSERT (errno == ENOENT);
649       memset (&st, 0, sizeof st);
650       ASSERT (lstat (BASE "link3", &st) == 0);
651     }
652   }
653   /* Files present here:
654        {BASE}file
655        {BASE}link1 -> {BASE}file
656        {BASE}link3 -> {BASE}nowhere
657        {BASE}dir/
658    */
659   { /* Trailing slash on dangling.  */
660     {
661       errno = 0;
662       ASSERT (func (BASE "link3/", BASE "link2") == -1);
663       ASSERT (errno == ENOENT || errno == ENOTDIR);
664     }
665     {
666       errno = 0;
667       ASSERT (func (BASE "link3", BASE "link2/") == -1);
668       ASSERT (errno == ENOENT || errno == ENOTDIR);
669     }
670     {
671       errno = 0;
672       ASSERT (lstat (BASE "link2", &st) == -1);
673       ASSERT (errno == ENOENT);
674     }
675     memset (&st, 0, sizeof st);
676     ASSERT (lstat (BASE "link3", &st) == 0);
677   }
678   /* Files present here:
679        {BASE}file
680        {BASE}link1 -> {BASE}file
681        {BASE}link3 -> {BASE}nowhere
682        {BASE}dir/
683    */
684   { /* Trailing slash on link to file.  */
685     {
686       errno = 0;
687       ASSERT (func (BASE "link1/", BASE "link2") == -1);
688       ASSERT (errno == ENOTDIR);
689     }
690     {
691       errno = 0;
692       ASSERT (func (BASE "link1", BASE "link3/") == -1);
693       ASSERT (errno == ENOENT || errno == ENOTDIR);
694     }
695   }
696   /* Files present here:
697        {BASE}file
698        {BASE}link1 -> {BASE}file
699        {BASE}link3 -> {BASE}nowhere
700        {BASE}dir/
701    */
702 
703   /* Mixing symlink and file.  */
704 
705   { /* File onto link.  */
706     ASSERT (close (creat (BASE "file2", 0600)) == 0);
707     /* Files present here:
708          {BASE}file
709          {BASE}file2
710          {BASE}link1 -> {BASE}file
711          {BASE}link3 -> {BASE}nowhere
712          {BASE}dir/
713      */
714     {
715       ASSERT (func (BASE "file2", BASE "link3") == 0);
716       errno = 0;
717       ASSERT (stat (BASE "file2", &st) == -1);
718       ASSERT (errno == ENOENT);
719       memset (&st, 0, sizeof st);
720       ASSERT (lstat (BASE "link3", &st) == 0);
721       ASSERT (S_ISREG (st.st_mode));
722     }
723     /* Files present here:
724          {BASE}file
725          {BASE}link1 -> {BASE}file
726          {BASE}link3
727          {BASE}dir/
728      */
729     ASSERT (unlink (BASE "link3") == 0);
730   }
731   /* Files present here:
732        {BASE}file
733        {BASE}link1 -> {BASE}file
734        {BASE}dir/
735    */
736   { /* Link onto file.  */
737     ASSERT (symlink (BASE "nowhere", BASE "link2") == 0);
738     /* Files present here:
739          {BASE}file
740          {BASE}link1 -> {BASE}file
741          {BASE}link2 -> {BASE}nowhere
742          {BASE}dir/
743      */
744     ASSERT (close (creat (BASE "file2", 0600)) == 0);
745     /* Files present here:
746          {BASE}file
747          {BASE}file2
748          {BASE}link1 -> {BASE}file
749          {BASE}link2 -> {BASE}nowhere
750          {BASE}dir/
751      */
752     {
753       ASSERT (func (BASE "link2", BASE "file2") == 0);
754       errno = 0;
755       ASSERT (lstat (BASE "link2", &st) == -1);
756       ASSERT (errno == ENOENT);
757       memset (&st, 0, sizeof st);
758       ASSERT (lstat (BASE "file2", &st) == 0);
759       ASSERT (S_ISLNK (st.st_mode));
760     }
761     /* Files present here:
762          {BASE}file
763          {BASE}file2 -> {BASE}nowhere
764          {BASE}link1 -> {BASE}file
765          {BASE}dir/
766      */
767     ASSERT (unlink (BASE "file2") == 0);
768   }
769   /* Files present here:
770        {BASE}file
771        {BASE}link1 -> {BASE}file
772        {BASE}dir/
773    */
774   { /* Trailing slash.  */
775     {
776       errno = 0;
777       ASSERT (func (BASE "file/", BASE "link1") == -1);
778       ASSERT (errno == ENOTDIR);
779     }
780     {
781       errno = 0;
782       ASSERT (func (BASE "file", BASE "link1/") == -1);
783       ASSERT (errno == ENOTDIR || errno == ENOENT);
784     }
785     {
786       errno = 0;
787       ASSERT (func (BASE "link1/", BASE "file") == -1);
788       ASSERT (errno == ENOTDIR);
789     }
790     {
791       errno = 0;
792       ASSERT (func (BASE "link1", BASE "file/") == -1);
793       ASSERT (errno == ENOTDIR || errno == ENOENT);
794       memset (&st, 0, sizeof st);
795       ASSERT (lstat (BASE "file", &st) == 0);
796       ASSERT (S_ISREG (st.st_mode));
797       memset (&st, 0, sizeof st);
798       ASSERT (lstat (BASE "link1", &st) == 0);
799       ASSERT (S_ISLNK (st.st_mode));
800     }
801   }
802   /* Files present here:
803        {BASE}file
804        {BASE}link1 -> {BASE}file
805        {BASE}dir/
806    */
807 
808   /* Mixing symlink and directory.  */
809 
810   { /* Directory onto link.  */
811     {
812       errno = 0;
813       ASSERT (func (BASE "dir", BASE "link1") == -1);
814       ASSERT (errno == ENOTDIR);
815     }
816     {
817       errno = 0;
818       ASSERT (func (BASE "dir/", BASE "link1") == -1);
819       ASSERT (errno == ENOTDIR);
820     }
821     {
822       errno = 0;
823       ASSERT (func (BASE "dir", BASE "link1/") == -1);
824       ASSERT (errno == ENOTDIR);
825     }
826   }
827   { /* Link onto directory.  */
828     {
829       errno = 0;
830       ASSERT (func (BASE "link1", BASE "dir") == -1);
831       ASSERT (errno == EISDIR || errno == ENOTDIR);
832     }
833     {
834       errno = 0;
835       ASSERT (func (BASE "link1", BASE "dir/") == -1);
836       ASSERT (errno == EISDIR || errno == ENOTDIR);
837     }
838     {
839       errno = 0;
840       ASSERT (func (BASE "link1/", BASE "dir") == -1);
841       ASSERT (errno == ENOTDIR);
842       memset (&st, 0, sizeof st);
843       ASSERT (lstat (BASE "link1", &st) == 0);
844       ASSERT (S_ISLNK (st.st_mode));
845       memset (&st, 0, sizeof st);
846       ASSERT (lstat (BASE "dir", &st) == 0);
847       ASSERT (S_ISDIR (st.st_mode));
848     }
849   }
850   /* Files present here:
851        {BASE}file
852        {BASE}link1 -> {BASE}file
853        {BASE}dir/
854    */
855 
856   /* POSIX requires rename("link-to-dir/","other") to rename "dir" and
857      leave "link-to-dir" dangling, but GNU rejects this.  POSIX
858      requires rename("dir","dangling/") to create the directory so
859      that "dangling/" now resolves, but GNU rejects this.  While we
860      prefer GNU behavior, we don't enforce it.  However, we do test
861      that the system either follows POSIX in both cases, or follows
862      GNU.  */
863   {
864     int result;
865     ASSERT (symlink (BASE "dir2", BASE "link2") == 0);
866     /* Files present here:
867          {BASE}file
868          {BASE}link1 -> {BASE}file
869          {BASE}link2 -> {BASE}dir2
870          {BASE}dir/
871      */
872     errno = 0;
873     result = func (BASE "dir", BASE "link2/");
874     if (result == 0)
875       {
876         /* POSIX.  */
877         errno = 0;
878         ASSERT (lstat (BASE "dir", &st) == -1);
879         ASSERT (errno == ENOENT);
880         memset (&st, 0, sizeof st);
881         ASSERT (lstat (BASE "dir2", &st) == 0);
882         ASSERT (S_ISDIR (st.st_mode));
883         memset (&st, 0, sizeof st);
884         ASSERT (lstat (BASE "link2", &st) == 0);
885         ASSERT (S_ISLNK (st.st_mode));
886         /* Files present here:
887              {BASE}file
888              {BASE}link1 -> {BASE}file
889              {BASE}link2 -> {BASE}dir2
890              {BASE}dir2/
891          */
892         {
893           ASSERT (func (BASE "link2/", BASE "dir") == 0);
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         }
904       }
905     else
906       {
907         /* GNU.  */
908         ASSERT (result == -1);
909         ASSERT (errno == ENOTDIR);
910         memset (&st, 0, sizeof st);
911         ASSERT (lstat (BASE "dir", &st) == 0);
912         ASSERT (S_ISDIR (st.st_mode));
913         errno = 0;
914         ASSERT (lstat (BASE "dir2", &st) == -1);
915         ASSERT (errno == ENOENT);
916         memset (&st, 0, sizeof st);
917         ASSERT (lstat (BASE "link2", &st) == 0);
918         ASSERT (S_ISLNK (st.st_mode));
919         ASSERT (unlink (BASE "link2") == 0);
920         ASSERT (symlink (BASE "dir", BASE "link2") == 0);
921         /* Files present here:
922              {BASE}file
923              {BASE}link1 -> {BASE}file
924              {BASE}link2 -> {BASE}dir
925              {BASE}dir/
926          */
927         errno = 0; /* OpenBSD notices that link2/ and dir are the same.  */
928         result = func (BASE "link2/", BASE "dir");
929         if (result) /* GNU/Linux rejects attempts to use link2/.  */
930           {
931             ASSERT (result == -1);
932             ASSERT (errno == ENOTDIR || errno == EISDIR);
933           }
934         memset (&st, 0, sizeof st);
935         ASSERT (lstat (BASE "dir", &st) == 0);
936         ASSERT (S_ISDIR (st.st_mode));
937         errno = 0;
938         ASSERT (lstat (BASE "dir2", &st) == -1);
939         ASSERT (errno == ENOENT);
940         memset (&st, 0, sizeof st);
941         ASSERT (lstat (BASE "link2", &st) == 0);
942         ASSERT (S_ISLNK (st.st_mode));
943       }
944   }
945   /* Files present here:
946        {BASE}file
947        {BASE}link1 -> {BASE}file
948        {BASE}link2 -> {BASE}dir or {BASE}dir2
949        {BASE}dir/
950    */
951 
952   /* Clean up.  */
953   ASSERT (unlink (BASE "file") == 0);
954   ASSERT (rmdir (BASE "dir") == 0);
955   ASSERT (unlink (BASE "link1") == 0);
956   ASSERT (unlink (BASE "link2") == 0);
957 
958   return 0;
959 }
960