1/* Work around a bug of lstat on some systems 2 3 Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free 4 Software Foundation, Inc. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software Foundation, 18 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 19 20/* written by Jim Meyering */ 21 22#include <config.h> 23 24/* The specification of these functions is in sys_stat.h. But we cannot 25 include this include file here, because on some systems, a 26 "#define lstat lstat64" is being used, and sys_stat.h deletes this 27 definition. */ 28 29#include <sys/types.h> 30#include <sys/stat.h> 31#include <string.h> 32#include <errno.h> 33 34/* lstat works differently on Linux and Solaris systems. POSIX (see 35 `pathname resolution' in the glossary) requires that programs like 36 `ls' take into consideration the fact that FILE has a trailing slash 37 when FILE is a symbolic link. On Linux and Solaris 10 systems, the 38 lstat function already has the desired semantics (in treating 39 `lstat ("symlink/", sbuf)' just like `lstat ("symlink/.", sbuf)', 40 but on Solaris 9 and earlier it does not. 41 42 If FILE has a trailing slash and specifies a symbolic link, 43 then use stat() to get more info on the referent of FILE. 44 If the referent is a non-directory, then set errno to ENOTDIR 45 and return -1. Otherwise, return stat's result. */ 46 47int 48rpl_lstat (const char *file, struct stat *sbuf) 49{ 50 size_t len; 51 int lstat_result = lstat (file, sbuf); 52 53 if (lstat_result != 0 || !S_ISLNK (sbuf->st_mode)) 54 return lstat_result; 55 56 len = strlen (file); 57 if (len == 0 || file[len - 1] != '/') 58 return 0; 59 60 /* FILE refers to a symbolic link and the name ends with a slash. 61 Call stat() to get info about the link's referent. */ 62 63 /* If stat fails, then we do the same. */ 64 if (stat (file, sbuf) != 0) 65 return -1; 66 67 /* If FILE references a directory, return 0. */ 68 if (S_ISDIR (sbuf->st_mode)) 69 return 0; 70 71 /* Here, we know stat succeeded and FILE references a non-directory. 72 But it was specified via a name including a trailing slash. 73 Fail with errno set to ENOTDIR to indicate the contradiction. */ 74 errno = ENOTDIR; 75 return -1; 76} 77