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