Beispiel #1
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;
}
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;
}