Beispiel #1
0
int
rtems_rfs_file_io_end (rtems_rfs_file_handle* handle,
                       size_t                 size,
                       bool                   read)
{
  bool atime;
  bool mtime;
  bool length;
  int  rc = 0;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
    printf ("rtems-rfs: file-io:   end: %s size=%zu\n",
            read ? "read" : "write", size);

  if (rtems_rfs_buffer_handle_has_block (&handle->buffer))
  {
    if (!read)
      rtems_rfs_buffer_mark_dirty (rtems_rfs_file_buffer (handle));
    rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
                                          rtems_rfs_file_buffer (handle));
    if (rc > 0)
    {
      printf (
        "rtems-rfs: file-io:   end: error on release: %s size=%zu: %d: %s\n",
        read ? "read" : "write", size, rc, strerror (rc));

      return rc;
    }
  }

  /*
   * Update the handle's position. Only a block size can be handled at a time
   * so no special maths is needed. If the offset is bigger than the block size
   * increase the block number and adjust the offset.
   *
   * If we are the last block and the position is past the current size update
   * the size with the new length. The map holds the block count.
   */
  handle->bpos.boff += size;

  if (handle->bpos.boff >=
      rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle)))
  {
    handle->bpos.bno++;
    handle->bpos.boff -= rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
  }

  length = false;
  mtime = false;

  if (!read &&
      rtems_rfs_block_map_past_end (rtems_rfs_file_map (handle),
                                    rtems_rfs_file_bpos (handle)))
  {
    rtems_rfs_block_map_set_size_offset (rtems_rfs_file_map (handle),
                                         handle->bpos.boff);
    length = true;
    mtime = true;
  }

  atime  = rtems_rfs_file_update_atime (handle);
  mtime  = rtems_rfs_file_update_mtime (handle) && mtime;
  length = rtems_rfs_file_update_length (handle) && length;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
    printf ("rtems-rfs: file-io:   end: pos=%" PRIu32 ":%" PRIu32 " %c %c %c\n",
            handle->bpos.bno, handle->bpos.boff,
            atime ? 'A' : '-', mtime ? 'M' : '-', length ? 'L' : '-');

  if (atime || mtime)
  {
    time_t now = time (NULL);
    if (read && atime)
      handle->shared->atime = now;
    if (!read && mtime)
      handle->shared->mtime = now;
  }
  if (length)
  {
    handle->shared->size.count =
      rtems_rfs_block_map_count (rtems_rfs_file_map (handle));
    handle->shared->size.offset =
      rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle));
  }

  return rc;
}
rtems_rfs_pos
rtems_rfs_block_get_pos (rtems_rfs_file_system* fs,
                         rtems_rfs_block_pos*   bpos)
{
  return (bpos->bno * rtems_rfs_fs_block_size (fs)) + bpos->boff;
}
Beispiel #3
0
int
rtems_rfs_file_io_start (rtems_rfs_file_handle* handle,
                         size_t*                available,
                         bool                   read)
{
  size_t size;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
    printf ("rtems-rfs: file-io: start: %s pos=%" PRIu32 ":%" PRIu32 "\n",
            read ? "read" : "write",  handle->bpos.bno, handle->bpos.boff);

  if (!rtems_rfs_buffer_handle_has_block (&handle->buffer))
  {
    rtems_rfs_buffer_block block;
    bool                   request_read;
    int                    rc;

    request_read = read;

    rc = rtems_rfs_block_map_find (rtems_rfs_file_fs (handle),
                                   rtems_rfs_file_map (handle),
                                   rtems_rfs_file_bpos (handle),
                                   &block);
    if (rc > 0)
    {
      /*
       * Has the read reached the EOF ?
       */
      if (read && (rc == ENXIO))
      {
        *available = 0;
        return 0;
      }

      if (rc != ENXIO)
        return rc;

      if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
        printf ("rtems-rfs: file-io: start: grow\n");

      rc = rtems_rfs_block_map_grow (rtems_rfs_file_fs (handle),
                                     rtems_rfs_file_map (handle),
                                     1, &block);
      if (rc > 0)
        return rc;

      request_read = false;
    }
    else
    {
      /*
       * If this is a write check if the write starts within a block or the
       * amount of data is less than a block size. If it is read the block
       * rather than getting a block to fill.
       */
      if (!read &&
          (rtems_rfs_file_block_offset (handle) ||
           (*available < rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle)))))
        request_read = true;
    }

    if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
      printf ("rtems-rfs: file-io: start: block=%" PRIu32 " request-read=%s\n",
              block, request_read ? "yes" : "no");

    rc = rtems_rfs_buffer_handle_request (rtems_rfs_file_fs (handle),
                                          rtems_rfs_file_buffer (handle),
                                          block, request_read);
    if (rc > 0)
      return rc;
  }

  if (read
      && rtems_rfs_block_map_last (rtems_rfs_file_map (handle))
      && rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle)))
    size = rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle));
  else
    size = rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));

  *available = size - rtems_rfs_file_block_offset (handle);

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
    printf ("rtems-rfs: file-io: start: available=%zu (%zu)\n",
            *available, size);

  return 0;
}
Beispiel #4
0
int
rtems_rfs_dir_read (rtems_rfs_file_system*  fs,
                    rtems_rfs_inode_handle* dir,
                    rtems_rfs_pos_rel       offset,
                    struct dirent*          dirent,
                    size_t*                 length)
{
  rtems_rfs_block_map     map;
  rtems_rfs_buffer_handle buffer;
  rtems_rfs_block_no      block;
  int                     rc;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
    printf ("rtems-rfs: dir-read: dir=%" PRId32 " offset=%" PRId64 "\n",
            rtems_rfs_inode_ino (dir), offset);

  *length = 0;

  rc = rtems_rfs_block_map_open (fs, dir, &map);
  if (rc > 0)
    return rc;

  if (((rtems_rfs_fs_block_size (fs) -
        (offset % rtems_rfs_fs_block_size (fs))) <= RTEMS_RFS_DIR_ENTRY_SIZE))
    offset = (((offset / rtems_rfs_fs_block_size (fs)) + 1) *
              rtems_rfs_fs_block_size (fs));

  rc = rtems_rfs_block_map_seek (fs, &map, offset, &block);
  if (rc > 0)
  {
    if (rc == ENXIO)
      rc = ENOENT;
    rtems_rfs_block_map_close (fs, &map);
    return rc;
  }

  rc = rtems_rfs_buffer_handle_open (fs, &buffer);
  if (rc > 0)
  {
    rtems_rfs_block_map_close (fs, &map);
    return rc;
  }

  /*
   * Look for an empty entry and if this is the last block that is the end of
   * the directory.
   */
  while (rc == 0)
  {
    uint8_t*      entry;
    rtems_rfs_ino eino;
    int           elength;
    int           remaining;

    rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
    if (rc > 0)
    {
      rtems_rfs_buffer_handle_close (fs, &buffer);
      rtems_rfs_block_map_close (fs, &map);
      return rc;
    }

    entry  = rtems_rfs_buffer_data (&buffer);
    entry += map.bpos.boff;

    elength = rtems_rfs_dir_entry_length (entry);
    eino    = rtems_rfs_dir_entry_ino (entry);

    if (elength != RTEMS_RFS_DIR_ENTRY_EMPTY)
    {
      if (rtems_rfs_dir_entry_valid (fs, elength, eino))
      {
        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
          printf ("rtems-rfs: dir-read: "
                  "bad length or ino for ino %" PRIu32 ": %u/%" PRId32 " @ %04" PRIx32 "\n",
                  rtems_rfs_inode_ino (dir), elength, eino, map.bpos.boff);
        rc = EIO;
        break;
      }

      memset (dirent, 0, sizeof (struct dirent));
      dirent->d_off = offset;
      dirent->d_reclen = sizeof (struct dirent);

      *length += elength;

      remaining = rtems_rfs_fs_block_size (fs) - (map.bpos.boff + elength);

      if (remaining <= RTEMS_RFS_DIR_ENTRY_SIZE)
        *length += remaining;

      elength -= RTEMS_RFS_DIR_ENTRY_SIZE;
      if (elength > NAME_MAX)
        elength = NAME_MAX;

      memcpy (dirent->d_name, entry + RTEMS_RFS_DIR_ENTRY_SIZE, elength);

      dirent->d_ino = rtems_rfs_dir_entry_ino (entry);
      dirent->d_namlen = elength;

      if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
        printf ("rtems-rfs: dir-read: found off:%" PRIooff_t " ino:%ld name=%s\n",
                dirent->d_off, dirent->d_ino, dirent->d_name);
      break;
    }

    *length += rtems_rfs_fs_block_size (fs) - map.bpos.boff;

    if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
      printf ("rtems-rfs: dir-read: next block: off:%" PRId64 " length:%zd\n",
              offset, *length);

    rc = rtems_rfs_block_map_next_block (fs, &map, &block);
    if (rc == ENXIO)
      rc = ENOENT;
  }

  rtems_rfs_buffer_handle_close (fs, &buffer);
  rtems_rfs_block_map_close (fs, &map);
  return rc;
}
Beispiel #5
0
int
rtems_rfs_dir_empty (rtems_rfs_file_system*  fs,
                     rtems_rfs_inode_handle* dir)
{
  rtems_rfs_block_map     map;
  rtems_rfs_buffer_handle buffer;
  rtems_rfs_block_no      block;
  bool                    empty;
  int                     rc;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
    printf ("rtems-rfs: dir-empty: dir=%" PRId32 "\n", rtems_rfs_inode_ino (dir));

  empty = true;

  rc = rtems_rfs_block_map_open (fs, dir, &map);
  if (rc > 0)
    return rc;

  rc = rtems_rfs_block_map_seek (fs, &map, 0, &block);
  if (rc > 0)
  {
    rtems_rfs_block_map_close (fs, &map);
    return rc;
  }

  rc = rtems_rfs_buffer_handle_open (fs, &buffer);
  if (rc > 0)
  {
    rtems_rfs_block_map_close (fs, &map);
    return rc;
  }

  /*
   * Look for an empty entry and if this is the last block that is the end of
   * the directory.
   */
  while (empty)
  {
    uint8_t* entry;
    int      offset;

    rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
    if (rc > 0)
      break;

    entry  = rtems_rfs_buffer_data (&buffer);
    offset = 0;

    while (offset < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE))
    {
      rtems_rfs_ino eino;
      int           elength;

      elength = rtems_rfs_dir_entry_length (entry);
      eino    = rtems_rfs_dir_entry_ino (entry);

      if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
        break;

      if (rtems_rfs_dir_entry_valid (fs, elength, eino))
      {
        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_EMPTY))
          printf ("rtems-rfs: dir-empty: "
                  "bad length or ino for ino %" PRIu32 ": %u/%" PRIu32 " @ %04x\n",
                  rtems_rfs_inode_ino (dir), elength, eino, offset);
        rc = EIO;
        break;
      }

      /*
       * Ignore the current (.) and parent (..) entries. Anything else means
       * the directory is not empty.
       */
      if (((elength != (RTEMS_RFS_DIR_ENTRY_SIZE + 1)) ||
           (entry[RTEMS_RFS_DIR_ENTRY_SIZE] != '.')) &&
          ((elength != (RTEMS_RFS_DIR_ENTRY_SIZE + 2)) ||
           (entry[RTEMS_RFS_DIR_ENTRY_SIZE] != '.') ||
           (entry[RTEMS_RFS_DIR_ENTRY_SIZE + 1] != '.')))
      {
        empty = false;
        break;
      }

      entry  += elength;
      offset += elength;
    }

    if (empty)
    {
      rc = rtems_rfs_block_map_next_block (fs, &map, &block);
      if (rc > 0)
      {
        if (rc == ENXIO)
          rc = 0;
        break;
      }
    }
  }

  if ((rc == 0) && !empty)
    rc = ENOTEMPTY;

  rtems_rfs_buffer_handle_close (fs, &buffer);
  rtems_rfs_block_map_close (fs, &map);
  return rc;
}
Beispiel #6
0
static int
rtems_rfs_fs_read_superblock (rtems_rfs_file_system* fs)
{
  rtems_rfs_buffer_handle handle;
  uint8_t*                sb;
  int                     group;
  int                     rc;

  rc = rtems_rfs_buffer_handle_open (fs, &handle);
  if (rc > 0)
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
      printf ("rtems-rfs: read-superblock: handle open failed: %d: %s\n",
              rc, strerror (rc));
    return rc;
  }

  rc = rtems_rfs_buffer_handle_request (fs, &handle, 0, true);
  if (rc > 0)
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
      printf ("rtems-rfs: read-superblock: request failed%d: %s\n",
              rc, strerror (rc));
    return rc;
  }

  sb = rtems_rfs_buffer_data (&handle);

