Пример #1
0
/*
 * read specified amount of bytes from given desc/offset to buffer
 * return amount of read bytes or negative error code if call failed
 */
static int32_t ZVMReadHandle(struct NaClApp *nap,
    int ch, char *buffer, int32_t size, int64_t offset)
{
  struct ChannelDesc *channel;
  int64_t tail;
  char *sys_buffer;

  assert(nap != NULL);
  assert(nap->manifest != NULL);
  assert(nap->manifest->channels != NULL);

  /* check the channel number */
  if(ch < 0 || ch >= nap->manifest->channels->len)
  {
    ZLOGS(LOG_DEBUG, "channel_id=%d, buffer=%p, size=%d, offset=%ld",
        ch, buffer, size, offset);
    return -EINVAL;
  }
  channel = CH_CH(nap->manifest, ch);
  ZLOGS(LOG_INSANE, "channel %s, buffer=%p, size=%d, offset=%ld",
      channel->alias, buffer, size, offset);

  /* check buffer and convert address */
  if(CheckRAMAccess(nap, (uintptr_t)buffer, size, PROT_WRITE) == -1) return -EINVAL;
  sys_buffer = (char*)NaClUserToSys(nap, (uintptr_t)buffer);

  /* ignore user offset for sequential access read */
  if(CH_SEQ_READABLE(channel))
    offset = channel->getpos;
  else
  /* prevent reading beyond the end of the random access channels */
    size = MIN(channel->size - offset, size);

  /* check arguments sanity */
  if(size == 0) return 0; /* success. user has read 0 bytes */
  if(size < 0) return -EFAULT;
  if(offset < 0) return -EINVAL;

  /* check for eof */
  if(channel->eof) return 0;

  /* check limits */
  if(channel->counters[GetsLimit] >= channel->limits[GetsLimit])
    return -EDQUOT;
  if(CH_RND_READABLE(channel))
    if(offset >= channel->limits[PutSizeLimit] - channel->counters[PutSizeLimit]
      + channel->size) return -EINVAL;

  /* calculate i/o leftovers */
  tail = channel->limits[GetSizeLimit] - channel->counters[GetSizeLimit];
  if(size > tail) size = tail;
  if(size < 1) return -EDQUOT;

  /* read data */
  return ChannelRead(channel, sys_buffer, (size_t)size, (off_t)offset);
}
Пример #2
0
/*
 * write specified amount of bytes from buffer to given desc/offset
 * return amount of read bytes or negative error code if call failed
 */
static int32_t ZVMWriteHandle(struct NaClApp *nap,
    int ch, const char *buffer, int32_t size, int64_t offset)
{
  struct ChannelDesc *channel;
  int64_t tail;
  const char *sys_buffer;

  assert(nap != NULL);
  assert(nap->manifest != NULL);
  assert(nap->manifest->channels != NULL);

  /* check the channel number */
  if(ch < 0 || ch >= nap->manifest->channels->len)
  {
    ZLOGS(LOG_DEBUG, "channel_id=%d, buffer=%p, size=%d, offset=%ld",
        ch, buffer, size, offset);
    return -EINVAL;
  }
  channel = CH_CH(nap->manifest, ch);
  ZLOGS(LOG_INSANE, "channel %s, buffer=%p, size=%d, offset=%ld",
      channel->alias, buffer, size, offset);

  /* check buffer and convert address */
  if(CheckRAMAccess(nap, (uintptr_t)buffer, size, PROT_READ) == -1) return -EINVAL;
  sys_buffer = (char*)NaClUserToSys(nap, (uintptr_t) buffer);

  /* ignore user offset for sequential access write */
  if(CH_SEQ_WRITEABLE(channel)) offset = channel->putpos;

  /* check arguments sanity */
  if(size == 0) return 0; /* success. user has read 0 bytes */
  if(size < 0) return -EFAULT;
  if(offset < 0) return -EINVAL;

  /* check limits */
  if(channel->counters[PutsLimit] >= channel->limits[PutsLimit])
    return -EDQUOT;
  tail = channel->limits[PutSizeLimit] - channel->counters[PutSizeLimit];
  if(offset >= channel->limits[PutSizeLimit] &&
      !((CH_RW_TYPE(channel) & 1) == 1)) return -EINVAL;

  if(offset >= channel->size + tail) return -EINVAL;
  if(size > tail) size = tail;
  if(size < 1) return -EDQUOT;

  /* write data */
  return ChannelWrite(channel, sys_buffer, (size_t)size, (off_t)offset);
}
Пример #3
0
/*
 * write specified amount of bytes from buffer to given desc/offset
 * return amount of read bytes or negative error code if call failed
 */
