1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <sys/inttypes.h> 30 #include <unistd.h> 31 #include <fcntl.h> 32 #include <errno.h> 33 #include <libintl.h> 34 #include <stdio.h> 35 36 #include <sys/lx_types.h> 37 #include <sys/lx_debug.h> 38 #include <sys/lx_syscall.h> 39 #include <sys/lx_fcntl.h> 40 #include <sys/lx_misc.h> 41 42 static int 43 ltos_open_flags(uintptr_t p2) 44 { 45 int flags; 46 47 if ((p2 & O_ACCMODE) == LX_O_RDONLY) 48 flags = O_RDONLY; 49 else if ((p2 & O_ACCMODE) == LX_O_WRONLY) 50 flags = O_WRONLY; 51 else 52 flags = O_RDWR; 53 54 if (p2 & LX_O_CREAT) { 55 flags |= O_CREAT; 56 } 57 58 if (p2 & LX_O_EXCL) 59 flags |= O_EXCL; 60 if (p2 & LX_O_NOCTTY) 61 flags |= O_NOCTTY; 62 if (p2 & LX_O_TRUNC) 63 flags |= O_TRUNC; 64 if (p2 & LX_O_APPEND) 65 flags |= O_APPEND; 66 if (p2 & LX_O_NONBLOCK) 67 flags |= O_NONBLOCK; 68 if (p2 & LX_O_SYNC) 69 flags |= O_SYNC; 70 if (p2 & LX_O_LARGEFILE) 71 flags |= O_LARGEFILE; 72 if (p2 & LX_O_NOFOLLOW) 73 flags |= O_NOFOLLOW; 74 75 /* 76 * Linux uses the LX_O_DIRECT flag to do raw, synchronous I/O to the 77 * device backing the fd in question. Solaris doesn't have similar 78 * functionality, but we can attempt to simulate it using the flags 79 * (O_RSYNC|O_SYNC) and directio(3C). 80 * 81 * The LX_O_DIRECT flag also requires that the transfer size and 82 * alignment of I/O buffers be a multiple of the logical block size for 83 * the underlying file system, but frankly there isn't an easy way to 84 * support that functionality without doing something like adding an 85 * fcntl(2) flag to denote LX_O_DIRECT mode. 86 * 87 * Since LX_O_DIRECT is merely a performance advisory, we'll just 88 * emulate what we can and trust that the only applications expecting 89 * an error when performing I/O from a misaligned buffer or when 90 * passing a transfer size is not a multiple of the underlying file 91 * system block size will be test suites. 92 */ 93 if (p2 & LX_O_DIRECT) 94 flags |= (O_RSYNC|O_SYNC); 95 96 return (flags); 97 } 98 99 static int 100 lx_open_postprocess(int fd, uintptr_t p2) 101 { 102 struct stat64 statbuf; 103 104 /* 105 * Check the file type AFTER opening the file to avoid a race condition 106 * where the file we want to open could change types between a stat64() 107 * and an open(). 108 */ 109 if (p2 & LX_O_DIRECTORY) { 110 if (fstat64(fd, &statbuf) < 0) { 111 int ret = -errno; 112 113 (void) close(fd); 114 return (ret); 115 } else if (!S_ISDIR(statbuf.st_mode)) { 116 (void) close(fd); 117 return (-ENOTDIR); 118 } 119 } 120 121 if (p2 & LX_O_DIRECT) 122 (void) directio(fd, DIRECTIO_ON); 123 124 /* 125 * Set the ASYNC flag if passsed. 126 */ 127 if (p2 & LX_O_ASYNC) { 128 if (fcntl(fd, F_SETFL, FASYNC) < 0) { 129 int ret = -errno; 130 131 (void) close(fd); 132 return (ret); 133 } 134 } 135 136 return (fd); 137 } 138 139 int 140 lx_openat(uintptr_t ext1, uintptr_t p1, uintptr_t p2, uintptr_t p3) 141 { 142 int atfd = (int)ext1; 143 int flags, fd; 144 mode_t mode = 0; 145 char *path = (char *)p1; 146 147 if (atfd == LX_AT_FDCWD) 148 atfd = AT_FDCWD; 149 150 flags = ltos_open_flags(p2); 151 152 if (flags & O_CREAT) { 153 mode = (mode_t)p3; 154 } 155 156 lx_debug("\topenat(%d, %s, 0%o, 0%o)", atfd, path, flags, mode); 157 158 if ((fd = openat(atfd, path, flags, mode)) < 0) 159 return (-errno); 160 161 return (lx_open_postprocess(fd, p2)); 162 } 163 164 int 165 lx_open(uintptr_t p1, uintptr_t p2, uintptr_t p3) 166 { 167 int flags, fd; 168 mode_t mode = 0; 169 char *path = (char *)p1; 170 171 flags = ltos_open_flags(p2); 172 173 if (flags & O_CREAT) { 174 mode = (mode_t)p3; 175 } 176 177 lx_debug("\topen(%s, 0%o, 0%o)", path, flags, mode); 178 179 if ((fd = open(path, flags, mode)) < 0) 180 return (-errno); 181 182 return (lx_open_postprocess(fd, p2)); 183 }