Buffer FAT::read(const Dirent& ent, uint64_t pos, uint64_t n) const { // bounds check the read position and length auto stapos = std::min(ent.size(), pos); auto endpos = std::min(ent.size(), pos + n); // new length n = endpos - stapos; // cluster -> sector + position auto sector = stapos / this->sector_size; auto nsect = roundup(endpos, sector_size) / sector_size - sector; // read @nsect sectors ahead buffer_t data = device.read_sync(this->cl_to_sector(ent.block()) + sector, nsect); // where to start copying from the device result auto internal_ofs = stapos % device.block_size(); // when the offset is non-zero we aren't on a sector boundary if (internal_ofs != 0) { data = construct_buffer(data->begin() + internal_ofs, data->begin() + internal_ofs + n); } else { // when not offset all we have to do is resize the buffer down from // a sector size multiple to its given length data->resize(n); } return Buffer(no_error, std::move(data)); }
void Async::disk_transfer( Disk disk, const Dirent& ent, on_write_func write_func, on_after_func callback, const size_t CHUNK_SIZE) { typedef delegate<void(size_t)> next_func_t; auto next = std::make_shared<next_func_t> (); auto weak_next = std::weak_ptr<next_func_t>(next); *next = next_func_t::make_packed( [weak_next, disk, ent, write_func, callback, CHUNK_SIZE] (size_t pos) { // number of write calls necessary const size_t writes = roundup(ent.size(), CHUNK_SIZE); // done condition if (pos >= writes) { callback(fs::no_error, true); return; } auto next = weak_next.lock(); // read chunk from file disk->fs().read( ent, pos * CHUNK_SIZE, CHUNK_SIZE, fs::on_read_func::make_packed( [next, pos, write_func, callback] ( fs::error_t err, fs::buffer_t buffer) { debug("<Async> len=%lu\n", buffer->size()); if (err) { printf("%s\n", err.to_string().c_str()); callback(err, false); return; } // call write callback with data write_func( buffer, next_func::make_packed( [next, pos, callback] (bool good) { // if the write succeeded, call next if (LIKELY(good)) (*next)(pos+1); else // otherwise, fail callback({fs::error_t::E_IO, "Write failed"}, false); }) ); }) ); }); // start async loop (*next)(0); }
void FAT::read(const Dirent& ent, uint64_t pos, uint64_t n, on_read_func callback) const { // when n=0 roundup() will return an invalid value if (n == 0) { callback({ error_t::E_IO, "Zero read length" }, nullptr); return; } // bounds check the read position and length uint32_t stapos = std::min(ent.size(), pos); uint32_t endpos = std::min(ent.size(), pos + n); // new length n = endpos - stapos; // calculate start and length in sectors uint32_t sector = stapos / this->sector_size; uint32_t nsect = roundup(endpos, sector_size) / sector_size - sector; uint32_t internal_ofs = stapos % device.block_size(); // cluster -> sector + position device.read( this->cl_to_sector(ent.block()) + sector, nsect, hw::Block_device::on_read_func::make_packed( [n, callback, internal_ofs] (buffer_t data) { if (!data) { // general I/O error occurred callback({ error_t::E_IO, "Unable to read file" }, nullptr); return; } // when the offset is non-zero we aren't on a sector boundary if (internal_ofs != 0) { // so, we need to create new buffer with offset data data = construct_buffer(data->begin() + internal_ofs, data->begin() + internal_ofs + n); } else { // when not offset all we have to do is resize the buffer down from // a sector size multiple to its given length data->resize(n); } callback(no_error, data); }) ); }
void FAT::read(const Dirent& ent, uint64_t pos, uint64_t n, on_read_func callback) { // when n=0 roundup() will return an invalid value if (n == 0) { callback({ error_t::E_IO, "Zero read length" }, buffer_t(), 0); return; } // bounds check the read position and length uint32_t stapos = std::min(ent.size(), pos); uint32_t endpos = std::min(ent.size(), pos + n); // new length n = endpos - stapos; // calculate start and length in sectors uint32_t sector = stapos / this->sector_size; uint32_t nsect = roundup(endpos, sector_size) / sector_size - sector; uint32_t internal_ofs = stapos % device.block_size(); // cluster -> sector + position device.read(this->cl_to_sector(ent.block) + sector, nsect, [pos, n, callback, internal_ofs] (buffer_t data) { if (!data) { // general I/O error occurred debug("Failed to read sector %u for read()", sector); callback({ error_t::E_IO, "Unable to read file" }, buffer_t(), 0); return; } // when the offset is non-zero we aren't on a sector boundary if (internal_ofs != 0) { // so, we need to copy offset data to data buffer auto* result = new uint8_t[n]; memcpy(result, data.get() + internal_ofs, n); data = buffer_t(result, std::default_delete<uint8_t[]>()); } callback(no_error, data, n); }); }