#define read_sb(_o) rtems_rfs_read_u32 (sb + (_o))

  if (read_sb (RTEMS_RFS_SB_OFFSET_MAGIC) != RTEMS_RFS_SB_MAGIC)
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
      printf ("rtems-rfs: read-superblock: invalid superblock, bad magic\n");
    rtems_rfs_buffer_handle_close (fs, &handle);
    return EIO;
  }

  fs->blocks     = read_sb (RTEMS_RFS_SB_OFFSET_BLOCKS);
  fs->block_size = read_sb (RTEMS_RFS_SB_OFFSET_BLOCK_SIZE);

  if (rtems_rfs_fs_size(fs) > rtems_rfs_fs_media_size (fs))
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
      printf ("rtems-rfs: read-superblock: invalid superblock block/size count\n");
    rtems_rfs_buffer_handle_close (fs, &handle);
    return EIO;
  }

  if ((read_sb (RTEMS_RFS_SB_OFFSET_VERSION) & RTEMS_RFS_VERSION_MASK) !=
      (RTEMS_RFS_VERSION * RTEMS_RFS_VERSION_MASK))
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
      printf ("rtems-rfs: read-superblock: incompatible version: %08" PRIx32 " (%08" PRIx32 ")\n",
              read_sb (RTEMS_RFS_SB_OFFSET_VERSION), RTEMS_RFS_VERSION_MASK);
    rtems_rfs_buffer_handle_close (fs, &handle);
    return EIO;
  }

  if (read_sb (RTEMS_RFS_SB_OFFSET_INODE_SIZE) != RTEMS_RFS_INODE_SIZE)
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
      printf ("rtems-rfs: read-superblock: inode size mismatch: fs:%" PRId32 " target:%" PRId32 "\n",
              read_sb (RTEMS_RFS_SB_OFFSET_VERSION), RTEMS_RFS_VERSION_MASK);
    rtems_rfs_buffer_handle_close (fs, &handle);
    return EIO;
  }

  fs->bad_blocks      = read_sb (RTEMS_RFS_SB_OFFSET_BAD_BLOCKS);
  fs->max_name_length = read_sb (RTEMS_RFS_SB_OFFSET_MAX_NAME_LENGTH);
  fs->group_count     = read_sb (RTEMS_RFS_SB_OFFSET_GROUPS);
  fs->group_blocks    = read_sb (RTEMS_RFS_SB_OFFSET_GROUP_BLOCKS);
  fs->group_inodes    = read_sb (RTEMS_RFS_SB_OFFSET_GROUP_INODES);

  fs->blocks_per_block =
    rtems_rfs_fs_block_size (fs) / sizeof (rtems_rfs_inode_block);

  fs->block_map_singly_blocks =
    fs->blocks_per_block * RTEMS_RFS_INODE_BLOCKS;
  fs->block_map_doubly_blocks =
    fs->blocks_per_block * fs->blocks_per_block * RTEMS_RFS_INODE_BLOCKS;

  fs->inodes = fs->group_count * fs->group_inodes;

  fs->inodes_per_block = fs->block_size / RTEMS_RFS_INODE_SIZE;

  if (fs->group_blocks >
      rtems_rfs_bitmap_numof_bits (rtems_rfs_fs_block_size (fs)))
  {
    rtems_rfs_buffer_handle_close (fs, &handle);
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
      printf ("rtems-rfs: read-superblock: groups blocks larger than block bits\n");
    return EIO;
  }

  rtems_rfs_buffer_handle_close (fs, &handle);

  /*
   * Change the block size to the value in the superblock.
   */
  rc = rtems_rfs_buffer_setblksize (fs, rtems_rfs_fs_block_size (fs));
  if (rc > 0)
  {
    rtems_rfs_buffer_handle_close (fs, &handle);
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
      printf ("rtems-rfs: read-superblock: invalid superblock block size%d: %s\n",
              rc, strerror (rc));
    return rc;
  }

  fs->groups = calloc (fs->group_count, sizeof (rtems_rfs_group));

  if (!fs->groups)
  {
    rtems_rfs_buffer_handle_close (fs, &handle);
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
      printf ("rtems-rfs: read-superblock: no memory for group table\n");
    return ENOMEM;
  }

  /*
   * Perform each phase of group initialisation at the same time. This way we
   * know how far the initialisation has gone if an error occurs and we need to
   * close everything.
   */
  for (group = 0; group < fs->group_count; group++)
  {
    rc = rtems_rfs_group_open (fs,
                               rtems_rfs_fs_block (fs, group, 0),
                               fs->group_blocks,
                               fs->group_inodes,
                               &fs->groups[group]);
    if (rc > 0)
    {
      int g;
      for (g = 0; g < group; g++)
        rtems_rfs_group_close (fs, &fs->groups[g]);
      rtems_rfs_buffer_handle_close (fs, &handle);
      if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
        printf ("rtems-rfs: read-superblock: no memory for group table%d: %s\n",
                rc, strerror (rc));
      return rc;
    }
  }

  return 0;
}
Beispiel #7
0
static bool
rtems_rfs_write_superblock (rtems_rfs_file_system* fs)
{
  rtems_rfs_buffer_handle handle;
  uint8_t*                sb;
  int                     rc;

  rc = rtems_rfs_buffer_handle_open (fs, &handle);
  if (rc > 0)
  {
    printf ("rtems-rfs: write-superblock: handle open failed: %d: %s\n",
            rc, strerror (rc));
    return false;
  }

  rc = rtems_rfs_buffer_handle_request (fs, &handle, 0, false);
  if (rc > 0)
  {
    rtems_rfs_buffer_handle_close (fs, &handle);
    printf ("rtems-rfs: write-superblock: request failed: %d: %s\n",
            rc, strerror (rc));
    return false;
  }

  sb = rtems_rfs_buffer_data (&handle);
  
#define write_sb(_o, _d) rtems_rfs_write_u32(sb + (_o), _d)
  
  memset (sb, 0xff, rtems_rfs_fs_block_size (fs));

  write_sb (RTEMS_RFS_SB_OFFSET_MAGIC, RTEMS_RFS_SB_MAGIC);
  write_sb (RTEMS_RFS_SB_OFFSET_VERSION, RTEMS_RFS_VERSION);
  write_sb (RTEMS_RFS_SB_OFFSET_BLOCKS, rtems_rfs_fs_blocks (fs));
  write_sb (RTEMS_RFS_SB_OFFSET_BLOCK_SIZE, rtems_rfs_fs_block_size (fs));
  write_sb (RTEMS_RFS_SB_OFFSET_BAD_BLOCKS, fs->bad_blocks);
  write_sb (RTEMS_RFS_SB_OFFSET_MAX_NAME_LENGTH, fs->max_name_length);
  write_sb (RTEMS_RFS_SB_OFFSET_GROUPS, fs->group_count);
  write_sb (RTEMS_RFS_SB_OFFSET_GROUP_BLOCKS, fs->group_blocks);
  write_sb (RTEMS_RFS_SB_OFFSET_GROUP_INODES, fs->group_inodes);
  write_sb (RTEMS_RFS_SB_OFFSET_INODE_SIZE, RTEMS_RFS_INODE_SIZE);

  rtems_rfs_buffer_mark_dirty (&handle);

  rc = rtems_rfs_buffer_handle_release (fs, &handle);
  if (rc > 0)
  {
    rtems_rfs_buffer_handle_close (fs, &handle);
    printf ("rtems-rfs: write-superblock: buffer release failed: %d: %s\n",
            rc, strerror (rc));
    return false;
  }

  rc = rtems_rfs_buffer_handle_close (fs, &handle);
  if (rc > 0)
  {
    printf ("rtems-rfs: write-superblock: buffer handle close failed: %d: %s\n",
            rc, strerror (rc));
    return false;
  }
  
  return true;
}
Beispiel #8
0
 * @param pathloc
 * @param sb
 * @return int
 */
