📄 ffs.c
字号:
{
static char name83[12];
int cnt;
char *p,c;
// copy name portion of filename, converting case
cnt=0;
p=filename;
while(cnt<8)
{
c=*p;
if(c=='.' || c==0)
break;
name83[cnt++]=toupper(c);
p++;
}
// pad name out with spaces
while(cnt<8)
name83[cnt++]=' ';
// copy extension portion of filename, converting case
if(*p++=='.')
{
while(cnt<11)
{
c=*p;
if(c==0)
break;
name83[cnt++]=toupper(c);
p++;
}
}
// pad extension out with spaces
while(cnt<11)
name83[cnt++]=' ';
name83[11]=0;
return name83;
}
bool dir_findbyname(char *filename)
{
char *name = __create_83_name(filename);
#ifdef CCD_DEBUG
char tmp[12];
mprintf("Open %s\n",name);
#endif
if (dir_examine(FILE_USED))
{
do
{
if (de_cur.Attr != ATTR_LONG_NAME)
{
#ifdef CCD_DEBUG
memcpy(tmp,de_cur.Name,11);
tmp[11]=0;
mprintf("Scan %s\n",tmp);
#endif
// We stop at first match, only comparing at strlen(filename) maxed at 11
if (!(strncmp(name, de_cur.Name, 11 )))
{
return TRUE;
}
}
}
while (dir_next(FILE_USED));
}
return FALSE;
}
//
//
// ****************** LV6 - P O S I X L I B P R O T O S ******************
//
//
static inline bool __h_in_use(u8 handle)
{
// Limit collateral damages in case of wrong handle
if (handle >= MAX_FILES) return FALSE;
return __files[handle].inuse;
}
static u8 __h_findfree(void)
{
u8 hnum;
for (hnum = 0 ; (hnum < MAX_FILES) && (__h_in_use(hnum)) ; ++hnum);
return hnum;
}
s8 close(u8 handle)
/* Close file handle
Parameter
handle Handle referring to open file
Returns
0 if the file was successfully closed.
A return value of -1 indicates an error,
in which case errno is set to EBADF,
indicating an invalid file-handle parameter.
*/
{
#ifdef CCD_DEBUG
mprintf("close %d",handle);
#endif
if (!(__h_in_use(handle))) return -1;
__files[handle].inuse = FALSE;
#ifdef CCD_DEBUG
mprintf("close() OK");
#endif
return 0;
}
s8 eof(u8 handle)
/* Tests for end-of-file.
Parameter
handle Handle referring to open file
Returns
1 if the current position is end of file,
or 0 if it is not. A return value of -1
indicates an error; in this case, errno
is set to EBADF, which indicates an invalid
file handle.
*/
{
if (!(__h_in_use(handle))) return -1;
if (__files[handle].pos + 1 > __files[handle].size) return 1;
return 0;
}
s8 open(char *filename, u8 oflag, u8 pmode)
/* Open a file.
Parameters
filename Filename
oflag Type of operations allowed
pmode Permission mode
Returns
Returns a file handle for the opened file.
A return value of -1 indicates an error,
in which case errno is set to one of the following
values:
EACCES Tried to open read-only file for
writing, or file抯 sharing mode does
not allow specified operations, or
given path is directory
EEXIST O_CREAT and O_EXCL flags specified,
but filename already exists
EINVAL Invalid oflag or pmode argument
EMFILE No more file handles available
(too many open files)
ENOENT File or path not found
oflag is an integer expression formed from one
or more of the following manifest constants
or constant combinations :
O_APPEND Moves file pointer to end of
file before every write operation.
O_CREAT Creates and opens new file for
writing. Has no effect if file
specified by filename exists. pmode
argument is required when O_CREAT is
specified.
O_CREAT | O_EXCL Returns error value
if file specified by filename
exists. Applies only when used
with O_CREAT.
O_RDONLY Opens file for reading only;
cannot be specified with O_RDWR
or O_WRONLY.
O_RDWR Opens file for both reading and
writing; you cannot specify this
flag with O_RDONLY or O_WRONLY.
O_TRUNC Opens file and truncates it to zero
length; file must have write
permission. You cannot specify this
flag with O_RDONLY. O_TRUNC used
with O_CREAT opens an existing file
or creates a new file.
Warning The O_TRUNC flag destroys
the contents of the specified file.
O_WRONLY Opens file for writing only;
cannot be specified with O_RDONLY
or O_RDWR.
To specify the file access mode, you must specify
either O_RDONLY, O_RDWR, or O_WRONLY. There is no
default value for the access mode.
The pmode argument is required only when O_CREAT
is specified. If the file already exists, pmode
is ignored. Otherwise, pmode specifies the file
permission settings, which are set when the new
file is closed the first time. open applies the
current file-permission mask to pmode before
setting the permissions (for more information,
see umask). pmode is an integer expression
containing one or both of the following manifest
constants :
S_IREAD Reading only permitted
S_IWRITE Writing permitted (effectively
permits reading and writing)
S_IREAD | S_IWRITE Reading and writing
permitted
*/
{
// Find a free handle
u8 handle = __h_findfree();
file_handle *fd = &(__files[handle]);
u32 curlba,next_lba;
// Check if file already exists
bool bexist;
#ifdef CCD_DEBUG
mprintf("open(%s mode %d)\n\r",filename,oflag);
#endif
bexist = dir_findbyname(filename);
// If no more handle available then error EMFILE
if (handle >= MAX_FILES) return -1;
// If asked to create a new file which already exists, error
if (bexist && (oflag & O_CREAT) && (oflag & O_EXCL)) return -1;
// If asked to truncate a file without write permission, error
if (bexist && (oflag & O_TRUNC) && (pde_cur -> Attr & ATTR_READ_ONLY)) return -1;
// If asked to create or truncate, error
if ((oflag & O_CREAT) || (oflag & O_TRUNC)) return -1;
// Now we are left with O_APPEND, O_RDONLY, O_RDWR. File must exist.
if (!bexist) return -1;
// If asked for meaningless combinations of RDWR, WRONLY and RDONLY then error
if ((oflag & O_RDWR) && (oflag & O_RDONLY)) return -1;
if ((oflag & O_RDWR) && (oflag & O_WRONLY)) return -1;
if ((oflag & O_RDONLY) && (oflag & O_WRONLY)) return -1;
// Everything is OK, open file
fd -> size = peekl((u16)((char *)&pde_cur->FileSize - (char*)sector));
fd -> clust = peekw((u16)((char *)&pde_cur->FstClusLO - (char*)sector));
fd -> pos = (oflag & O_APPEND ? pde_cur -> FileSize : 0);
fd -> mode = oflag & (O_RDWR | O_WRONLY | O_RDONLY);
fd -> inuse = TRUE;
fd -> dirlba = lba_tmpdir;
fd -> dirptr = pde_cur;
fd -> curlba = clust2lba(fd -> clust);
// Scan for contigous clusters
curlba = fd->curlba;
fd->sector_rl=0;
next_lba=clust_nextlba(curlba);
while(next_lba && (next_lba == curlba+1))
{
fd->sector_rl++;
curlba=next_lba;
next_lba=clust_nextlba(curlba);
}
return handle;
}
long lseek(u8 handle, s32 offset, u8 origin)
/* Move a file pointer to the specified location.
Parameters
handle Handle referring to open file
offset Number of u8s from origin
origin Initial position
origin argument must be one of the following
constants :
SEEK_SET Beginning of file
SEEK_CUR Current position of file pointer
SEEK_END End of file
Returns
the offset, in u8s, of the new position from
the beginning of the file. Returns -1L to
indicate an error and sets errno either to EBADF,
meaning the file handle is invalid, or to EINVAL,
meaning the value for origin is invalid or the
position specified by offset is before the
beginning of the file.
*/
{
file_handle *fd = &(__files[handle]);
u16 clust, clustcnt;
u8 secoff;
if (!(__h_in_use(handle))) return -1;
// Recalculate the offset from the start of the file
switch(origin)
{
default:
return -1;
case SEEK_SET:
break;
case SEEK_CUR : // Current position of file pointer
offset += fd -> pos;
break;
case SEEK_END : // End of file
offset = fd -> size - 1 + offset;
break;
}
// Process special offsets
if (offset > fd -> size ) return -1;
if (offset == fd -> pos)
return offset;
// Update current pos
fd -> pos = offset;
// Calculate cluster / sector number of new pos
clustcnt = offset / hd1_geom_clustsize;
secoff = (u8) ((offset % hd1_geom_clustsize) / (u32) BLOCKSIZE);
// Update current LBA
clust = fd -> clust;
while ((clustcnt--) && (clust < CLUSTCHAIN_END)) clust = clust_next(clust);
if (clust < CLUSTCHAIN_END)
{
fd -> curlba = clust2lba(clust) + secoff;
}
else
fd->curlba = 0; // flag for extending chain
return offset;
}
s16 read(u8 handle, u8 *buffer, u16 count)
/* Reads data from a file.
Parameters
handle Handle referring to open file
buffer Storage location for data
count Maximum number of u8s
Returns
the number of u8s read, which may be less
than count if there are fewer than count u8s
left in the file.
If the function tries to read at end of file,
it returns 0. If the handle is invalid, or the
file is not open for reading, the function
returns -1 and sets errno to EBADF.
*/
{
file_handle *fd = &(__files[handle]);
u16
offset_start = (u16) (fd -> pos & (BLOCKSIZE-1)),
u8s_read = 0,
u8s_toread,
u8s_leftinsec;
if (!(__h_in_use(handle))) return -1;
// If asked to read from a non read file then error
if (!((fd -> mode & O_RDWR) || (fd -> mode & O_RDONLY))) return -1;
while ((u8s_read < count) && !(eof(handle)))
{
// Read in the file current sector
sec_get(&(fd -> curlba));
// 1 - calculate how many u8s are left in the current sector
u8s_leftinsec = BLOCKSIZE - offset_start;
// 2 - calculate how many u8s we can thus read in the current sector
u8s_toread = min(count - u8s_read, u8s_leftinsec);
// 3 - read these u8s in the user buffer
memcpy(buffer+u8s_read, sector+offset_start,u8s_toread);
// 4 - increment the read u8s counter
u8s_read += u8s_toread;
// 5 - if necessary go to next sector
if (u8s_toread == u8s_leftinsec)
{
if(fd->sector_rl)
{
fd->sector_rl--;
fd->curlba++;
}
else
{
fd -> curlba = clust_nextlba(fd -> curlba);
}
}
// 6 - zero offset_start, which is only useful in 1st pass
offset_start = 0;
}
// Adjust file pos
fd -> pos += u8s_read;
return u8s_read;
}
//
// read N sectors. file position must be aligned on sector offset
//
s16 read_sectors(u8 handle,u8 *buffer,u16 sectors)
{
file_handle *fd = &(__files[handle]);
u16 actual;
if (!(__h_in_use(handle))) return -1;
// If asked to read from a non read file then error
if (!((fd -> mode & O_RDWR) || (fd -> mode & O_RDONLY))) return -1;
if(fd->pos & 511) return -1;
actual=0;
while(!eof(handle) && sectors!=0)
{
mmc_SectorRead(buffer,fd -> curlba);
fd->pos+=512;
buffer+=512;
sectors--;
actual++;
if(fd->sector_rl)
{
fd->sector_rl--;
fd->curlba++;
}
else
{
fd -> curlba = clust_nextlba(fd -> curlba);
}
}
return actual;
}
//
// count number of directories, or seek to a particular directory index
//
s16 scan_dirs(int no,char *dirname)
{
s16 count=0;
// back to root directory
lba_curdir = lba_rd;
strcpy(dirname,"TOP");
if(!no)
return 0;
if (dir_examine(FILE_USED))
{
do
{
if(de_cur.Attr & ATTR_DIRECTORY)
{
if(++count==no)
{
if(dirname!=NULL)
{
memcpy(dirname,&de_cur.Name[0],11);
dirname[11]=0;
}
// change current directory
lba_curdir = clust2lba(peekw((u16)((char *)&pde_cur->FstClusLO - (char*)sector)));
return count;
}
}
}
while (dir_next(FILE_USED));
}
return count;
}
//
// count number of tracks within a given directory, or seek to a particular track
//
s16 scan_tracks(int dirno,int fileno,char *filename,char *dirname)
{
s16 count=0;
int i;
// scan to appropriate directory
if(scan_dirs(dirno,dirname)!=dirno)
{
return -1; // not found
}
if (dir_examine(FILE_USED))
{
do
{
if (de_cur.Attr != ATTR_LONG_NAME && (!(de_cur.Attr & ATTR_DIRECTORY)))
{
if(!strncmp("WAV", &de_cur.Name[8], 3))
{
if(++count == fileno)
{
if(filename!=NULL)
{
memcpy(filename, &de_cur.Name[0], 11);
filename[11]=0;
// convert name back to standard filename convention
for(i=7; i>0; i--)
{
if(filename[i]!=' ')
break;
}
filename[i+1]=0;
strcat(filename, ".WAV");
}
return count;
}
}
}
}
while (dir_next(FILE_USED));
}
return count;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -