| 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 |