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 }