static int
rtems_rfs_rtems_statvfs (
  const rtems_filesystem_location_info_t *__restrict pathloc,
  struct statvfs *__restrict                         sb)
{
  rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
  size_t                 blocks;
  size_t                 inodes;

  rtems_rfs_group_usage (fs, &blocks, &inodes);

  sb->f_bsize   = rtems_rfs_fs_block_size (fs);
  sb->f_frsize  = rtems_rfs_fs_media_block_size (fs);
  sb->f_blocks  = rtems_rfs_fs_media_blocks (fs);
  sb->f_bfree   = rtems_rfs_fs_blocks (fs) - blocks - 1; /* do not count the superblock */
  sb->f_bavail  = sb->f_bfree;
  sb->f_files   = rtems_rfs_fs_inodes (fs);
  sb->f_ffree   = rtems_rfs_fs_inodes (fs) - inodes;
  sb->f_favail  = sb->f_ffree;
  sb->f_fsid    = RTEMS_RFS_SB_MAGIC;
  sb->f_flag    = rtems_rfs_fs_flags (fs);
  sb->f_namemax = rtems_rfs_fs_max_name (fs);

  return 0;
}

/**
Beispiel #9
0
int
rtems_rfs_dir_add_entry (rtems_rfs_file_system*  fs,
                         rtems_rfs_inode_handle* dir,
                         const char*             name,
                         size_t                  length,
                         rtems_rfs_ino           ino)
{
  rtems_rfs_block_map     map;
  rtems_rfs_block_pos     bpos;
  rtems_rfs_buffer_handle buffer;
  int                     rc;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
  {
    int c;
    printf ("rtems-rfs: dir-add-entry: dir=%" PRId32 ", name=",
            rtems_rfs_inode_ino (dir));
    for (c = 0; c < length; c++)
      printf ("%c", name[c]);
    printf (", len=%zd\n", length);
  }

  rc = rtems_rfs_block_map_open (fs, dir, &map);
  if (rc > 0)
    return rc;

  rc = rtems_rfs_buffer_handle_open (fs, &buffer);
  if (rc > 0)
  {
    rtems_rfs_block_map_close (fs, &map);
    return rc;
  }

  /*
   * Search the map from the beginning to find any empty space.
   */
  rtems_rfs_block_set_bpos_zero (&bpos);

  while (true)
  {
    rtems_rfs_block_no block;
    uint8_t*           entry;
    int                offset;
    bool               read = true;

    /*
     * Locate the first block. If an error the block will be 0. If the map is
     * empty which happens when creating a directory and adding the first entry
     * the seek will return ENXIO. In this case we need to grow the directory.
     */
    rc = rtems_rfs_block_map_find (fs, &map, &bpos, &block);
    if (rc > 0)
    {
      if (rc != ENXIO)
      {
        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
          printf ("rtems-rfs: dir-add-entry: "
                  "block map find failed for ino %" PRIu32 ": %d: %s\n",
                  rtems_rfs_inode_ino (dir), rc, strerror (rc));
        break;
      }

      /*
       * We have reached the end of the directory so add a block.
       */
      rc = rtems_rfs_block_map_grow (fs, &map, 1, &block);
      if (rc > 0)
      {
        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
          printf ("rtems-rfs: dir-add-entry: "
                  "block map grow failed for ino %" PRIu32 ": %d: %s\n",
                  rtems_rfs_inode_ino (dir), rc, strerror (rc));
        break;
      }

      read = false;
    }

    bpos.bno++;

    rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, read);
    if (rc > 0)
    {
      if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
        printf ("rtems-rfs: dir-add-entry: "
                "block buffer req failed for ino %" PRIu32 ": %d: %s\n",
                rtems_rfs_inode_ino (dir), rc, strerror (rc));
      break;
    }

    entry  = rtems_rfs_buffer_data (&buffer);

    if (!read)
      memset (entry, 0xff, rtems_rfs_fs_block_size (fs));

    offset = 0;

    while (offset < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE))
    {
      rtems_rfs_ino eino;
      int           elength;

      elength = rtems_rfs_dir_entry_length (entry);
      eino    = rtems_rfs_dir_entry_ino (entry);

      if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
      {
        if ((length + RTEMS_RFS_DIR_ENTRY_SIZE) <
            (rtems_rfs_fs_block_size (fs) - offset))
        {
          uint32_t hash;
          hash = rtems_rfs_dir_hash (name, length);
          rtems_rfs_dir_set_entry_hash (entry, hash);
          rtems_rfs_dir_set_entry_ino (entry, ino);
          rtems_rfs_dir_set_entry_length (entry,
                                          RTEMS_RFS_DIR_ENTRY_SIZE + length);
          memcpy (entry + RTEMS_RFS_DIR_ENTRY_SIZE, name, length);
          rtems_rfs_buffer_mark_dirty (&buffer);
          rtems_rfs_buffer_handle_close (fs, &buffer);
          rtems_rfs_block_map_close (fs, &map);
          return 0;
        }

        break;
      }

      if (rtems_rfs_dir_entry_valid (fs, elength, eino))
      {
        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
          printf ("rtems-rfs: dir-add-entry: "
                  "bad length or ino for ino %" PRIu32 ": %u/%" PRId32 " @ %04x\n",
                  rtems_rfs_inode_ino (dir), elength, eino, offset);
        rtems_rfs_buffer_handle_close (fs, &buffer);
        rtems_rfs_block_map_close (fs, &map);
        return EIO;
      }

      entry  += elength;
      offset += elength;
    }
  }

  rtems_rfs_buffer_handle_close (fs, &buffer);
  rtems_rfs_block_map_close (fs, &map);
  return rc;
}
Beispiel #10
0
static int
rtems_rfs_shell_block (rtems_rfs_file_system* fs, int argc, char *argv[])
{
  rtems_rfs_buffer_handle buffer;
  rtems_rfs_block_no      block;
  uint8_t*                data;
  bool                    state;
  int                     b;
  int                     rc;
  
  if (argc <= 1)
  {
    printf ("error: no block number provided\n");
    return 1;
  }

  block = strtoul (argv[1], 0, 0);

  rtems_rfs_shell_lock_rfs (fs);
  
  rc = rtems_rfs_group_bitmap_test (fs, false, block, &state);
  if (rc > 0)
  {
    rtems_rfs_shell_unlock_rfs (fs);
    printf ("error: testing block state: block=%" PRIu32 ": (%d) %s\n",
            block, rc, strerror (rc));
    return 1;
  }

  printf (" %5" PRIu32 ": block %s\n", block, state ? "allocated" : "free");
    
  rc = rtems_rfs_buffer_handle_open (fs, &buffer);
  if (rc > 0)
  {
    rtems_rfs_shell_unlock_rfs (fs);
    printf ("error: opening buffer handle: block=%" PRIu32 ": (%d) %s\n",
            block, rc, strerror (rc));
    return 1;
  }

  rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
  if (rc > 0)
  {
    rtems_rfs_buffer_handle_close (fs, &buffer);
    rtems_rfs_shell_unlock_rfs (fs);
    printf ("error: requesting buffer handle: block=%" PRIu32 ": (%d) %s\n",
            block, rc, strerror (rc));
    return 1;
  }

  for (b = 0, data = rtems_rfs_buffer_data (&buffer);
       b < rtems_rfs_fs_block_size (fs);
       b++, data++)
  {
    int mod = b % 16;
    if (mod == 0)
    {
      if (b)
        printf ("\n");
      printf ("%04x ", b);
    }
    if (mod == 8)
      printf (" ");
    printf ("%02x ", *data);
  }

  printf ("\n");
  
  rc = rtems_rfs_buffer_handle_close (fs, &buffer);
  if (rc > 0)
  {
    rtems_rfs_shell_unlock_rfs (fs);
    printf ("error: closing buffer handle: block=%" PRIu32 ": (%d) %s\n",
            block, rc, strerror (rc));
    return 1;
  }
  
  rtems_rfs_shell_unlock_rfs (fs);
  
  return 0;
}
Beispiel #11
0
static int
rtems_rfs_shell_dir (rtems_rfs_file_system* fs, int argc, char *argv[])
{
  rtems_rfs_buffer_handle buffer;
  rtems_rfs_block_no      block;
  uint8_t*                data;
  bool                    state;
  int                     entry;
  int                     b;
  int                     rc;
  
  if (argc <= 1)
  {
    printf ("error: no block number provided\n");
    return 1;
  }

  block = strtoul (argv[1], 0, 0);

  rtems_rfs_shell_lock_rfs (fs);
  
  rc = rtems_rfs_group_bitmap_test (fs, false, block, &state);
  if (rc > 0)
  {
    rtems_rfs_shell_unlock_rfs (fs);
    printf ("error: testing block state: block=%" PRIu32 ": (%d) %s\n",
            block, rc, strerror (rc));
    return 1;
  }

  printf (" %5" PRIu32 ": block %s\n", block, state ? "allocated" : "free");

  rc = rtems_rfs_buffer_handle_open (fs, &buffer);
  if (rc > 0)
  {
    rtems_rfs_shell_unlock_rfs (fs);
    printf ("error: opening buffer handle: block=%" PRIu32 ": (%d) %s\n",
            block, rc, strerror (rc));
    return 1;
  }

  rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
  if (rc > 0)
  {
    rtems_rfs_buffer_handle_close (fs, &buffer);
    rtems_rfs_shell_unlock_rfs (fs);
    printf ("error: requesting buffer handle: block=%" PRIu32 ": (%d) %s\n",
            block, rc, strerror (rc));
    return 1;
  }

  b = 0;
  entry = 1;
  data = rtems_rfs_buffer_data (&buffer);
  
  while (b < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE - 1))
  {
    rtems_rfs_ino eino;
    int           elength;
    int           length;
    int           c;

    eino    = rtems_rfs_dir_entry_ino (data);
    elength = rtems_rfs_dir_entry_length (data);
    
    if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
      break;

    if ((elength < RTEMS_RFS_DIR_ENTRY_SIZE) ||
        (elength >= rtems_rfs_fs_max_name (fs)))
    {
      printf (" %5d: entry length appears corrupt: %d\n", entry, elength);
      break;
    }
    
    if ((eino < RTEMS_RFS_ROOT_INO) || (eino >= rtems_rfs_fs_inodes (fs)))
    {
      printf (" %5d: entry ino appears corrupt: ino=%" PRId32 "\n", entry, eino);
      break;
    }
    
    length = elength - RTEMS_RFS_DIR_ENTRY_SIZE;
    
    printf (" %5d: %04x inode=%-6" PRIu32 " hash=%08" PRIx32 " name[%03u]=",
            entry, b,
            rtems_rfs_dir_entry_ino (data),
            rtems_rfs_dir_entry_hash (data),
            length);

    if (length > 50)
      length = 50;
    
    for (c = 0; c < length; c++)
      printf ("%c", data[RTEMS_RFS_DIR_ENTRY_SIZE + c]);
    if (length < elength - RTEMS_RFS_DIR_ENTRY_SIZE)
      printf ("...");
    printf ("\n");

    b += elength;
    data += elength;
    entry++;
  }
  
  rc = rtems_rfs_buffer_handle_close (fs, &buffer);
  if (rc > 0)
  {
    rtems_rfs_shell_unlock_rfs (fs);
    printf ("error: closing buffer handle: block=%" PRIu32 ": (%d) %s\n",
            block, rc, strerror (rc));
    return 1;
  }
  
  rtems_rfs_shell_unlock_rfs (fs);
  
  return 0;
}
Beispiel #12
0
static bool
rtems_rfs_check_config (rtems_rfs_file_system*         fs,
                        const rtems_rfs_format_config* config)
{
  fs->block_size = config->block_size;
  if (!fs->block_size)
  {
    uint64_t total_size = rtems_rfs_fs_media_size (fs);

    if (total_size >= GIGS (1))
    {
      uint32_t gigs = (total_size + GIGS (1)) / GIGS (1);
      int      b;
      for (b = 31; b > 0; b--)
        if ((gigs & (1 << b)) != 0)
          break;
      fs->block_size = 1 << b;
    }

    if (fs->block_size < 512)
      fs->block_size = 512;
    
    if (fs->block_size > (4 * 1024))
      fs->block_size = (4 * 1024);
  }
  
  if ((fs->block_size % rtems_rfs_fs_media_block_size (fs)) != 0)
  {
    printf ("block size (%zd) is not a multiple of media block size (%" PRId32 ")\n",
            fs->block_size, rtems_rfs_fs_media_block_size (fs));
    return false;
  }

  fs->group_blocks = config->group_blocks;
  if (!fs->group_blocks)
  {
    /*
     * The number of blocks per group is defined by the number of bits in a
     * block.
     */
    fs->group_blocks = rtems_rfs_bitmap_numof_bits (fs->block_size);
  }

  if (fs->group_blocks > rtems_rfs_bitmap_numof_bits (fs->block_size))
  {
    printf ("group block count is higher than bits in block\n");
    return false;
  }
  
  fs->blocks = rtems_rfs_fs_media_size (fs) / fs->block_size;

  /*
   * The bits per block sets the upper limit for the number of blocks in a
   * group. The disk will be divided into groups which are the number of bits
   * per block.
   */  
  fs->group_count = rtems_rfs_rup_quotient (rtems_rfs_fs_blocks (fs),
                                            rtems_rfs_bits_per_block (fs));

  fs->group_inodes = config->group_inodes;
  if (!fs->group_inodes)
  {
    int inode_overhead = RTEMS_RFS_INODE_OVERHEAD_PERCENTAGE;
    
    /*
     * The number of inodes per group is set as a percentage.
     */
    if (config->inode_overhead)
      inode_overhead = config->inode_overhead;
      
    fs->group_inodes = rtems_rfs_inodes_from_percent (fs, inode_overhead);
  }

  /*
   * Round up to fill a block because the minimum allocation unit is a block.
   */
  fs->inodes_per_block = rtems_rfs_fs_block_size (fs) / RTEMS_RFS_INODE_SIZE;
  fs->group_inodes =
    rtems_rfs_rup_quotient (fs->group_inodes,
                            fs->inodes_per_block) * fs->inodes_per_block;
  
  if (fs->group_inodes > rtems_rfs_bitmap_numof_bits (fs->block_size))
    fs->group_inodes = rtems_rfs_bitmap_numof_bits (fs->block_size);

  fs->max_name_length = config->max_name_length;
  if (!fs->max_name_length)
  {
    fs->max_name_length = 512;
  }
  
  return true;
}
Beispiel #13
0
int
rtems_rfs_format (const char* name, const rtems_rfs_format_config* config)
{
  rtems_rfs_file_system fs;
  int                   group;
  int                   rc;

  if (config->verbose)
    printf ("rtems-rfs: format: %s\n", name);
  
  memset (&fs, 0, sizeof (rtems_rfs_file_system));

  rtems_chain_initialize_empty (&fs.buffers);
  rtems_chain_initialize_empty (&fs.release);
  rtems_chain_initialize_empty (&fs.release_modified);
  rtems_chain_initialize_empty (&fs.file_shares);

  fs.max_held_buffers = RTEMS_RFS_FS_MAX_HELD_BUFFERS;

  fs.release_count = 0;
  fs.release_modified_count = 0;

  fs.flags = RTEMS_RFS_FS_NO_LOCAL_CACHE;
  
  /*
   * Open the buffer interface.
   */
  rc = rtems_rfs_buffer_open (name, &fs);
  if (rc > 0)
  {
    printf ("rtems-rfs: format: buffer open failed: %d: %s\n",
            rc, strerror (rc));
    return -1;
  }

  /*
   * Check the media.
   */
  if (rtems_rfs_fs_media_block_size (&fs) == 0)
  {
    printf ("rtems-rfs: media block is invalid: %" PRIu32 "\n",
            rtems_rfs_fs_media_block_size (&fs));
    return -1;
  }
  
  /*
   * Check the configuration data.
   */
  if (!rtems_rfs_check_config (&fs, config))
    return -1;

  if (config->verbose)
  {
    printf ("rtems-rfs: format: media size = %" PRIu64 "\n",
            rtems_rfs_fs_media_size (&fs));
    printf ("rtems-rfs: format: media blocks = %" PRIu32 "\n",
            rtems_rfs_fs_media_blocks (&fs));
    printf ("rtems-rfs: format: media block size = %" PRIu32 "\n",
            rtems_rfs_fs_media_block_size (&fs));
    printf ("rtems-rfs: format: size = %" PRIu64 "\n",
            rtems_rfs_fs_size (&fs));
    printf ("rtems-rfs: format: blocks = %zu\n",
            rtems_rfs_fs_blocks (&fs));
    printf ("rtems-rfs: format: block size = %zu\n",
            rtems_rfs_fs_block_size (&fs));
    printf ("rtems-rfs: format: bits per block = %u\n",
            rtems_rfs_bits_per_block (&fs));
    printf ("rtems-rfs: format: inode size = %zu\n", RTEMS_RFS_INODE_SIZE);
    printf ("rtems-rfs: format: inodes = %zu (%d.%d%%)\n",
            fs.group_inodes * fs.group_count,
            rtems_rfs_inode_overhead (&fs) / 10,
            rtems_rfs_inode_overhead (&fs) % 10);
    printf ("rtems-rfs: format: groups = %u\n", fs.group_count);
    printf ("rtems-rfs: format: group blocks = %zu\n", fs.group_blocks);
    printf ("rtems-rfs: format: group inodes = %zu\n", fs.group_inodes);
  }

  rc = rtems_rfs_buffer_setblksize (&fs, rtems_rfs_fs_block_size (&fs));
  if (rc > 0)
  {
    printf ("rtems-rfs: format: setting block size failed: %d: %s\n",
            rc, strerror (rc));
    return -1;
  }
  
  if (!rtems_rfs_write_superblock (&fs))
  {
    printf ("rtems-rfs: format: superblock write failed\n");
    return -1;
  }

  for (group = 0; group < fs.group_count; group++)
    if (!rtems_rfs_write_group (&fs, group,
                                config->initialise_inodes, config->verbose))
      return -1;

  if (config->verbose)
    printf ("\n");
  
  rc = rtems_rfs_buffer_close (&fs);
  if (rc > 0)
  {
    printf ("rtems-rfs: format: buffer close failed: %d: %s\n",
            rc, strerror (rc));
    return -1;
  }

  rc = rtems_rfs_write_root_dir (name);
  if (rc > 0)
  {
    printf ("rtems-rfs: format: writing root dir failed: %d: %s\n",
            rc, strerror (rc));
    return -1;
  }
  
  return 0;
}
Beispiel #14
0
/**
 * Return the number of bits that fit in the block size.
 */
