1/* Work around a bug of lstat on some systems
2
3   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 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#include <sys/cdefs.h>
20__RCSID("$NetBSD: lstat.c,v 1.2 2016/05/17 14:00:09 christos Exp $");
21
22
23/* written by Jim Meyering */
24
25#ifdef HAVE_CONFIG_H
26# include <config.h>
27#endif
28
29/* The specification of these functions is in sys_stat.h.  But we cannot
30   include this include file here, because on some systems, a
31   "#define lstat lstat64" is being used, and sys_stat.h deletes this
32   definition.  */
33
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <stdlib.h>
37#include <string.h>
38
39#include "stat-macros.h"
40#include "xalloc.h"
41
42/* lstat works differently on Linux and Solaris systems.  POSIX (see
43   `pathname resolution' in the glossary) requires that programs like `ls'
44   take into consideration the fact that FILE has a trailing slash when
45   FILE is a symbolic link.  On Linux systems, the lstat function already
46   has the desired semantics (in treating `lstat("symlink/",sbuf)' just like
47   `lstat("symlink/.",sbuf)', but on Solaris it does not.
48
49   If FILE has a trailing slash and specifies a symbolic link,
50   then append a `.' to FILE and call lstat a second time.  */
51
52int
53rpl_lstat (const char *file, struct stat *sbuf)
54{
55  size_t len;
56  char *new_file;
57
58  int lstat_result = lstat (file, sbuf);
59
60  if (lstat_result != 0 || !S_ISLNK (sbuf->st_mode))
61    return lstat_result;
62
63  len = strlen (file);
64  if (len == 0 || file[len - 1] != '/')
65    return lstat_result;
66
67  /* FILE refers to a symbolic link and the name ends with a slash.
68     Append a `.' to FILE and repeat the lstat call.  */
69
70  /* Add one for the `.' we'll append, and one more for the trailing NUL.  */
71  new_file = xmalloc (len + 1 + 1);
72  memcpy (new_file, file, len);
73  new_file[len] = '.';
74  new_file[len + 1] = 0;
75
76  lstat_result = lstat (new_file, sbuf);
77  free (new_file);
78
79  return lstat_result;
80}
81