1 /* -*- buffer-read-only: t -*- vi: set ro: */
2 /* DO NOT EDIT! GENERATED AUTOMATICALLY! */
4 Copyright (C) 2006-2010 Free Software Foundation, Inc.
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 3 of the License, or
9 (at your option) any later version.
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.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
31 #include <sys/types.h>
34 #ifndef REPLACE_OPEN_DIRECTORY
35 # define REPLACE_OPEN_DIRECTORY 0
38 #ifndef HAVE_CANONICALIZE_FILE_NAME
39 # if GNULIB_CANONICALIZE || GNULIB_CANONICALIZE_LGPL
40 # define HAVE_CANONICALIZE_FILE_NAME 1
42 # define HAVE_CANONICALIZE_FILE_NAME 0
43 # define canonicalize_file_name(name) NULL
47 /* This replacement assumes that a directory is not renamed while opened
48 through a file descriptor.
50 FIXME: On mingw, this would be possible to enforce if we were to
51 also open a HANDLE to each directory currently visited by a file
52 descriptor, since mingw refuses to rename any in-use file system
55 /* Array of file descriptors opened. If REPLACE_OPEN_DIRECTORY or if it points
56 to a directory, it stores info about this directory. */
59 char *name; /* Absolute name of the directory, or NULL. */
60 /* FIXME - add a DIR* member to make dirfd possible on mingw? */
62 static dir_info_t *dirs;
63 static size_t dirs_allocated;
65 /* Try to ensure dirs has enough room for a slot at index fd; free any
66 contents already in that slot. Return false and set errno to
67 ENOMEM on allocation failure. */
69 ensure_dirs_slot (size_t fd)
71 if (fd < dirs_allocated)
78 new_allocated = 2 * dirs_allocated + 1;
79 if (new_allocated <= fd)
80 new_allocated = fd + 1;
83 ? (dir_info_t *) realloc (dirs, new_allocated * sizeof *dirs)
84 : (dir_info_t *) malloc (new_allocated * sizeof *dirs));
87 memset (new_dirs + dirs_allocated, 0,
88 (new_allocated - dirs_allocated) * sizeof *dirs);
90 dirs_allocated = new_allocated;
95 /* Return the canonical name of DIR in malloc'd storage. */
97 get_name (char const *dir)
100 if (REPLACE_OPEN_DIRECTORY || !HAVE_CANONICALIZE_FILE_NAME)
102 /* The function canonicalize_file_name has not yet been ported
103 to mingw, with all its drive letter and backslash quirks.
104 Fortunately, getcwd is reliable in this case, but we ensure
105 we can get back to where we started before using it. Treat
106 "." as a special case, as it is frequently encountered. */
107 char *cwd = getcwd (NULL, 0);
109 if (dir[0] == '.' && dir[1] == '\0')
113 result = chdir (dir) ? NULL : getcwd (NULL, 0);
122 /* Avoid changing the directory. */
123 result = canonicalize_file_name (dir);
128 /* Hook into the gnulib replacements for open() and close() to keep track
129 of the open file descriptors. */
131 /* Close FD, cleaning up any fd to name mapping if fd was visiting a
134 _gl_unregister_fd (int fd)
136 if (fd >= 0 && fd < dirs_allocated)
138 free (dirs[fd].name);
139 dirs[fd].name = NULL;
143 /* Mark FD as visiting FILENAME. FD must be non-negative, and refer
144 to an open file descriptor. If REPLACE_OPEN_DIRECTORY is non-zero,
145 this should only be called if FD is visiting a directory. Close FD
146 and return -1 if there is insufficient memory to track the
147 directory name; otherwise return FD. */
149 _gl_register_fd (int fd, const char *filename)
154 if (REPLACE_OPEN_DIRECTORY
155 || (fstat (fd, &statbuf) == 0 && S_ISDIR (statbuf.st_mode)))
157 if (!ensure_dirs_slot (fd)
158 || (dirs[fd].name = get_name (filename)) == NULL)
160 int saved_errno = errno;
169 /* Mark NEWFD as a duplicate of OLDFD; useful from dup, dup2, dup3,
170 and fcntl. Both arguments must be valid and distinct file
171 descriptors. Close NEWFD and return -1 if OLDFD is tracking a
172 directory, but there is insufficient memory to track the same
173 directory in NEWFD; otherwise return NEWFD. */
175 _gl_register_dup (int oldfd, int newfd)
177 assert (0 <= oldfd && 0 <= newfd && oldfd != newfd);
178 if (oldfd < dirs_allocated && dirs[oldfd].name)
180 /* Duplicated a directory; must ensure newfd is allocated. */
181 if (!ensure_dirs_slot (newfd)
182 || (dirs[newfd].name = strdup (dirs[oldfd].name)) == NULL)
184 int saved_errno = errno;
190 else if (newfd < dirs_allocated)
192 /* Duplicated a non-directory; ensure newfd is cleared. */
193 free (dirs[newfd].name);
194 dirs[newfd].name = NULL;
199 /* If FD is currently visiting a directory, then return the name of
200 that directory. Otherwise, return NULL and set errno. */
202 _gl_directory_name (int fd)
204 if (0 <= fd && fd < dirs_allocated && dirs[fd].name != NULL)
205 return dirs[fd].name;
206 /* At this point, fd is either invalid, or open but not a directory.
207 If dup2 fails, errno is correctly EBADF. */
210 if (dup2 (fd, fd) == fd)
218 #if REPLACE_OPEN_DIRECTORY
219 /* Return stat information about FD in STATBUF. Needed when
220 rpl_open() used a dummy file to work around an open() that can't
221 normally visit directories. */
224 rpl_fstat (int fd, struct stat *statbuf)
226 if (0 <= fd && fd < dirs_allocated && dirs[fd].name != NULL)
227 return stat (dirs[fd].name, statbuf);
228 return fstat (fd, statbuf);
232 /* Override opendir() and closedir(), to keep track of the open file
233 descriptors. Needed because there is a function dirfd(). */
236 rpl_closedir (DIR *dp)
240 int retval = closedir (dp);
243 _gl_unregister_fd (fd);
248 rpl_opendir (const char *filename)
253 dp = opendir (filename);
257 if (0 <= fd && _gl_register_fd (fd, filename) != fd)
259 int saved_errno = errno;
268 /* Override dup(), to keep track of open file descriptors. */
274 int newfd = dup (oldfd);
277 newfd = _gl_register_dup (oldfd, newfd);
282 /* Implement fchdir() in terms of chdir(). */
287 const char *name = _gl_directory_name (fd);
288 return name ? chdir (name) : -1;