static TACommandVerdict __fxstat64_cmd(TAThread thread,TAInputStream stream) { struct stat64 buffer; int res; int fildes; // Prepare fildes = readInt(&stream); START_TARGET_OPERATION(thread); errno=0; #if ( __i386__ || __powerpc__ || (__s390__ && !__s390x__)) res = __fxstat64(3, fildes, &buffer); #else res = __fxstat64(0, fildes, &buffer); #endif END_TARGET_OPERATION(thread); // Response writeInt(thread, res); writeInt(thread, errno); writeFileStatus64(thread, &buffer); sendResponse(thread); return taDefaultVerdict; }
/* Create a device file named PATH relative to FD, with permission and special bits MODE and device number DEV (which can be constructed from major and minor device numbers with the `makedev' macro above). */ int __xmknodat (int vers, int fd, const char *path, mode_t mode, dev_t *dev) { if (vers != _MKNOD_VER) { __set_errno (EINVAL); return -1; } if (path == NULL) { __set_errno (EINVAL); return -1; } if (fd != AT_FDCWD && path[0] != '/') { /* Check FD is associated with a directory. */ struct stat64 st; if (__fxstat64 (_STAT_VER, fd, &st) != 0) return -1; if (!S_ISDIR (st.st_mode)) { __set_errno (ENOTDIR); return -1; } } __set_errno (ENOSYS); return -1; }
internal_function _dl_sysdep_read_whole_file (const char *file, size_t *sizep, int prot) { void *result = MAP_FAILED; struct stat64 st; int flags = O_RDONLY; #ifdef O_CLOEXEC flags |= O_CLOEXEC; #endif int fd = __open (file, flags); if (fd >= 0) { if (__fxstat64 (_STAT_VER, fd, &st) >= 0) { *sizep = st.st_size; /* No need to map the file if it is empty. */ if (*sizep != 0) /* Map a copy of the file contents. */ result = __mmap (NULL, *sizep, prot, #ifdef MAP_COPY MAP_COPY #else MAP_PRIVATE #endif #ifdef MAP_FILE | MAP_FILE #endif , fd, 0); } __close (fd); } return result; }
/* Open FILE with access OFLAG. Interpret relative paths relative to the directory associated with FD. If OFLAG includes O_CREAT, a third argument is the file protection. */ int __openat (int fd, const char *file, int oflag, ...) { int mode; if (file == NULL) { __set_errno (EINVAL); return -1; } if (fd != AT_FDCWD && file[0] != '/') { /* Check FD is associated with a directory. */ struct stat64 st; if (__fxstat64 (_STAT_VER, fd, &st) != 0) return -1; if (!S_ISDIR (st.st_mode)) { __set_errno (ENOTDIR); return -1; } } if (oflag & O_CREAT) { va_list arg; va_start (arg, oflag); mode = va_arg (arg, int); va_end (arg); ignore_value (mode); }
DIR * __fdopendir (int fd) { struct stat64 statbuf; if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &statbuf), 0) < 0) return NULL; if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { __set_errno (ENOTDIR); return NULL; } /* Make sure the descriptor allows for reading. */ int flags = __fcntl (fd, F_GETFL); if (__builtin_expect (flags == -1, 0)) return NULL; if (__builtin_expect ((flags & O_ACCMODE) == O_WRONLY, 0)) { __set_errno (EINVAL); return NULL; } return __alloc_dir (fd, false, flags, &statbuf); }
/* * Change to dir specified by fd or p->fts_accpath without getting * tricked by someone changing the world out from underneath us. * Assumes p->fts_dev and p->fts_ino are filled in. */ static int internal_function fts_safe_changedir (FTSOBJ *sp, FTSENTRY *p, int fd, const char *path) { int ret, oerrno, newfd; struct stat64 sb; newfd = fd; if (ISSET(FTS_NOCHDIR)) return (0); if (fd < 0 && (newfd = __open(path, O_RDONLY, 0)) < 0) return (-1); if (__fxstat64(_STAT_VER, newfd, &sb)) { ret = -1; goto bail; } if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) { __set_errno (ENOENT); /* disinformation */ ret = -1; goto bail; } ret = __fchdir(newfd); bail: oerrno = errno; if (fd < 0) (void)__close(newfd); __set_errno (oerrno); return (ret); }
/* Open a directory stream on NAME. */ DIR * __opendir (const char *name) { struct stat64 statbuf; if (__builtin_expect (name[0], '\1') == '\0') { /* POSIX.1-1990 says an empty name gets ENOENT; but `open' might like it fine. */ __set_errno (ENOENT); return NULL; } #ifdef O_DIRECTORY /* Test whether O_DIRECTORY works. */ if (o_directory_works == 0) tryopen_o_directory (); /* We can skip the expensive `stat' call if O_DIRECTORY works. */ if (o_directory_works < 0) #endif { /* We first have to check whether the name is for a directory. We cannot do this after the open() call since the open/close operation performed on, say, a tape device might have undesirable effects. */ if (__builtin_expect (__xstat64 (_STAT_VER, name, &statbuf), 0) < 0) return NULL; if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { __set_errno (ENOTDIR); return NULL; } } int fd = open_not_cancel_2 (name, O_RDONLY|O_NDELAY|EXTRA_FLAGS|O_LARGEFILE); if (__builtin_expect (fd, 0) < 0) return NULL; /* Now make sure this really is a directory and nothing changed since the `stat' call. We do not have to perform the test for the descriptor being associated with a directory if we know the O_DIRECTORY flag is honored by the kernel. */ if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &statbuf), 0) < 0) goto lose; #ifdef O_DIRECTORY if (o_directory_works <= 0) #endif { if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { __set_errno (ENOTDIR); lose: close_not_cancel_no_status (fd); return NULL; } } return __alloc_dir (fd, true, &statbuf); }
/* Return the pathname of the terminal FD is open on, or NULL on errors. The returned storage is good only until the next call to this function. */ char * ttyname (int fd) { struct stat64 st, st1; int dostat = 0; char *name; int save = errno; struct termios term; /* isatty check, tcgetattr is used because it sets the correct errno (EBADF resp. ENOTTY) on error. */ if (__builtin_expect (__tcgetattr (fd, &term) < 0, 0)) return NULL; if (__fxstat64 (_STAT_VER, fd, &st) < 0) return NULL; if (__xstat64 (_STAT_VER, "/dev/pts", &st1) == 0 && S_ISDIR (st1.st_mode)) { #ifdef _STATBUF_ST_RDEV name = getttyname ("/dev/pts", st.st_rdev, st.st_ino, save, &dostat); #else name = getttyname ("/dev/pts", st.st_dev, st.st_ino, save, &dostat); #endif } else { __set_errno (save); name = NULL; } if (!name && dostat != -1) { #ifdef _STATBUF_ST_RDEV name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat); #else name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat); #endif } if (!name && dostat != -1) { dostat = 1; #ifdef _STATBUF_ST_RDEV name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat); #else name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat); #endif } return name; }
int __fxstat64(int ver, int fd, struct stat64 *buf) { if (iscsi_fd_list[fd].is_iscsi == 1) { if (iscsi_fd_list[fd].dup2fd >= 0) { return __fxstat64(ver, iscsi_fd_list[fd].dup2fd, buf); } memset(buf, 0, sizeof(struct stat64)); buf->st_mode = S_IRUSR | S_IRGRP | S_IROTH | S_IFREG; buf->st_size = iscsi_fd_list[fd].num_blocks * iscsi_fd_list[fd].block_size; return 0; } return real_fxstat64(ver, fd, buf); }
/* Should other OSes (e.g., Hurd) have different versions which can be written in a better way? */ static void check_one_fd (int fd, int mode) { /* Note that fcntl() with this parameter is not a cancellation point. */ if (__builtin_expect (__libc_fcntl (fd, F_GETFD), 0) == -1 && errno == EBADF) { const char *name; dev_t dev; /* For writable descriptors we use /dev/full. */ if ((mode & O_ACCMODE) == O_WRONLY) { name = _PATH_DEV "full"; dev = makedev (DEV_FULL_MAJOR, DEV_FULL_MINOR); } else { name = _PATH_DEVNULL; dev = makedev (DEV_NULL_MAJOR, DEV_NULL_MINOR); } /* Something is wrong with this descriptor, it's probably not opened. Open /dev/null so that the SUID program we are about to start does not accidently use this descriptor. */ int nullfd = open_not_cancel (name, mode, 0); /* We are very paranoid here. With all means we try to ensure that we are actually opening the /dev/null device and nothing else. Note that the following code assumes that STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO are the three lowest file decsriptor numbers, in this order. */ struct stat64 st; if (__builtin_expect (nullfd != fd, 0) || __builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) != 0 || __builtin_expect (S_ISCHR (st.st_mode), 1) == 0 || st.st_rdev != dev) /* We cannot even give an error message here since it would run into the same problems. */ while (1) /* Try for ever and ever. */ ABORT_INSTRUCTION; } }
int __lxstat64(int ver, const char *path, struct stat64 *buf) { if (!strncmp(path, "iscsi:", 6)) { int fd, ret; fd = open64(path, 0, 0); if (fd == -1) { return fd; } ret = __fxstat64(ver, fd, buf); close(fd); return ret; } return real_lxstat64(ver, path, buf); }
int __lxstat64(int ver, const char *path, struct stat64 *buf) { if (!strncmp(path, "nfs:", 4)) { int fd, ret; LD_NFS_DPRINTF(9, "__lxstat64(%s)", path); fd = open(path, 0, 0); if (fd == -1) { return fd; } ret = __fxstat64(ver, fd, buf); close(fd); return ret; } return real_lxstat64(ver, path, buf); }
static DIR * opendir_tail (int fd) { if (__glibc_unlikely (fd < 0)) return NULL; /* Now make sure this really is a directory and nothing changed since the `stat' call. The S_ISDIR check is superfluous if O_DIRECTORY works, but it's cheap and we need the stat call for st_blksize anyway. */ struct stat64 statbuf; if (__glibc_unlikely (__fxstat64 (_STAT_VER, fd, &statbuf) < 0)) goto lose; if (__glibc_unlikely (! S_ISDIR (statbuf.st_mode))) { __set_errno (ENOTDIR); lose: close_not_cancel_no_status (fd); return NULL; } return __alloc_dir (fd, true, 0, &statbuf); }
/* Return the pathname of the terminal FD is open on, or NULL on errors. The returned storage is good only until the next call to this function. */ char * ttyname (int fd) { struct stat64 st; char *name; int save = errno; if (!__isatty (fd)) return NULL; if (__fxstat64 (_STAT_VER, fd, &st) < 0) return NULL; name = getttyname ("/dev/pty/slv", st.st_dev, st.st_ino, save); if (!name) { name = getttyname ("/dev/pty/mst", st.st_dev, st.st_ino, save); } return name; }
/* * Change to dir specified by fd or p->fts_accpath without getting * tricked by someone changing the world out from underneath us. * Assumes p->fts_dev and p->fts_ino are filled in. */ static int fts_safe_changedir(FTS * sp, FTSENT * p, int fd, const char * path) { int ret, oerrno, newfd; struct stat64 sb; newfd = fd; if (ISSET(FTS_NOCHDIR)) return (0); /* Permit open(2) on file:// prefixed URI paths. */ /* XXX todo: use Open(2), which is Chroot(2) path invariant. */ /* XXX todo: add Fts(3) options to disable the hackery? */ { const char * lpath = NULL; int ut = urlPath(path, &lpath); if (ut == URL_IS_PATH) path = lpath; } if (fd < 0 && (newfd = __open(path, O_RDONLY, 0)) < 0) return (-1); /*@-sysunrecog -unrecog @*/ if (__fxstat64(_STAT_VER, newfd, &sb)) { ret = -1; goto bail; } /*@=sysunrecog =unrecog @*/ if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) { __set_errno (ENOENT); /* disinformation */ ret = -1; goto bail; } ret = __fchdir(newfd); bail: oerrno = errno; if (fd < 0) (void)__close(newfd); __set_errno (oerrno); return (ret); }
/* Store at most BUFLEN character of the pathname of the terminal FD is open on in BUF. Return 0 on success, otherwise an error number. */ int __ttyname_r (int fd, char *buf, size_t buflen) { struct stat64 st; int save = errno; int ret; if (buflen < sizeof ("/dev/pty/slv/")) { __set_errno (ERANGE); return ERANGE; } if (!__isatty (fd)) { __set_errno (ENOTTY); return ENOTTY; } if (__fxstat64 (_STAT_VER, fd, &st) < 0) return errno; /* Prepare the result buffer. */ memcpy (buf, "/dev/pty/slv/", sizeof ("/dev/pty/slv/")); buflen -= sizeof ("/dev/pty/slv/") - 1; ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save); if (ret) { memcpy (buf, "/dev/pty/mst/", sizeof ("/dev/pty/mst/")); ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save); } return ret; }
int _IO_file_stat (_IO_FILE *fp, void *st) { return __fxstat64 (_STAT_VER, fp->_fileno, (struct stat64 *) st); }
int internal_function __gconv_load_cache (void) { #if 0 int fd; struct stat64 st; struct gconvcache_header *header; #endif /* We cannot use the cache if the GCONV_PATH environment variable is set. */ // __gconv_path_envvar = getenv ("GCONV_PATH"); // if (__gconv_path_envvar != NULL) return -1; #if 0 /* See whether the cache file exists. */ fd = __open (GCONV_MODULES_CACHE, O_RDONLY); if (__builtin_expect (fd, 0) == -1) /* Not available. */ return -1; /* Get information about the file. */ if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) < 0 /* We do not have to start looking at the file if it cannot contain at least the cache header. */ || (size_t) st.st_size < sizeof (struct gconvcache_header)) { close_and_exit: __close (fd); return -1; } /* Make the file content available. */ cache_size = st.st_size; #ifdef _POSIX_MAPPED_FILES gconv_cache = __mmap (NULL, cache_size, PROT_READ, MAP_SHARED, fd, 0); if (__builtin_expect (gconv_cache == MAP_FAILED, 0)) #endif { size_t already_read; gconv_cache = malloc (cache_size); if (gconv_cache == NULL) goto close_and_exit; already_read = 0; do { ssize_t n = __read (fd, (char *) gconv_cache + already_read, cache_size - already_read); if (__builtin_expect (n, 0) == -1) { free (gconv_cache); gconv_cache = NULL; goto close_and_exit; } already_read += n; } while (already_read < cache_size); cache_malloced = 1; } /* We don't need the file descriptor anymore. */ __close (fd); /* Check the consistency. */ header = (struct gconvcache_header *) gconv_cache; if (__builtin_expect (header->magic, GCONVCACHE_MAGIC) != GCONVCACHE_MAGIC || __builtin_expect (header->string_offset >= cache_size, 0) || __builtin_expect (header->hash_offset >= cache_size, 0) || __builtin_expect (header->hash_size == 0, 0) || __builtin_expect ((header->hash_offset + header->hash_size * sizeof (struct hash_entry)) > cache_size, 0) || __builtin_expect (header->module_offset >= cache_size, 0) || __builtin_expect (header->otherconv_offset > cache_size, 0)) { if (cache_malloced) { free (gconv_cache); cache_malloced = 0; } #ifdef _POSIX_MAPPED_FILES else __munmap (gconv_cache, cache_size); #endif gconv_cache = NULL; return -1; } /* That worked. */ return 0; #endif }
/* Return the pathname of the terminal FD is open on, or NULL on errors. The returned storage is good only until the next call to this function. */ char * ttyname (int fd) { static size_t buflen; char procname[30]; struct stat64 st, st1; int dostat = 0; char *name; int save = errno; struct termios term; /* isatty check, tcgetattr is used because it sets the correct errno (EBADF resp. ENOTTY) on error. */ if (__builtin_expect (__tcgetattr (fd, &term) < 0, 0)) return NULL; /* We try using the /proc filesystem. */ *_fitoa_word (fd, __stpcpy (procname, "/proc/self/fd/"), 10, 0) = '\0'; if (buflen == 0) { buflen = 4095; ttyname_buf = (char *) malloc (buflen + 1); if (ttyname_buf == NULL) { buflen = 0; return NULL; } } ssize_t len = __readlink (procname, ttyname_buf, buflen); if (__builtin_expect (len == -1 && errno == ENOENT, 0)) { __set_errno (EBADF); return NULL; } if (__builtin_expect (len != -1 #ifndef __ASSUME_PROC_SELF_FD_SYMLINK /* This is for Linux 2.0. */ && ttyname_buf[0] != '[' #endif , 1)) { if ((size_t) len >= buflen) return NULL; /* readlink need not terminate the string. */ ttyname_buf[len] = '\0'; return ttyname_buf; } if (__fxstat64 (_STAT_VER, fd, &st) < 0) return NULL; if (__xstat64 (_STAT_VER, "/dev/pts", &st1) == 0 && S_ISDIR (st1.st_mode)) { #ifdef _STATBUF_ST_RDEV name = getttyname ("/dev/pts", st.st_rdev, st.st_ino, save, &dostat); #else name = getttyname ("/dev/pts", st.st_dev, st.st_ino, save, &dostat); #endif } else { __set_errno (save); name = NULL; } if (!name && dostat != -1) { #ifdef _STATBUF_ST_RDEV name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat); #else name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat); #endif } if (!name && dostat != -1) { dostat = 1; #ifdef _STATBUF_ST_RDEV name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat); #else name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat); #endif } return name; }
/* Store at most BUFLEN character of the pathname of the terminal FD is open on in BUF. Return 0 on success, otherwise an error number. */ int __ttyname_r (int fd, char *buf, size_t buflen) { char procname[30]; struct stat64 st, st1; int dostat = 0; int save = errno; /* Test for the absolute minimal size. This makes life easier inside the loop. */ if (!buf) { __set_errno (EINVAL); return EINVAL; } if (buflen < sizeof ("/dev/pts/")) { __set_errno (ERANGE); return ERANGE; } /* isatty check, tcgetattr is used because it sets the correct errno (EBADF resp. ENOTTY) on error. */ struct termios term; if (__glibc_unlikely (__tcgetattr (fd, &term) < 0)) return errno; if (__fxstat64 (_STAT_VER, fd, &st) < 0) return errno; /* We try using the /proc filesystem. */ *_fitoa_word (fd, __stpcpy (procname, "/proc/self/fd/"), 10, 0) = '\0'; ssize_t ret = __readlink (procname, buf, buflen - 1); if (__glibc_unlikely (ret == -1 && errno == ENAMETOOLONG)) { __set_errno (ERANGE); return ERANGE; } if (__glibc_likely (ret != -1)) { #define UNREACHABLE_LEN strlen ("(unreachable)") if (ret > UNREACHABLE_LEN && memcmp (buf, "(unreachable)", UNREACHABLE_LEN) == 0) { memmove (buf, buf + UNREACHABLE_LEN, ret - UNREACHABLE_LEN); ret -= UNREACHABLE_LEN; } /* readlink need not terminate the string. */ buf[ret] = '\0'; /* Verify readlink result, fall back on iterating through devices. */ if (buf[0] == '/' && __xstat64 (_STAT_VER, buf, &st1) == 0 #ifdef _STATBUF_ST_RDEV && S_ISCHR (st1.st_mode) && st1.st_rdev == st.st_rdev #else && st1.st_ino == st.st_ino && st1.st_dev == st.st_dev #endif ) return 0; } /* Prepare the result buffer. */ memcpy (buf, "/dev/pts/", sizeof ("/dev/pts/")); buflen -= sizeof ("/dev/pts/") - 1; if (__xstat64 (_STAT_VER, buf, &st1) == 0 && S_ISDIR (st1.st_mode)) { #ifdef _STATBUF_ST_RDEV ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save, &dostat); #else ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save, &dostat); #endif } else { __set_errno (save); ret = ENOENT; } if (ret && dostat != -1) { buf[sizeof ("/dev/") - 1] = '\0'; buflen += sizeof ("pts/") - 1; #ifdef _STATBUF_ST_RDEV ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save, &dostat); #else ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save, &dostat); #endif } if (ret && dostat != -1) { buf[sizeof ("/dev/") - 1] = '\0'; dostat = 1; #ifdef _STATBUF_ST_RDEV ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save, &dostat); #else ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save, &dostat); #endif } return ret; }
/* Store at most BUFLEN character of the pathname of the terminal FD is open on in BUF. Return 0 on success, otherwise an error number. */ int __ttyname_r (int fd, char *buf, size_t buflen) { char procname[30]; struct stat64 st, st1; int dostat = 0; int save = errno; int ret; /* Test for the absolute minimal size. This makes life easier inside the loop. */ if (!buf) { __set_errno (EINVAL); return EINVAL; } if (buflen < sizeof ("/dev/pts/")) { __set_errno (ERANGE); return ERANGE; } /* We try using the /proc filesystem. */ *_fitoa_word (fd, __stpcpy (procname, "/proc/self/fd/"), 10, 0) = '\0'; ret = __readlink (procname, buf, buflen - 1); if (ret == -1 && errno == ENOENT) { __set_errno (EBADF); return EBADF; } if (!__isatty (fd)) { __set_errno (ENOTTY); return ENOTTY; } if (ret == -1 && errno == ENAMETOOLONG) { __set_errno (ERANGE); return ERANGE; } if (ret != -1 && buf[0] != '[') { buf[ret] = '\0'; return 0; } if (__fxstat64 (_STAT_VER, fd, &st) < 0) return errno; /* Prepare the result buffer. */ memcpy (buf, "/dev/pts/", sizeof ("/dev/pts/")); buflen -= sizeof ("/dev/pts/") - 1; if (__xstat64 (_STAT_VER, buf, &st1) == 0 && S_ISDIR (st1.st_mode)) { #ifdef _STATBUF_ST_RDEV ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save, &dostat); #else ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save, &dostat); #endif } else { __set_errno (save); ret = ENOENT; } if (ret && dostat != -1) { buf[sizeof ("/dev/") - 1] = '\0'; buflen += sizeof ("pts/") - 1; #ifdef _STATBUF_ST_RDEV ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save, &dostat); #else ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save, &dostat); #endif } if (ret && dostat != -1) { buf[sizeof ("/dev/") - 1] = '\0'; dostat = 1; #ifdef _STATBUF_ST_RDEV ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save, &dostat); #else ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save, &dostat); #endif } return ret; }
/* Get file-specific information about descriptor FD. */ long int __fpathconf (int fd, int name) { if (fd < 0) { __set_errno (EBADF); return -1; } switch (name) { default: __set_errno (EINVAL); return -1; case _PC_LINK_MAX: #ifdef LINK_MAX return LINK_MAX; #else return -1; #endif case _PC_MAX_CANON: #ifdef MAX_CANON return MAX_CANON; #else return -1; #endif case _PC_MAX_INPUT: #ifdef MAX_INPUT return MAX_INPUT; #else return -1; #endif case _PC_NAME_MAX: #ifdef NAME_MAX { struct statvfs64 sv; int save_errno = errno; if (__fstatvfs64 (fd, &sv) < 0) { if (errno == ENOSYS) { __set_errno (save_errno); return NAME_MAX; } else if (errno == ENODEV) __set_errno (EINVAL); return -1; } else { return sv.f_namemax; } } #else return -1; #endif case _PC_PATH_MAX: #ifdef PATH_MAX return PATH_MAX; #else return -1; #endif case _PC_PIPE_BUF: #ifdef PIPE_BUF return PIPE_BUF; #else return -1; #endif case _PC_CHOWN_RESTRICTED: #ifdef _POSIX_CHOWN_RESTRICTED return _POSIX_CHOWN_RESTRICTED; #else return -1; #endif case _PC_NO_TRUNC: #ifdef _POSIX_NO_TRUNC return _POSIX_NO_TRUNC; #else return -1; #endif case _PC_VDISABLE: #ifdef _POSIX_VDISABLE return _POSIX_VDISABLE; #else return -1; #endif case _PC_SYNC_IO: #ifdef _POSIX_SYNC_IO return _POSIX_SYNC_IO; #else return -1; #endif case _PC_ASYNC_IO: #ifdef _POSIX_ASYNC_IO { /* AIO is only allowed on regular files and block devices. */ struct stat64 st; if (__fxstat64 (_STAT_VER, fd, &st) < 0 || (! S_ISREG (st.st_mode) && ! S_ISBLK (st.st_mode))) return -1; else return 1; } #else return -1; #endif case _PC_PRIO_IO: #ifdef _POSIX_PRIO_IO return _POSIX_PRIO_IO; #else return -1; #endif case _PC_SOCK_MAXBUF: #ifdef SOCK_MAXBUF return SOCK_MAXBUF; #else return -1; #endif case _PC_FILESIZEBITS: #ifdef FILESIZEBITS return FILESIZEBITS; #else /* We let platforms with larger file sizes overwrite this value. */ return 32; #endif case _PC_REC_INCR_XFER_SIZE: /* XXX It is not entirely clear what the limit is supposed to do. What is incremented? */ return -1; case _PC_REC_MAX_XFER_SIZE: /* XXX It is not entirely clear what the limit is supposed to do. In general there is no top limit of the number of bytes which case be transported at once. */ return -1; case _PC_REC_MIN_XFER_SIZE: { /* XXX It is not entirely clear what the limit is supposed to do. I assume this is the block size of the filesystem. */ struct statvfs64 sv; if (__fstatvfs64 (fd, &sv) < 0) return -1; return sv.f_bsize; } case _PC_REC_XFER_ALIGN: { /* XXX It is not entirely clear what the limit is supposed to do. I assume that the number should reflect the minimal block alignment. */ struct statvfs64 sv; if (__fstatvfs64 (fd, &sv) < 0) return -1; return sv.f_frsize; } case _PC_ALLOC_SIZE_MIN: { /* XXX It is not entirely clear what the limit is supposed to do. I assume that the number should reflect the minimal block alignment. */ struct statvfs64 sv; if (__fstatvfs64 (fd, &sv) < 0) return -1; return sv.f_frsize; } case _PC_SYMLINK_MAX: /* In general there are no limits. If a system has one it should overwrite this case. */ return -1; case _PC_2_SYMLINKS: /* Unix systems generally have symlinks. */ return 1; } }
int attribute_hidden fstat64 (int fd, struct stat64 *buf) { return __fxstat64 (_STAT_VER, fd, buf); }
internal_function __opendirat (int dfd, const char *name) { struct stat64 statbuf; struct stat64 *statp = NULL; if (__builtin_expect (name[0], '\1') == '\0') { /* POSIX.1-1990 says an empty name gets ENOENT; but `open' might like it fine. */ __set_errno (ENOENT); return NULL; } #ifdef O_DIRECTORY /* Test whether O_DIRECTORY works. */ if (o_directory_works == 0) tryopen_o_directory (); /* We can skip the expensive `stat' call if O_DIRECTORY works. */ if (o_directory_works < 0) #endif { /* We first have to check whether the name is for a directory. We cannot do this after the open() call since the open/close operation performed on, say, a tape device might have undesirable effects. */ if (__builtin_expect (__xstat64 (_STAT_VER, name, &statbuf), 0) < 0) return NULL; if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { __set_errno (ENOTDIR); return NULL; } } int flags = O_RDONLY|O_NDELAY|EXTRA_FLAGS|O_LARGEFILE; #ifdef O_CLOEXEC flags |= O_CLOEXEC; #endif int fd; #ifdef IS_IN_rtld assert (dfd == AT_FDCWD); fd = open_not_cancel_2 (name, flags); #else fd = openat_not_cancel_3 (dfd, name, flags); #endif if (__builtin_expect (fd, 0) < 0) return NULL; #ifdef O_DIRECTORY if (o_directory_works <= 0) #endif { /* Now make sure this really is a directory and nothing changed since the `stat' call. */ if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &statbuf), 0) < 0) goto lose; if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { __set_errno (ENOTDIR); lose: close_not_cancel_no_status (fd); return NULL; } statp = &statbuf; } return __alloc_dir (fd, true, 0, statp); }
/* Return the pathname of the terminal FD is open on, or NULL on errors. The returned storage is good only until the next call to this function. */ char * ttyname (int fd) { static size_t buflen; char procname[30]; struct stat64 st, st1; int dostat = 0; char *name; int save = errno; struct termios term; /* isatty check, tcgetattr is used because it sets the correct errno (EBADF resp. ENOTTY) on error. */ if (__glibc_unlikely (__tcgetattr (fd, &term) < 0)) return NULL; if (__fxstat64 (_STAT_VER, fd, &st) < 0) return NULL; /* We try using the /proc filesystem. */ *_fitoa_word (fd, __stpcpy (procname, "/proc/self/fd/"), 10, 0) = '\0'; if (buflen == 0) { buflen = 4095; ttyname_buf = (char *) malloc (buflen + 1); if (ttyname_buf == NULL) { buflen = 0; return NULL; } } ssize_t len = __readlink (procname, ttyname_buf, buflen); if (__glibc_likely (len != -1)) { if ((size_t) len >= buflen) return NULL; #define UNREACHABLE_LEN strlen ("(unreachable)") if (len > UNREACHABLE_LEN && memcmp (ttyname_buf, "(unreachable)", UNREACHABLE_LEN) == 0) { memmove (ttyname_buf, ttyname_buf + UNREACHABLE_LEN, len - UNREACHABLE_LEN); len -= UNREACHABLE_LEN; } /* readlink need not terminate the string. */ ttyname_buf[len] = '\0'; /* Verify readlink result, fall back on iterating through devices. */ if (ttyname_buf[0] == '/' && __xstat64 (_STAT_VER, ttyname_buf, &st1) == 0 #ifdef _STATBUF_ST_RDEV && S_ISCHR (st1.st_mode) && st1.st_rdev == st.st_rdev #else && st1.st_ino == st.st_ino && st1.st_dev == st.st_dev #endif ) return ttyname_buf; } if (__xstat64 (_STAT_VER, "/dev/pts", &st1) == 0 && S_ISDIR (st1.st_mode)) { #ifdef _STATBUF_ST_RDEV name = getttyname ("/dev/pts", st.st_rdev, st.st_ino, save, &dostat); #else name = getttyname ("/dev/pts", st.st_dev, st.st_ino, save, &dostat); #endif } else { __set_errno (save); name = NULL; } if (!name && dostat != -1) { #ifdef _STATBUF_ST_RDEV name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat); #else name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat); #endif } if (!name && dostat != -1) { dostat = 1; #ifdef _STATBUF_ST_RDEV name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat); #else name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat); #endif } return name; }
void attribute_hidden __atfct_seterrno_2 (int errval, int fd1, const char *buf1, int fd2, const char *buf2) { if (buf1 != NULL || buf2 != NULL) { struct stat64 st; if (errval == ENOTDIR) { /* This can mean either the file descriptor is invalid or /proc is not mounted. */ if (buf1 != NULL) { if (__fxstat64 (_STAT_VER, fd1, &st) != 0) /* errno is already set correctly. */ return; /* If /proc is not mounted there is nothing we can do. */ if (S_ISDIR (st.st_mode) && (__xstat64 (_STAT_VER, "/proc/self/fd", &st) != 0 || !S_ISDIR (st.st_mode))) { errval = ENOSYS; goto out; } } if (buf2 != NULL) { if (__fxstat64 (_STAT_VER, fd2, &st) != 0) /* errno is already set correctly. */ return; /* If /proc is not mounted there is nothing we can do. */ if (S_ISDIR (st.st_mode) && (__xstat64 (_STAT_VER, "/proc/self/fd", &st) != 0 || !S_ISDIR (st.st_mode))) errval = ENOSYS; } } else if (errval == ENOENT) { /* This could mean the file descriptor is not valid. We reuse BUF for the stat call. Find the slash after the file descriptor number. */ if (buf1 != NULL) { *(char *) strchr (buf1 + sizeof "/proc/self/fd", '/') = '\0'; int e = __lxstat64 (_STAT_VER, buf1, &st); if ((e == -1 && errno == ENOENT) ||(e == 0 && !S_ISLNK (st.st_mode))) { errval = EBADF; goto out; } } if (buf2 != NULL) { *(char *) strchr (buf2 + sizeof "/proc/self/fd", '/') = '\0'; int e = __lxstat64 (_STAT_VER, buf2, &st); if ((e == -1 && errno == ENOENT) ||(e == 0 && !S_ISLNK (st.st_mode))) errval = EBADF; } } } out: __set_errno (errval); }
int __open_catalog (const char *cat_name, const char *nlspath, const char *env_var, __nl_catd catalog) { int fd = -1; struct stat64 st; int swapping; size_t cnt; size_t max_offset; size_t tab_size; const char *lastp; int result = -1; char *buf = NULL; if (strchr (cat_name, '/') != NULL || nlspath == NULL) fd = open_not_cancel_2 (cat_name, O_RDONLY); else { const char *run_nlspath = nlspath; #define ENOUGH(n) \ if (__glibc_unlikely (bufact + (n) >= bufmax)) \ { \ char *old_buf = buf; \ bufmax += (bufmax < 256 + (n)) ? 256 + (n) : bufmax; \ buf = realloc (buf, bufmax); \ if (__glibc_unlikely (buf == NULL)) \ { \ free (old_buf); \ return -1; \ } \ } /* The RUN_NLSPATH variable contains a colon separated list of descriptions where we expect to find catalogs. We have to recognize certain % substitutions and stop when we found the first existing file. */ size_t bufact; size_t bufmax = 0; size_t len; fd = -1; while (*run_nlspath != '\0') { bufact = 0; if (*run_nlspath == ':') { /* Leading colon or adjacent colons - treat same as %N. */ len = strlen (cat_name); ENOUGH (len); memcpy (&buf[bufact], cat_name, len); bufact += len; } else while (*run_nlspath != ':' && *run_nlspath != '\0') if (*run_nlspath == '%') { const char *tmp; ++run_nlspath; /* We have seen the `%'. */ switch (*run_nlspath++) { case 'N': /* Use the catalog name. */ len = strlen (cat_name); ENOUGH (len); memcpy (&buf[bufact], cat_name, len); bufact += len; break; case 'L': /* Use the current locale category value. */ len = strlen (env_var); ENOUGH (len); memcpy (&buf[bufact], env_var, len); bufact += len; break; case 'l': /* Use language element of locale category value. */ tmp = env_var; do { ENOUGH (1); buf[bufact++] = *tmp++; } while (*tmp != '\0' && *tmp != '_' && *tmp != '.'); break; case 't': /* Use territory element of locale category value. */ tmp = env_var; do ++tmp; while (*tmp != '\0' && *tmp != '_' && *tmp != '.'); if (*tmp == '_') { ++tmp; do { ENOUGH (1); buf[bufact++] = *tmp++; } while (*tmp != '\0' && *tmp != '.'); } break; case 'c': /* Use code set element of locale category value. */ tmp = env_var; do ++tmp; while (*tmp != '\0' && *tmp != '.'); if (*tmp == '.') { ++tmp; do { ENOUGH (1); buf[bufact++] = *tmp++; } while (*tmp != '\0'); } break; case '%': ENOUGH (1); buf[bufact++] = '%'; break; default: /* Unknown variable: ignore this path element. */ bufact = 0; while (*run_nlspath != '\0' && *run_nlspath != ':') ++run_nlspath; break; } } else { ENOUGH (1); buf[bufact++] = *run_nlspath++; } ENOUGH (1); buf[bufact] = '\0'; if (bufact != 0) { fd = open_not_cancel_2 (buf, O_RDONLY); if (fd >= 0) break; } ++run_nlspath; } } /* Avoid dealing with directories and block devices */ if (__builtin_expect (fd, 0) < 0) { free (buf); return -1; } if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) < 0) goto close_unlock_return; if (__builtin_expect (!S_ISREG (st.st_mode), 0) || (size_t) st.st_size < sizeof (struct catalog_obj)) { /* `errno' is not set correctly but the file is not usable. Use an reasonable error value. */ __set_errno (EINVAL); goto close_unlock_return; } catalog->file_size = st.st_size; #ifdef _POSIX_MAPPED_FILES # ifndef MAP_COPY /* Linux seems to lack read-only copy-on-write. */ # define MAP_COPY MAP_PRIVATE # endif # ifndef MAP_FILE /* Some systems do not have this flag; it is superfluous. */ # define MAP_FILE 0 # endif catalog->file_ptr = (struct catalog_obj *) __mmap (NULL, st.st_size, PROT_READ, MAP_FILE|MAP_COPY, fd, 0); if (__builtin_expect (catalog->file_ptr != (struct catalog_obj *) MAP_FAILED, 1)) /* Tell the world we managed to mmap the file. */ catalog->status = mmapped; else #endif /* _POSIX_MAPPED_FILES */ { /* mmap failed perhaps because the system call is not implemented. Try to load the file. */ size_t todo; catalog->file_ptr = malloc (st.st_size); if (catalog->file_ptr == NULL) goto close_unlock_return; todo = st.st_size; /* Save read, handle partial reads. */ do { size_t now = read_not_cancel (fd, (((char *) catalog->file_ptr) + (st.st_size - todo)), todo); if (now == 0 || now == (size_t) -1) { #ifdef EINTR if (now == (size_t) -1 && errno == EINTR) continue; #endif free ((void *) catalog->file_ptr); goto close_unlock_return; } todo -= now; } while (todo > 0); catalog->status = malloced; } /* Determine whether the file is a catalog file and if yes whether it is written using the correct byte order. Else we have to swap the values. */ if (__glibc_likely (catalog->file_ptr->magic == CATGETS_MAGIC)) swapping = 0; else if (catalog->file_ptr->magic == SWAPU32 (CATGETS_MAGIC)) swapping = 1; else { invalid_file: /* Invalid file. Free the resources and mark catalog as not usable. */ #ifdef _POSIX_MAPPED_FILES if (catalog->status == mmapped) __munmap ((void *) catalog->file_ptr, catalog->file_size); else #endif /* _POSIX_MAPPED_FILES */ free (catalog->file_ptr); goto close_unlock_return; } #define SWAP(x) (swapping ? SWAPU32 (x) : (x)) /* Get dimensions of the used hashing table. */ catalog->plane_size = SWAP (catalog->file_ptr->plane_size); catalog->plane_depth = SWAP (catalog->file_ptr->plane_depth); /* The file contains two versions of the pointer tables. Pick the right one for the local byte order. */ #if __BYTE_ORDER == __LITTLE_ENDIAN catalog->name_ptr = &catalog->file_ptr->name_ptr[0]; #elif __BYTE_ORDER == __BIG_ENDIAN catalog->name_ptr = &catalog->file_ptr->name_ptr[catalog->plane_size * catalog->plane_depth * 3]; #else # error Cannot handle __BYTE_ORDER byte order #endif /* The rest of the file contains all the strings. They are addressed relative to the position of the first string. */ catalog->strings = (const char *) &catalog->file_ptr->name_ptr[catalog->plane_size * catalog->plane_depth * 3 * 2]; /* Determine the largest string offset mentioned in the table. */ max_offset = 0; tab_size = 3 * catalog->plane_size * catalog->plane_depth; for (cnt = 2; cnt < tab_size; cnt += 3) if (catalog->name_ptr[cnt] > max_offset) max_offset = catalog->name_ptr[cnt]; /* Now we can check whether the file is large enough to contain the tables it says it contains. */ if ((size_t) st.st_size <= (sizeof (struct catalog_obj) + 2 * tab_size + max_offset)) /* The last string is not contained in the file. */ goto invalid_file; lastp = catalog->strings + max_offset; max_offset = (st.st_size - sizeof (struct catalog_obj) + 2 * tab_size + max_offset); while (*lastp != '\0') { if (--max_offset == 0) goto invalid_file; ++lastp; } /* We succeeded. */ result = 0; /* Release the lock again. */ close_unlock_return: close_not_cancel_no_status (fd); free (buf); return result; }
int __posix_fallocate64_l64 (int fd, __off64_t offset, __off64_t len) { struct stat64 st; if (offset < 0 || len < 0) return EINVAL; /* Perform overflow check. The outer cast relies on a GCC extension. */ if ((__off64_t) ((uint64_t) offset + (uint64_t) len) < 0) return EFBIG; /* pwrite64 below will not do the right thing in O_APPEND mode. */ { int flags = __fcntl (fd, F_GETFL, 0); if (flags < 0 || (flags & O_APPEND) != 0) return EBADF; } /* We have to make sure that this is really a regular file. */ if (__fxstat64 (_STAT_VER, fd, &st) != 0) return EBADF; if (S_ISFIFO (st.st_mode)) return ESPIPE; if (! S_ISREG (st.st_mode)) return ENODEV; if (len == 0) { /* This is racy, but there is no good way to satisfy a zero-length allocation request. */ if (st.st_size < offset) { int ret = __ftruncate64 (fd, offset); if (ret != 0) ret = errno; return ret; } return 0; } /* Minimize data transfer for network file systems, by issuing single-byte write requests spaced by the file system block size. (Most local file systems have fallocate support, so this fallback code is not used there.) */ unsigned increment; { struct statfs64 f; if (__fstatfs64 (fd, &f) != 0) return errno; if (f.f_bsize == 0) increment = 512; else if (f.f_bsize < 4096) increment = f.f_bsize; else /* NFS clients do not propagate the block size of the underlying storage and may report a much larger value which would still leave holes after the loop below, so we cap the increment at 4096. */ increment = 4096; } /* Write a null byte to every block. This is racy; we currently lack a better option. Compare-and-swap against a file mapping might address local races, but requires interposition of a signal handler to catch SIGBUS. */ for (offset += (len - 1) % increment; len > 0; offset += increment) { len -= increment; if (offset < st.st_size) { unsigned char c; ssize_t rsize = __libc_pread64 (fd, &c, 1, offset); if (rsize < 0) return errno; /* If there is a non-zero byte, the block must have been allocated already. */ else if (rsize == 1 && c != 0) continue; } if (__libc_pwrite64 (fd, "", 1, offset) != 1) return errno; } return 0; }
/* Open a directory stream on NAME. */ DIR * __opendir (const char *name) { DIR *dirp; struct stat64 statbuf; int fd; size_t allocation; int save_errno; if (__builtin_expect (name[0], '\1') == '\0') { /* POSIX.1-1990 says an empty name gets ENOENT; but `open' might like it fine. */ __set_errno (ENOENT); return NULL; } #ifdef O_DIRECTORY /* Test whether O_DIRECTORY works. */ if (o_directory_works == 0) tryopen_o_directory (); /* We can skip the expensive `stat' call if O_DIRECTORY works. */ if (o_directory_works < 0) #endif { /* We first have to check whether the name is for a directory. We cannot do this after the open() call since the open/close operation performed on, say, a tape device might have undesirable effects. */ if (__builtin_expect (__xstat64 (_STAT_VER, name, &statbuf), 0) < 0) return NULL; if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { __set_errno (ENOTDIR); return NULL; } } fd = open_not_cancel_2 (name, O_RDONLY|O_NDELAY|EXTRA_FLAGS|O_LARGEFILE); if (__builtin_expect (fd, 0) < 0) return NULL; /* Now make sure this really is a directory and nothing changed since the `stat' call. We do not have to perform the test for the descriptor being associated with a directory if we know the O_DIRECTORY flag is honored by the kernel. */ if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &statbuf), 0) < 0) goto lose; #ifdef O_DIRECTORY if (o_directory_works <= 0) #endif { if (__builtin_expect (! S_ISDIR (statbuf.st_mode), 0)) { save_errno = ENOTDIR; goto lose; } } if (__builtin_expect (__fcntl (fd, F_SETFD, FD_CLOEXEC), 0) < 0) goto lose; #ifdef _STATBUF_ST_BLKSIZE if (__builtin_expect ((size_t) statbuf.st_blksize >= sizeof (struct dirent64), 1)) allocation = statbuf.st_blksize; else #endif allocation = (BUFSIZ < sizeof (struct dirent64) ? sizeof (struct dirent64) : BUFSIZ); const int pad = -sizeof (DIR) % __alignof__ (struct dirent64); dirp = (DIR *) malloc (sizeof (DIR) + allocation + pad); if (dirp == NULL) lose: { save_errno = errno; close_not_cancel_no_status (fd); __set_errno (save_errno); return NULL; } memset (dirp, '\0', sizeof (DIR)); dirp->data = (char *) (dirp + 1) + pad; dirp->allocation = allocation; dirp->fd = fd; __libc_lock_init (dirp->lock); return dirp; }
int __ptsname_internal (int fd, char *buf, size_t buflen, struct stat64 *stp) { int save_errno = errno; unsigned int ptyno; if (buf == NULL) { __set_errno (EINVAL); return EINVAL; } if (!__isatty (fd)) { __set_errno (ENOTTY); return ENOTTY; } #ifdef TIOCGPTN if (__ioctl (fd, TIOCGPTN, &ptyno) == 0) { /* Buffer we use to print the number in. For a maximum size for `int' of 8 bytes we never need more than 20 digits. */ char numbuf[21]; const char *devpts = _PATH_DEVPTS; const size_t devptslen = strlen (_PATH_DEVPTS); char *p; numbuf[sizeof (numbuf) - 1] = '\0'; p = _itoa_word (ptyno, &numbuf[sizeof (numbuf) - 1], 10, 0); if (buflen < devptslen + (&numbuf[sizeof (numbuf)] - p)) { __set_errno (ERANGE); return ERANGE; } memcpy (__stpcpy (buf, devpts), p, &numbuf[sizeof (numbuf)] - p); } else if (errno != EINVAL) return errno; else #endif { char *p; if (buflen < strlen (_PATH_TTY) + 3) { __set_errno (ERANGE); return ERANGE; } if (__fxstat64 (_STAT_VER, fd, stp) < 0) return errno; /* Check if FD really is a master pseudo terminal. */ if (! MASTER_P (stp->st_rdev)) { __set_errno (ENOTTY); return ENOTTY; } ptyno = minor (stp->st_rdev); if (ptyno / 16 >= strlen (__libc_ptyname1)) { __set_errno (ENOTTY); return ENOTTY; } p = __stpcpy (buf, _PATH_TTY); p[0] = __libc_ptyname1[ptyno / 16]; p[1] = __libc_ptyname2[ptyno % 16]; p[2] = '\0'; } if (__xstat64 (_STAT_VER, buf, stp) < 0) return errno; /* Check if the name we're about to return really corresponds to a slave pseudo terminal. */ if (! S_ISCHR (stp->st_mode) || ! SLAVE_P (stp->st_rdev)) { /* This really is a configuration problem. */ __set_errno (ENOTTY); return ENOTTY; } __set_errno (save_errno); return 0; }