X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fopen.c;h=13af274602661bb5b628c6d225d51ad2f4673007;hb=217969cf220de4c0515eccd614de1640c3f46bcf;hp=7f7134e59dbd799cc9433d7b65e95f81063d75ae;hpb=5e6b92bb993a0e913877c495687556df918d7d86;p=gnulib.git diff --git a/lib/open.c b/lib/open.c index 7f7134e59..13af27460 100644 --- a/lib/open.c +++ b/lib/open.c @@ -1,40 +1,49 @@ /* Open a descriptor to a file. - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007-2008 Free Software Foundation, Inc. - This program is free software; you can redistribute it and/or modify + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ /* Written by Bruno Haible , 2007. */ #include -/* Specification. */ +/* Get the original definition of open. It might be defined as a macro. */ +#define __need_system_fcntl_h #include +#undef __need_system_fcntl_h +#include -/* If the fchdir replacement is used, open() is defined in fchdir.c. */ -#ifndef FCHDIR_REPLACEMENT +static inline int +orig_open (const char *filename, int flags, mode_t mode) +{ + return open (filename, flags, mode); +} -# include -# include -# include -# include +/* Specification. */ +#include + +#include +#include +#include +#include +#include int open (const char *filename, int flags, ...) -# undef open { mode_t mode; + int fd; mode = 0; if (flags & O_CREAT) @@ -52,11 +61,80 @@ open (const char *filename, int flags, ...) va_end (arg); } -# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ if (strcmp (filename, "/dev/null") == 0) filename = "NUL"; -# endif +#endif - return open (filename, flags, mode); -} +#if OPEN_TRAILING_SLASH_BUG + /* If the filename ends in a slash and one of O_CREAT, O_WRONLY, O_RDWR + is specified, then fail. + Rationale: POSIX + says that + "A pathname that contains at least one non-slash character and that + ends with one or more trailing slashes shall be resolved as if a + single dot character ( '.' ) were appended to the pathname." + and + "The special filename dot shall refer to the directory specified by + its predecessor." + If the named file already exists as a directory, then + - if O_CREAT is specified, open() must fail because of the semantics + of O_CREAT, + - if O_WRONLY or O_RDWR is specified, open() must fail because POSIX + says that it + fails with errno = EISDIR in this case. + If the named file does not exist or does not name a directory, then + - if O_CREAT is specified, open() must fail since open() cannot create + directories, + - if O_WRONLY or O_RDWR is specified, open() must fail because the + file does not contain a '.' directory. */ + if (flags & (O_CREAT | O_WRONLY | O_RDWR)) + { + size_t len = strlen (filename); + if (len > 0 && filename[len - 1] == '/') + { + errno = EISDIR; + return -1; + } + } #endif + + fd = orig_open (filename, flags, mode); + +#if OPEN_TRAILING_SLASH_BUG + /* If the filename ends in a slash and fd does not refer to a directory, + then fail. + Rationale: POSIX + says that + "A pathname that contains at least one non-slash character and that + ends with one or more trailing slashes shall be resolved as if a + single dot character ( '.' ) were appended to the pathname." + and + "The special filename dot shall refer to the directory specified by + its predecessor." + If the named file without the slash is not a directory, open() must fail + with ENOTDIR. */ + if (fd >= 0) + { + size_t len = strlen (filename); + if (len > 0 && filename[len - 1] == '/') + { + struct stat statbuf; + + if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode)) + { + close (fd); + errno = ENOTDIR; + return -1; + } + } + } +#endif + +#ifdef FCHDIR_REPLACEMENT + if (fd >= 0) + _gl_register_fd (fd, filename); +#endif + + return fd; +}