Hm. I think it could be possible to buid it on top of existing api. This will still require OS modification. I'll post my patch later.
Here is an example of how i will implement it.
Code:
if(!FS_OpenFile(VolumeInfo, "path/to/directory", FS_CREATEDIR, &FileInfo))
{
FS_Close(&fileInfo); // Directory created or allready exists
}else{
//Directory is not created
}
UPDATE: Nope. It didn't work. There is a bug in DFS - empty files should not use any clusters at all. Yet in DFS empty file uses a single cluster. This results in directories filled with garbage.
do ypu get to work ? If the empty "directories" contain trash then your are quite close to the solution juste need to make it "empty" , a two time directory create would be fine for me.
even if i can survive without a primer directori create it will enable to manage data storage in a clean way ( one series of numbered file per run directori each run creat a new dire ) / -- +/ RUN000 | +image000.bmp | ~ | +image999.bmp | +/ RUN001 +image000.bmp ~ +image006.bmp
UPDATE: trash was caused by wrong cluster numbering. I fixed that. But there is yet another problem - directory owerwrites the last file in the parent directory and fails to cteate on an empty disk.
This looks strange. I tried to use RecWav application to write some files on the pre-formated flash and i'm geting the same result. Looks like there is a bug in DFS file creation process.
YES! Here is a new functions with CREATEDIR support.
Replace following functions in file dosfs.c:
Code:
NODEBUG uint32_t DFS_GetNext(PVOLINFO volinfo, PDIRINFO dirinfo, PDIRENT dirent)
{
uint32_t tempint; // required by DFS_GetFAT
/* Do we need to read the next sector of the directory?*/
if (dirinfo->currententry >= SECTOR_SIZE / sizeof(DIRENT)) {
dirinfo->currententry = 0;
dirinfo->currentsector++;
/* Root directory; special case handling */
/* Note that currentcluster will only ever be zero if both:*/
/* (a) this is the root directory, and*/
/* (b) we are on a FAT12/16 volume, where the root dir can't be expanded*/
if (dirinfo->currentcluster == 0) {
/* Trying to read past end of root directory?*/
if (dirinfo->currentsector * (SECTOR_SIZE / sizeof(DIRENT)) >= volinfo->rootentries)
return DFS_EOF;
/* Otherwise try to read the next sector*/
if (DFS_ReadSector(volinfo->unit, dirinfo->scratch, volinfo->rootdir + dirinfo->currentsector, 1))
return DFS_ERRMISC;
}
/* Normal handling*/
else {
if (dirinfo->currentsector >= volinfo->secperclus) {
dirinfo->currentsector = 0;
if ((dirinfo->currentcluster >= 0xff7 && volinfo->filesystem == FAT12) ||
(dirinfo->currentcluster >= 0xfff7 && volinfo->filesystem == FAT16) ||
(dirinfo->currentcluster >= 0x0ffffff7 && volinfo->filesystem == FAT32)) {
/* We are at the end of the directory chain. If this is a normal*/
/* find operation, we should indicate that there is nothing more*/
/* to see.*/
if (!(dirinfo->flags & DFS_DI_BLANKENT))
return DFS_EOF;
/* On the other hand, if this is a "find free entry" search,*/
/* we need to tell the caller to allocate a new cluster*/
else
return DFS_ALLOCNEW;
}
dirinfo->currentcluster = DFS_GetFAT(volinfo, dirinfo->scratch, &tempint, dirinfo->currentcluster);
}
if (DFS_ReadSector(volinfo->unit, dirinfo->scratch, volinfo->dataarea + ((dirinfo->currentcluster - 2) * volinfo->secperclus) + dirinfo->currentsector, 1))
return DFS_ERRMISC;
}
}
DFS_memcpy(dirent, &(((PDIRENT) dirinfo->scratch)[dirinfo->currententry]), sizeof(DIRENT));
if (dirent->name[0] == 0) { /* no more files in this directory*/
/* If this is a "find blank" then we can reuse this name.*/
if (dirinfo->flags & DFS_DI_BLANKENT)
{
//NTRF: Invalid indexing! Current must be incremented proir to returning OK
dirinfo->currententry++;
return DFS_OK;
}else
return DFS_EOF;
}
if (dirent->name[0] == 0xe5) /* handle deleted file entries*/
dirent->name[0] = 0;
else if( ((dirent->attr & ATTR_LONG_NAME) == ATTR_LONG_NAME) &&
!(dirinfo->flags & DFS_DI_BLANKENT) ) //NTRF: don't replace longnames with new files
dirent->name[0] = 0;
else if (dirent->name[0] == 0x05) /* handle kanji filenames beginning with 0xE5*/
dirent->name[0] = 0xe5;
dirinfo->currententry++;
return DFS_OK;
}
Code:
NODEBUG uint32_t DFS_OpenFile(PVOLINFO volinfo, uint8_t *path, uint8_t mode, uint8_t *scratch, PFILEINFO fileinfo)
{
uint8_t tmppath[MAX_PATH];
uint8_t filename[12];
uint8_t *p;
DIRINFO di;
DIRENT de;
uint32_t dircluster;
/* larwe 2006-09-16 +1 zero out file structure*/
DFS_memset(fileinfo, 0, sizeof(FILEINFO));
/* save access mode*/
fileinfo->mode = mode;
/* Get a local copy of the path. If it's longer than MAX_PATH, abort.*/
DFS_strncpy((u8 *) tmppath, (u8 *) path, MAX_PATH);
tmppath[MAX_PATH - 1] = 0;
if (DFS_strcmp((u8 *) path,(u8 *) tmppath)) {
return DFS_PATHLEN;
}
/* strip leading path separators*/
while (tmppath[0] == DIR_SEPARATOR)
DFS_strcpy((u8 *) tmppath, (u8 *) tmppath + 1);
/* Parse filename off the end of the supplied path*/
p = tmppath;
while (*(p++));
p--;
while (p > tmppath && *p != DIR_SEPARATOR) /* larwe 9/16/06 ">=" to ">" bugfix*/
p--;
if (*p == DIR_SEPARATOR)
p++;
DFS_CanonicalToDir(filename, p);
if (p > tmppath)
p--;
if (*p == DIR_SEPARATOR || p == tmppath) // larwe 9/16/06 +"|| p == tmppath" bugfix
*p = 0;
/* At this point, if our path was MYDIR/MYDIR2/FILE.EXT, filename = "FILE EXT" and*/
/* tmppath = "MYDIR/MYDIR2".*/
di.scratch = scratch;
dircluster = di.currentcluster;
if (DFS_OpenDir(volinfo, tmppath, &di))
return DFS_NOTFOUND;
while (!DFS_GetNext(volinfo, &di, &de)) {
if (!DFS_memcmp(de.name, filename, 11)) {
/* You can't use this function call to open a directory.*/
//NTRF: allows to create directories
if ((de.attr & ATTR_DIRECTORY) && (mode != DFS_CREATEDIR))
return DFS_NOTFOUND;
fileinfo->volinfo = volinfo;
fileinfo->pointer = 0;
/* The reason we store this extra info about the file is so that we can*/
/* speedily update the file size, modification date, etc. on a file that is*/
/* opened for writing.*/
if (di.currentcluster == 0)
fileinfo->dirsector = volinfo->rootdir + di.currentsector;
else
fileinfo->dirsector = volinfo->dataarea + ((di.currentcluster - 2) * volinfo->secperclus) + di.currentsector;
fileinfo->diroffset = di.currententry - 1;
if (volinfo->filesystem == FAT32) {
fileinfo->cluster = (uint32_t) de.startclus_l_l |
((uint32_t) de.startclus_l_h) << 8 |
((uint32_t) de.startclus_h_l) << 16 |
((uint32_t) de.startclus_h_h) << 24;
}
else {
fileinfo->cluster = (uint32_t) de.startclus_l_l |
((uint32_t) de.startclus_l_h) << 8;
}
fileinfo->firstcluster = fileinfo->cluster;
fileinfo->filelen = (uint32_t) de.filesize_0 |
((uint32_t) de.filesize_1) << 8 |
((uint32_t) de.filesize_2) << 16 |
((uint32_t) de.filesize_3) << 24;
return DFS_OK;
}
}
/* At this point, we KNOW the file does not exist. If the file was opened*/
/* with write access, we can create it.*/
if (mode & DFS_WRITE) {
uint32_t cluster, temp;
/* Locate or create a directory entry for this file*/
if (DFS_OK != DFS_GetFreeDirEnt(volinfo, tmppath, &di, &de))
return DFS_ERRMISC;
/* put sane values in the directory entry*/
DFS_memset(&de, 0, sizeof(de));
DFS_memcpy(de.name, filename, 11);
de.crttime_l = 0x20; /* 01:01:00am, Jan 1, 2006.*/
de.crttime_h = 0x08;
de.crtdate_l = 0x11;
de.crtdate_h = 0x34;
de.lstaccdate_l = 0x11;
de.lstaccdate_h = 0x34;
de.wrttime_l = 0x20;
de.wrttime_h = 0x08;
de.wrtdate_l = 0x11;
de.wrtdate_h = 0x34;
//NTRF: create directory
if(mode == DFS_CREATEDIR) de.attr |= ATTR_DIRECTORY;
/* allocate a starting cluster for the directory entry*/
cluster = DFS_GetFreeFAT(volinfo, scratch);
de.startclus_l_l = cluster & 0xff;
de.startclus_l_h = (cluster & 0xff00) >> 8;
de.startclus_h_l = (cluster & 0xff0000) >> 16;
de.startclus_h_h = (cluster & 0xff000000) >> 24;
/* update FILEINFO for our caller's sake*/
fileinfo->volinfo = volinfo;
fileinfo->pointer = 0;
/* The reason we store this extra info about the file is so that we can*/
/* speedily update the file size, modification date, etc. on a file that is*/
/* opened for writing.*/
if (di.currentcluster == 0)
fileinfo->dirsector = volinfo->rootdir + di.currentsector;
else
fileinfo->dirsector = volinfo->dataarea + ((di.currentcluster - 2) * volinfo->secperclus) + di.currentsector;
fileinfo->diroffset = di.currententry - 1;
fileinfo->cluster = cluster;
fileinfo->firstcluster = cluster;
fileinfo->filelen = 0;
/* write the directory entry*/
/* note that we no longer have the sector containing the directory entry,*/
/* tragically, so we have to re-read it*/
if (DFS_ReadSector(volinfo->unit, scratch, fileinfo->dirsector, 1))
return DFS_ERRMISC;
DFS_memcpy(&(((PDIRENT) scratch)[di.currententry-1]), &de, sizeof(DIRENT));
if (DFS_WriteSector(volinfo->unit, scratch, fileinfo->dirsector, 1))
return DFS_ERRMISC;
/* Mark newly allocated cluster as end of chain */
switch(volinfo->filesystem) {
case FAT12: cluster = 0xff8; break;
case FAT16: cluster = 0xfff8; break;
case FAT32: cluster = 0x0ffffff8; break;
default: return DFS_ERRMISC;
}
temp = 0;
DFS_SetFAT(volinfo, scratch, &temp, fileinfo->cluster, cluster);
//Fill new directory with required info
if(mode == DFS_CREATEDIR)
{
if(dircluster <= 2) //Root
dircluster = 0;
uint32_t startsector = volinfo->dataarea + ((fileinfo->cluster - 2) * volinfo->secperclus);
uint32_t endsector = startsector + volinfo->secperclus - 1;
DFS_memset(scratch, 0, SECTOR_SIZE);
for(; endsector > startsector; endsector -= 1)
DFS_WriteSector(volinfo->unit, scratch, endsector, 1);
DFS_memcpy(&(de.name), ". ", 11);
de.filesize_0 = 0;
de.filesize_1 = 0;
de.filesize_2 = 0;
de.filesize_3 = 0;
DFS_memcpy(scratch, &de, sizeof(DIRENT));
DFS_memcpy(&(de.name), ".. ", 11);
de.startclus_l_l = dircluster & 0xff;
de.startclus_l_h = (dircluster & 0xff00) >> 8;
de.startclus_h_l = (dircluster & 0xff0000) >> 16;
de.startclus_h_h = (dircluster & 0xff000000) >> 24;
DFS_memcpy(scratch + sizeof(DIRENT), &de, sizeof(DIRENT));
DFS_WriteSector(volinfo->unit, scratch, startsector, 1);
}
return DFS_OK;
}
return DFS_NOTFOUND;
}
Now add define into the /* File access modes*/ block in dosfs.h file:
Add them into the CircleOS distribution, build it and put the result (Primer2_obj/Primer2_circle.elf) file into the <RIDE7_InstallDir>/Lib/ARM/CircleOS. See this for details.
You will also have to update copy of circle_api.h in your project.
And here is a small exmple of hot to use it:
Code:
VOLINFO volume_info;
FILEINFO file_info;
//Mount file system
uint32_t StartMBR=FS_Mount(MMCSD_SDIO);
// Open volume on first partition (0)
if (FS_GetVolumeInfo(0, StartMBR, &volume_info))
{
DRAW_Puts("\nErr: GetVolInfo");
return -1;
}
if (FS_OpenFile(&volume_info, "TESTDIR", FS_CREATEDIR, &file_info))
{
DRAW_Puts("\n Err op: DirCreate");
return -1;
}else{
FS_Close(&file_info);
}
You'll have to modify a few more functions anyway. And technicaly crating directory in FAT32 is the same as creating file, so adding another function would be waste of flash memory. And there's also a fix for wrong directory entry numbering.
it work great By the way is it possible to keep mulitple file open on the same directori with the current FS ? I somehow feel this is should be fine but did anybody tried and could confirm ?
Yes. It's posible to keep two files open unless you try to open a file for reading and writing at the same time. It won't fail but you will have wrong offsets when reading.