static int
rtems_rfs_bits_per_block (rtems_rfs_file_system* fs)
{
  return rtems_rfs_bitmap_numof_bits (rtems_rfs_fs_block_size (fs));
}
Beispiel #15
0
int
rtems_rfs_file_set_size (rtems_rfs_file_handle* handle,
                         rtems_rfs_pos          new_size)
{
  rtems_rfs_block_map* map  = rtems_rfs_file_map (handle);
  rtems_rfs_pos        size;
  int                  rc;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
    printf ("rtems-rfs: file-set-size: size=%" PRIu64 "\n", new_size);

  size = rtems_rfs_file_size (handle);
  
  /*
   * If the file is same size do nothing else grow or shrink it ?
   *
   * If the file does not change size do not update the times.
   */
  if (size != new_size)
  {
    /*
     * Short cut for the common truncate on open call.
     */
    if (new_size == 0)
    {
      rc = rtems_rfs_block_map_free_all (rtems_rfs_file_fs (handle), map);
      if (rc > 0)
        return rc;
    }
    else
    {
      if (size < new_size)
      {
        /*
         * Grow. Fill with 0's.
         */
        rtems_rfs_pos count;
        uint32_t      length;
        bool          read_block;

        count = new_size - size;
        length = rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
        read_block = false;

        while (count)
        {
          rtems_rfs_buffer_block block;
          rtems_rfs_block_pos    bpos;
          uint8_t*               dst;

          /*
           * Get the block position for the current end of the file as seen by
           * the map. If not found and the EOF grow the map then fill the block
           * with 0.
           */
          rtems_rfs_block_size_get_bpos (rtems_rfs_block_map_size (map), &bpos);
          rc = rtems_rfs_block_map_find (rtems_rfs_file_fs (handle),
                                         map, &bpos, &block);
          if (rc > 0)
          {
            /*
             * Have we reached the EOF ?
             */
            if (rc != ENXIO)
              return rc;

            rc = rtems_rfs_block_map_grow (rtems_rfs_file_fs (handle),
                                           map, 1, &block);
            if (rc > 0)
              return rc;
          }

          if (count < (length - bpos.boff))
          {
            length = count + bpos.boff;
            read_block = true;
            rtems_rfs_block_map_set_size_offset (map, length);
          }
          else
          {
            rtems_rfs_block_map_set_size_offset (map, 0);
          }

          /*
           * Only read the block if the length is not the block size.
           */
          rc = rtems_rfs_buffer_handle_request (rtems_rfs_file_fs (handle),
                                                rtems_rfs_file_buffer (handle),
                                                block, read_block);
          if (rc > 0)
            return rc;

          dst = rtems_rfs_buffer_data (&handle->buffer);
          memset (dst + bpos.boff, 0, length - bpos.boff);

          rtems_rfs_buffer_mark_dirty (rtems_rfs_file_buffer (handle));

          rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
                                                rtems_rfs_file_buffer (handle));
          if (rc > 0)
            return rc;

          count -= length - bpos.boff;
        }
      }
      else
      {
        /*
         * Shrink
         */
        rtems_rfs_block_no blocks;
        uint32_t           offset;

        blocks =
          rtems_rfs_block_map_count (map) -
          (((new_size - 1) /
            rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle))) + 1);

        offset =
          new_size % rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));

        if (blocks)
        {
          int rc;
          rc = rtems_rfs_block_map_shrink (rtems_rfs_file_fs (handle),
                                           rtems_rfs_file_map (handle),
                                           blocks);
          if (rc > 0)
            return rc;
        }

        rtems_rfs_block_map_set_size_offset (map, offset);

        if (rtems_rfs_block_pos_past_end (rtems_rfs_file_bpos (handle),
                                          rtems_rfs_block_map_size (map)))
          rtems_rfs_block_size_get_bpos (rtems_rfs_block_map_size (map),
                                         rtems_rfs_file_bpos (handle));
      }
    }

    handle->shared->size.count  = rtems_rfs_block_map_count (map);
    handle->shared->size.offset = rtems_rfs_block_map_size_offset (map);

    if (rtems_rfs_file_update_mtime (handle))
      handle->shared->mtime = time (NULL);
  }
  
  return 0;
}
Beispiel #16
0
int
rtems_rfs_dir_del_entry (rtems_rfs_file_system*  fs,
                         rtems_rfs_inode_handle* dir,
                         rtems_rfs_ino           ino,
                         uint32_t                offset)
{
  rtems_rfs_block_map     map;
  rtems_rfs_block_no      block;
  rtems_rfs_buffer_handle buffer;
  bool                    search;
  int                     rc;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
    printf ("rtems-rfs: dir-del-entry: dir=%" PRId32 ", entry=%" PRId32 " offset=%" PRIu32 "\n",
            rtems_rfs_inode_ino (dir), ino, offset);

  rc = rtems_rfs_block_map_open (fs, dir, &map);
  if (rc > 0)
    return rc;

  rc = rtems_rfs_block_map_seek (fs, &map, offset, &block);
  if (rc > 0)
  {
    if (rc == ENXIO)
      rc = ENOENT;
    rtems_rfs_block_map_close (fs, &map);
    return rc;
  }

  rc = rtems_rfs_buffer_handle_open (fs, &buffer);
  if (rc > 0)
  {
    rtems_rfs_block_map_close (fs, &map);
    return rc;
  }

  /*
   * Only search if the offset is 0 else we are at that position.
   */
  search = offset ? false : true;

  while (rc == 0)
  {
    uint8_t* entry;
    int      eoffset;

    rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
    if (rc > 0)
    {
      if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
        printf ("rtems-rfs: dir-del-entry: "
                "block buffer req failed for ino %" PRIu32 ": %d: %s\n",
                rtems_rfs_inode_ino (dir), rc, strerror (rc));
      break;
    }

    /*
     * If we are searching start at the beginning of the block. If not searching
     * skip to the offset in the block.
     */
    if (search)
      eoffset = 0;
    else
      eoffset = offset % rtems_rfs_fs_block_size (fs);

    entry = rtems_rfs_buffer_data (&buffer) + eoffset;

    while (eoffset < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE))
    {
      rtems_rfs_ino eino;
      int           elength;

      elength = rtems_rfs_dir_entry_length (entry);
      eino    = rtems_rfs_dir_entry_ino (entry);

      if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
        break;

      if (rtems_rfs_dir_entry_valid (fs, elength, eino))
      {
        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
          printf ("rtems-rfs: dir-del-entry: "
                  "bad length or ino for ino %" PRIu32 ": %u/%" PRId32
                  " @ %" PRIu32 ".%04x\n",
                  rtems_rfs_inode_ino (dir), elength, eino, block, eoffset);
        rc = EIO;
        break;
      }

      if (ino == rtems_rfs_dir_entry_ino (entry))
      {
        uint32_t remaining;
        remaining = rtems_rfs_fs_block_size (fs) - (eoffset + elength);
        memmove (entry, entry + elength, remaining);
        memset (entry + remaining, 0xff, elength);

        /*
         * If the remainder of the block is empty and this is the start of the
         * block and it is the last block in the map shrink the map.
         *
         * @note We could check again to see if the new end block in the map is
         *       also empty. This way we could clean up an empty directory.
         */
        elength = rtems_rfs_dir_entry_length (entry);

        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
          printf ("rtems-rfs: dir-del-entry: "
                  "last block free for ino %" PRIu32 ": elength=%i block=%" PRIu32
                  " offset=%d last=%s\n",
                  ino, elength, block, eoffset,
                  rtems_rfs_block_map_last (&map) ? "yes" : "no");

        if ((elength == RTEMS_RFS_DIR_ENTRY_EMPTY) &&
            (eoffset == 0) && rtems_rfs_block_map_last (&map))
        {
          rc = rtems_rfs_block_map_shrink (fs, &map, 1);
          if (rc > 0)
          {
            if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
              printf ("rtems-rfs: dir-del-entry: "
                      "block map shrink failed for ino %" PRIu32 ": %d: %s\n",
                      rtems_rfs_inode_ino (dir), rc, strerror (rc));
          }
        }

        rtems_rfs_buffer_mark_dirty (&buffer);
        rtems_rfs_buffer_handle_close (fs, &buffer);
        rtems_rfs_block_map_close (fs, &map);
        return 0;
      }

      if (!search)
      {
        rc = EIO;
        break;
      }

      entry   += elength;
      eoffset += elength;
    }

    if (rc == 0)
    {
      rc = rtems_rfs_block_map_next_block (fs, &map, &block);
      if (rc == ENXIO)
        rc = ENOENT;
    }
  }

  rtems_rfs_buffer_handle_close (fs, &buffer);
  rtems_rfs_block_map_close (fs, &map);
  return rc;
}
Beispiel #17
0
int
rtems_rfs_symlink (rtems_rfs_file_system* fs,
                   const char*            name,
                   int                    length,
                   const char*            link,
                   int                    link_length,
                   uid_t                  uid,
                   gid_t                  gid,
                   rtems_rfs_ino          parent)
{
  rtems_rfs_inode_handle inode;
  rtems_rfs_ino          ino;
  int                    rc;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_SYMLINK))
  {
    int c;
    printf ("rtems-rfs: symlink: parent:%" PRIu32 " name:", parent);
    for (c = 0; c < length; c++)
      printf ("%c", name[c]);
    printf (" link:");
    for (c = 0; c < link_length; c++)
      printf ("%c", link[c]);
  }

  if (link_length >= rtems_rfs_fs_block_size (fs))
    return ENAMETOOLONG;

  rc = rtems_rfs_inode_create (fs, parent, name, strlen (name),
                               RTEMS_RFS_S_SYMLINK,
                               1, uid, gid, &ino);
  if (rc > 0)
    return rc;

  rc = rtems_rfs_inode_open (fs, ino, &inode, true);
  if (rc > 0)
    return rc;

  /*
   * If the link length is less than the length of data union in the inode
   * place the link into the data area else allocate a block and write the link
   * to that.
   */
  if (link_length < RTEMS_RFS_INODE_DATA_NAME_SIZE)
  {
    memset (inode.node->data.name, 0, RTEMS_RFS_INODE_DATA_NAME_SIZE);
    memcpy (inode.node->data.name, link, link_length);
    rtems_rfs_inode_set_block_count (&inode, 0);
  }
  else
  {
    rtems_rfs_block_map     map;
    rtems_rfs_block_no      block;
    rtems_rfs_buffer_handle buffer;
    uint8_t*                data;

    rc = rtems_rfs_block_map_open (fs, &inode, &map);
    if (rc > 0)
    {
      rtems_rfs_inode_close (fs, &inode);
      return rc;
    }

    rc = rtems_rfs_block_map_grow (fs, &map, 1, &block);
    if (rc > 0)
    {
      rtems_rfs_block_map_close (fs, &map);
      rtems_rfs_inode_close (fs, &inode);
      return rc;
    }

    rc = rtems_rfs_buffer_handle_open (fs, &buffer);
    if (rc > 0)
    {
      rtems_rfs_block_map_close (fs, &map);
      rtems_rfs_inode_close (fs, &inode);
      return rc;
    }

    rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, false);
    if (rc > 0)
    {
      rtems_rfs_block_map_close (fs, &map);
      rtems_rfs_inode_close (fs, &inode);
      return rc;
    }

    data = rtems_rfs_buffer_data (&buffer);

    memset (data, 0xff, rtems_rfs_fs_block_size (fs));
    memcpy (data, link, link_length);

    rc = rtems_rfs_buffer_handle_close (fs, &buffer);
    if (rc > 0)
    {
      rtems_rfs_block_map_close (fs, &map);
      rtems_rfs_inode_close (fs, &inode);
      return rc;
    }

    rc = rtems_rfs_block_map_close (fs, &map);
    if (rc > 0)
    {
      rtems_rfs_inode_close (fs, &inode);
      return rc;
    }
  }

  rtems_rfs_inode_set_block_offset (&inode, link_length);

  rc = rtems_rfs_inode_close (fs, &inode);

  return rc;
}
Beispiel #18
0
int
rtems_rfs_dir_lookup_ino (rtems_rfs_file_system*  fs,
                          rtems_rfs_inode_handle* inode,
                          const char*             name,
                          int                     length,
                          rtems_rfs_ino*          ino,
                          uint32_t*               offset)
{
  rtems_rfs_block_map     map;
  rtems_rfs_buffer_handle entries;
  int                     rc;

  if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
  {
    int c;
    printf ("rtems-rfs: dir-lookup-ino: lookup ino: root=%" PRId32 ", path=",
            inode->ino);
    for (c = 0; c < length; c++)
      printf ("%c", name[c]);
    printf (", len=%d\n", length);
  }

  *ino = RTEMS_RFS_EMPTY_INO;
  *offset = 0;

  rc = rtems_rfs_block_map_open (fs, inode, &map);
  if (rc > 0)
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
      printf ("rtems-rfs: dir-lookup-ino: map open failed for ino %" PRIu32 ": %d: %s",
              rtems_rfs_inode_ino (inode), rc, strerror (rc));
    return rc;
  }

  rc = rtems_rfs_buffer_handle_open (fs, &entries);
  if (rc > 0)
  {
    if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
      printf ("rtems-rfs: dir-lookup-ino: handle open failed for ino %" PRIu32 ": %d: %s",
              rtems_rfs_inode_ino (inode), rc, strerror (rc));
    rtems_rfs_block_map_close (fs, &map);
    return rc;
  }
  else
  {
    rtems_rfs_block_no block;
    uint32_t           hash;

    /*
     * Calculate the hash of the look up string.
     */
    hash = rtems_rfs_dir_hash (name, length);

    /*
     * Locate the first block. The map points to the start after open so just
     * seek 0. If an error the block will be 0.
     */
    rc = rtems_rfs_block_map_seek (fs, &map, 0, &block);
    if (rc > 0)
    {
      if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
        printf ("rtems-rfs: dir-lookup-ino: block map find failed: %d: %s\n",
                rc, strerror (rc));
      if (rc == ENXIO)
        rc = ENOENT;
      rtems_rfs_buffer_handle_close (fs, &entries);
      rtems_rfs_block_map_close (fs, &map);
      return rc;
    }

    while ((rc == 0) && block)
    {
      uint8_t* entry;

      if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
        printf ("rtems-rfs: dir-lookup-ino: block read, ino=%" PRIu32 " bno=%" PRId32 "\n",
                rtems_rfs_inode_ino (inode), map.bpos.bno);

      rc = rtems_rfs_buffer_handle_request (fs, &entries, block, true);
      if (rc > 0)
      {
        if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
          printf ("rtems-rfs: dir-lookup-ino: block read, ino=%" PRIu32 " block=%" PRId32 ": %d: %s\n",
                  rtems_rfs_inode_ino (inode), block, rc, strerror (rc));
        break;
      }

      /*
       * Search the block to see if the name matches. A hash of 0xffff or 0x0
       * means the entry is empty.
       */

      entry = rtems_rfs_buffer_data (&entries);

      map.bpos.boff = 0;

      while (map.bpos.boff < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE))
      {
        uint32_t ehash;
        int      elength;

        ehash  = rtems_rfs_dir_entry_hash (entry);
        elength = rtems_rfs_dir_entry_length (entry);
        *ino = rtems_rfs_dir_entry_ino (entry);

        if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
          break;

        if (rtems_rfs_dir_entry_valid (fs, elength, *ino))
        {
          if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
            printf ("rtems-rfs: dir-lookup-ino: "
                    "bad length or ino for ino %" PRIu32 ": %u/%" PRId32 " @ %04" PRIx32 "\n",
                    rtems_rfs_inode_ino (inode), elength, *ino, map.bpos.boff);
          rc = EIO;
          break;
        }

        if (ehash == hash)
        {
          if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO_CHECK))
            printf ("rtems-rfs: dir-lookup-ino: "
                    "checking entry for ino %" PRId32 ": bno=%04" PRIx32 "/off=%04" PRIx32
                    " length:%d ino:%" PRId32 "\n",
                    rtems_rfs_inode_ino (inode), map.bpos.bno, map.bpos.boff,
                    elength, rtems_rfs_dir_entry_ino (entry));

          if (memcmp (entry + RTEMS_RFS_DIR_ENTRY_SIZE, name, length) == 0)
          {
            *offset = rtems_rfs_block_map_pos (fs, &map);

            if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO_FOUND))
              printf ("rtems-rfs: dir-lookup-ino: "
                      "entry found in ino %" PRIu32 ", ino=%" PRIu32 " offset=%" PRIu32 "\n",
                      rtems_rfs_inode_ino (inode), *ino, *offset);

            rtems_rfs_buffer_handle_close (fs, &entries);
            rtems_rfs_block_map_close (fs, &map);
            return 0;
          }
        }

        map.bpos.boff += elength;
        entry += elength;
      }

      if (rc == 0)
      {
        rc = rtems_rfs_block_map_next_block (fs, &map, &block);
        if ((rc > 0) && (rc != ENXIO))
        {
          if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
            printf ("rtems-rfs: dir-lookup-ino: "
                    "block map next block failed in ino %" PRIu32 ": %d: %s\n",
                    rtems_rfs_inode_ino (inode), rc, strerror (rc));
        }
        if (rc == ENXIO)
          rc = ENOENT;
      }
    }

    if ((rc == 0) && (block == 0))
    {
      rc = EIO;
      if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
        printf ("rtems-rfs: dir-lookup-ino: block is 0 in ino %" PRIu32 ": %d: %s\n",
                rtems_rfs_inode_ino (inode), rc, strerror (rc));
    }
  }

  rtems_rfs_buffer_handle_close (fs, &entries);
  rtems_rfs_block_map_close (fs, &map);
  return rc;
}
Beispiel #19
0
int
rtems_rfs_rtems_fstat (const rtems_filesystem_location_info_t* pathloc,
                       struct stat*                            buf)
{
  rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
  rtems_rfs_ino          ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
  rtems_rfs_inode_handle inode;
  rtems_rfs_file_shared* shared;
  uint16_t               mode;
  int                    rc;

