"Fossies" - the Fresh Open Source Software Archive

Member "cpio-2.13/gnu/openat.c" (2 Jan 2017, 8661 Bytes) of package /linux/misc/cpio-2.13.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "openat.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.12_vs_2.13.

    1 /* provide a replacement openat function
    2    Copyright (C) 2004-2017 Free Software Foundation, Inc.
    3 
    4    This program is free software: you can redistribute it and/or modify
    5    it under the terms of the GNU General Public License as published by
    6    the Free Software Foundation; either version 3 of the License, or
    7    (at your option) any later version.
    8 
    9    This program is distributed in the hope that it will be useful,
   10    but WITHOUT ANY WARRANTY; without even the implied warranty of
   11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12    GNU General Public License for more details.
   13 
   14    You should have received a copy of the GNU General Public License
   15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
   16 
   17 /* written by Jim Meyering */
   18 
   19 /* If the user's config.h happens to include <fcntl.h>, let it include only
   20    the system's <fcntl.h> here, so that orig_openat doesn't recurse to
   21    rpl_openat.  */
   22 #define __need_system_fcntl_h
   23 #include <config.h>
   24 
   25 /* Get the original definition of open.  It might be defined as a macro.  */
   26 #include <fcntl.h>
   27 #include <sys/types.h>
   28 #undef __need_system_fcntl_h
   29 
   30 #if HAVE_OPENAT
   31 static int
   32 orig_openat (int fd, char const *filename, int flags, mode_t mode)
   33 {
   34   return openat (fd, filename, flags, mode);
   35 }
   36 #endif
   37 
   38 /* Write "fcntl.h" here, not <fcntl.h>, otherwise OSF/1 5.1 DTK cc eliminates
   39    this include because of the preliminary #include <fcntl.h> above.  */
   40 #include "fcntl.h"
   41 
   42 #include "openat.h"
   43 
   44 #include <stdarg.h>
   45 #include <stdbool.h>
   46 #include <stddef.h>
   47 #include <string.h>
   48 #include <sys/stat.h>
   49 #include <errno.h>
   50 
   51 #if HAVE_OPENAT
   52 
   53 /* Like openat, but work around Solaris 9 bugs with trailing slash.  */
   54 int
   55 rpl_openat (int dfd, char const *filename, int flags, ...)
   56 {
   57   mode_t mode;
   58   int fd;
   59 
   60   mode = 0;
   61   if (flags & O_CREAT)
   62     {
   63       va_list arg;
   64       va_start (arg, flags);
   65 
   66       /* We have to use PROMOTED_MODE_T instead of mode_t, otherwise GCC 4
   67          creates crashing code when 'mode_t' is smaller than 'int'.  */
   68       mode = va_arg (arg, PROMOTED_MODE_T);
   69 
   70       va_end (arg);
   71     }
   72 
   73 # if OPEN_TRAILING_SLASH_BUG
   74   /* If the filename ends in a slash and one of O_CREAT, O_WRONLY, O_RDWR
   75      is specified, then fail.
   76      Rationale: POSIX <http://www.opengroup.org/susv3/basedefs/xbd_chap04.html>
   77      says that
   78        "A pathname that contains at least one non-slash character and that
   79         ends with one or more trailing slashes shall be resolved as if a
   80         single dot character ( '.' ) were appended to the pathname."
   81      and
   82        "The special filename dot shall refer to the directory specified by
   83         its predecessor."
   84      If the named file already exists as a directory, then
   85        - if O_CREAT is specified, open() must fail because of the semantics
   86          of O_CREAT,
   87        - if O_WRONLY or O_RDWR is specified, open() must fail because POSIX
   88          <http://www.opengroup.org/susv3/functions/open.html> says that it
   89          fails with errno = EISDIR in this case.
   90      If the named file does not exist or does not name a directory, then
   91        - if O_CREAT is specified, open() must fail since open() cannot create
   92          directories,
   93        - if O_WRONLY or O_RDWR is specified, open() must fail because the
   94          file does not contain a '.' directory.  */
   95   if (flags & (O_CREAT | O_WRONLY | O_RDWR))
   96     {
   97       size_t len = strlen (filename);
   98       if (len > 0 && filename[len - 1] == '/')
   99         {
  100           errno = EISDIR;
  101           return -1;
  102         }
  103     }
  104 # endif
  105 
  106   fd = orig_openat (dfd, filename, flags, mode);
  107 
  108 # if OPEN_TRAILING_SLASH_BUG
  109   /* If the filename ends in a slash and fd does not refer to a directory,
  110      then fail.
  111      Rationale: POSIX <http://www.opengroup.org/susv3/basedefs/xbd_chap04.html>
  112      says that
  113        "A pathname that contains at least one non-slash character and that
  114         ends with one or more trailing slashes shall be resolved as if a
  115         single dot character ( '.' ) were appended to the pathname."
  116      and
  117        "The special filename dot shall refer to the directory specified by
  118         its predecessor."
  119      If the named file without the slash is not a directory, open() must fail
  120      with ENOTDIR.  */
  121   if (fd >= 0)
  122     {
  123       /* We know len is positive, since open did not fail with ENOENT.  */
  124       size_t len = strlen (filename);
  125       if (filename[len - 1] == '/')
  126         {
  127           struct stat statbuf;
  128 
  129           if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode))
  130             {
  131               close (fd);
  132               errno = ENOTDIR;
  133               return -1;
  134             }
  135         }
  136     }
  137 # endif
  138 
  139   return fd;
  140 }
  141 
  142 #else /* !HAVE_OPENAT */
  143 
  144 # include "dosname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
  145 # include "openat-priv.h"
  146 # include "save-cwd.h"
  147 
  148 /* Replacement for Solaris' openat function.
  149    <http://www.google.com/search?q=openat+site:docs.sun.com>
  150    First, try to simulate it via open ("/proc/self/fd/FD/FILE").
  151    Failing that, simulate it by doing save_cwd/fchdir/open/restore_cwd.
  152    If either the save_cwd or the restore_cwd fails (relatively unlikely),
  153    then give a diagnostic and exit nonzero.
  154    Otherwise, upon failure, set errno and return -1, as openat does.
  155    Upon successful completion, return a file descriptor.  */
  156 int
  157 openat (int fd, char const *file, int flags, ...)
  158 {
  159   mode_t mode = 0;
  160 
  161   if (flags & O_CREAT)
  162     {
  163       va_list arg;
  164       va_start (arg, flags);
  165 
  166       /* We have to use PROMOTED_MODE_T instead of mode_t, otherwise GCC 4
  167          creates crashing code when 'mode_t' is smaller than 'int'.  */
  168       mode = va_arg (arg, PROMOTED_MODE_T);
  169 
  170       va_end (arg);
  171     }
  172 
  173   return openat_permissive (fd, file, flags, mode, NULL);
  174 }
  175 
  176 /* Like openat (FD, FILE, FLAGS, MODE), but if CWD_ERRNO is
  177    nonnull, set *CWD_ERRNO to an errno value if unable to save
  178    or restore the initial working directory.  This is needed only
  179    the first time remove.c's remove_dir opens a command-line
  180    directory argument.
  181 
  182    If a previous attempt to restore the current working directory
  183    failed, then we must not even try to access a '.'-relative name.
  184    It is the caller's responsibility not to call this function
  185    in that case.  */
  186 
  187 int
  188 openat_permissive (int fd, char const *file, int flags, mode_t mode,
  189                    int *cwd_errno)
  190 {
  191   struct saved_cwd saved_cwd;
  192   int saved_errno;
  193   int err;
  194   bool save_ok;
  195 
  196   if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
  197     return open (file, flags, mode);
  198 
  199   {
  200     char buf[OPENAT_BUFFER_SIZE];
  201     char *proc_file = openat_proc_name (buf, fd, file);
  202     if (proc_file)
  203       {
  204         int open_result = open (proc_file, flags, mode);
  205         int open_errno = errno;
  206         if (proc_file != buf)
  207           free (proc_file);
  208         /* If the syscall succeeds, or if it fails with an unexpected
  209            errno value, then return right away.  Otherwise, fall through
  210            and resort to using save_cwd/restore_cwd.  */
  211         if (0 <= open_result || ! EXPECTED_ERRNO (open_errno))
  212           {
  213             errno = open_errno;
  214             return open_result;
  215           }
  216       }
  217   }
  218 
  219   save_ok = (save_cwd (&saved_cwd) == 0);
  220   if (! save_ok)
  221     {
  222       if (! cwd_errno)
  223         openat_save_fail (errno);
  224       *cwd_errno = errno;
  225     }
  226   if (0 <= fd && fd == saved_cwd.desc)
  227     {
  228       /* If saving the working directory collides with the user's
  229          requested fd, then the user's fd must have been closed to
  230          begin with.  */
  231       free_cwd (&saved_cwd);
  232       errno = EBADF;
  233       return -1;
  234     }
  235 
  236   err = fchdir (fd);
  237   saved_errno = errno;
  238 
  239   if (! err)
  240     {
  241       err = open (file, flags, mode);
  242       saved_errno = errno;
  243       if (save_ok && restore_cwd (&saved_cwd) != 0)
  244         {
  245           if (! cwd_errno)
  246             {
  247               /* Don't write a message to just-created fd 2.  */
  248               saved_errno = errno;
  249               if (err == STDERR_FILENO)
  250                 close (err);
  251               openat_restore_fail (saved_errno);
  252             }
  253           *cwd_errno = errno;
  254         }
  255     }
  256 
  257   free_cwd (&saved_cwd);
  258   errno = saved_errno;
  259   return err;
  260 }
  261 
  262 /* Return true if our openat implementation must resort to
  263    using save_cwd and restore_cwd.  */
  264 bool
  265 openat_needs_fchdir (void)
  266 {
  267   bool needs_fchdir = true;
  268   int fd = open ("/", O_SEARCH);
  269 
  270   if (0 <= fd)
  271     {
  272       char buf[OPENAT_BUFFER_SIZE];
  273       char *proc_file = openat_proc_name (buf, fd, ".");
  274       if (proc_file)
  275         {
  276           needs_fchdir = false;
  277           if (proc_file != buf)
  278             free (proc_file);
  279         }
  280       close (fd);
  281     }
  282 
  283   return needs_fchdir;
  284 }
  285 
  286 #endif /* !HAVE_OPENAT */