summaryrefslogtreecommitdiffstats
path: root/gl/open.c
diff options
context:
space:
mode:
Diffstat (limited to 'gl/open.c')
-rw-r--r--gl/open.c76
1 files changed, 51 insertions, 25 deletions
diff --git a/gl/open.c b/gl/open.c
index 13af274..f612b80 100644
--- a/gl/open.c
+++ b/gl/open.c
@@ -1,5 +1,5 @@
1/* Open a descriptor to a file. 1/* Open a descriptor to a file.
2 Copyright (C) 2007-2008 Free Software Foundation, Inc. 2 Copyright (C) 2007-2010 Free Software Foundation, Inc.
3 3
4 This program is free software: you can redistribute it and/or modify 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 5 it under the terms of the GNU General Public License as published by
@@ -38,6 +38,11 @@ orig_open (const char *filename, int flags, mode_t mode)
38#include <string.h> 38#include <string.h>
39#include <sys/types.h> 39#include <sys/types.h>
40#include <sys/stat.h> 40#include <sys/stat.h>
41#include <unistd.h>
42
43#ifndef REPLACE_OPEN_DIRECTORY
44# define REPLACE_OPEN_DIRECTORY 0
45#endif
41 46
42int 47int
43open (const char *filename, int flags, ...) 48open (const char *filename, int flags, ...)
@@ -51,12 +56,9 @@ open (const char *filename, int flags, ...)
51 va_list arg; 56 va_list arg;
52 va_start (arg, flags); 57 va_start (arg, flags);
53 58
54 /* If mode_t is narrower than int, use the promoted type (int), 59 /* We have to use PROMOTED_MODE_T instead of mode_t, otherwise GCC 4
55 not mode_t. Use sizeof to guess whether mode_t is narrower; 60 creates crashing code when 'mode_t' is smaller than 'int'. */
56 we don't know of any practical counterexamples. */ 61 mode = va_arg (arg, PROMOTED_MODE_T);
57 mode = (sizeof (mode_t) < sizeof (int)
58 ? va_arg (arg, int)
59 : va_arg (arg, mode_t));
60 62
61 va_end (arg); 63 va_end (arg);
62 } 64 }
@@ -92,15 +94,38 @@ open (const char *filename, int flags, ...)
92 { 94 {
93 size_t len = strlen (filename); 95 size_t len = strlen (filename);
94 if (len > 0 && filename[len - 1] == '/') 96 if (len > 0 && filename[len - 1] == '/')
95 { 97 {
96 errno = EISDIR; 98 errno = EISDIR;
97 return -1; 99 return -1;
98 } 100 }
99 } 101 }
100#endif 102#endif
101 103
102 fd = orig_open (filename, flags, mode); 104 fd = orig_open (filename, flags, mode);
103 105
106#if REPLACE_FCHDIR
107 /* Implementing fchdir and fdopendir requires the ability to open a
108 directory file descriptor. If open doesn't support that (as on
109 mingw), we use a dummy file that behaves the same as directories
110 on Linux (ie. always reports EOF on attempts to read()), and
111 override fstat() in fchdir.c to hide the fact that we have a
112 dummy. */
113 if (REPLACE_OPEN_DIRECTORY && fd < 0 && errno == EACCES
114 && (flags & O_ACCMODE) == O_RDONLY)
115 {
116 struct stat statbuf;
117 if (stat (filename, &statbuf) == 0 && S_ISDIR (statbuf.st_mode))
118 {
119 /* Maximum recursion depth of 1. */
120 fd = open ("/dev/null", flags, mode);
121 if (0 <= fd)
122 fd = _gl_register_fd (fd, filename);
123 }
124 else
125 errno = EACCES;
126 }
127#endif
128
104#if OPEN_TRAILING_SLASH_BUG 129#if OPEN_TRAILING_SLASH_BUG
105 /* If the filename ends in a slash and fd does not refer to a directory, 130 /* If the filename ends in a slash and fd does not refer to a directory,
106 then fail. 131 then fail.
@@ -116,24 +141,25 @@ open (const char *filename, int flags, ...)
116 with ENOTDIR. */ 141 with ENOTDIR. */
117 if (fd >= 0) 142 if (fd >= 0)
118 { 143 {
144 /* We know len is positive, since open did not fail with ENOENT. */
119 size_t len = strlen (filename); 145 size_t len = strlen (filename);
120 if (len > 0 && filename[len - 1] == '/') 146 if (filename[len - 1] == '/')
121 { 147 {
122 struct stat statbuf; 148 struct stat statbuf;
123 149
124 if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode)) 150 if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode))
125 { 151 {
126 close (fd); 152 close (fd);
127 errno = ENOTDIR; 153 errno = ENOTDIR;
128 return -1; 154 return -1;
129 } 155 }
130 } 156 }
131 } 157 }
132#endif 158#endif
133 159
134#ifdef FCHDIR_REPLACEMENT 160#if REPLACE_FCHDIR
135 if (fd >= 0) 161 if (!REPLACE_OPEN_DIRECTORY && 0 <= fd)
136 _gl_register_fd (fd, filename); 162 fd = _gl_register_fd (fd, filename);
137#endif 163#endif
138 164
139 return fd; 165 return fd;