// See RedSea File System U0 RedSeaFreeFreeLst(CDrv *dv) { CFreeLst *tmpf,*tmpf1; Bool unlock; try { unlock=DrvLock(dv); if (tmpf=dv->next_free) { while (tmpf!=&dv->next_free) { tmpf1=tmpf->next; Free(tmpf); tmpf=tmpf1; } } dv->next_free=NULL; if (unlock) DrvUnlock(dv); } catch if (unlock) DrvUnlock(dv); } U0 RedSeaFreeLstBuild(CDrv *dv) { Bool unlock; CFreeLst *tmpf; I64 i,first=dv->data_area,max_blk=dv->size+dv->drv_offset; try { unlock=DrvLock(dv); if (dv->next_free) RedSeaFreeFreeLst(dv); QueInit(&dv->next_free); while (first<max_blk) { i=0; //count free clus while (first+i<max_blk) { DrvFATBlkSet(dv,first+i); if (Bt(dv->cur_fat_blk,(first+i-dv->data_area)&(BLK_SIZE<<3-1))) break; else i++; } if (i) { tmpf=AMAlloc(sizeof(CFreeLst)); tmpf->size=i; tmpf->start=first; QueIns(tmpf,dv->last_free); } first+=i+1; } if (unlock) DrvUnlock(dv); } catch if (unlock) DrvUnlock(dv); } U0 RedSeaInit(CDrv *dv) { CRedSeaBoot br; Bool unlock; try { unlock=DrvLock(dv); BlkRead(dv,&br,dv->drv_offset,1); if (br.signature!=MBR_PT_REDSEA || br.signature2!=0xAA55) throw('Drv'); dv->fs_type=FSt_REDSEA; RedSeaFreeFreeLst(dv); dv->spc=1; dv->size=br.sects; dv->data_area=dv->drv_offset+br.bitmap_sects; dv->root_clus=br.root_clus; dv->fat1=dv->fat2=dv->drv_offset+1; DrvFATBlkAlloc(dv); if (unlock) DrvUnlock(dv); } catch if (unlock) DrvUnlock(dv); } Bool RedSeaValidate(U8 drv_let) { CDrv *dv; CRedSeaBoot br; if ((dv=Let2Drv(drv_let,FALSE)) && dv->fs_type==FSt_REDSEA && BlkRead(dv,&br,dv->drv_offset,1) && br.signature==MBR_PT_REDSEA && br.signature2==0xAA55) return TRUE; else return FALSE; } U0 RedSeaFmt(U8 drv_let,Bool quick=TRUE) { U8 *root_dir; CDirEntry *d_native; CRedSeaBoot *br=CAlloc(BLK_SIZE); CDrv *dv=Let2Drv(drv_let); I64 i,n,root_dir_blks; try { DrvLock(dv); // DrvTypeSet(drv_let,FSt_REDSEA); DrvTypeSet(drv_let,FSt_FAT32); dv->fs_type=FSt_REDSEA; br->signature=MBR_PT_REDSEA; br->signature2=0xAA55; br->drv_offset=dv->drv_offset; //For CD/DVD image copy. br->sects=dv->size; n=(br->sects+BLK_SIZE<<3-1)/BLK_SIZE<<3; br->bitmap_sects=n; br->unique_id=GetTSC^Now()(U64); br->root_clus=0; if (quick) i=n+1; else i=dv->size; BlkWriteZero(dv,dv->drv_offset,i); BlkWrite(dv,br,dv->drv_offset,1); RedSeaInit(dv); ClusAlloc(dv,0,1,FALSE); //Alloc #1 root_dir_blks=MaxI64(1,dv->bd->init_root_dir_blks); br->root_clus=ClusAlloc(dv,0,root_dir_blks,FALSE); BlkWrite(dv,br,dv->drv_offset,1); root_dir=CAlloc(BLK_SIZE*root_dir_blks); d_native=root_dir-offset(CDirEntry.start); d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS; *d_native->name='.'; d_native->clus=br->root_clus; d_native->size=BLK_SIZE*root_dir_blks; d_native->datetime=Now; d_native(U8 *)+=CDIR_SIZE; *d_native->name='.'; d_native->name[1]='.'; d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS; d_native->clus=br->root_clus; d_native->datetime=Now; BlkWrite(dv,root_dir,br->root_clus,root_dir_blks); RedSeaInit(dv); DrvUnlock(dv); } catch DrvUnlock(dv); Free(br); Free(root_dir); } Bool RedSeaFileFind(CDrv *dv,I64 cur_dir_clus,U8 *name, CDirEntry *_res,I64 fuf_flags=0) {//FUF_JUST_DIRS, FUF_JUST_FILES CDirEntry *buf,*buf2,*ptr; U8 dname[CDIR_FILENAME_LEN]; I64 ch; Bool res=FALSE,unlock; if (fuf_flags&~FUG_FILE_FIND) throw('FUF'); MemSet(_res,0,sizeof(CDirEntry)); DrvChk(dv); if (dv->fs_type!=FSt_REDSEA) PrintErr("Not RedSea Drv\n"); else if (!CFileNameTo(dname,name)) PrintErr("Invalid FileName: \"%s\".\n",name); else try { unlock=DrvLock(dv); buf2=MAlloc(BLK_SIZE); BlkRead(dv,buf2,cur_dir_clus,1); ptr=buf2(U8 *)-offset(CDirEntry.start); buf=MAlloc(ptr->size); BlkRead(dv,buf,cur_dir_clus,ptr->size>>BLK_SIZE_BITS); Free(buf2); ptr=buf(U8 *)-offset(CDirEntry.start); *ptr->name='.'; ptr->name[1]=0; while (TRUE) { if (!(ch=*ptr->name)) break; else if (!(ptr->attr & RS_ATTR_DELETED) && !(fuf_flags&FUF_JUST_DIRS && !(ptr->attr & RS_ATTR_DIR)) && !(fuf_flags&FUF_JUST_FILES && ptr->attr & RS_ATTR_DIR) && !StrCmp(dname,ptr->name)) { MemCpy(&_res->attr,&ptr->attr,CDIR_SIZE); res=TRUE; goto rsff_done; } ptr(U8 *)+=CDIR_SIZE; } rsff_done: Free(buf); if (unlock) DrvUnlock(dv); } catch if (unlock) DrvUnlock(dv); return res; } U8 *RedSeaFileRead(CDrv *dv,U8 *cur_dir,U8 *filename,I64 *_size,I64 *_attr) { U8 *buf=NULL; CDirEntry de; I64 c,blk_cnt,cur_dir_clus; DrvChk(dv); *_size=0; *_attr=0; if (dv->fs_type!=FSt_REDSEA) PrintErr("Not RedSea Drv\n"); else try { DrvLock(dv); cur_dir_clus=Name2DirClus(dv,cur_dir); if (RedSeaFileFind(dv,cur_dir_clus,filename,&de,FUF_JUST_FILES)) { blk_cnt=(de.size+BLK_SIZE-1)>>BLK_SIZE_BITS; buf=MAlloc(blk_cnt<<BLK_SIZE_BITS+1); c=de.clus; c=BlkRead(dv,buf,c,blk_cnt); buf[de.size]=0; //Terminate *_size=de.size; *_attr=FileAttr(de.name,de.attr); } DrvUnlock(dv); } catch DrvUnlock(dv); return buf; } Bool RedSeaCd(U8 *name,I64 cur_dir_clus) { CDirEntry de; if (Fs->cur_dv->fs_type!=FSt_REDSEA) PrintErr("Not RedSea Drv\n"); else if (RedSeaFileFind(Fs->cur_dv,cur_dir_clus,name,&de,FUF_JUST_DIRS)) return TRUE; else PrintErr("File not found: \"%s\".\n",name); return FALSE; } U0 RedSeaFreeClus(CDrv *dv,I64 c,I64 cnt) { CFreeLst *tmpf; Bool found=FALSE,unlock,unlock_break; DrvChk(dv); if (!c) return; if (dv->fs_type!=FSt_REDSEA) PrintErr("Not RedSea Drv\n"); else try { unlock_break=BreakLock; unlock=DrvLock(dv); if (!dv->next_free) RedSeaFreeLstBuild(dv); tmpf=dv->next_free; while (!found && tmpf!=&dv->next_free) { if (tmpf->start+tmpf->size==c) { tmpf->size+=cnt; found=TRUE; } else if (c+cnt==tmpf->start) { tmpf->size+=cnt; tmpf->start=c; found=TRUE; } tmpf=tmpf->next; } if (!found) { tmpf=AMAlloc(sizeof(CFreeLst)); tmpf->size=cnt; tmpf->start=c; QueIns(tmpf,dv->last_free); } while (cnt-->0) { DrvFATBlkSet(dv,c); LBtr(dv->cur_fat_blk,(c-dv->data_area)&(BLK_SIZE<<3-1)); LBts(&dv->fat_blk_dirty,0); c++; } DrvFATBlkClean(dv); if (unlock) DrvUnlock(dv); if (unlock_break) BreakUnlock; } catch { if (unlock) DrvUnlock(dv); if (unlock_break) BreakUnlock; } } I64 RedSeaAllocClus(CDrv *dv,I64 cnt) { CFreeLst *tmpf,*best_free=NULL; I64 i,first,best_size=I64_MAX; Bool unlock,unlock_break; if (cnt<=0) throw('Drv'); try { unlock_break=BreakLock; unlock=DrvLock(dv); if (!dv->next_free) RedSeaFreeLstBuild(dv); tmpf=dv->next_free; while (tmpf!=&dv->next_free) { if (tmpf->size>=cnt && tmpf->size<best_size) { best_free=tmpf; best_size=tmpf->size; if (tmpf->size==cnt) break; } tmpf=tmpf->next; } if (!best_free) throw('Drv'); first=best_free->start; for (i=0; i<cnt; i++) { DrvFATBlkSet(dv,first+i); LBts(dv->cur_fat_blk,(first+i-dv->data_area)&(BLK_SIZE<<3-1)); LBts(&dv->fat_blk_dirty,0); } DrvFATBlkClean(dv); if (best_free->size-=cnt) best_free->start+=cnt; else { QueRem(best_free); Free(best_free); } if (unlock) DrvUnlock(dv); if (unlock_break) BreakUnlock; } catch { if (unlock) DrvUnlock(dv); if (unlock_break) BreakUnlock; } return first; } Bool RedSeaDirNew(CDrv *dv,U8 *cur_dir,CDirEntry *tmpde,Bool free_old_chain) { CDirEntry *buf,*buf2,*ptr,de2; CRedSeaBoot *br; I64 c,ch,i=1,j=0,n=BLK_SIZE/CDIR_SIZE,dir_size,cur_dir_clus; Bool written=FALSE,unlock,unlock_break; U8 *tmp,*parent_dir; try { unlock_break=BreakLock; tmpde->attr|=RS_ATTR_CONTIGUOUS; unlock=DrvLock(dv); cur_dir_clus=Name2DirClus(dv,cur_dir); buf2=MAlloc(BLK_SIZE); BlkRead(dv,buf2,cur_dir_clus,1); ptr=buf2(U8 *)-offset(CDirEntry.start); buf=MAlloc(ptr->size); BlkRead(dv,buf,cur_dir_clus,ptr->size>>BLK_SIZE_BITS); dir_size=ptr->size; ptr=buf(U8 *)-offset(CDirEntry.start)+CDIR_SIZE; Free(buf2); while (TRUE) { if (!(ch=*ptr->name)) { if (!written) MemCpy(&ptr->start,&tmpde->start,CDIR_SIZE); if ((i+1)*CDIR_SIZE+j<<BLK_SIZE_BITS<dir_size) BlkWrite(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_clus+j,1); else { buf2=CAlloc(dir_size+BLK_SIZE); MemCpy(buf2,buf,dir_size); RedSeaFreeClus(dv,cur_dir_clus,dir_size>>BLK_SIZE_BITS); dir_size+=BLK_SIZE; c=ClusAlloc(dv,0,dir_size>>BLK_SIZE_BITS,TRUE); Free(buf); buf=buf2; ptr=buf(U8 *)-offset(CDirEntry.start); ptr->size=dir_size; ptr->clus=c; BlkWrite(dv,buf,c,dir_size>>BLK_SIZE_BITS); if (cur_dir_clus==dv->root_clus) { br=CAlloc(BLK_SIZE); BlkRead(dv,br,dv->drv_offset,1); br->root_clus=c; BlkWrite(dv,br,dv->drv_offset,1); Free(br); dv->root_clus=c; } else { tmp=StrNew(cur_dir); parent_dir=StrNew(cur_dir); StrLastRem(parent_dir,"/",tmp); if (!*parent_dir) { Free(parent_dir); parent_dir=StrNew("/"); } if (RedSeaFileFind(dv,Name2DirClus(dv,parent_dir), tmp,&de2,FUF_JUST_DIRS)) { de2.clus=c; de2.size=dir_size; RedSeaDirNew(dv,parent_dir,&de2,FALSE); } else throw('Drv'); Free(tmp); Free(parent_dir); } } break; } else if (ptr->attr & RS_ATTR_DELETED) { if (!written) { MemCpy(&ptr->start,&tmpde->start,CDIR_SIZE); BlkWrite(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_clus+j,1); written=TRUE; } } else { if (!StrCmp(tmpde->name,ptr->name)) { if (free_old_chain) RedSeaFreeClus(dv,ptr->clus, (ptr->size+BLK_SIZE-1)>>BLK_SIZE_BITS); if (!written) MemCpy(&ptr->start,&tmpde->start,CDIR_SIZE); else ptr->attr|=RS_ATTR_DELETED; BlkWrite(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_clus+j,1); break; } } ptr(U8 *)+=CDIR_SIZE; if (++i>=n) { j++; i=0; } } Free(buf); if (unlock) DrvUnlock(dv); if (unlock_break) BreakUnlock; } catch { if (unlock) DrvUnlock(dv); if (unlock_break) BreakUnlock; } return FALSE; } I64 RedSeaFilesDel(CDrv *dv,U8 *cur_dir,U8 *files_find_mask,I64 fuf_flags, Bool del_dir,Bool print_msg) { CDirEntry *buf,*buf2,*ptr; I64 i=0,res=0,ch,j=0,n=BLK_SIZE/CDIR_SIZE,cur_dir_clus; Bool unlock_break; try { unlock_break=BreakLock; DrvLock(dv); cur_dir_clus=Name2DirClus(dv,cur_dir); buf2=MAlloc(BLK_SIZE); BlkRead(dv,buf2,cur_dir_clus,1); ptr=buf2(U8 *)-offset(CDirEntry.start); buf=MAlloc(ptr->size); BlkRead(dv,buf,cur_dir_clus,ptr->size>>BLK_SIZE_BITS); Free(buf2); ptr=buf(U8 *)-offset(CDirEntry.start); *ptr->name='.'; ptr->name[1]=0; while (TRUE) { if (!(ch=*ptr->name)) break; else if (!(ptr->attr & RS_ATTR_DELETED) && ch!='.' && (del_dir || !(ptr->attr & RS_ATTR_DIR)) && FilesFindMatch(ptr->name,files_find_mask,fuf_flags)) { if (!(ptr->attr & RS_ATTR_DIR)) res++; if (print_msg) "Del %s\n",ptr->name; ptr->attr|=RS_ATTR_DELETED; BlkWrite(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_clus+j,1); RedSeaFreeClus(dv,ptr->clus, (ptr->size+BLK_SIZE-1)>>BLK_SIZE_BITS); } ptr(U8 *)+=CDIR_SIZE; if (++i>=n) { j++; i=0; } } Free(buf); DrvUnlock(dv); if (unlock_break) BreakUnlock; } catch { DrvUnlock(dv); if (unlock_break) BreakUnlock; } return res; } I64 RedSeaFileWrite(CDrv *dv,U8 *cur_dir,U8 *name,U8 *buf,I64 size, CDate cdt,I64 attr) { CDirEntry de; I64 c=0,blk_cnt; MemSet(&de,0,sizeof(CDirEntry)); if (size<0) size=0; if (dv->fs_type!=FSt_REDSEA) PrintErr("Not RedSea Drv\n"); else if (!CFileNameTo(de.name,name)) PrintErr("Invalid FileName: \"%s\".\n",name); else { RedSeaFilesDel(dv,cur_dir,de.name,0,FALSE,FALSE); de.size=size; if (blk_cnt=(size+BLK_SIZE-1)>>BLK_SIZE_BITS) c=ClusAlloc(dv,0,blk_cnt,TRUE); //Always contiguous else c=INVALID_CLUS; de.clus=c; de.attr=attr|RS_ATTR_CONTIGUOUS; de.datetime=cdt; if (blk_cnt) BlkWrite(dv,buf,c,blk_cnt); RedSeaDirNew(dv,cur_dir,&de,TRUE); } return c; } CDirEntry *RedSeaFilesFind(U8 *files_find_mask,I64 fuf_flags, CDirEntry *parent=NULL) { CDrv *dv=Fs->cur_dv; CDirEntry *buf,*buf2,*ptr,*res=NULL,*tmpde; I64 ch,cur_dir_clus; if (fuf_flags&~FUG_FILES_FIND) throw('FUF'); try { DrvLock(dv); cur_dir_clus=Name2DirClus(dv,Fs->cur_dir); buf2=MAlloc(BLK_SIZE); BlkRead(dv,buf2,cur_dir_clus,1); ptr=buf2(U8 *)-offset(CDirEntry.start); buf=MAlloc(ptr->size); BlkRead(dv,buf,cur_dir_clus,ptr->size>>BLK_SIZE_BITS); Free(buf2); ptr=buf(U8 *)-offset(CDirEntry.start); *ptr->name='.'; ptr->name[1]=0; ptr(U8 *)+=CDIR_SIZE; ptr->clus=Name2ParentDirClus(dv,Fs->cur_dir); ptr(U8 *)-=CDIR_SIZE; while (TRUE) { if (!(ch=*ptr->name)) break; else if (!(ptr->attr & RS_ATTR_DELETED)) { tmpde=CAlloc(sizeof(CDirEntry)); MemCpy(&tmpde->start,&ptr->start,CDIR_SIZE); tmpde->parent=parent; if (Bt(&fuf_flags,FUf_RECURSE) && tmpde->attr&RS_ATTR_DIR && *tmpde->name!='.') { tmpde->next=res; res=tmpde; tmpde->full_name=DirNameAbs(tmpde->name); DrvUnlock(dv); if (Cd(tmpde->name)) { tmpde->sub=RedSeaFilesFind(files_find_mask,fuf_flags,tmpde); Cd(".."); } DrvLock(dv); } else { tmpde->full_name=FileNameAbs(tmpde->name); if ((tmpde->attr&RS_ATTR_DIR || !Bt(&fuf_flags,FUf_JUST_DIRS)) && !(Bt(&fuf_flags,FUf_RECURSE) && *tmpde->name=='.' && tmpde->attr&RS_ATTR_DIR) && FilesFindMatch(tmpde->full_name,files_find_mask,fuf_flags)) { tmpde->next=res; res=tmpde; } else DirEntryDel(tmpde); } } ptr(U8 *)+=CDIR_SIZE; } Free(buf); DrvUnlock(dv); } catch DrvUnlock(dv); return res; } Bool RedSeaMkDir(CDrv *dv,U8 *cur_dir,U8 *name,I64 entry_cnt) {//entry_cnt is for preallocating dir blks. I64 c,cur_dir_clus=Name2DirClus(dv,cur_dir), size=CeilU64((entry_cnt+3)<<6,BLK_SIZE); #assert CDIR_SIZE==64 U8 *buf=CAlloc(size); CDirEntry *d_native=buf-offset(CDirEntry.start); Bool unlock_break; try { unlock_break=BreakLock; c=FileWrite(name,buf,size,0,RS_ATTR_DIR); d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS; StrCpy(d_native->name,name); d_native->clus=c; d_native->size=size; d_native->datetime=Now; d_native(U8 *)+=CDIR_SIZE; d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS; *d_native->name='.'; d_native->name[1]='.'; d_native->name[2]=0; d_native->clus=cur_dir_clus; d_native->size=0; d_native->datetime=Now; BlkWrite(dv,buf,c,1); Free(buf); if (unlock_break) BreakUnlock; } catch if (unlock_break) BreakUnlock; return TRUE; }