OLD | NEW |
| (Empty) |
1 /* Copyright (c) 2012 The Chromium 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 "nacl_mounts/kernel_proxy.h" | |
6 | |
7 #include <assert.h> | |
8 #include <errno.h> | |
9 #include <fcntl.h> | |
10 #include <pthread.h> | |
11 #include <string.h> | |
12 #include <string> | |
13 | |
14 #include "nacl_mounts/kernel_handle.h" | |
15 #include "nacl_mounts/mount.h" | |
16 #include "nacl_mounts/mount_dev.h" | |
17 #include "nacl_mounts/mount_html5fs.h" | |
18 #include "nacl_mounts/mount_http.h" | |
19 #include "nacl_mounts/mount_mem.h" | |
20 #include "nacl_mounts/mount_node.h" | |
21 #include "nacl_mounts/osstat.h" | |
22 #include "nacl_mounts/path.h" | |
23 #include "nacl_mounts/pepper_interface.h" | |
24 #include "utils/auto_lock.h" | |
25 #include "utils/ref_object.h" | |
26 | |
27 #ifndef MAXPATHLEN | |
28 #define MAXPATHLEN 256 | |
29 #endif | |
30 | |
31 // TODO(noelallen) : Grab/Redefine these in the kernel object once available. | |
32 #define USR_ID 1002 | |
33 #define GRP_ID 1003 | |
34 | |
35 | |
36 KernelProxy::KernelProxy() | |
37 : dev_(0), | |
38 ppapi_(NULL) { | |
39 } | |
40 | |
41 KernelProxy::~KernelProxy() { | |
42 delete ppapi_; | |
43 } | |
44 | |
45 void KernelProxy::Init(PepperInterface* ppapi) { | |
46 ppapi_ = ppapi; | |
47 cwd_ = "/"; | |
48 dev_ = 1; | |
49 | |
50 factories_["memfs"] = MountMem::Create<MountMem>; | |
51 factories_["dev"] = MountDev::Create<MountDev>; | |
52 factories_["html5fs"] = MountHtml5Fs::Create<MountHtml5Fs>; | |
53 factories_["httpfs"] = MountHttp::Create<MountHttp>; | |
54 | |
55 // Create memory mount at root | |
56 StringMap_t smap; | |
57 mounts_["/"] = MountMem::Create<MountMem>(dev_++, smap, ppapi_); | |
58 mounts_["/dev"] = MountDev::Create<MountDev>(dev_++, smap, ppapi_); | |
59 } | |
60 | |
61 int KernelProxy::open(const char *path, int oflags) { | |
62 Path rel; | |
63 | |
64 Mount* mnt = AcquireMountAndPath(path, &rel); | |
65 if (mnt == NULL) return -1; | |
66 | |
67 MountNode* node = mnt->Open(rel, oflags); | |
68 if (node == NULL) { | |
69 ReleaseMount(mnt); | |
70 return -1; | |
71 } | |
72 | |
73 KernelHandle* handle = new KernelHandle(mnt, node, oflags); | |
74 int fd = AllocateFD(handle); | |
75 mnt->AcquireNode(node); | |
76 | |
77 ReleaseHandle(handle); | |
78 ReleaseMount(mnt); | |
79 | |
80 return fd; | |
81 } | |
82 | |
83 int KernelProxy::close(int fd) { | |
84 KernelHandle* handle = AcquireHandle(fd); | |
85 | |
86 if (NULL == handle) return -1; | |
87 | |
88 Mount* mount = handle->mount_; | |
89 // Acquire the mount to ensure FreeFD doesn't prematurely destroy it. | |
90 mount->Acquire(); | |
91 | |
92 // FreeFD will release the handle/mount held by this fd. | |
93 FreeFD(fd); | |
94 | |
95 // If this handle is the last reference to its node, releasing it will close | |
96 // the node. | |
97 ReleaseHandle(handle); | |
98 | |
99 // Finally, release the mount. | |
100 mount->Release(); | |
101 | |
102 return 0; | |
103 } | |
104 | |
105 int KernelProxy::dup(int oldfd) { | |
106 KernelHandle* handle = AcquireHandle(oldfd); | |
107 if (NULL == handle) return -1; | |
108 | |
109 int newfd = AllocateFD(handle); | |
110 ReleaseHandle(handle); | |
111 | |
112 return newfd; | |
113 } | |
114 | |
115 int KernelProxy::dup2(int oldfd, int newfd) { | |
116 KernelHandle* old_handle = AcquireHandle(oldfd); | |
117 if (NULL == old_handle) return -1; | |
118 | |
119 if (oldfd == newfd) { | |
120 ReleaseHandle(old_handle); | |
121 return 0; | |
122 } | |
123 | |
124 // Ignore the result, we don't care if newfd is valid or not. | |
125 close(newfd); | |
126 | |
127 AssignFD(newfd, old_handle); | |
128 ReleaseHandle(old_handle); | |
129 | |
130 return newfd; | |
131 } | |
132 | |
133 | |
134 char* KernelProxy::getcwd(char* buf, size_t size) { | |
135 AutoLock lock(&process_lock_); | |
136 if (size <= 0) { | |
137 errno = EINVAL; | |
138 return NULL; | |
139 } | |
140 // If size is 0, allocate as much as we need. | |
141 if (size == 0) { | |
142 size = cwd_.size() + 1; | |
143 } | |
144 | |
145 // Verify the buffer is large enough | |
146 if (size <= cwd_.size()) { | |
147 errno = ERANGE; | |
148 return NULL; | |
149 } | |
150 | |
151 // Allocate the buffer if needed | |
152 if (buf == NULL) { | |
153 buf = static_cast<char*>(malloc(size)); | |
154 } | |
155 | |
156 strcpy(buf, cwd_.c_str()); | |
157 return buf; | |
158 } | |
159 | |
160 char* KernelProxy::getwd(char* buf) { | |
161 if (NULL == buf) { | |
162 errno = EFAULT; | |
163 return NULL; | |
164 } | |
165 return getcwd(buf, MAXPATHLEN); | |
166 } | |
167 | |
168 int KernelProxy::chmod(const char *path, mode_t mode) { | |
169 int fd = KernelProxy::open(path, O_RDWR); | |
170 if (-1 == fd) return -1; | |
171 | |
172 int ret = fchmod(fd, mode); | |
173 close(fd); | |
174 return ret; | |
175 } | |
176 | |
177 int KernelProxy::mkdir(const char *path, mode_t mode) { | |
178 Path rel; | |
179 Mount* mnt = AcquireMountAndPath(path, &rel); | |
180 if (mnt == NULL) return -1; | |
181 | |
182 int val = mnt->Mkdir(rel, mode); | |
183 ReleaseMount(mnt); | |
184 return val; | |
185 } | |
186 | |
187 int KernelProxy::rmdir(const char *path) { | |
188 Path rel; | |
189 Mount* mnt = AcquireMountAndPath(path, &rel); | |
190 if (mnt == NULL) return -1; | |
191 | |
192 int val = mnt->Rmdir(rel); | |
193 ReleaseMount(mnt); | |
194 return val; | |
195 } | |
196 | |
197 int KernelProxy::stat(const char *path, struct stat *buf) { | |
198 int fd = open(path, O_RDONLY); | |
199 if (-1 == fd) return -1; | |
200 | |
201 int ret = fstat(fd, buf); | |
202 close(fd); | |
203 return ret; | |
204 } | |
205 | |
206 int KernelProxy::chdir(const char* path) { | |
207 struct stat statbuf; | |
208 if (stat(path, &statbuf) == -1) | |
209 return -1; | |
210 | |
211 bool is_dir = (statbuf.st_mode & S_IFDIR) != 0; | |
212 if (is_dir) { | |
213 AutoLock lock(&process_lock_); | |
214 cwd_ = GetAbsPathLocked(path).Join(); | |
215 return 0; | |
216 } | |
217 | |
218 errno = ENOTDIR; | |
219 return -1; | |
220 } | |
221 | |
222 int KernelProxy::mount(const char *source, const char *target, | |
223 const char *filesystemtype, unsigned long mountflags, | |
224 const void *data) { | |
225 // See if it's already mounted | |
226 std::string abs_targ; | |
227 | |
228 // Scope this lock to prevent holding both process and kernel locks | |
229 { | |
230 AutoLock lock(&process_lock_); | |
231 abs_targ = GetAbsPathLocked(target).Join(); | |
232 } | |
233 | |
234 AutoLock lock(&kernel_lock_); | |
235 if (mounts_.find(abs_targ) != mounts_.end()) { | |
236 errno = EBUSY; | |
237 return -1; | |
238 } | |
239 | |
240 // Find a factory of that type | |
241 MountFactoryMap_t::iterator factory = factories_.find(filesystemtype); | |
242 if (factory == factories_.end()) { | |
243 errno = ENODEV; | |
244 return -1; | |
245 } | |
246 | |
247 StringMap_t smap; | |
248 smap["SOURCE"] = source; | |
249 smap["TARGET"] = abs_targ; | |
250 | |
251 if (data) { | |
252 char* str = strdup(static_cast<const char *>(data)); | |
253 char* ptr = strtok(str,","); | |
254 char* val; | |
255 while (ptr != NULL) { | |
256 val = strchr(ptr, '='); | |
257 if (val) { | |
258 *val = 0; | |
259 smap[ptr] = val + 1; | |
260 } else { | |
261 smap[ptr] = "TRUE"; | |
262 } | |
263 ptr = strtok(NULL, ","); | |
264 } | |
265 free(str); | |
266 } | |
267 | |
268 Mount* mnt = factory->second(dev_++, smap, ppapi_); | |
269 if (mnt) { | |
270 mounts_[abs_targ] = mnt; | |
271 return 0; | |
272 } | |
273 errno = EINVAL; | |
274 return -1; | |
275 } | |
276 | |
277 int KernelProxy::umount(const char *path) { | |
278 Path abs_path; | |
279 | |
280 // Scope this lock to prevent holding both process and kernel locks | |
281 { | |
282 AutoLock lock(&process_lock_); | |
283 abs_path = GetAbsPathLocked(path); | |
284 } | |
285 | |
286 AutoLock lock(&kernel_lock_); | |
287 MountMap_t::iterator it = mounts_.find(abs_path.Join()); | |
288 | |
289 if (mounts_.end() == it) { | |
290 errno = EINVAL; | |
291 return -1; | |
292 } | |
293 | |
294 if (it->second->RefCount() != 1) { | |
295 errno = EBUSY; | |
296 return -1; | |
297 } | |
298 | |
299 it->second->Release(); | |
300 mounts_.erase(it); | |
301 return 0; | |
302 } | |
303 | |
304 ssize_t KernelProxy::read(int fd, void *buf, size_t nbytes) { | |
305 KernelHandle* handle = AcquireHandle(fd); | |
306 | |
307 // check if fd is valid and handle exists | |
308 if (NULL == handle) return -1; | |
309 | |
310 AutoLock lock(&handle->lock_); | |
311 ssize_t cnt = handle->node_->Read(handle->offs_, buf, nbytes); | |
312 if (cnt > 0) handle->offs_ += cnt; | |
313 | |
314 ReleaseHandle(handle); | |
315 return cnt; | |
316 } | |
317 | |
318 ssize_t KernelProxy::write(int fd, const void *buf, size_t nbytes) { | |
319 KernelHandle* handle = AcquireHandle(fd); | |
320 | |
321 // check if fd is valid and handle exists | |
322 if (NULL == handle) return -1; | |
323 | |
324 AutoLock lock(&handle->lock_); | |
325 ssize_t cnt = handle->node_->Write(handle->offs_, buf, nbytes); | |
326 if (cnt > 0) handle->offs_ += cnt; | |
327 | |
328 ReleaseHandle(handle); | |
329 return cnt; | |
330 } | |
331 | |
332 int KernelProxy::fstat(int fd, struct stat* buf) { | |
333 KernelHandle* handle = AcquireHandle(fd); | |
334 | |
335 // check if fd is valid and handle exists | |
336 if (NULL == handle) return -1; | |
337 | |
338 int ret = handle->node_->GetStat(buf); | |
339 ReleaseHandle(handle); | |
340 return ret; | |
341 } | |
342 | |
343 int KernelProxy::getdents(int fd, void* buf, unsigned int count) { | |
344 KernelHandle* handle = AcquireHandle(fd); | |
345 | |
346 // check if fd is valid and handle exists | |
347 if (NULL == handle) return -1; | |
348 | |
349 AutoLock lock(&handle->lock_); | |
350 int cnt = handle->node_->GetDents(handle->offs_, | |
351 static_cast<dirent *>(buf), count); | |
352 | |
353 if (cnt > 0) handle->offs_ += cnt; | |
354 | |
355 ReleaseHandle(handle); | |
356 return cnt; | |
357 } | |
358 | |
359 int KernelProxy::fsync(int fd) { | |
360 KernelHandle* handle = AcquireHandle(fd); | |
361 | |
362 // check if fd is valid and handle exists | |
363 if (NULL == handle) return -1; | |
364 int ret = handle->node_->FSync(); | |
365 | |
366 ReleaseHandle(handle); | |
367 return ret; | |
368 } | |
369 | |
370 int KernelProxy::isatty(int fd) { | |
371 KernelHandle* handle = AcquireHandle(fd); | |
372 | |
373 // check if fd is valid and handle exists | |
374 if (NULL == handle) return -1; | |
375 int ret = handle->node_->IsaTTY(); | |
376 | |
377 ReleaseHandle(handle); | |
378 return ret; | |
379 } | |
380 | |
381 off_t KernelProxy::lseek(int fd, off_t offset, int whence) { | |
382 KernelHandle* handle = AcquireHandle(fd); | |
383 | |
384 // check if fd is valid and handle exists | |
385 if (NULL == handle) return -1; | |
386 int ret = handle->Seek(offset, whence); | |
387 | |
388 ReleaseHandle(handle); | |
389 return ret; | |
390 } | |
391 | |
392 int KernelProxy::unlink(const char* path) { | |
393 Path rel; | |
394 Mount* mnt = AcquireMountAndPath(path, &rel); | |
395 if (mnt == NULL) return -1; | |
396 | |
397 int val = mnt->Unlink(rel); | |
398 ReleaseMount(mnt); | |
399 return val; | |
400 } | |
401 | |
402 int KernelProxy::remove(const char* path) { | |
403 Path rel; | |
404 Mount* mnt = AcquireMountAndPath(path, &rel); | |
405 if (mnt == NULL) return -1; | |
406 | |
407 int val = mnt->Remove(rel); | |
408 ReleaseMount(mnt); | |
409 return val; | |
410 } | |
411 | |
412 // TODO(noelallen): Needs implementation. | |
413 int KernelProxy::fchmod(int fd, int mode) { | |
414 errno = EINVAL; | |
415 return -1; | |
416 } | |
417 | |
418 int KernelProxy::access(const char* path, int amode) { | |
419 errno = EINVAL; | |
420 return -1; | |
421 } | |
422 | |
423 int KernelProxy::link(const char* oldpath, const char* newpath) { | |
424 errno = EINVAL; | |
425 return -1; | |
426 } | |
427 | |
428 int KernelProxy::symlink(const char* oldpath, const char* newpath) { | |
429 errno = EINVAL; | |
430 return -1; | |
431 } | |
OLD | NEW |