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