static int32_t ZVMWriteHandle(struct NaClApp *nap,
    int ch, const char *buffer, int32_t size, int64_t offset)
{
  struct ChannelDesc *channel;
  int64_t tail;
  const char *sys_buffer;
  int32_t retcode = -1;

  assert(nap != NULL);
  assert(nap->system_manifest != NULL);
  assert(nap->system_manifest->channels != NULL);

  /* check the channel number */
  if(ch < 0 || ch >= nap->system_manifest->channels_count)
  {
    ZLOGS(LOG_DEBUG, "channel_id=%d, buffer=0x%lx, size=%d, offset=%ld",
        ch, (intptr_t)buffer, size, offset);
    return -EINVAL;
  }
  channel = &nap->system_manifest->channels[ch];
  ZLOGS(LOG_DEBUG, "channel %s, buffer=0x%lx, size=%d, offset=%ld",
      channel->alias, (intptr_t)buffer, size, offset);

  /* check buffer and convert address */
  if(CheckRAMAccess(nap, (uintptr_t)buffer, size, PROT_READ) == -1) return -EINVAL;
  sys_buffer = (char*)NaClUserToSys(nap, (uintptr_t) buffer);

  /* ignore user offset for sequential access write */
  if(CHANNEL_SEQ_WRITEABLE(channel)) offset = channel->putpos;

  /* check arguments sanity */
  if(size == 0) return 0; /* success. user has read 0 bytes */
  if(size < 0) return -EFAULT;
  if(offset < 0) return -EINVAL;

  /* check limits */
  if(channel->counters[PutsLimit] >= channel->limits[PutsLimit])
    return -EDQUOT;
  tail = channel->limits[PutSizeLimit] - channel->counters[PutSizeLimit];
  if(offset >= channel->limits[PutSizeLimit] &&
      !CHANNEL_READABLE(channel)) return -EINVAL;
  if(offset >= channel->size + tail) return -EINVAL;
  if(size > tail) size = tail;
  if(size < 1) return -EDQUOT;

  /* write data and update position */
  switch(channel->source)
  {
    case ChannelRegular:
      retcode = pwrite(channel->handle, sys_buffer, (size_t)size, (off_t)offset);
      if(retcode == -1) retcode = -errno;
      break;
    case ChannelCharacter:
    case ChannelFIFO:
      retcode = fwrite(sys_buffer, 1, (size_t)size, (FILE*)channel->socket);
      if(retcode == -1) retcode = -errno;
      break;
    case ChannelTCP:
      retcode = SendMessage(channel, sys_buffer, size);
      if(retcode == -1) retcode = -EIO;
      break;
    default: /* design error */
      ZLOGFAIL(1, EFAULT, "invalid channel source");
      break;
  }

  /* update the channel counter, size, position and tag */
  ++channel->counters[PutsLimit];
  if(retcode > 0)
  {
    channel->counters[PutSizeLimit] += retcode;
    UpdateChannelTag(channel, (const char*)sys_buffer, retcode);

    channel->putpos = offset + retcode;
    channel->size = (channel->type == SGetRPut) || (channel->type == RGetRPut) ?
        MAX(channel->size, channel->putpos) : channel->putpos;
    channel->getpos = channel->putpos;
  }

  return retcode;
}
Пример #4
0
/*
 * read specified amount of bytes from given desc/offset to buffer
 * return amount of read bytes or negative error code if call failed
 */
