/** * This routine processes the lseek() system call. * * @param iop * @param offset * @param whence * @return off_t */ static off_t rtems_rfs_rtems_file_lseek (rtems_libio_t* iop, off_t offset, int whence) { rtems_rfs_file_handle* file = rtems_rfs_rtems_get_iop_file_handle (iop); off_t old_offset; off_t new_offset; if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_LSEEK)) printf("rtems-rfs: file-lseek: handle:%p offset:%" PRIdoff_t "\n", file, offset); rtems_rfs_rtems_lock (rtems_rfs_file_fs (file)); old_offset = iop->offset; new_offset = rtems_filesystem_default_lseek_file (iop, offset, whence); if (new_offset != -1) { rtems_rfs_pos pos = iop->offset; int rc = rtems_rfs_file_seek (file, pos, &pos); if (rc) { rtems_rfs_rtems_error ("file_lseek: lseek", rc); iop->offset = old_offset; new_offset = -1; } } rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file)); return new_offset; }
/** * This routine processes the lseek() system call. * * @param iop * @param offset * @param whence * @return off_t */ static off_t rtems_rfs_rtems_file_lseek (rtems_libio_t* iop, off_t offset, int whence) { rtems_rfs_file_handle* file = rtems_rfs_rtems_get_iop_file_handle (iop); rtems_rfs_pos pos; int rc; if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_LSEEK)) printf("rtems-rfs: file-lseek: handle:%p offset:%" PRIdoff_t "\n", file, offset); rtems_rfs_rtems_lock (rtems_rfs_file_fs (file)); pos = iop->offset; rc = rtems_rfs_file_seek (file, pos, &pos); if (rc) { rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file)); return rtems_rfs_rtems_error ("file_lseek: lseek", rc); } rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file)); return iop->offset; }
/** * This routine processes the read() system call. * * @param iop * @param buffer * @param count * @return int */ static ssize_t rtems_rfs_rtems_file_read (rtems_libio_t* iop, void* buffer, size_t count) { rtems_rfs_file_handle* file = rtems_rfs_rtems_get_iop_file_handle (iop); rtems_rfs_pos pos; uint8_t* data = buffer; ssize_t read = 0; int rc; if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_READ)) printf("rtems-rfs: file-read: handle:%p count:%zd\n", file, count); rtems_rfs_rtems_lock (rtems_rfs_file_fs (file)); pos = iop->offset; if (pos < rtems_rfs_file_size (file)) { while (count) { size_t size; rc = rtems_rfs_file_io_start (file, &size, true); if (rc > 0) { read = rtems_rfs_rtems_error ("file-read: read: io-start", rc); break; } if (size == 0) break; if (size > count) size = count; memcpy (data, rtems_rfs_file_data (file), size); data += size; count -= size; read += size; rc = rtems_rfs_file_io_end (file, size, true); if (rc > 0) { read = rtems_rfs_rtems_error ("file-read: read: io-end", rc); break; } } } if (read >= 0) iop->offset = pos + read; rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file)); return read; }
int rtems_rfs_file_io_release (rtems_rfs_file_handle* handle) { int rc = 0; if (rtems_rfs_buffer_handle_has_block (&handle->buffer)) rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle), rtems_rfs_file_buffer (handle)); return rc; }
/** * This routine processes the ftruncate() system call. * * @param iop * @param length * @return int */ static int rtems_rfs_rtems_file_ftruncate (rtems_libio_t* iop, off_t length) { rtems_rfs_file_handle* file = rtems_rfs_rtems_get_iop_file_handle (iop); int rc; if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_FTRUNC)) printf("rtems-rfs: file-ftrunc: handle:%p length:%" PRIdoff_t "\n", file, length); rtems_rfs_rtems_lock (rtems_rfs_file_fs (file)); rc = rtems_rfs_file_set_size (file, length); if (rc) rc = rtems_rfs_rtems_error ("file_ftruncate: set size", rc); rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file)); return rc; }
/** * This routine processes the close() system call. Note that there is nothing * to flush at this point. * * @param iop * @return int */ static int rtems_rfs_rtems_file_close (rtems_libio_t* iop) { rtems_rfs_file_handle* file = rtems_rfs_rtems_get_iop_file_handle (iop); rtems_rfs_file_system* fs = rtems_rfs_file_fs (file); int rc; if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_CLOSE)) printf("rtems-rfs: file-close: handle:%p\n", file); rtems_rfs_rtems_lock (fs); rc = rtems_rfs_file_close (fs, file); if (rc > 0) rc = rtems_rfs_rtems_error ("file-close: file close", rc); rtems_rfs_rtems_unlock (fs); return rc; }
/** * This routine processes the write() system call. * * @param iop * @param buffer * @param count * @return ssize_t */ static ssize_t rtems_rfs_rtems_file_write (rtems_libio_t* iop, const void* buffer, size_t count) { rtems_rfs_file_handle* file = rtems_rfs_rtems_get_iop_file_handle (iop); rtems_rfs_pos pos; rtems_rfs_pos file_size; const uint8_t* data = buffer; ssize_t write = 0; int rc; if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_WRITE)) printf("rtems-rfs: file-write: handle:%p count:%zd\n", file, count); rtems_rfs_rtems_lock (rtems_rfs_file_fs (file)); pos = iop->offset; file_size = rtems_rfs_file_size (file); if (pos > file_size) { /* * If the iop position is past the physical end of the file we need to set * the file size to the new length before writing. The * rtems_rfs_file_io_end() will grow the file subsequently. */ rc = rtems_rfs_file_set_size (file, pos); if (rc) { rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file)); return rtems_rfs_rtems_error ("file-write: write extend", rc); } rtems_rfs_file_set_bpos (file, pos); } else if (pos < file_size && rtems_libio_iop_is_append(iop)) { pos = file_size; rc = rtems_rfs_file_seek (file, pos, &pos); if (rc) { rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file)); return rtems_rfs_rtems_error ("file-write: write append seek", rc); } } while (count) { size_t size = count; rc = rtems_rfs_file_io_start (file, &size, false); if (rc) { /* * If we have run out of space and have written some data return that * amount first as the inode will have accounted for it. This means * there was no error and the return code from can be ignored. */ if (!write) write = rtems_rfs_rtems_error ("file-write: write open", rc); break; } if (size > count) size = count; memcpy (rtems_rfs_file_data (file), data, size); data += size; count -= size; write += size; rc = rtems_rfs_file_io_end (file, size, false); if (rc) { write = rtems_rfs_rtems_error ("file-write: write close", rc); break; } } if (write >= 0) iop->offset = pos + write; rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file)); return write; }
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_file_seek (rtems_rfs_file_handle* handle, rtems_rfs_pos pos, rtems_rfs_pos* new_pos) { if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO)) printf ("rtems-rfs: file-seek: new=%" PRIu64 "\n", pos); /* * This call only sets the position if it is in a valid part of the file. The * user can request past the end of the file then write to extend the * file. The lseek entry states: * * "Although lseek() may position the file offset beyond the end of the * file, this function does not itself extend the size of the file." * * This means the file needs to set the file size to the pos only when a * write occurs. */ if (pos < rtems_rfs_file_shared_get_size (rtems_rfs_file_fs (handle), handle->shared)) { rtems_rfs_file_set_bpos (handle, pos); /* * If the file has a block check if it maps to the current position and it * does not release it. That will force us to get the block at the new * position when the I/O starts. */ if (rtems_rfs_buffer_handle_has_block (&handle->buffer)) { rtems_rfs_buffer_block block; int rc; 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) return rc; if (rtems_rfs_buffer_bnum (&handle->buffer) != block) { rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle), rtems_rfs_file_buffer (handle)); if (rc > 0) return rc; } } } else { /* * The seek is outside the current file so release any buffer. A write will * extend the file. */ int rc = rtems_rfs_file_io_release (handle); if (rc > 0) return rc; } *new_pos = pos; return 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; }
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; }
/** * This routine processes the write() system call. * * @param iop * @param buffer * @param count * @return ssize_t */ static ssize_t rtems_rfs_rtems_file_write (rtems_libio_t* iop, const void* buffer, size_t count) { rtems_rfs_file_handle* file = rtems_rfs_rtems_get_iop_file_handle (iop); rtems_rfs_pos pos; const uint8_t* data = buffer; ssize_t write = 0; int rc; if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_WRITE)) printf("rtems-rfs: file-write: handle:%p count:%zd\n", file, count); rtems_rfs_rtems_lock (rtems_rfs_file_fs (file)); pos = iop->offset; /* * If the iop position is past the physical end of the file we need to set * the file size to the new length before writing. If the position equals the * size of file we are still past the end of the file as positions number * from 0. For a specific position we need a file that has a length of one * more. */ if (pos >= rtems_rfs_file_size (file)) { rc = rtems_rfs_file_set_size (file, pos + 1); if (rc) { rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file)); return rtems_rfs_rtems_error ("file-write: write extend", rc); } } rtems_rfs_file_set_bpos (file, pos); while (count) { size_t size = count; rc = rtems_rfs_file_io_start (file, &size, false); if (rc) { write = rtems_rfs_rtems_error ("file-write: write open", rc); break; } if (size > count) size = count; memcpy (rtems_rfs_file_data (file), data, size); data += size; count -= size; write += size; rc = rtems_rfs_file_io_end (file, size, false); if (rc) { write = rtems_rfs_rtems_error ("file-write: write close", rc); break; } } iop->size = rtems_rfs_file_size (file); rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file)); return write; }