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; }
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_block_map_free_all (rtems_rfs_file_system* fs, rtems_rfs_block_map* map) { return rtems_rfs_block_map_shrink (fs, map, map->size.count); }