1 /* Test for ftw function related to symbolic links for BZ #23501
2 Copyright (C) 2019-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
22 #include <sys/types.h>
28 #include <support/support.h>
29 #include <support/check.h>
31 #define TSTDIR "tst-ftw-lnk.d"
37 /* Does the file exist? */
38 if (lstat (file
, &st
) < 0
42 /* If so, try to remove it. */
43 if (unlink (file
) < 0)
44 FAIL_EXIT1 ("Unable to unlink %s", file
);
48 debug_cb (const char *which
, const char *fpath
,
49 const struct stat
*sb
, int typeflags
)
51 const char *sb_type
= "???";
52 const char *ftw_type
= "???";
54 /* Coding style here is intentionally "wrong" to increase readability. */
55 if (S_ISREG (sb
->st_mode
)) sb_type
= "REG";
56 if (S_ISDIR (sb
->st_mode
)) sb_type
= "DIR";
57 if (S_ISLNK (sb
->st_mode
)) sb_type
= "LNK";
59 if (typeflags
== FTW_F
) ftw_type
= "F";
60 if (typeflags
== FTW_D
) ftw_type
= "D";
61 if (typeflags
== FTW_DNR
) ftw_type
= "DNR";
62 if (typeflags
== FTW_DP
) ftw_type
= "DP";
63 if (typeflags
== FTW_NS
) ftw_type
= "NS";
64 if (typeflags
== FTW_SL
) ftw_type
= "SL";
65 if (typeflags
== FTW_SLN
) ftw_type
= "SLN";
67 printf ("%s %5d %-3s %-3s %s\n", which
, (int)(sb
->st_ino
% 100000), sb_type
, ftw_type
, fpath
);
71 #define EXPECTED_GOOD 12
73 /* See if the stat buffer SB refers to the file AS_FNAME. */
75 check_same_stats (const struct stat
*sb
, const char *as_fname
)
78 if (lstat (as_fname
, &as
) < 0)
79 FAIL_EXIT1 ("unable to stat %s for comparison", as_fname
);
81 if (as
.st_mode
== sb
->st_mode
82 && as
.st_ino
== sb
->st_ino
83 && as
.st_size
== sb
->st_size
)
86 printf ("statbuf data doesn't match %s\n", as_fname
);
90 callback_phys (const char *fpath
, const struct stat
*sb
, int typeflags
, struct FTW
*ftwbuf
)
92 debug_cb ("P", fpath
, sb
, typeflags
);
94 /* This callback is for when the FTW_PHYS flag is set. The results
95 should reflect the physical filesystem entry, not what it might
98 /* link1-bad is a dangling symlink, but we're reporting on the link
99 anyway (ala lstat ()). */
100 if (strcmp (fpath
, "./link1-bad") == 0)
102 if (S_ISLNK (sb
->st_mode
) && typeflags
== FTW_SL
)
105 printf ("link1-bad had wrong phys stats\n");
107 check_same_stats (sb
, "link1-bad");
110 /* link2-ok is a regular non-dangling symlink. */
111 if (strcmp (fpath
, "./link2-ok") == 0)
113 if (S_ISLNK (sb
->st_mode
) && typeflags
== FTW_SL
)
116 printf ("link2-ok had wrong phys stats\n");
118 check_same_stats (sb
, "link2-ok");
121 /* This is the file link2-ok points to. */
122 if (strcmp (fpath
, "./link2-tgt") == 0)
124 if (S_ISREG (sb
->st_mode
) && typeflags
== FTW_F
)
127 printf ("link2-tgt had wrong phys stats\n");
129 check_same_stats (sb
, "link2-tgt");
136 callback_log (const char *fpath
, const struct stat
*sb
, int typeflags
, struct FTW
*ftwbuf
)
138 debug_cb ("L", fpath
, sb
, typeflags
);
140 /* This callback is for when the FTW_PHYS flags is NOT set. The
141 results should reflect the logical file, i.e. symlinks should be
144 /* We would normally report what link1-bad links to, but link1-bad
145 is a dangling symlink. This is an exception to FTW_PHYS in that
146 we report FTW_SLN (dangling symlink) but the stat data is
147 correctly set to the link itself (ala lstat ()). */
148 if (strcmp (fpath
, "./link1-bad") == 0)
150 if (S_ISLNK (sb
->st_mode
) && typeflags
== FTW_SLN
)
153 printf ("link1-bad had wrong logical stats\n");
155 check_same_stats (sb
, "link1-bad");
158 /* link2-ok points to link2-tgt, so we expect data reflecting
159 link2-tgt (ala stat ()). */
160 if (strcmp (fpath
, "./link2-ok") == 0)
162 if (S_ISREG (sb
->st_mode
) && typeflags
== FTW_F
)
165 printf ("link2-ok had wrong logical stats\n");
167 check_same_stats (sb
, "link2-tgt");
170 /* This is the file link2-ok points to. */
171 if (strcmp (fpath
, "./link2-tgt") == 0)
173 if (S_ISREG (sb
->st_mode
) && typeflags
== FTW_F
)
176 printf ("link2-tgt had wrong logical stats\n");
178 check_same_stats (sb
, "link2-tgt");
189 if (chdir (support_objdir_root
) < 0)
190 FAIL_EXIT1 ("cannot chdir to objdir root");
192 if (chdir ("io") < 0)
193 FAIL_EXIT1 ("cannot chdir to objdir/io subdir");
195 if (stat (TSTDIR
, &st
) >= 0)
197 /* Directory does exist, delete any potential conflicts. */
198 if (chdir (TSTDIR
) < 0)
199 FAIL_EXIT1 ("cannot chdir to %s\n", TSTDIR
);
207 /* Directory does not exist, create it. */
208 mkdir (TSTDIR
, 0777);
209 if (chdir (TSTDIR
) < 0)
210 FAIL_EXIT1 ("cannot chdir to %s\n", TSTDIR
);
213 /* At this point, we're inside our test directory, and need to
216 if (symlink ("link1-tgt", "link1-bad") < 0)
217 FAIL_EXIT1 ("symlink link1-bad failed");
218 if (symlink ("link2-tgt", "link2-ok") < 0)
219 FAIL_EXIT1 ("symlink link2-ok failed");
220 if (open ("link2-tgt", O_RDWR
|O_CREAT
, 0777) < 0)
221 FAIL_EXIT1 ("create of link2-tgt failed");
223 /* Now we run the tests. */
225 nftw (".", callback_phys
, 10, FTW_PHYS
);
226 nftw (".", callback_log
, 10, 0);
228 /* Did we see the expected number of correct callbacks? */
230 if (good_cb
!= EXPECTED_GOOD
)
232 FAIL_EXIT1 ("Saw %d good callbacks, expected %d\n",
233 good_cb
, EXPECTED_GOOD
);
239 #include <support/test-driver.c>