1 /* 2 * 9p utilities 3 * 4 * Copyright IBM, Corp. 2017 5 * 6 * Authors: 7 * Greg Kurz <groug@kaod.org> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2 or later. 10 * See the COPYING file in the top-level directory. 11 */ 12 13 #ifndef QEMU_9P_UTIL_H 14 #define QEMU_9P_UTIL_H 15 16 #ifdef O_PATH 17 #define O_PATH_9P_UTIL O_PATH 18 #else 19 #define O_PATH_9P_UTIL 0 20 #endif 21 22 static inline void close_preserve_errno(int fd) 23 { 24 int serrno = errno; 25 close(fd); 26 errno = serrno; 27 } 28 29 static inline int openat_dir(int dirfd, const char *name) 30 { 31 return openat(dirfd, name, 32 O_DIRECTORY | O_RDONLY | O_NOFOLLOW | O_PATH_9P_UTIL); 33 } 34 35 static inline int openat_file(int dirfd, const char *name, int flags, 36 mode_t mode) 37 { 38 int fd, serrno, ret; 39 40 again: 41 fd = openat(dirfd, name, flags | O_NOFOLLOW | O_NOCTTY | O_NONBLOCK, 42 mode); 43 if (fd == -1) { 44 if (errno == EPERM && (flags & O_NOATIME)) { 45 /* 46 * The client passed O_NOATIME but we lack permissions to honor it. 47 * Rather than failing the open, fall back without O_NOATIME. This 48 * doesn't break the semantics on the client side, as the Linux 49 * open(2) man page notes that O_NOATIME "may not be effective on 50 * all filesystems". In particular, NFS and other network 51 * filesystems ignore it entirely. 52 */ 53 flags &= ~O_NOATIME; 54 goto again; 55 } 56 return -1; 57 } 58 59 serrno = errno; 60 /* O_NONBLOCK was only needed to open the file. Let's drop it. We don't 61 * do that with O_PATH since fcntl(F_SETFL) isn't supported, and openat() 62 * ignored it anyway. 63 */ 64 if (!(flags & O_PATH_9P_UTIL)) { 65 ret = fcntl(fd, F_SETFL, flags); 66 assert(!ret); 67 } 68 errno = serrno; 69 return fd; 70 } 71 72 ssize_t fgetxattrat_nofollow(int dirfd, const char *path, const char *name, 73 void *value, size_t size); 74 int fsetxattrat_nofollow(int dirfd, const char *path, const char *name, 75 void *value, size_t size, int flags); 76 ssize_t flistxattrat_nofollow(int dirfd, const char *filename, 77 char *list, size_t size); 78 ssize_t fremovexattrat_nofollow(int dirfd, const char *filename, 79 const char *name); 80 81 #endif 82