105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Work around platform bugs in stat.
205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Copyright (C) 2009-2012 Free Software Foundation, Inc.
305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
405436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is free software: you can redistribute it and/or modify
505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   it under the terms of the GNU General Public License as published by
605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   the Free Software Foundation; either version 3 of the License, or
705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   (at your option) any later version.
805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
905436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is distributed in the hope that it will be useful,
1005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   but WITHOUT ANY WARRANTY; without even the implied warranty of
1105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   GNU General Public License for more details.
1305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1405436638acc7c010349a69c3395f1a57c642dc62Ying Wang   You should have received a copy of the GNU General Public License
1505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
1605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1705436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* written by Eric Blake */
1805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1905436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* If the user's config.h happens to include <sys/stat.h>, let it include only
2005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   the system's <sys/stat.h> here, so that orig_stat doesn't recurse to
2105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   rpl_stat.  */
2205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#define __need_system_sys_stat_h
2305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <config.h>
2405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2505436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Get the original definition of stat.  It might be defined as a macro.  */
2605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <sys/types.h>
2705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <sys/stat.h>
2805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#undef __need_system_sys_stat_h
2905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
3105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if _GL_WINDOWS_64_BIT_ST_SIZE
3205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  undef stat /* avoid warning on mingw64 with _FILE_OFFSET_BITS=64 */
3305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  define stat _stati64
3405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  define REPLACE_FUNC_STAT_DIR 1
3505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  undef REPLACE_FUNC_STAT_FILE
3605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# elif REPLACE_FUNC_STAT_FILE
3705436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* mingw64 has a broken stat() function, based on _stat(), in libmingwex.a.
3805436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Bypass it.  */
3905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  define stat _stat
4005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  define REPLACE_FUNC_STAT_DIR 1
4105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  undef REPLACE_FUNC_STAT_FILE
4205436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
4305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
4405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4505436638acc7c010349a69c3395f1a57c642dc62Ying Wangstatic int
4605436638acc7c010349a69c3395f1a57c642dc62Ying Wangorig_stat (const char *filename, struct stat *buf)
4705436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
4805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return stat (filename, buf);
4905436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
5005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Specification.  */
5205436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Write "sys/stat.h" here, not <sys/stat.h>, otherwise OSF/1 5.1 DTK cc
5305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   eliminates this include because of the preliminary #include <sys/stat.h>
5405436638acc7c010349a69c3395f1a57c642dc62Ying Wang   above.  */
5505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include "sys/stat.h"
5605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <errno.h>
5805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <limits.h>
5905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <stdbool.h>
6005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <string.h>
6105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include "dosname.h"
6205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include "verify.h"
6305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
6405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if REPLACE_FUNC_STAT_DIR
6505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include "pathmax.h"
6605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* The only known systems where REPLACE_FUNC_STAT_DIR is needed also
6705436638acc7c010349a69c3395f1a57c642dc62Ying Wang     have a constant PATH_MAX.  */
6805436638acc7c010349a69c3395f1a57c642dc62Ying Wang# ifndef PATH_MAX
6905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  error "Please port this replacement to your platform"
7005436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
7105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
7205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
7305436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Store information about NAME into ST.  Work around bugs with
7405436638acc7c010349a69c3395f1a57c642dc62Ying Wang   trailing slashes.  Mingw has other bugs (such as st_ino always
7505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   being 0 on success) which this wrapper does not work around.  But
7605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   at least this implementation provides the ability to emulate fchdir
7705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   correctly.  */
7805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
7905436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
8005436638acc7c010349a69c3395f1a57c642dc62Ying Wangrpl_stat (char const *name, struct stat *st)
8105436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
8205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int result = orig_stat (name, st);
8305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if REPLACE_FUNC_STAT_FILE
8405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Solaris 9 mistakenly succeeds when given a non-directory with a
8505436638acc7c010349a69c3395f1a57c642dc62Ying Wang     trailing slash.  */
8605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (result == 0 && !S_ISDIR (st->st_mode))
8705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
8805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      size_t len = strlen (name);
8905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (ISSLASH (name[len - 1]))
9005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
9105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          errno = ENOTDIR;
9205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          return -1;
9305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
9405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
9505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif /* REPLACE_FUNC_STAT_FILE */
9605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if REPLACE_FUNC_STAT_DIR
9705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
9805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (result == -1 && errno == ENOENT)
9905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
10005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Due to mingw's oddities, there are some directories (like
10105436638acc7c010349a69c3395f1a57c642dc62Ying Wang         c:\) where stat() only succeeds with a trailing slash, and
10205436638acc7c010349a69c3395f1a57c642dc62Ying Wang         other directories (like c:\windows) where stat() only
10305436638acc7c010349a69c3395f1a57c642dc62Ying Wang         succeeds without a trailing slash.  But we want the two to be
10405436638acc7c010349a69c3395f1a57c642dc62Ying Wang         synonymous, since chdir() manages either style.  Likewise, Mingw also
10505436638acc7c010349a69c3395f1a57c642dc62Ying Wang         reports ENOENT for names longer than PATH_MAX, when we want
10605436638acc7c010349a69c3395f1a57c642dc62Ying Wang         ENAMETOOLONG, and for stat("file/"), when we want ENOTDIR.
10705436638acc7c010349a69c3395f1a57c642dc62Ying Wang         Fortunately, mingw PATH_MAX is small enough for stack
10805436638acc7c010349a69c3395f1a57c642dc62Ying Wang         allocation.  */
10905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      char fixed_name[PATH_MAX + 1] = {0};
11005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      size_t len = strlen (name);
11105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      bool check_dir = false;
11205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      verify (PATH_MAX <= 4096);
11305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (PATH_MAX <= len)
11405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        errno = ENAMETOOLONG;
11505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      else if (len)
11605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
11705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          strcpy (fixed_name, name);
11805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (ISSLASH (fixed_name[len - 1]))
11905436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
12005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              check_dir = true;
12105436638acc7c010349a69c3395f1a57c642dc62Ying Wang              while (len && ISSLASH (fixed_name[len - 1]))
12205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                fixed_name[--len] = '\0';
12305436638acc7c010349a69c3395f1a57c642dc62Ying Wang              if (!len)
12405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                fixed_name[0] = '/';
12505436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
12605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          else
12705436638acc7c010349a69c3395f1a57c642dc62Ying Wang            fixed_name[len++] = '/';
12805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          result = orig_stat (fixed_name, st);
12905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (result == 0 && check_dir && !S_ISDIR (st->st_mode))
13005436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
13105436638acc7c010349a69c3395f1a57c642dc62Ying Wang              result = -1;
13205436638acc7c010349a69c3395f1a57c642dc62Ying Wang              errno = ENOTDIR;
13305436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
13405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
13505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
13605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif /* REPLACE_FUNC_STAT_DIR */
13705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return result;
13805436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
139