  if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_STAT))
    printf ("rtems-rfs-rtems: stat: in: ino:%" PRId32 "\n", ino);

  rc = rtems_rfs_inode_open (fs, ino, &inode, true);
  if (rc)
  {
    return rtems_rfs_rtems_error ("stat: opening inode", rc);
  }

  mode = rtems_rfs_inode_get_mode (&inode);

  if (RTEMS_RFS_S_ISCHR (mode) || RTEMS_RFS_S_ISBLK (mode))
  {
    buf->st_rdev =
      rtems_filesystem_make_dev_t (rtems_rfs_inode_get_block (&inode, 0),
                                   rtems_rfs_inode_get_block (&inode, 1));
  }

  buf->st_dev     = rtems_rfs_fs_device (fs);
  buf->st_ino     = rtems_rfs_inode_ino (&inode);
  buf->st_mode    = rtems_rfs_rtems_mode (mode);
  buf->st_nlink   = rtems_rfs_inode_get_links (&inode);
  buf->st_uid     = rtems_rfs_inode_get_uid (&inode);
  buf->st_gid     = rtems_rfs_inode_get_gid (&inode);

  /*
   * Need to check is the ino is an open file. If so we take the values from
   * the open file rather than the inode.
   */
  shared = rtems_rfs_file_get_shared (fs, rtems_rfs_inode_ino (&inode));

  if (shared)
  {
    buf->st_atime   = rtems_rfs_file_shared_get_atime (shared);
    buf->st_mtime   = rtems_rfs_file_shared_get_mtime (shared);
    buf->st_ctime   = rtems_rfs_file_shared_get_ctime (shared);
    buf->st_blocks  = rtems_rfs_file_shared_get_block_count (shared);

    if (S_ISLNK (buf->st_mode))
      buf->st_size = rtems_rfs_file_shared_get_block_offset (shared);
    else
      buf->st_size = rtems_rfs_file_shared_get_size (fs, shared);
  }
  else
  {
    buf->st_atime   = rtems_rfs_inode_get_atime (&inode);
    buf->st_mtime   = rtems_rfs_inode_get_mtime (&inode);
    buf->st_ctime   = rtems_rfs_inode_get_ctime (&inode);
    buf->st_blocks  = rtems_rfs_inode_get_block_count (&inode);

    if (S_ISLNK (buf->st_mode))
      buf->st_size = rtems_rfs_inode_get_block_offset (&inode);
    else
      buf->st_size = rtems_rfs_inode_get_size (fs, &inode);
  }

  buf->st_blksize = rtems_rfs_fs_block_size (fs);

  rc = rtems_rfs_inode_close (fs, &inode);
  if (rc > 0)
  {
    return rtems_rfs_rtems_error ("stat: closing inode", rc);
  }

  return 0;
}
Beispiel #20
0
static bool
rtems_rfs_write_group (rtems_rfs_file_system* fs,
                       int                    group,
                       bool                   initialise_inodes,
                       bool                   verbose)
{
  rtems_rfs_buffer_handle  handle;
  rtems_rfs_bitmap_control bitmap;
  rtems_rfs_buffer_block   group_base;
  size_t                   group_size;
  int                      blocks;
  int                      b;
  int                      rc;
  
  group_base = rtems_rfs_fs_block (fs, group, 0);

  if (group_base > rtems_rfs_fs_blocks (fs))
  {
    printf ("rtems-rfs: write-group: group %d base beyond disk limit\n",
            group);
    return false;
  }

  group_size = fs->group_blocks;

  /*
   * Be nice to strange sizes of disks. These are embedded systems after all
   * and nice numbers do not always work out. Let the last block pick up the
   * remainder of the blocks.
   */
  if ((group_base + group_size) > rtems_rfs_fs_blocks (fs))
    group_size = rtems_rfs_fs_blocks (fs) - group_base;

  if (verbose)
    printf ("\rrtems-rfs: format: group %3d: base = %" PRId32 ", size = %zd",
            group, group_base, group_size);

  /*
   * Open a handle and request an empty buffer.
   */
  rc = rtems_rfs_buffer_handle_open (fs, &handle);
  if (rc > 0)
  {
    printf ("\nrtems-rfs: write-group: handle open failed: %d: %s\n",
            rc, strerror (rc));
    return false;
  }

  if (verbose)
    printf (", blocks");
  
  /*
   * Open the block bitmap using the new buffer.
   */
  rc = rtems_rfs_bitmap_open (&bitmap, fs, &handle, group_size,
                              group_base + RTEMS_RFS_GROUP_BLOCK_BITMAP_BLOCK);
  if (rc > 0)
  {
    rtems_rfs_buffer_handle_close (fs, &handle);
    printf ("\nrtems-rfs: write-group: group %3d: open block bitmap failed: %d: %s\n",
            group, rc, strerror (rc));
    return false;
  }

  /*
   * Force the whole buffer to a known state. The bit map may not occupy the
   * whole block.
   */
  memset (rtems_rfs_buffer_data (&handle), 0xff, rtems_rfs_fs_block_size (fs));
  
  /*
   * Clear the bitmap.
   */
  rc = rtems_rfs_bitmap_map_clear_all (&bitmap);
  if (rc > 0)
  {
    rtems_rfs_bitmap_close (&bitmap);
    rtems_rfs_buffer_handle_close (fs, &handle);
    printf ("\nrtems-rfs: write-group: group %3d: block bitmap clear all failed: %d: %s\n",
            group, rc, strerror (rc));
    return false;
  }
  
  /*
   * Forced allocation of the block bitmap.
   */
  rtems_rfs_bitmap_map_set (&bitmap, RTEMS_RFS_GROUP_BLOCK_BITMAP_BLOCK);

  /*
   * Forced allocation of the inode bitmap.
   */
  rtems_rfs_bitmap_map_set (&bitmap, RTEMS_RFS_GROUP_INODE_BITMAP_BLOCK);

  /*
   * Determine the number of inodes blocks in the group.
   */
  blocks = rtems_rfs_rup_quotient (fs->group_inodes, fs->inodes_per_block);

  /*
   * Forced allocation of the inode blocks which follow the block bitmap.
   */
  for (b = 0; b < blocks; b++)
    rtems_rfs_bitmap_map_set (&bitmap, b + RTEMS_RFS_GROUP_INODE_BLOCK);

  /*
   * Close the block bitmap.
   */
  rc = rtems_rfs_bitmap_close (&bitmap);
  if (rc > 0)
  {
    rtems_rfs_buffer_handle_close (fs, &handle);
    printf ("\nrtems-rfs: write-group: group %3d: close block bitmap failed: %d: %s\n",
            group, rc, strerror (rc));
    return false;
  }

  rtems_rfs_buffer_mark_dirty (&handle);

  if (verbose)
    printf (", inodes");
  
  /*
   * Open the inode bitmap using the old buffer. Should release any changes.
   */
  rc = rtems_rfs_bitmap_open (&bitmap, fs, &handle, group_size,
                              group_base + RTEMS_RFS_GROUP_INODE_BITMAP_BLOCK);
  if (rc > 0)
  {
    rtems_rfs_buffer_handle_close (fs, &handle);
    printf ("\nrtems-rfs: write-group: group %3d: open inode bitmap failed: %d: %s\n",
            group, rc, strerror (rc));
    return false;
  }

  /*
   * Force the whole buffer to a known state. The bit map may not occupy the
   * whole block.
   */
  memset (rtems_rfs_buffer_data (&handle), 0x00, rtems_rfs_fs_block_size (fs));
  
  /*
   * Clear the inode bitmap.
   */
  rc = rtems_rfs_bitmap_map_clear_all (&bitmap);
  if (rc > 0)
  {
    rtems_rfs_bitmap_close (&bitmap);
    rtems_rfs_buffer_handle_close (fs, &handle);
    printf ("\nrtems-rfs: write-group: group %3d: inode bitmap" \
            " clear all failed: %d: %s\n", group, rc, strerror (rc));
    return false;
  }
  
  /*
   * Close the inode bitmap.
   */
  rc = rtems_rfs_bitmap_close (&bitmap);
  if (rc > 0)
  {
    rtems_rfs_buffer_handle_close (fs, &handle);
    printf ("\nrtems-rfs: write-group: group %3d: close inode" \
            " bitmap failed: %d: %s\n", group, rc, strerror (rc));
    return false;
  }

  rtems_rfs_buffer_mark_dirty (&handle);

  /*
   * Initialise the inode tables if required to do so.
   */
  if (initialise_inodes)
  {
    for (b = 0; b < blocks; b++)
    {
      rc = rtems_rfs_buffer_handle_request (fs, &handle,
                                            group_base + b + RTEMS_RFS_GROUP_INODE_BLOCK,
                                            false);
      if (rc > 0)
      {
        rtems_rfs_buffer_handle_close (fs, &handle);
        printf ("\nrtems-rfs: write-group: group %3d: block %" PRId32 " request failed: %d: %s\n",
                group, group_base + b + RTEMS_RFS_GROUP_INODE_BLOCK,
                rc, strerror (rc));
        return false;
      }
    
      /*
       * Force the whole buffer to a known state. The bit map may not occupy the
       * whole block.
       */
      memset (rtems_rfs_buffer_data (&handle), 0xff, rtems_rfs_fs_block_size (fs));
  
      rtems_rfs_buffer_mark_dirty (&handle);
    }
  }
  
  rc = rtems_rfs_buffer_handle_close (fs, &handle);
  if (rc > 0)
  {
    printf ("\nrtems-rfs: write-group: buffer handle close failed: %d: %s\n",
            rc, strerror (rc));
    return false;
  }
  
  return true;
}