summaryrefslogtreecommitdiff
path: root/lib/lstat.c
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2006-02-14 23:00:23 +0000
committerPaul Eggert <eggert@cs.ucla.edu>2006-02-14 23:00:23 +0000
commit28fe652e06a47bc9d02812968dc8c188e5d68593 (patch)
treebcd4bdc903f7361c7df092c7c9a889f624d31e53 /lib/lstat.c
parentf6fbc1414522daf6ccbb2503a75948377b900685 (diff)
downloadgnulib-28fe652e06a47bc9d02812968dc8c188e5d68593.tar.gz
Sync from coreutils.
* modules/lstat (Depends-on): Don't depend on xalloc. (License): Change from GPL to LGPL, since this is now simply a replacement for a libc function. Eliminate the unwelcome (albeit unlikely) possibility of xmalloc failure on deficient systems, and simplify gnulib lgpl dependencies. * lib/lstat.c (rpl_lstat): Rewrite to use stat() in place of the xmalloc/lstat combination. Based on a patch from Bruno Haible. * lib/xalloc-die.c: Remove unused definition of N_. * m4/ls-mntd-fs.m4 (AC_FUNC_GETMNTENT): Invoke AC_CHECK_FUNCS(getmntent) unconditionally so that tests of $ac_cv_func_getmntent (e.g., in gl_LIST_MOUNTED_FILE_SYSTEMS) need not double-quote uses of that variable, to accommodate the rare case in which getmntent is available in none of the libraries checked. This happens at least on FreeBSD 5.0.
Diffstat (limited to 'lib/lstat.c')
-rw-r--r--lib/lstat.c45
1 files changed, 24 insertions, 21 deletions
diff --git a/lib/lstat.c b/lib/lstat.c
index f5a22b07b2..9b9c33e415 100644
--- a/lib/lstat.c
+++ b/lib/lstat.c
@@ -1,6 +1,6 @@
/* Work around a bug of lstat on some systems
- Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free
+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free
Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
@@ -30,28 +30,28 @@
#include <sys/types.h>
#include <sys/stat.h>
-#include <stdlib.h>
#include <string.h>
+#include <errno.h>
#include "stat-macros.h"
-#include "xalloc.h"
/* lstat works differently 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.
+ `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 and Solaris 10 systems, the
+ lstat function already has the desired semantics (in treating
+ `lstat ("symlink/", sbuf)' just like `lstat ("symlink/.", sbuf)',
+ but on Solaris 9 and earlier 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. */
+ then use stat() to get more info on the referent of FILE.
+ If the referent is a non-directory, then set errno to ENOTDIR
+ and return -1. Otherwise, return stat's result. */
int
rpl_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))
@@ -59,19 +59,22 @@ rpl_lstat (const char *file, struct stat *sbuf)
len = strlen (file);
if (len == 0 || file[len - 1] != '/')
- return lstat_result;
+ return 0;
/* FILE refers to a symbolic link and the name ends with a slash.
- Append a `.' to FILE and repeat the lstat call. */
+ Call stat() to get info about the link's referent. */
- /* Add one for the `.' we'll 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;
+ /* If stat fails, then we do the same. */
+ if (stat (file, sbuf) != 0)
+ return -1;
- lstat_result = lstat (new_file, sbuf);
- free (new_file);
+ /* If FILE references a directory, return 0. */
+ if (S_ISDIR (sbuf->st_mode))
+ return 0;
- return lstat_result;
+ /* Here, we know stat succeeded and FILE references a non-directory.
+ But it was specified via a name including a trailing slash.
+ Fail with errno set to ENOTDIR to indicate the contradiction. */
+ errno = ENOTDIR;
+ return -1;
}