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; }
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; }
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_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; }