Home | History | Annotate | Download | only in nacl_io
      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_io/kernel_handle.h"
      6 
      7 #include <errno.h>
      8 #include <pthread.h>
      9 
     10 #include "nacl_io/mount.h"
     11 #include "nacl_io/mount_node.h"
     12 #include "nacl_io/mount_node_socket.h"
     13 #include "nacl_io/osunistd.h"
     14 
     15 #include "sdk_util/auto_lock.h"
     16 
     17 namespace nacl_io {
     18 
     19 // It is only legal to construct a handle while the kernel lock is held.
     20 KernelHandle::KernelHandle()
     21     : mount_(NULL), node_(NULL) {}
     22 
     23 KernelHandle::KernelHandle(const ScopedMount& mnt, const ScopedMountNode& node)
     24     : mount_(mnt), node_(node) {}
     25 
     26 KernelHandle::~KernelHandle() {
     27   // Force release order for cases where mount_ is not ref'd by mounting.
     28   node_.reset(NULL);
     29   mount_.reset(NULL);
     30 }
     31 
     32 // Returns the MountNodeSocket* if this node is a socket.
     33 MountNodeSocket* KernelHandle::socket_node() {
     34   if (node_.get() && node_->IsaSock())
     35     return reinterpret_cast<MountNodeSocket*>(node_.get());
     36   return NULL;
     37 }
     38 
     39 Error KernelHandle::Init(int open_flags) {
     40   handle_attr_.flags = open_flags;
     41 
     42   if (!node_->CanOpen(open_flags)) {
     43     return EACCES;
     44   }
     45 
     46   if (open_flags & O_APPEND) {
     47     Error error = node_->GetSize(&handle_attr_.offs);
     48     if (error)
     49       return error;
     50   }
     51 
     52   return 0;
     53 }
     54 
     55 Error KernelHandle::Seek(off_t offset, int whence, off_t* out_offset) {
     56   // By default, don't move the offset.
     57   *out_offset = offset;
     58   ssize_t base;
     59   size_t node_size;
     60 
     61   AUTO_LOCK(handle_lock_);
     62   Error error = node_->GetSize(&node_size);
     63   if (error)
     64     return error;
     65 
     66   switch (whence) {
     67     case SEEK_SET:
     68       base = 0;
     69       break;
     70     case SEEK_CUR:
     71       base = handle_attr_.offs;
     72       break;
     73     case SEEK_END:
     74       base = node_size;
     75       break;
     76     default:
     77       return -1;
     78   }
     79 
     80   if (base + offset < 0)
     81     return EINVAL;
     82 
     83   size_t new_offset = base + offset;
     84 
     85   // Seeking past the end of the file will zero out the space between the old
     86   // end and the new end.
     87   if (new_offset > node_size) {
     88     error = node_->FTruncate(new_offset);
     89     if (error)
     90       return EINVAL;
     91   }
     92 
     93   *out_offset = handle_attr_.offs = new_offset;
     94   return 0;
     95 }
     96 
     97 Error KernelHandle::Read(void* buf, size_t nbytes, int* cnt) {
     98   AUTO_LOCK(handle_lock_);
     99   if (OpenMode() == O_WRONLY)
    100     return EACCES;
    101   Error error = node_->Read(handle_attr_, buf, nbytes, cnt);
    102   if (0 == error)
    103     handle_attr_.offs += *cnt;
    104   return error;
    105 }
    106 
    107 Error KernelHandle::Write(const void* buf, size_t nbytes, int* cnt) {
    108   AUTO_LOCK(handle_lock_);
    109   if (OpenMode() == O_RDONLY)
    110     return EACCES;
    111   Error error = node_->Write(handle_attr_, buf, nbytes, cnt);
    112   if (0 == error)
    113     handle_attr_.offs += *cnt;
    114   return error;
    115 }
    116 
    117 Error KernelHandle::GetDents(struct dirent* pdir, size_t nbytes, int* cnt) {
    118   AUTO_LOCK(handle_lock_);
    119   Error error = node_->GetDents(handle_attr_.offs, pdir, nbytes, cnt);
    120   if (0 == error)
    121     handle_attr_.offs += *cnt;
    122   return error;
    123 }
    124 
    125 Error KernelHandle::Fcntl(int request, int* result, ...) {
    126   va_list ap;
    127   va_start(ap, result);
    128   Error rtn = VFcntl(request, result, ap);
    129   va_end(ap);
    130   return rtn;
    131 }
    132 
    133 Error KernelHandle::VFcntl(int request, int* result, va_list args) {
    134   switch (request) {
    135     case F_GETFL: {
    136       *result = handle_attr_.flags;
    137       return 0;
    138     }
    139     case F_SETFL: {
    140       AUTO_LOCK(handle_lock_);
    141       int flags = va_arg(args, int);
    142       if (!(flags & O_APPEND) && (handle_attr_.flags & O_APPEND)) {
    143         // Attempt to clear O_APPEND.
    144         return EPERM;
    145       }
    146       // Only certain flags are mutable
    147       const int mutable_flags = O_ASYNC | O_NONBLOCK;
    148       flags &= mutable_flags;
    149       handle_attr_.flags &= ~mutable_flags;
    150       handle_attr_.flags |= flags;
    151       return 0;
    152     }
    153   }
    154   return ENOSYS;
    155 }
    156 
    157 Error KernelHandle::Accept(PP_Resource* new_sock, struct sockaddr* addr,
    158                            socklen_t* len) {
    159   MountNodeSocket* sock = socket_node();
    160   if (!sock)
    161     return ENOTSOCK;
    162 
    163   AUTO_LOCK(handle_lock_);
    164   return sock->Accept(handle_attr_, new_sock, addr, len);
    165 }
    166 
    167 Error KernelHandle::Connect(const struct sockaddr* addr, socklen_t len) {
    168   MountNodeSocket* sock = socket_node();
    169   if (!sock)
    170     return ENOTSOCK;
    171 
    172   AUTO_LOCK(handle_lock_);
    173   return sock->Connect(handle_attr_, addr, len);
    174 }
    175 
    176 Error KernelHandle::Recv(void* buf, size_t len, int flags, int* out_len) {
    177   MountNodeSocket* sock = socket_node();
    178   if (!sock)
    179     return ENOTSOCK;
    180   if (OpenMode() == O_WRONLY)
    181     return EACCES;
    182 
    183   AUTO_LOCK(handle_lock_);
    184   return sock->Recv(handle_attr_, buf, len, flags, out_len);
    185 }
    186 
    187 Error KernelHandle::RecvFrom(void* buf,
    188                              size_t len,
    189                              int flags,
    190                              struct sockaddr* src_addr,
    191                              socklen_t* addrlen,
    192                              int* out_len) {
    193   MountNodeSocket* sock = socket_node();
    194   if (!sock)
    195     return ENOTSOCK;
    196   if (OpenMode() == O_WRONLY)
    197     return EACCES;
    198 
    199   AUTO_LOCK(handle_lock_);
    200   return sock->RecvFrom(handle_attr_, buf, len, flags, src_addr, addrlen,
    201                         out_len);
    202 }
    203 
    204 Error KernelHandle::Send(const void* buf,
    205                          size_t len,
    206                          int flags,
    207                          int* out_len) {
    208   MountNodeSocket* sock = socket_node();
    209   if (!sock)
    210     return ENOTSOCK;
    211   if (OpenMode() == O_RDONLY)
    212     return EACCES;
    213 
    214   AUTO_LOCK(handle_lock_);
    215   return sock->Send(handle_attr_, buf, len, flags, out_len);
    216 }
    217 
    218 Error KernelHandle::SendTo(const void* buf,
    219                            size_t len,
    220                            int flags,
    221                            const struct sockaddr* dest_addr,
    222                            socklen_t addrlen,
    223                            int* out_len) {
    224   MountNodeSocket* sock = socket_node();
    225   if (!sock)
    226     return ENOTSOCK;
    227   if (OpenMode() == O_RDONLY)
    228     return EACCES;
    229 
    230   AUTO_LOCK(handle_lock_);
    231   return sock->SendTo(handle_attr_, buf, len, flags, dest_addr, addrlen,
    232                       out_len);
    233 }
    234 
    235 }  // namespace nacl_io
    236