/* provide a replacement openat function
- Copyright (C) 2004-2009 Free Software Foundation, Inc.
+ Copyright (C) 2004-2011 Free Software Foundation, Inc.
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
#include <string.h>
#include <sys/stat.h>
-#include "dirname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
+#include "dosname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
#include "openat-priv.h"
#include "save-cwd.h"
va_start (arg, flags);
/* We have to use PROMOTED_MODE_T instead of mode_t, otherwise GCC 4
- creates crashing code when 'mode_t' is smaller than 'int'. */
+ creates crashing code when 'mode_t' is smaller than 'int'. */
mode = va_arg (arg, PROMOTED_MODE_T);
va_end (arg);
}
-#if OPEN_TRAILING_SLASH_BUG
+# 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 <http://www.opengroup.org/susv3/basedefs/xbd_chap04.html>
{
size_t len = strlen (filename);
if (len > 0 && filename[len - 1] == '/')
- {
- errno = EISDIR;
- return -1;
- }
+ {
+ errno = EISDIR;
+ return -1;
+ }
}
-#endif
+# endif
fd = openat (dfd, filename, flags, mode);
-#if OPEN_TRAILING_SLASH_BUG
+# if OPEN_TRAILING_SLASH_BUG
/* If the filename ends in a slash and fd does not refer to a directory,
then fail.
Rationale: POSIX <http://www.opengroup.org/susv3/basedefs/xbd_chap04.html>
/* We know len is positive, since open did not fail with ENOENT. */
size_t len = strlen (filename);
if (filename[len - 1] == '/')
- {
- struct stat statbuf;
-
- if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode))
- {
- close (fd);
- errno = ENOTDIR;
- return -1;
- }
- }
+ {
+ struct stat statbuf;
+
+ if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode))
+ {
+ close (fd);
+ errno = ENOTDIR;
+ return -1;
+ }
+ }
}
-#endif
+# endif
return fd;
}
va_start (arg, flags);
/* We have to use PROMOTED_MODE_T instead of mode_t, otherwise GCC 4
- creates crashing code when 'mode_t' is smaller than 'int'. */
+ creates crashing code when 'mode_t' is smaller than 'int'. */
mode = va_arg (arg, PROMOTED_MODE_T);
va_end (arg);
int
openat_permissive (int fd, char const *file, int flags, mode_t mode,
- int *cwd_errno)
+ int *cwd_errno)
{
struct saved_cwd saved_cwd;
int saved_errno;
char *proc_file = openat_proc_name (buf, fd, file);
if (proc_file)
{
- int open_result = open (proc_file, flags, mode);
- int open_errno = errno;
- if (proc_file != buf)
- free (proc_file);
- /* If the syscall succeeds, or if it fails with an unexpected
- errno value, then return right away. Otherwise, fall through
- and resort to using save_cwd/restore_cwd. */
- if (0 <= open_result || ! EXPECTED_ERRNO (open_errno))
- {
- errno = open_errno;
- return open_result;
- }
+ int open_result = open (proc_file, flags, mode);
+ int open_errno = errno;
+ if (proc_file != buf)
+ free (proc_file);
+ /* If the syscall succeeds, or if it fails with an unexpected
+ errno value, then return right away. Otherwise, fall through
+ and resort to using save_cwd/restore_cwd. */
+ if (0 <= open_result || ! EXPECTED_ERRNO (open_errno))
+ {
+ errno = open_errno;
+ return open_result;
+ }
}
}
if (! save_ok)
{
if (! cwd_errno)
- openat_save_fail (errno);
+ openat_save_fail (errno);
*cwd_errno = errno;
}
+ if (0 <= fd && fd == saved_cwd.desc)
+ {
+ /* If saving the working directory collides with the user's
+ requested fd, then the user's fd must have been closed to
+ begin with. */
+ free_cwd (&saved_cwd);
+ errno = EBADF;
+ return -1;
+ }
err = fchdir (fd);
saved_errno = errno;
err = open (file, flags, mode);
saved_errno = errno;
if (save_ok && restore_cwd (&saved_cwd) != 0)
- {
- if (! cwd_errno)
- {
- /* Don't write a message to just-created fd 2. */
- saved_errno = errno;
- if (err == STDERR_FILENO)
- close (err);
- openat_restore_fail (saved_errno);
- }
- *cwd_errno = errno;
- }
+ {
+ if (! cwd_errno)
+ {
+ /* Don't write a message to just-created fd 2. */
+ saved_errno = errno;
+ if (err == STDERR_FILENO)
+ close (err);
+ openat_restore_fail (saved_errno);
+ }
+ *cwd_errno = errno;
+ }
}
free_cwd (&saved_cwd);
openat_needs_fchdir (void)
{
bool needs_fchdir = true;
- int fd = open ("/", O_RDONLY);
+ int fd = open ("/", O_SEARCH);
if (0 <= fd)
{
char buf[OPENAT_BUFFER_SIZE];
char *proc_file = openat_proc_name (buf, fd, ".");
if (proc_file)
- {
- needs_fchdir = false;
- if (proc_file != buf)
- free (proc_file);
- }
+ {
+ needs_fchdir = false;
+ if (proc_file != buf)
+ free (proc_file);
+ }
close (fd);
}