diff options
author | Jim Meyering <jim@meyering.net> | 1999-12-19 10:45:50 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 1999-12-19 10:45:50 +0000 |
commit | 036b3bdae775b8e0b82c7bff8dca81aa42440328 (patch) | |
tree | b49e03c9371a6663598e5a06ea69d7bd71d7db56 /lib | |
parent | f802f286756cb1e8c385ab08fe71952633751b0f (diff) | |
download | coreutils-036b3bdae775b8e0b82c7bff8dca81aa42440328.tar.xz |
(slash_aware_lstat): New function.
(rpl_@xstat@): Use it.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/xstat.in | 66 |
1 files changed, 64 insertions, 2 deletions
diff --git a/lib/xstat.in b/lib/xstat.in index d5420a4d3..04fe0fbf2 100644 --- a/lib/xstat.in +++ b/lib/xstat.in @@ -4,7 +4,7 @@ /* Work around the bug in some systems whereby @xstat@ succeeds when given the zero-length file name argument. The @xstat@ from SunOS4.1.4 has this bug. - Copyright (C) 1997, 1998 Free Software Foundation, Inc. + Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,6 +30,58 @@ #ifndef errno extern int errno; #endif +@BEGIN_LSTAT_ONLY@ + +#ifdef STAT_MACROS_BROKEN +# undef S_ISLNK +#endif +#if !defined(S_ISLNK) && defined(S_IFLNK) +# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#endif + +char *xmalloc (); + +/* lstat works different on Linux and Solaris systems. POSIX (see + `pathname resolution' in the glossary) requires that programs like `ls' + take into consideration the fact that FILE has a trailing slash when + FILE is a symbolic link. On Linux systems, the lstat function already + has the desired semantics (in treating `lstat("symlink/",sbuf)' just like + `lstat("symlink/.",sbuf)', but on Solaris it does not. + + If FILE has a trailing slash and specifies a symbolic link, + then append a `.' to FILE and call lstat a second time. */ + +static int +slash_aware_lstat (const char *file, struct stat *sbuf) +{ + size_t len; + char *new_file; + + int lstat_result = lstat (file, sbuf); + + if (lstat_result != 0 || !S_ISLNK (sbuf->st_mode)) + return lstat_result; + + len = strlen (file); + if (file[len - 1] != '/') + return lstat_result; + + /* FILE refers to a symbolic link and the name ends with a slash. + Append a `.' to FILE and repeat the lstat call. */ + + /* Add one for the `.' we might have to append, and one more + for the trailing NUL. */ + new_file = xmalloc (len + 1 + 1); + memcpy (new_file, file, len); + new_file[len] = '.'; + new_file[len + 1] = 0; + + lstat_result = lstat (new_file, sbuf); + free (new_file); + + return lstat_result; +} +@END_LSTAT_ONLY@ /* This is a wrapper for @xstat@(2). If FILE is the empty string, fail with errno == ENOENT. @@ -38,6 +90,11 @@ extern int errno; This works around the bug in some systems whereby @xstat@ succeeds when given the zero-length file name argument. The @xstat@ from SunOS4.1.4 has this bug. */ +@BEGIN_LSTAT_ONLY@ + +/* This function also provides a version of lstat with consistent semantics + when FILE specifies a symbolic link and has a trailing slash. */ +@END_LSTAT_ONLY@ int rpl_@xstat@ (const char *file, struct stat *sbuf) @@ -48,5 +105,10 @@ rpl_@xstat@ (const char *file, struct stat *sbuf) return -1; } - return @xstat@ (file, sbuf); +@BEGIN_LSTAT_ONLY@ + return slash_aware_lstat (file, sbuf); +@END_LSTAT_ONLY@ +@BEGIN_STAT_ONLY@ + return stat (file, sbuf); +@END_STAT_ONLY@ } |