1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <dirent.h>
6 #include <fcntl.h>
7 #include <sys/socket.h>
8 #include <unistd.h>
9
10 #include <errno.h>
11 #include <sys/stat.h>
12
13 #include "unistd.h"
14
15 // checkfile, checkfileat, and checkfd let us error out if the object
16 // doesn't exist, which allows the stubs to be a little more 'real'
seterr(int err)17 static int seterr(int err) {
18 if (err) {
19 errno = err;
20 return -1;
21 }
22 return 0;
23 }
24
checkfile(const char * path,int err)25 static int checkfile(const char* path, int err) {
26 struct stat s;
27 if (stat(path, &s)) {
28 return -1;
29 }
30 return seterr(err);
31 }
32
checkfileat(int fd,const char * path,int flags,int err)33 static int checkfileat(int fd, const char* path, int flags, int err) {
34 struct stat s;
35 if (fstatat(fd, path, &s, flags)) {
36 return -1;
37 }
38 return seterr(err);
39 }
40
checkfd(int fd,int err)41 static int checkfd(int fd, int err) {
42 fdio_t* io;
43 if ((io = fd_to_io(fd)) == NULL) {
44 errno = EBADF;
45 return -1;
46 }
47 fdio_release(io);
48 return seterr(err);
49 }
50
check2fds(int fd1,int fd2,int err)51 static int check2fds(int fd1, int fd2, int err) {
52 fdio_t* io;
53 if ((io = fd_to_io(fd1)) == NULL) {
54 errno = EBADF;
55 return -1;
56 }
57 fdio_release(io);
58 if ((io = fd_to_io(fd2)) == NULL) {
59 errno = EBADF;
60 return -1;
61 }
62 fdio_release(io);
63 return seterr(err);
64 }
65
checkfilefd(const char * path,int fd,int err)66 static int checkfilefd(const char* path, int fd, int err) {
67 struct stat s;
68 if (stat(path, &s)) {
69 return -1;
70 }
71 fdio_t* io;
72 if ((io = fd_to_io(fd)) == NULL) {
73 errno = EBADF;
74 return -1;
75 }
76 fdio_release(io);
77 return seterr(err);
78 }
79
checksocket(int fd,int sock_err,int err)80 static int checksocket(int fd, int sock_err, int err) {
81 fdio_t* io = fd_to_io(fd);
82 if (io == NULL) {
83 errno = EBADF;
84 return -1;
85 }
86 int32_t is_socket = io->ioflag & IOFLAG_SOCKET;
87 fdio_release(io);
88 if (!is_socket) {
89 errno = sock_err;
90 return -1;
91 }
92 return seterr(err);
93 }
94
checkdir(DIR * dir,int err)95 static int checkdir(DIR* dir, int err) {
96 if (dirfd(dir) < 0) {
97 errno = EBADF;
98 return -1;
99 }
100 return seterr(err);
101 }
102
103 // not supported by any filesystems yet
104 __EXPORT
symlink(const char * existing,const char * new)105 int symlink(const char* existing, const char* new) {
106 errno = ENOSYS;
107 return -1;
108 }
109 __EXPORT
readlink(const char * restrict path,char * restrict buf,size_t bufsize)110 ssize_t readlink(const char* restrict path, char* restrict buf, size_t bufsize) {
111 // EINVAL = not symlink
112 return checkfile(path, EINVAL);
113 }
114
115 // creating things we don't have plumbing for yet
116 __EXPORT
mkfifo(const char * path,mode_t mode)117 int mkfifo(const char *path, mode_t mode) {
118 errno = ENOSYS;
119 return -1;
120 }
121 __EXPORT
mknod(const char * path,mode_t mode,dev_t dev)122 int mknod(const char* path, mode_t mode, dev_t dev) {
123 errno = ENOSYS;
124 return -1;
125 }
126
127 // no permissions support yet
128 __EXPORT
chown(const char * path,uid_t owner,gid_t group)129 int chown(const char *path, uid_t owner, gid_t group) {
130 return checkfile(path, ENOSYS);
131 }
132 __EXPORT
fchown(int fd,uid_t owner,gid_t group)133 int fchown(int fd, uid_t owner, gid_t group) {
134 return checkfd(fd, ENOSYS);
135 }
136 __EXPORT
lchown(const char * path,uid_t owner,gid_t group)137 int lchown(const char *path, uid_t owner, gid_t group) {
138 return checkfile(path, ENOSYS);
139 }
140
141 // no permissions support, but treat rwx bits as don't care rather than error
142 __EXPORT
chmod(const char * path,mode_t mode)143 int chmod(const char *path, mode_t mode) {
144 return checkfile(path, (mode & (~0777)) ? ENOSYS : 0);
145 }
146 __EXPORT
fchmod(int fd,mode_t mode)147 int fchmod(int fd, mode_t mode) {
148 return checkfd(fd, (mode & (~0777)) ? ENOSYS : 0);
149 }
150 __EXPORT
fchmodat(int fd,const char * path,mode_t mode,int flags)151 int fchmodat(int fd, const char* path, mode_t mode, int flags) {
152 if (flags & ~AT_SYMLINK_NOFOLLOW) {
153 errno = EINVAL;
154 return -1;
155 }
156
157 return checkfileat(fd, path, flags, (mode & (~0777)) ? ENOSYS : 0);
158 }
159
160 __EXPORT
access(const char * path,int mode)161 int access(const char* path, int mode) {
162 return checkfile(path, 0);
163 }
164
165 __EXPORT
sync(void)166 void sync(void) {
167 }
168
169 // at the moment our unlink works on all fs objects
170 __EXPORT
rmdir(const char * path)171 int rmdir(const char* path) {
172 return unlink(path);
173 }
174
175 // tty stubbing.
176 __EXPORT
ttyname_r(int fd,char * name,size_t size)177 int ttyname_r(int fd, char* name, size_t size) {
178 if (!isatty(fd)) {
179 return ENOTTY;
180 }
181
182 return checkfd(fd, ENOSYS);
183 }
184
185 __EXPORT
sendmmsg(int fd,struct mmsghdr * msgvec,unsigned int vlen,unsigned int flags)186 int sendmmsg(int fd, struct mmsghdr* msgvec, unsigned int vlen, unsigned int flags) {
187 return checksocket(fd, ENOTSOCK, ENOSYS);
188 }
189
190 __EXPORT
recvmmsg(int fd,struct mmsghdr * msgvec,unsigned int vlen,unsigned int flags,struct timespec * timeout)191 int recvmmsg(int fd, struct mmsghdr* msgvec, unsigned int vlen, unsigned int flags, struct timespec* timeout) {
192 return checksocket(fd, ENOTSOCK, ENOSYS);
193 }
194
195 __EXPORT
sockatmark(int fd)196 int sockatmark(int fd) {
197 // ENOTTY is sic.
198 return checksocket(fd, ENOTTY, ENOSYS);
199 }
200
201 __EXPORT
fchownat(int fd,const char * path,uid_t uid,gid_t gid,int flag)202 int fchownat(int fd, const char* path, uid_t uid, gid_t gid, int flag) {
203 return checkfd(fd, ENOSYS);
204 }
205
206 __EXPORT
linkat(int fd1,const char * existing,int fd2,const char * new,int flag)207 int linkat(int fd1, const char* existing, int fd2, const char* new, int flag) {
208 return check2fds(fd1, fd2, ENOSYS);
209 }
210
211 __EXPORT
symlinkat(const char * existing,int fd,const char * new)212 int symlinkat(const char* existing, int fd, const char* new) {
213 return checkfilefd(existing, fd, ENOSYS);
214 }
215
216 __EXPORT
readlinkat(int fd,const char * restrict path,char * restrict buf,size_t bufsize)217 ssize_t readlinkat(int fd, const char* restrict path, char* restrict buf, size_t bufsize) {
218 return checkfilefd(path, fd, ENOSYS);
219 }
220
221 __EXPORT
seekdir(DIR * dir,long loc)222 void seekdir(DIR* dir, long loc) {
223 }
224
225 __EXPORT
telldir(DIR * dir)226 long telldir(DIR* dir) {
227 return checkdir(dir, ENOSYS);
228 }
229
230 __EXPORT
posix_fadvise(int fd,off_t base,off_t len,int advice)231 int posix_fadvise(int fd, off_t base, off_t len, int advice) {
232 return checkfd(fd, ENOSYS);
233 }
234
235 __EXPORT
posix_fallocate(int fd,off_t base,off_t len)236 int posix_fallocate(int fd, off_t base, off_t len) {
237 return checkfd(fd, ENOSYS);
238 }
239
240 __EXPORT
readdir_r(DIR * dir,struct dirent * entry,struct dirent ** result)241 int readdir_r(DIR* dir, struct dirent* entry, struct dirent** result) {
242 return checkdir(dir, ENOSYS);
243 }
244