Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / libraries / nacl_io / kernel_proxy.cc
index 680eaac..b5cf443 100644 (file)
@@ -26,6 +26,7 @@
 #include "nacl_io/httpfs/http_fs.h"
 #include "nacl_io/kernel_handle.h"
 #include "nacl_io/kernel_wrap_real.h"
+#include "nacl_io/log.h"
 #include "nacl_io/memfs/mem_fs.h"
 #include "nacl_io/node.h"
 #include "nacl_io/osmman.h"
 
 namespace nacl_io {
 
-
-KernelProxy::KernelProxy() : dev_(0), ppapi_(NULL),
-                             exit_handler_(NULL),
-                             signal_emitter_(new EventEmitter) {
-   memset(&sigwinch_handler_, 0, sizeof(sigwinch_handler_));
-   sigwinch_handler_.sa_handler = SIG_DFL;
+KernelProxy::KernelProxy()
+    : dev_(0),
+      ppapi_(NULL),
+      exit_callback_(NULL),
+      exit_callback_user_data_(NULL),
+      mount_callback_(NULL),
+      mount_callback_user_data_(NULL),
+      signal_emitter_(new EventEmitter) {
+  memset(&sigwinch_handler_, 0, sizeof(sigwinch_handler_));
+  sigwinch_handler_.sa_handler = SIG_DFL;
 }
 
 KernelProxy::~KernelProxy() {
-  // Clean up the MountFactories.
+  // Clean up the FsFactories.
   for (FsFactoryMap_t::iterator i = factories_.begin(); i != factories_.end();
        ++i) {
     delete i->second;
   }
-
-  delete ppapi_;
 }
 
 Error KernelProxy::Init(PepperInterface* ppapi) {
@@ -78,32 +81,40 @@ Error KernelProxy::Init(PepperInterface* ppapi) {
   factories_["httpfs"] = new TypedFsFactory<HttpFs>;
   factories_["passthroughfs"] = new TypedFsFactory<PassthroughFs>;
 
-  int result;
-  result = mount("", "/", "passthroughfs", 0, NULL);
-  if (result != 0) {
+  ScopedFilesystem root_fs;
+  rtn = MountInternal("", "/", "passthroughfs", 0, NULL, false, &root_fs);
+  if (rtn != 0)
     assert(false);
-    rtn = errno;
-  }
 
-  result = mount("", "/dev", "dev", 0, NULL);
-  if (result != 0) {
+  ScopedFilesystem fs;
+  rtn = MountInternal("", "/dev", "dev", 0, NULL, false, &fs);
+  if (rtn != 0)
+    assert(false);
+  dev_fs_ = sdk_util::static_scoped_ref_cast<DevFs>(fs);
+
+  // Create the filesystem nodes for / and /dev afterward. They can't be
+  // created the normal way because the dev filesystem didn't exist yet.
+  rtn = CreateFsNode(root_fs);
+  if (rtn != 0)
+    assert(false);
+
+  rtn = CreateFsNode(dev_fs_);
+  if (rtn != 0)
     assert(false);
-    rtn = errno;
-  }
 
   // Open the first three in order to get STDIN, STDOUT, STDERR
   int fd;
-  fd = open("/dev/stdin", O_RDONLY);
+  fd = open("/dev/stdin", O_RDONLY, 0);
   assert(fd == 0);
   if (fd < 0)
     rtn = errno;
 
-  fd = open("/dev/stdout", O_WRONLY);
+  fd = open("/dev/stdout", O_WRONLY, 0);
   assert(fd == 1);
   if (fd < 0)
     rtn = errno;
 
-  fd = open("/dev/stderr", O_WRONLY);
+  fd = open("/dev/stderr", O_WRONLY, 0);
   assert(fd == 2);
   if (fd < 0)
     rtn = errno;
@@ -115,8 +126,8 @@ Error KernelProxy::Init(PepperInterface* ppapi) {
   FsInitArgs args;
   args.dev = dev_++;
   args.ppapi = ppapi_;
-  stream_mount_.reset(new StreamFs());
-  result = stream_mount_->Init(args);
+  stream_fs_.reset(new StreamFs());
+  int result = stream_fs_->Init(args);
   if (result != 0) {
     assert(false);
     rtn = result;
@@ -145,13 +156,16 @@ bool KernelProxy::UnregisterFsType(const char* fs_type) {
   return true;
 }
 
-bool KernelProxy::RegisterExitHandler(nacl_io_exit_handler_t exit_handler,
-                                      void* user_data) {
-  if (exit_handler_ != NULL)
-    return false;
-  exit_handler_ = exit_handler;
-  exit_handler_user_data_ = user_data;
-  return true;
+void KernelProxy::SetExitCallback(nacl_io_exit_callback_t exit_callback,
+                                  void* user_data) {
+  exit_callback_ = exit_callback;
+  exit_callback_user_data_ = user_data;
+}
+
+void KernelProxy::SetMountCallback(nacl_io_mount_callback_t mount_callback,
+                                   void* user_data) {
+  mount_callback_ = mount_callback;
+  mount_callback_user_data_ = user_data;
 }
 
 int KernelProxy::open_resource(const char* path) {
@@ -185,11 +199,11 @@ int KernelProxy::open_resource(const char* path) {
   return AllocateFD(handle, path);
 }
 
-int KernelProxy::open(const char* path, int open_flags) {
+int KernelProxy::open(const char* path, int open_flags, mode_t mode) {
   ScopedFilesystem fs;
   ScopedNode node;
 
-  Error error = AcquireFsAndNode(path, open_flags, &fs, &node);
+  Error error = AcquireFsAndNode(path, open_flags, mode, &fs, &node);
   if (error) {
     errno = error;
     return -1;
@@ -206,12 +220,12 @@ int KernelProxy::open(const char* path, int open_flags) {
 }
 
 int KernelProxy::pipe(int pipefds[2]) {
-  PipeNode* pipe = new PipeNode(stream_mount_.get());
+  PipeNode* pipe = new PipeNode(stream_fs_.get());
   ScopedNode node(pipe);
 
   if (pipe->Init(O_RDWR) == 0) {
-    ScopedKernelHandle handle0(new KernelHandle(stream_mount_, node));
-    ScopedKernelHandle handle1(new KernelHandle(stream_mount_, node));
+    ScopedKernelHandle handle0(new KernelHandle(stream_fs_, node));
+    ScopedKernelHandle handle1(new KernelHandle(stream_fs_, node));
 
     // Should never fail, but...
     if (handle0->Init(O_RDONLY) || handle1->Init(O_WRONLY)) {
@@ -279,8 +293,8 @@ int KernelProxy::chdir(const char* path) {
 }
 
 void KernelProxy::exit(int status) {
-  if (exit_handler_)
-    exit_handler_(status, exit_handler_user_data_);
+  if (exit_callback_)
+    exit_callback_(status, exit_callback_user_data_);
 }
 
 char* KernelProxy::getcwd(char* buf, size_t size) {
@@ -310,7 +324,7 @@ char* KernelProxy::getwd(char* buf) {
 }
 
 int KernelProxy::chmod(const char* path, mode_t mode) {
-  int fd = KernelProxy::open(path, O_RDONLY);
+  int fd = open(path, O_RDONLY, mode);
   if (-1 == fd)
     return -1;
 
@@ -331,10 +345,6 @@ int KernelProxy::lchown(const char* path, uid_t owner, gid_t group) {
   return 0;
 }
 
-int KernelProxy::utime(const char* filename, const struct utimbuf* times) {
-  return 0;
-}
-
 int KernelProxy::mkdir(const char* path, mode_t mode) {
   ScopedFilesystem fs;
   Path rel;
@@ -374,7 +384,7 @@ int KernelProxy::rmdir(const char* path) {
 }
 
 int KernelProxy::stat(const char* path, struct stat* buf) {
-  int fd = open(path, O_RDONLY);
+  int fd = open(path, O_RDONLY, 0);
   if (-1 == fd)
     return -1;
 
@@ -383,32 +393,49 @@ int KernelProxy::stat(const char* path, struct stat* buf) {
   return result;
 }
 
-
 int KernelProxy::mount(const char* source,
                        const char* target,
                        const char* filesystemtype,
                        unsigned long mountflags,
                        const void* data) {
+  ScopedFilesystem fs;
+  Error error = MountInternal(
+      source, target, filesystemtype, mountflags, data, true, &fs);
+  if (error) {
+    errno = error;
+    return -1;
+  }
+
+  return 0;
+}
+
+Error KernelProxy::MountInternal(const char* source,
+                                 const char* target,
+                                 const char* filesystemtype,
+                                 unsigned long mountflags,
+                                 const void* data,
+                                 bool create_fs_node,
+                                 ScopedFilesystem* out_filesystem) {
   std::string abs_path = GetAbsParts(target).Join();
 
   // Find a factory of that type
   FsFactoryMap_t::iterator factory = factories_.find(filesystemtype);
   if (factory == factories_.end()) {
-    errno = ENODEV;
-    return -1;
+    LOG_ERROR("Unknown filesystem type: %s", filesystemtype);
+    return ENODEV;
   }
 
   // Create a map of settings
   StringMap_t smap;
   smap["SOURCE"] = source;
-  smap["TARGET"] = abs_path;
 
   if (data) {
     std::vector<std::string> elements;
     sdk_util::SplitString(static_cast<const char*>(data), ',', &elements);
 
     for (std::vector<std::string>::const_iterator it = elements.begin();
-         it != elements.end(); ++it) {
+         it != elements.end();
+         ++it) {
       size_t location = it->find('=');
       if (location != std::string::npos) {
         std::string key = it->substr(0, location);
@@ -427,26 +454,55 @@ int KernelProxy::mount(const char* source,
 
   ScopedFilesystem fs;
   Error error = factory->second->CreateFilesystem(args, &fs);
-  if (error) {
-    errno = error;
-    return -1;
-  }
+  if (error)
+    return error;
 
   error = AttachFsAtPath(fs, abs_path);
-  if (error) {
-    errno = error;
-    return -1;
+  if (error)
+    return error;
+
+  if (create_fs_node) {
+    error = CreateFsNode(fs);
+    if (error) {
+      DetachFsAtPath(abs_path, &fs);
+      return error;
+    }
+  }
+
+  *out_filesystem = fs;
+
+  if (mount_callback_) {
+    mount_callback_(source,
+                    target,
+                    filesystemtype,
+                    mountflags,
+                    data,
+                    fs->dev(),
+                    mount_callback_user_data_);
   }
 
   return 0;
 }
 
+Error KernelProxy::CreateFsNode(const ScopedFilesystem& fs) {
+  assert(dev_fs_);
+
+  return dev_fs_->CreateFsNode(fs.get());
+}
+
 int KernelProxy::umount(const char* path) {
-  Error error = DetachFsAtPath(path);
+  ScopedFilesystem fs;
+  Error error = DetachFsAtPath(path, &fs);
   if (error) {
     errno = error;
     return -1;
   }
+
+  error = dev_fs_->DestroyFsNode(fs.get());
+  if (error) {
+    // Ignore any errors here, just log.
+    LOG_ERROR("Unable to destroy FsNode: %s", strerror(error));
+  }
   return 0;
 }
 
@@ -620,6 +676,23 @@ int KernelProxy::ioctl(int fd, int request, va_list args) {
   return 0;
 }
 
+int KernelProxy::futimens(int fd, const struct timespec times[2]) {
+  ScopedKernelHandle handle;
+  Error error = AcquireHandle(fd, &handle);
+  if (error) {
+    errno = error;
+    return -1;
+  }
+
+  error = handle->node()->Futimens(times);
+  if (error) {
+    errno = error;
+    return -1;
+  }
+
+  return 0;
+}
+
 off_t KernelProxy::lseek(int fd, off_t offset, int whence) {
   ScopedKernelHandle handle;
   Error error = AcquireHandle(fd, &handle);
@@ -658,7 +731,7 @@ int KernelProxy::unlink(const char* path) {
 }
 
 int KernelProxy::truncate(const char* path, off_t len) {
-  int fd = KernelProxy::open(path, O_WRONLY);
+  int fd = open(path, O_WRONLY, 0);
   if (-1 == fd)
     return -1;
 
@@ -726,8 +799,7 @@ int KernelProxy::remove(const char* path) {
   return 0;
 }
 
-// TODO(noelallen): Needs implementation.
-int KernelProxy::fchmod(int fd, int mode) {
+int KernelProxy::fchmod(int fd, mode_t mode) {
   ScopedKernelHandle handle;
   Error error = AcquireHandle(fd, &handle);
   if (error) {
@@ -735,14 +807,20 @@ int KernelProxy::fchmod(int fd, int mode) {
     return -1;
   }
 
+  error = handle->node()->Fchmod(mode);
+  if (error) {
+    errno = error;
+    return -1;
+  }
+
   return 0;
 }
 
 int KernelProxy::fcntl(int fd, int request, va_list args) {
   Error error = 0;
 
-  // F_GETFD and F_SETFD are descirptor specific flags that
-  // are stored in the KernelObject's decriptor map unlink
+  // F_GETFD and F_SETFD are descriptor specific flags that
+  // are stored in the KernelObject's decriptor map unlike
   // F_GETFL and F_SETFL which are handle specific.
   switch (request) {
     case F_GETFD: {
@@ -783,40 +861,46 @@ int KernelProxy::fcntl(int fd, int request, va_list args) {
 }
 
 int KernelProxy::access(const char* path, int amode) {
-  ScopedFilesystem fs;
-  Path rel;
+  struct stat buf;
+  int rtn = stat(path, &buf);
+  if (rtn != 0)
+    return rtn;
 
-  Error error = AcquireFsAndRelPath(path, &fs, &rel);
-  if (error) {
-    errno = error;
+  if (((amode & R_OK) && !(buf.st_mode & S_IREAD)) ||
+      ((amode & W_OK) && !(buf.st_mode & S_IWRITE)) ||
+      ((amode & X_OK) && !(buf.st_mode & S_IEXEC))) {
+    errno = EACCES;
     return -1;
   }
 
-  error = fs->Access(rel, amode);
-  if (error) {
-    errno = error;
-    return -1;
-  }
   return 0;
 }
 
-int KernelProxy::readlink(const char *path, char *buf, size_t count) {
+int KernelProxy::readlink(const char* path, char* buf, size_t count) {
+  LOG_TRACE("readlink is not implemented.");
   errno = EINVAL;
   return -1;
 }
 
-int KernelProxy::utimes(const char *filename, const struct timeval times[2]) {
-  errno = EINVAL;
-  return -1;
+int KernelProxy::utimens(const char* path, const struct timespec times[2]) {
+  int fd = open(path, O_RDONLY, 0);
+  if (-1 == fd)
+    return -1;
+
+  int result = futimens(fd, times);
+  close(fd);
+  return result;
 }
 
 // TODO(noelallen): Needs implementation.
 int KernelProxy::link(const char* oldpath, const char* newpath) {
+  LOG_TRACE("link is not implemented.");
   errno = EINVAL;
   return -1;
 }
 
 int KernelProxy::symlink(const char* oldpath, const char* newpath) {
+  LOG_TRACE("symlink is not implemented.");
   errno = EINVAL;
   return -1;
 }
@@ -917,8 +1001,9 @@ int KernelProxy::tcgetattr(int fd, struct termios* termios_p) {
   return 0;
 }
 
-int KernelProxy::tcsetattr(int fd, int optional_actions,
-                           const struct termios *termios_p) {
+int KernelProxy::tcsetattr(int fd,
+                           int optional_actions,
+                           const struct termios* termios_p) {
   ScopedKernelHandle handle;
   Error error = AcquireHandle(fd, &handle);
   if (error) {
@@ -961,13 +1046,15 @@ int KernelProxy::kill(pid_t pid, int sig) {
       break;
 
     default:
+      LOG_TRACE("Unsupported signal: %d", sig);
       errno = EINVAL;
       return -1;
   }
   return 0;
 }
 
-int KernelProxy::sigaction(int signum, const struct sigaction* action,
+int KernelProxy::sigaction(int signum,
+                           const struct sigaction* action,
                            struct sigaction* oaction) {
   if (action && action->sa_flags & SA_SIGINFO) {
     // We don't support SA_SIGINFO (sa_sigaction field) yet
@@ -1003,6 +1090,7 @@ int KernelProxy::sigaction(int signum, const struct sigaction* action,
       if (action && action->sa_handler != SIG_DFL) {
         // Trying to set this action to anything other than SIG_DFL
         // is not yet supported.
+        LOG_TRACE("sigaction on signal %d != SIG_DFL not supported.", sig);
         errno = EINVAL;
         return -1;
       }
@@ -1016,6 +1104,7 @@ int KernelProxy::sigaction(int signum, const struct sigaction* action,
     // KILL and STOP cannot be handled
     case SIGKILL:
     case SIGSTOP:
+      LOG_TRACE("sigaction on SIGKILL/SIGSTOP not supported.");
       errno = EINVAL;
       return -1;
   }
@@ -1027,30 +1116,29 @@ int KernelProxy::sigaction(int signum, const struct sigaction* action,
 
 #ifdef PROVIDES_SOCKET_API
 
-int KernelProxy::select(int nfds, fd_set* readfds, fd_set* writefds,
-                        fd_set* exceptfds, struct timeval* timeout) {
-  fd_set ignore;
+int KernelProxy::select(int nfds,
+                        fd_set* readfds,
+                        fd_set* writefds,
+                        fd_set* exceptfds,
+                        struct timeval* timeout) {
   std::vector<pollfd> pollfds;
 
-  // Simplify logic, by using an IGNORE set for any undefined set
-  FD_ZERO(&ignore);
-  if (NULL == readfds)
-    readfds = &ignore;
-  if (NULL == writefds)
-    writefds = &ignore;
-  if (NULL == exceptfds)
-    exceptfds = &ignore;
-
   for (int fd = 0; fd < nfds; fd++) {
     int events = 0;
-    if (FD_ISSET(fd, readfds))
+    if (readfds && FD_ISSET(fd, readfds)) {
       events |= POLLIN;
+      FD_CLR(fd, readfds);
+    }
 
-    if (FD_ISSET(fd, writefds))
+    if (writefds && FD_ISSET(fd, writefds)) {
       events |= POLLOUT;
+      FD_CLR(fd, writefds);
+    }
 
-    if (FD_ISSET(fd, exceptfds))
+    if (exceptfds && FD_ISSET(fd, exceptfds)) {
       events |= POLLERR | POLLHUP;
+      FD_CLR(fd, exceptfds);
+    }
 
     if (events) {
       pollfd info;
@@ -1060,10 +1148,6 @@ int KernelProxy::select(int nfds, fd_set* readfds, fd_set* writefds,
     }
   }
 
-  FD_ZERO(readfds);
-  FD_ZERO(writefds);
-  FD_ZERO(exceptfds);
-
   // NULL timeout signals wait forever.
   int ms_timeout = -1;
   if (timeout != NULL) {
@@ -1071,8 +1155,11 @@ int KernelProxy::select(int nfds, fd_set* readfds, fd_set* writefds,
 
     // If the timeout is invalid or too long (larger than signed 32 bit).
     if ((timeout->tv_sec < 0) || (timeout->tv_sec >= (INT_MAX / 1000)) ||
-        (timeout->tv_usec < 0) || (timeout->tv_usec >= 1000000) ||
-        (ms < 0) || (ms >= INT_MAX)) {
+        (timeout->tv_usec < 0) || (timeout->tv_usec >= 1000000) || (ms < 0) ||
+        (ms >= INT_MAX)) {
+      LOG_TRACE("Invalid timeout: tv_sec=%d tv_usec=%d.",
+                timeout->tv_sec,
+                timeout->tv_usec);
       errno = EINVAL;
       return -1;
     }
@@ -1113,7 +1200,7 @@ struct PollInfo {
 
 typedef std::map<EventEmitter*, PollInfo> EventPollMap_t;
 
-int KernelProxy::poll(struct pollfd *fds, nfds_t nfds, int timeout) {
+int KernelProxy::poll(struct pollfdfds, nfds_t nfds, int timeout) {
   EventPollMap_t event_map;
 
   std::vector<EventRequest> requests;
@@ -1194,7 +1281,6 @@ int KernelProxy::poll(struct pollfd *fds, nfds_t nfds, int timeout) {
   return event_cnt;
 }
 
-
 // Socket Functions
 int KernelProxy::accept(int fd, struct sockaddr* addr, socklen_t* len) {
   if (NULL == addr || NULL == len) {
@@ -1216,7 +1302,7 @@ int KernelProxy::accept(int fd, struct sockaddr* addr, socklen_t* len) {
     return -1;
   }
 
-  SocketNode* sock = new TcpNode(stream_mount_.get(), new_sock);
+  SocketNode* sock = new TcpNode(stream_fs_.get(), new_sock);
 
   // The SocketNode now holds a reference to the new socket
   // so we release ours.
@@ -1228,7 +1314,7 @@ int KernelProxy::accept(int fd, struct sockaddr* addr, socklen_t* len) {
   }
 
   ScopedNode node(sock);
-  ScopedKernelHandle new_handle(new KernelHandle(stream_mount_, node));
+  ScopedKernelHandle new_handle(new KernelHandle(stream_fs_, node));
   error = new_handle->Init(O_RDWR);
   if (error != 0) {
     errno = error;
@@ -1279,16 +1365,28 @@ int KernelProxy::connect(int fd, const struct sockaddr* addr, socklen_t len) {
   return 0;
 }
 
-void KernelProxy::freeaddrinfo(struct addrinfo *res) {
+void KernelProxy::freeaddrinfo(struct addrinfores) {
   return host_resolver_.freeaddrinfo(res);
 }
 
-int KernelProxy::getaddrinfo(const char* node, const char* service,
+int KernelProxy::getaddrinfo(const char* node,
+                             const char* service,
                              const struct addrinfo* hints,
                              struct addrinfo** res) {
   return host_resolver_.getaddrinfo(node, service, hints, res);
 }
 
+int KernelProxy::getnameinfo(const struct sockaddr *sa,
+                             socklen_t salen,
+                             char *host,
+                             size_t hostlen,
+                             char *serv,
+                             size_t servlen,
+                             int flags) {
+  return host_resolver_.getnameinfo(sa, salen, host, hostlen, serv, servlen,
+                                    flags);
+}
+
 struct hostent* KernelProxy::gethostbyname(const char* name) {
   return host_resolver_.gethostbyname(name);
 }
@@ -1368,10 +1466,7 @@ int KernelProxy::listen(int fd, int backlog) {
   return 0;
 }
 
-ssize_t KernelProxy::recv(int fd,
-                          void* buf,
-                          size_t len,
-                          int flags) {
+ssize_t KernelProxy::recv(int fd, void* buf, size_t len, int flags) {
   if (NULL == buf) {
     errno = EFAULT;
     return -1;
@@ -1428,7 +1523,7 @@ ssize_t KernelProxy::recvfrom(int fd,
 }
 
 ssize_t KernelProxy::recvmsg(int fd, struct msghdr* msg, int flags) {
-  if (NULL == msg ) {
+  if (NULL == msg) {
     errno = EFAULT;
     return -1;
   }
@@ -1574,11 +1669,11 @@ int KernelProxy::socket(int domain, int type, int protocol) {
   SocketNode* sock = NULL;
   switch (type) {
     case SOCK_DGRAM:
-      sock = new UdpNode(stream_mount_.get());
+      sock = new UdpNode(stream_fs_.get());
       break;
 
     case SOCK_STREAM:
-      sock = new TcpNode(stream_mount_.get());
+      sock = new TcpNode(stream_fs_.get());
       break;
 
     case SOCK_SEQPACKET:
@@ -1599,7 +1694,7 @@ int KernelProxy::socket(int domain, int type, int protocol) {
     return -1;
   }
 
-  ScopedKernelHandle handle(new KernelHandle(stream_mount_, node));
+  ScopedKernelHandle handle(new KernelHandle(stream_fs_, node));
   rtn = handle->Init(open_flags);
   if (rtn != 0) {
     errno = rtn;