static int32_t ZVMReadHandle(struct NaClApp *nap,
    int ch, char *buffer, int32_t size, int64_t offset)
{
  struct ChannelDesc *channel;
  int64_t tail;
  char *sys_buffer;
  int32_t retcode = -1;

  assert(nap != NULL);
  assert(nap->system_manifest != NULL);
  assert(nap->system_manifest->channels != NULL);

  /* check the channel number */
  if(ch < 0 || ch >= nap->system_manifest->channels_count)
  {
    ZLOGS(LOG_DEBUG, "channel_id=%d, buffer=0x%lx, size=%d, offset=%ld",
        ch, (intptr_t)buffer, size, offset);
    return -EINVAL;
  }
  channel = &nap->system_manifest->channels[ch];
  ZLOGS(LOG_DEBUG, "channel %s, buffer=0x%lx, size=%d, offset=%ld",
      channel->alias, (intptr_t)buffer, size, offset);

  /* check buffer and convert address */
  if(CheckRAMAccess(nap, (uintptr_t)buffer, size, PROT_READ) == -1) return -EINVAL;
  sys_buffer = (char*)NaClUserToSys(nap, (uintptr_t) buffer);

  /* ignore user offset for sequential access read */
  if(CHANNEL_SEQ_READABLE(channel))
    offset = channel->getpos;
  else
    /* prevent reading beyond the end of the random access channels */
    size = MIN(channel->size - offset, size);

  /* check arguments sanity */
  if(size == 0) return 0; /* success. user has read 0 bytes */
  if(size < 0) return -EFAULT;
  if(offset < 0) return -EINVAL;

  /* check for eof */
  if(channel->eof) return 0;

  /* check limits */
  if(channel->counters[GetsLimit] >= channel->limits[GetsLimit])
    return -EDQUOT;
  if(CHANNEL_RND_READABLE(channel))
    if(offset >= channel->limits[PutSizeLimit] - channel->counters[PutSizeLimit]
      + channel->size) return -EINVAL;

  /* calculate i/o leftovers */
  tail = channel->limits[GetSizeLimit] - channel->counters[GetSizeLimit];
  if(size > tail) size = tail;
  if(size < 1) return -EDQUOT;

  /* read data and update position */
  switch(channel->source)
  {
    case ChannelRegular:
      retcode = pread(channel->handle, sys_buffer, (size_t)size, (off_t)offset);
      if(retcode == -1) retcode = -errno;
      break;
    case ChannelCharacter:
    case ChannelFIFO:
     retcode = fread(sys_buffer, 1, (size_t)size, (FILE*)channel->socket);
      if(retcode == -1) retcode = -errno;
      break;
    case ChannelTCP:
      retcode = FetchMessage(channel, sys_buffer, size);
      if(retcode == -1) retcode = -EIO;
      break;
    default: /* design error */
      ZLOGFAIL(1, EFAULT, "invalid channel source");
      break;
  }

  /* update the channel counter, size, position and tag */
  ++channel->counters[GetsLimit];
  if(retcode > 0)
  {
    channel->counters[GetSizeLimit] += retcode;
    UpdateChannelTag(channel, (const char*)sys_buffer, retcode);

    /*
     * current get cursor. must be updated if channel have seq get
     * but there is nothing wrong to update it even it have random get
     */
    channel->getpos = offset + retcode;

    /* if channel have random put update put cursor. not allowed for cdr */
    if(CHANNEL_RND_WRITEABLE(channel)) channel->putpos = offset + retcode;
  }

  /*
   * set eof if 0 bytes has been read. it is safe because
   * 1. if user asked for a 0 bytes control will not reach this code
   * 2. if user asked more then 0 bytes and got 0 that means end of data
   * 3. if quota exceeded user will get an error before an actual read
   */
  if(retcode == 0) channel->eof = 1;

  return retcode;
}