mirror of
https://git.code.sf.net/p/newrpl/sources
synced 2024-11-16 19:51:25 +01:00
216 lines
6.6 KiB
C
216 lines
6.6 KiB
C
/*
|
|
* Copyright (c) 2014-2015, Claudio Lapilli and the newRPL Team
|
|
* All rights reserved.
|
|
* This file is released under the 3-clause BSD license.
|
|
* See the file LICENSE.txt that shipped with this distribution.
|
|
*/
|
|
|
|
#include "fsyspriv.h"
|
|
|
|
#ifndef CONFIG_NO_FSYSTEM
|
|
|
|
// LOW-LEVEL READ FROM FILE'S CURRENT POSITION
|
|
|
|
int FSReadLL(unsigned char *buffer, int nbytes, FS_FILE * file, FS_VOLUME * fs)
|
|
{
|
|
int bytesread, totalcount, bytescachedl, bytescachedr;
|
|
uint64_t currentaddr;
|
|
FS_FRAGMENT *fr;
|
|
|
|
// RETURN IF EOF
|
|
if(file->CurrentOffset >= file->FileSize) {
|
|
return 0;
|
|
}
|
|
// TRUNCATE IF TRYING TO READ BEYOND EOF
|
|
|
|
// INITIALIZE READ BUFFER IF NEEDED
|
|
if(!file->RdBuffer.Data) {
|
|
// MALLOC ONE SECTOR READ BUFFER
|
|
file->RdBuffer.Data = simpmallocb(512);
|
|
if(!file->RdBuffer.Data)
|
|
return 0; // NOT ENOUGH MEMORY FOR READ BUFFER, FAIL TO READ
|
|
file->RdBuffer.Used = 0;
|
|
}
|
|
|
|
if(file->CurrentOffset + nbytes > file->FileSize)
|
|
nbytes = file->FileSize - file->CurrentOffset;
|
|
|
|
// VERIFY IF DATA IS ALREADY IN BUFFER
|
|
bytescachedl = 0;
|
|
bytescachedr = 0;
|
|
|
|
if(file->RdBuffer.Used) {
|
|
int offsetdiff = file->CurrentOffset - file->RdBuffer.Offset;
|
|
|
|
if(offsetdiff < 0) // CURRENTOFFSET TO THE LEFT
|
|
{
|
|
|
|
if(offsetdiff + nbytes > 0) // THERE IS OVERLAP WITH READ BUFFER!
|
|
{
|
|
if(offsetdiff + nbytes <= 512) // END-OF-READ IS WITHIN BUFFER
|
|
{
|
|
|
|
bytescachedr = offsetdiff + nbytes;
|
|
//printf("End hit=%d\n",bytescachedr);
|
|
memmoveb(buffer - offsetdiff, file->RdBuffer.Data,
|
|
bytescachedr);
|
|
nbytes -= bytescachedr;
|
|
}
|
|
else // READ BUFFER IS COMPLETELY WITHIN READ SECTION
|
|
{
|
|
// IGNORE THIS CASE, DON'T SPLIT THE READ OPERATION IN HALF
|
|
|
|
}
|
|
}
|
|
}
|
|
else // CURENTOFFSET TO THE RIGHT
|
|
{
|
|
if(offsetdiff < 512) // READ SECTION START WITHIN BLOCK
|
|
{
|
|
if(offsetdiff + nbytes <= 512) // READ SECTION COMPLETELY WITHIN READ BUFFER
|
|
{
|
|
//printf("total hit\n");
|
|
memmoveb(buffer, file->RdBuffer.Data + offsetdiff, nbytes);
|
|
file->CurrentOffset += nbytes;
|
|
return nbytes;
|
|
}
|
|
else // READ SECTION BEGIN IN READ BUFFER
|
|
{
|
|
bytescachedl = 512 - offsetdiff;
|
|
//printf("start hit=%d\n",bytescachedl);
|
|
memmoveb(buffer, file->RdBuffer.Data + offsetdiff,
|
|
bytescachedl);
|
|
file->CurrentOffset += bytescachedl;
|
|
nbytes -= bytescachedl;
|
|
buffer += bytescachedl;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fr = &file->Chain;
|
|
currentaddr = (((uint64_t) fr->StartAddr) << 9) + file->CurrentOffset;
|
|
|
|
// FIND STARTING ADDRESS
|
|
while(currentaddr >= (((uint64_t) fr->EndAddr) << 9)) {
|
|
|
|
currentaddr -= ((uint64_t) fr->EndAddr) << 9;
|
|
|
|
fr = fr->NextFragment;
|
|
if(fr == NULL) {
|
|
// MALFORMED CLUSTER CHAIN!!! CLUSTER CHAIN IS SHORTER THAN FileSize
|
|
return 0;
|
|
}
|
|
currentaddr += ((uint64_t) fr->StartAddr) << 9;
|
|
|
|
}
|
|
|
|
// START READING FULL FRAGMENTS
|
|
totalcount = bytescachedl;
|
|
|
|
/*
|
|
// SET BLOCK LENGTH TO OPTIMIZE READ SPEED
|
|
temp=nbytes;
|
|
temp2=0;
|
|
while(temp) { temp>>=1; ++temp2; }
|
|
temp2-=2; // USE BLOCK LEN=(nbytes/4) aprox.
|
|
if(temp2<5) temp2=5; // MINIMUM BLOCK LEN=32 BYTES;
|
|
|
|
if(!SDDSetBlockLen(fs->Disk,temp2)) {
|
|
// ERROR
|
|
return totalcount;
|
|
}
|
|
*/
|
|
|
|
while(nbytes + currentaddr > (((uint64_t) fr->EndAddr) << 9)) {
|
|
|
|
bytesread =
|
|
SDDRead(currentaddr,
|
|
(((uint64_t) fr->EndAddr) << 9) - currentaddr, buffer,
|
|
fs->Disk);
|
|
totalcount += bytesread;
|
|
file->CurrentOffset += bytesread;
|
|
if((uint64_t) bytesread !=
|
|
(((uint64_t) fr->EndAddr) << 9) - currentaddr) {
|
|
// ERROR READING LAST BLOCK, RETURN WHAT WAS READ SO FAR
|
|
return totalcount;
|
|
}
|
|
nbytes -= bytesread;
|
|
fr = fr->NextFragment;
|
|
if(fr == NULL) {
|
|
// MALFORMED CLUSTER CHAIN!!! CLUSTER CHAIN IS SHORTER THAN FileSize
|
|
return totalcount;
|
|
}
|
|
currentaddr = ((uint64_t) fr->StartAddr) << 9;
|
|
buffer += bytesread;
|
|
}
|
|
|
|
if(nbytes) {
|
|
int readnow = ((currentaddr + nbytes) & (~511)) - currentaddr;
|
|
|
|
if(readnow > 0) {
|
|
// READ SECTORS DIRECTLY INTO BUFFER
|
|
bytesread = SDDRead(currentaddr, readnow, buffer, fs->Disk);
|
|
|
|
totalcount += bytesread;
|
|
file->CurrentOffset += bytesread;
|
|
currentaddr += bytesread;
|
|
buffer += bytesread;
|
|
nbytes -= bytesread;
|
|
if(bytesread != readnow)
|
|
return totalcount;
|
|
readnow = 0;
|
|
}
|
|
|
|
// READ LAST SECTOR IN CACHE
|
|
currentaddr += readnow;
|
|
if((!file->RdBuffer.Used) || (file->CurrentOffset + readnow != (unsigned int)file->RdBuffer.Offset)) // CHECK IF SECTOR ALREADY IN CACHE
|
|
{
|
|
|
|
if(file->CurrentOffset < file->FileSize) // CHECK IF ANY MORE BYTES TO CACHE
|
|
{
|
|
|
|
// UPDATE FRAGMENT AS NEEDED
|
|
while(currentaddr >= (((uint64_t) fr->EndAddr) << 9)) {
|
|
|
|
currentaddr -= (((uint64_t) fr->EndAddr) << 9);
|
|
|
|
fr = fr->NextFragment;
|
|
if(fr == NULL) {
|
|
// CURRENTADDR POINTING EXACTLY AT END-OF-FILE, NOTHING TO READ
|
|
return 0;
|
|
}
|
|
currentaddr += (((uint64_t) fr->StartAddr) << 9);
|
|
|
|
}
|
|
bytesread =
|
|
SDDRead(currentaddr, 512, file->RdBuffer.Data,
|
|
fs->Disk);
|
|
|
|
if(bytesread != 512) {
|
|
file->RdBuffer.Used = 0;
|
|
return totalcount;
|
|
}
|
|
|
|
file->RdBuffer.Offset = file->CurrentOffset + readnow;
|
|
file->RdBuffer.Used = 1;
|
|
|
|
}
|
|
}
|
|
|
|
memmoveb(buffer, file->RdBuffer.Data - readnow, nbytes);
|
|
|
|
totalcount += nbytes;
|
|
file->CurrentOffset += nbytes;
|
|
|
|
}
|
|
|
|
totalcount += bytescachedr;
|
|
file->CurrentOffset += bytescachedr;
|
|
|
|
return totalcount;
|
|
|
|
}
|
|
#endif
|