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