hschumann2/TempleOS-Source-Code
0847
1 2// See RedSea File System3 4U0 RedSeaFreeFreeLst(CDrv *dv)5{6 CFreeLst *tmpf,*tmpf1;7 Bool unlock;8 try {9 unlock=DrvLock(dv);10 if (tmpf=dv->next_free) {11 while (tmpf!=&dv->next_free) {12 tmpf1=tmpf->next;13 Free(tmpf);14 tmpf=tmpf1;15 }16 }17 dv->next_free=NULL;18 if (unlock)19 DrvUnlock(dv);20 } catch21 if (unlock)22 DrvUnlock(dv);23}24 25U0 RedSeaFreeLstBuild(CDrv *dv)26{27 Bool unlock;28 CFreeLst *tmpf;29 I64 i,first=dv->data_area,max_blk=dv->size+dv->drv_offset;30 try {31 unlock=DrvLock(dv);32 if (dv->next_free)33 RedSeaFreeFreeLst(dv);34 QueInit(&dv->next_free);35 while (first<max_blk) {36 i=0; //count free clus37 while (first+i<max_blk) {38 DrvFATBlkSet(dv,first+i);39 if (Bt(dv->cur_fat_blk,(first+i-dv->data_area)&(BLK_SIZE<<3-1)))40 break;41 else42 i++;43 }44 if (i) {45 tmpf=AMAlloc(sizeof(CFreeLst));46 tmpf->size=i;47 tmpf->start=first;48 QueIns(tmpf,dv->last_free);49 }50 first+=i+1;51 }52 if (unlock)53 DrvUnlock(dv);54 } catch55 if (unlock)56 DrvUnlock(dv);57}58 59U0 RedSeaInit(CDrv *dv)60{61 CRedSeaBoot br;62 Bool unlock;63 try {64 unlock=DrvLock(dv);65 BlkRead(dv,&br,dv->drv_offset,1);66 if (br.signature!=MBR_PT_REDSEA || br.signature2!=0xAA55)67 throw('Drv');68 dv->fs_type=FSt_REDSEA;69 RedSeaFreeFreeLst(dv);70 dv->spc=1;71 dv->size=br.sects;72 dv->data_area=dv->drv_offset+br.bitmap_sects;73 dv->root_clus=br.root_clus;74 dv->fat1=dv->fat2=dv->drv_offset+1;75 DrvFATBlkAlloc(dv);76 if (unlock)77 DrvUnlock(dv);78 } catch79 if (unlock)80 DrvUnlock(dv);81}82 83Bool RedSeaValidate(U8 drv_let)84{85 CDrv *dv;86 CRedSeaBoot br;87 if ((dv=Let2Drv(drv_let,FALSE)) && dv->fs_type==FSt_REDSEA &&88 BlkRead(dv,&br,dv->drv_offset,1) && br.signature==MBR_PT_REDSEA &&89 br.signature2==0xAA55 && br.sects==dv->size)90 return TRUE;91 else92 return FALSE;93}94 95U0 RedSeaFmt(U8 drv_let,Bool quick=TRUE)96{97 U8 *root_dir;98 CDirEntry *d_native;99 CRedSeaBoot *br=CAlloc(BLK_SIZE);100 CDrv *dv=Let2Drv(drv_let);101 I64 i,n,root_dir_blks;102 try {103 DrvLock(dv);104// DrvTypeSet(drv_let,FSt_REDSEA);105 DrvTypeSet(drv_let,FSt_FAT32);106 dv->fs_type=FSt_REDSEA;107 br->signature=MBR_PT_REDSEA;108 br->signature2=0xAA55;109 br->drv_offset=dv->drv_offset; //For CD/DVD image copy.110 br->sects=dv->size;111 n=(br->sects+BLK_SIZE<<3-1)/BLK_SIZE<<3;112 br->bitmap_sects=n;113 br->unique_id=GetTSC^Now()(U64);114 br->root_clus=0;115 116 if (quick)117 i=n+1;118 else119 i=dv->size;120 BlkWriteZero(dv,dv->drv_offset,i);121 122 BlkWrite(dv,br,dv->drv_offset,1);123 RedSeaInit(dv);124 ClusAlloc(dv,0,1,FALSE); //Alloc #1125 126 root_dir_blks=MaxI64(1,dv->bd->init_root_dir_blks);127 br->root_clus=ClusAlloc(dv,0,root_dir_blks,FALSE);128 BlkWrite(dv,br,dv->drv_offset,1);129 root_dir=CAlloc(BLK_SIZE*root_dir_blks);130 131 d_native=root_dir-offset(CDirEntry.start);132 133 d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS;134 *d_native->name='.';135 d_native->clus=br->root_clus;136 d_native->size=BLK_SIZE*root_dir_blks;137 d_native->datetime=Now;138 139 d_native(U8 *)+=CDIR_SIZE;140 141 *d_native->name='.';142 d_native->name[1]='.';143 d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS;144 d_native->clus=br->root_clus;145 d_native->datetime=Now;146 147 BlkWrite(dv,root_dir,br->root_clus,root_dir_blks);148 RedSeaInit(dv);149 DrvUnlock(dv);150 } catch151 DrvUnlock(dv);152 Free(br);153 Free(root_dir);154}155 156Bool RedSeaFileFind(CDrv *dv,I64 cur_dir_clus,U8 *name,157 CDirEntry *_res,I64 fuf_flags=0)158{//FUF_JUST_DIRS, FUF_JUST_FILES159 CDirEntry *buf,*buf2,*ptr;160 U8 dname[CDIR_FILENAME_LEN];161 I64 ch;162 Bool res=FALSE,unlock;163 if (fuf_flags&~FUG_FILE_FIND)164 throw('FUF');165 MemSet(_res,0,sizeof(CDirEntry));166 DrvChk(dv);167 if (dv->fs_type!=FSt_REDSEA)168 PrintErr("Not RedSea Drv\n");169 else if (!CFileNameTo(dname,name))170 PrintErr("Invalid FileName: \"%s\".\n",name);171 else172 try {173 unlock=DrvLock(dv);174 buf2=MAlloc(BLK_SIZE);175 BlkRead(dv,buf2,cur_dir_clus,1);176 177 ptr=buf2(U8 *)-offset(CDirEntry.start);178 buf=MAlloc(ptr->size);179 BlkRead(dv,buf,cur_dir_clus,ptr->size>>BLK_SIZE_BITS);180 Free(buf2);181 182 ptr=buf(U8 *)-offset(CDirEntry.start);183 *ptr->name='.';184 ptr->name[1]=0;185 while (TRUE) {186 if (!(ch=*ptr->name))187 break;188 else if (!(ptr->attr & RS_ATTR_DELETED) &&189 !(fuf_flags&FUF_JUST_DIRS && !(ptr->attr & RS_ATTR_DIR)) &&190 !(fuf_flags&FUF_JUST_FILES && ptr->attr & RS_ATTR_DIR) &&191 !StrCmp(dname,ptr->name)) {192 MemCpy(&_res->attr,&ptr->attr,CDIR_SIZE);193 res=TRUE;194 goto rsff_done;195 }196 ptr(U8 *)+=CDIR_SIZE;197 }198rsff_done:199 Free(buf);200 if (unlock)201 DrvUnlock(dv);202 } catch203 if (unlock)204 DrvUnlock(dv);205 return res;206}207 208U8 *RedSeaFileRead(CDrv *dv,U8 *cur_dir,U8 *filename,I64 *_size,I64 *_attr)209{210 U8 *buf=NULL;211 CDirEntry de;212 I64 c,blk_cnt,cur_dir_clus;213 DrvChk(dv);214 *_size=0;215 *_attr=0;216 if (dv->fs_type!=FSt_REDSEA)217 PrintErr("Not RedSea Drv\n");218 else219 try {220 DrvLock(dv);221 cur_dir_clus=Name2DirClus(dv,cur_dir);222 if (RedSeaFileFind(dv,cur_dir_clus,filename,&de,FUF_JUST_FILES)) {223 blk_cnt=(de.size+BLK_SIZE-1)>>BLK_SIZE_BITS;224 buf=MAlloc(blk_cnt<<BLK_SIZE_BITS+1);225 c=de.clus;226 c=BlkRead(dv,buf,c,blk_cnt);227 buf[de.size]=0; //Terminate228 *_size=de.size;229 *_attr=FileAttr(de.name,de.attr);230 }231 DrvUnlock(dv);232 } catch233 DrvUnlock(dv);234 return buf;235}236 237Bool RedSeaCd(U8 *name,I64 cur_dir_clus)238{239 CDirEntry de;240 if (Fs->cur_dv->fs_type!=FSt_REDSEA)241 PrintErr("Not RedSea Drv\n");242 else if (RedSeaFileFind(Fs->cur_dv,cur_dir_clus,name,&de,FUF_JUST_DIRS))243 return TRUE;244 else245 PrintErr("File not found: \"%s\".\n",name);246 return FALSE;247}248 249U0 RedSeaFreeClus(CDrv *dv,I64 c,I64 cnt)250{251 CFreeLst *tmpf;252 Bool found=FALSE,unlock,unlock_break;253 DrvChk(dv);254 if (!c) return;255 if (dv->fs_type!=FSt_REDSEA)256 PrintErr("Not RedSea Drv\n");257 else258 try {259 unlock_break=BreakLock;260 unlock=DrvLock(dv);261 if (!dv->next_free)262 RedSeaFreeLstBuild(dv);263 tmpf=dv->next_free;264 while (!found && tmpf!=&dv->next_free) {265 if (tmpf->start+tmpf->size==c) {266 tmpf->size+=cnt;267 found=TRUE;268 } else if (c+cnt==tmpf->start) {269 tmpf->size+=cnt;270 tmpf->start=c;271 found=TRUE;272 }273 tmpf=tmpf->next;274 }275 if (!found) {276 tmpf=AMAlloc(sizeof(CFreeLst));277 tmpf->size=cnt;278 tmpf->start=c;279 QueIns(tmpf,dv->last_free);280 }281 while (cnt-->0) {282 DrvFATBlkSet(dv,c);283 LBtr(dv->cur_fat_blk,(c-dv->data_area)&(BLK_SIZE<<3-1));284 LBts(&dv->fat_blk_dirty,0);285 c++;286 }287 DrvFATBlkClean(dv);288 289 if (unlock)290 DrvUnlock(dv);291 if (unlock_break)292 BreakUnlock;293 } catch {294 if (unlock)295 DrvUnlock(dv);296 if (unlock_break)297 BreakUnlock;298 }299}300 301I64 RedSeaAllocClus(CDrv *dv,I64 cnt)302{303 CFreeLst *tmpf,*best_free=NULL;304 I64 i,first,best_size=I64_MAX;305 Bool unlock,unlock_break;306 if (cnt<=0)307 throw('Drv');308 try {309 unlock_break=BreakLock;310 unlock=DrvLock(dv);311 if (!dv->next_free)312 RedSeaFreeLstBuild(dv);313 tmpf=dv->next_free;314 while (tmpf!=&dv->next_free) {315 if (tmpf->size>=cnt && tmpf->size<best_size) {316 best_free=tmpf;317 best_size=tmpf->size;318 if (tmpf->size==cnt)319 break;320 }321 tmpf=tmpf->next;322 }323 if (!best_free)324 throw('Drv');325 first=best_free->start;326 for (i=0;i<cnt;i++) {327 DrvFATBlkSet(dv,first+i);328 LBts(dv->cur_fat_blk,(first+i-dv->data_area)&(BLK_SIZE<<3-1));329 LBts(&dv->fat_blk_dirty,0);330 }331 DrvFATBlkClean(dv);332 if (best_free->size-=cnt)333 best_free->start+=cnt;334 else {335 QueRem(best_free);336 Free(best_free);337 }338 if (unlock)339 DrvUnlock(dv);340 if (unlock_break)341 BreakUnlock;342 } catch {343 if (unlock)344 DrvUnlock(dv);345 if (unlock_break)346 BreakUnlock;347 }348 return first;349}350 351Bool RedSeaDirNew(CDrv *dv,U8 *cur_dir,CDirEntry *tmpde,Bool free_old_chain)352{353 CDirEntry *buf,*buf2,*ptr,de2;354 CRedSeaBoot *br;355 I64 c,ch,i=1,j=0,n=BLK_SIZE/CDIR_SIZE,dir_size,cur_dir_clus;356 Bool written=FALSE,unlock,unlock_break;357 U8 *tmp,*parent_dir;358 try {359 unlock_break=BreakLock;360 tmpde->attr|=RS_ATTR_CONTIGUOUS;361 unlock=DrvLock(dv);362 cur_dir_clus=Name2DirClus(dv,cur_dir);363 buf2=MAlloc(BLK_SIZE);364 BlkRead(dv,buf2,cur_dir_clus,1);365 366 ptr=buf2(U8 *)-offset(CDirEntry.start);367 buf=MAlloc(ptr->size);368 BlkRead(dv,buf,cur_dir_clus,ptr->size>>BLK_SIZE_BITS);369 370 dir_size=ptr->size;371 ptr=buf(U8 *)-offset(CDirEntry.start)+CDIR_SIZE;372 Free(buf2);373 while (TRUE) {374 if (!(ch=*ptr->name)) {375 if (!written)376 MemCpy(&ptr->start,&tmpde->start,CDIR_SIZE);377 if ((i+1)*CDIR_SIZE+j<<BLK_SIZE_BITS<dir_size)378 BlkWrite(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_clus+j,1);379 else {380 buf2=CAlloc(dir_size+BLK_SIZE);381 MemCpy(buf2,buf,dir_size);382 RedSeaFreeClus(dv,cur_dir_clus,dir_size>>BLK_SIZE_BITS);383 dir_size+=BLK_SIZE;384 c=ClusAlloc(dv,0,dir_size>>BLK_SIZE_BITS,TRUE);385 Free(buf);386 buf=buf2;387 ptr=buf(U8 *)-offset(CDirEntry.start);388 ptr->size=dir_size;389 ptr->clus=c;390 BlkWrite(dv,buf,c,dir_size>>BLK_SIZE_BITS);391 if (cur_dir_clus==dv->root_clus) {392 br=CAlloc(BLK_SIZE);393 BlkRead(dv,br,dv->drv_offset,1);394 br->root_clus=c;395 BlkWrite(dv,br,dv->drv_offset,1);396 Free(br);397 dv->root_clus=c;398 } else {399 tmp=StrNew(cur_dir);400 parent_dir=StrNew(cur_dir);401 StrLastRem(parent_dir,"/",tmp);402 if (!*parent_dir) {403 Free(parent_dir);404 parent_dir=StrNew("/");405 }406 if (RedSeaFileFind(dv,Name2DirClus(dv,parent_dir),407 tmp,&de2,FUF_JUST_DIRS)) {408 de2.clus=c;409 de2.size=dir_size;410 RedSeaDirNew(dv,parent_dir,&de2,FALSE);411 } else412 throw('Drv');413 Free(tmp);414 Free(parent_dir);415 }416 }417 break;418 } else if (ptr->attr & RS_ATTR_DELETED) {419 if (!written) {420 MemCpy(&ptr->start,&tmpde->start,CDIR_SIZE);421 BlkWrite(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_clus+j,1);422 written=TRUE;423 }424 } else {425 if (!StrCmp(tmpde->name,ptr->name)) {426 if (free_old_chain)427 RedSeaFreeClus(dv,ptr->clus,428 (ptr->size+BLK_SIZE-1)>>BLK_SIZE_BITS);429 if (!written)430 MemCpy(&ptr->start,&tmpde->start,CDIR_SIZE);431 else432 ptr->attr|=RS_ATTR_DELETED;433 BlkWrite(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_clus+j,1);434 break;435 }436 }437 ptr(U8 *)+=CDIR_SIZE;438 if (++i>=n) {439 j++;440 i=0;441 }442 }443 Free(buf);444 if (unlock)445 DrvUnlock(dv);446 if (unlock_break)447 BreakUnlock;448 } catch {449 if (unlock)450 DrvUnlock(dv);451 if (unlock_break)452 BreakUnlock;453 }454 return FALSE;455}456 457I64 RedSeaFilesDel(CDrv *dv,U8 *cur_dir,U8 *files_find_mask,I64 fuf_flags,458 Bool del_dir,Bool print_msg)459{460 CDirEntry *buf,*buf2,*ptr;461 I64 i=0,res=0,ch,j=0,n=BLK_SIZE/CDIR_SIZE,cur_dir_clus;462 Bool unlock_break;463 try {464 unlock_break=BreakLock;465 DrvLock(dv);466 cur_dir_clus=Name2DirClus(dv,cur_dir);467 buf2=MAlloc(BLK_SIZE);468 BlkRead(dv,buf2,cur_dir_clus,1);469 470 ptr=buf2(U8 *)-offset(CDirEntry.start);471 buf=MAlloc(ptr->size);472 BlkRead(dv,buf,cur_dir_clus,ptr->size>>BLK_SIZE_BITS);473 Free(buf2);474 475 ptr=buf(U8 *)-offset(CDirEntry.start);476 *ptr->name='.';477 ptr->name[1]=0;478 while (TRUE) {479 if (!(ch=*ptr->name))480 break;481 else if (!(ptr->attr & RS_ATTR_DELETED) && ch!='.' && (del_dir ||482 !(ptr->attr & RS_ATTR_DIR)) &&483 FilesFindMatch(ptr->name,files_find_mask,fuf_flags)) {484 if (!(ptr->attr & RS_ATTR_DIR)) res++;485 if (print_msg)486 "Del %s\n",ptr->name;487 ptr->attr|=RS_ATTR_DELETED;488 BlkWrite(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_clus+j,1);489 RedSeaFreeClus(dv,ptr->clus,490 (ptr->size+BLK_SIZE-1)>>BLK_SIZE_BITS);491 }492 ptr(U8 *)+=CDIR_SIZE;493 if (++i>=n) {494 j++;495 i=0;496 }497 }498 Free(buf);499 DrvUnlock(dv);500 if (unlock_break)501 BreakUnlock;502 } catch {503 DrvUnlock(dv);504 if (unlock_break)505 BreakUnlock;506 }507 return res;508}509 510I64 RedSeaFileWrite(CDrv *dv,U8 *cur_dir,U8 *name,U8 *buf,I64 size,511 CDate cdt,I64 attr)512{513 CDirEntry de;514 I64 c=0,blk_cnt;515 MemSet(&de,0,sizeof(CDirEntry));516 if (size<0) size=0;517 if (dv->fs_type!=FSt_REDSEA)518 PrintErr("Not RedSea Drv\n");519 else if (!CFileNameTo(de.name,name))520 PrintErr("Invalid FileName: \"%s\".\n",name);521 else {522 RedSeaFilesDel(dv,cur_dir,de.name,0,FALSE,FALSE);523 de.size=size;524 if (blk_cnt=(size+BLK_SIZE-1)>>BLK_SIZE_BITS)525 c=ClusAlloc(dv,0,blk_cnt,TRUE); //Always contiguous526 else527 c=INVALID_CLUS;528 de.clus=c;529 de.attr=attr|RS_ATTR_CONTIGUOUS;530 de.datetime=cdt;531 if (blk_cnt)532 BlkWrite(dv,buf,c,blk_cnt);533 RedSeaDirNew(dv,cur_dir,&de,TRUE);534 }535 return c;536}537 538CDirEntry *RedSeaFilesFind(U8 *files_find_mask,I64 fuf_flags,539 CDirEntry *parent=NULL)540{541 CDrv *dv=Fs->cur_dv;542 CDirEntry *buf,*buf2,*ptr,*res=NULL,*tmpde;543 I64 ch,cur_dir_clus;544 if (fuf_flags&~FUG_FILES_FIND)545 throw('FUF');546 try {547 DrvLock(dv);548 cur_dir_clus=Name2DirClus(dv,Fs->cur_dir);549 buf2=MAlloc(BLK_SIZE);550 BlkRead(dv,buf2,cur_dir_clus,1);551 552 ptr=buf2(U8 *)-offset(CDirEntry.start);553 buf=MAlloc(ptr->size);554 BlkRead(dv,buf,cur_dir_clus,ptr->size>>BLK_SIZE_BITS);555 Free(buf2);556 557 ptr=buf(U8 *)-offset(CDirEntry.start);558 *ptr->name='.';559 ptr->name[1]=0;560 ptr(U8 *)+=CDIR_SIZE;561 ptr->clus=Name2ParentDirClus(dv,Fs->cur_dir);562 ptr(U8 *)-=CDIR_SIZE;563 while (TRUE) {564 if (!(ch=*ptr->name))565 break;566 else if (!(ptr->attr & RS_ATTR_DELETED)) {567 tmpde=CAlloc(sizeof(CDirEntry));568 MemCpy(&tmpde->start,&ptr->start,CDIR_SIZE);569 tmpde->parent=parent;570 if (Bt(&fuf_flags,FUf_RECURSE) && tmpde->attr&RS_ATTR_DIR &&571 *tmpde->name!='.') {572 tmpde->next=res;573 res=tmpde;574 tmpde->full_name=DirNameAbs(tmpde->name);575 DrvUnlock(dv);576 if (Cd(tmpde->name)) {577 tmpde->sub=RedSeaFilesFind(files_find_mask,fuf_flags,tmpde);578 Cd("..");579 }580 DrvLock(dv);581 } else {582 tmpde->full_name=FileNameAbs(tmpde->name);583 if ((tmpde->attr&RS_ATTR_DIR ||584 !Bt(&fuf_flags,FUf_JUST_DIRS)) &&585 !(Bt(&fuf_flags,FUf_RECURSE) && *tmpde->name=='.' &&586 tmpde->attr&RS_ATTR_DIR) &&587 FilesFindMatch(tmpde->full_name,files_find_mask,fuf_flags)) {588 tmpde->next=res;589 res=tmpde;590 } else591 DirEntryDel(tmpde);592 }593 }594 ptr(U8 *)+=CDIR_SIZE;595 }596 Free(buf);597 DrvUnlock(dv);598 } catch599 DrvUnlock(dv);600 return res;601}602 603Bool RedSeaMkDir(CDrv *dv,U8 *cur_dir,U8 *name,I64 entry_cnt)604{//entry_cnt is for preallocating dir blks.605 I64 c,cur_dir_clus=Name2DirClus(dv,cur_dir),606 size=CeilU64((entry_cnt+3)<<6,BLK_SIZE);607#assert CDIR_SIZE==64608 U8 *buf=CAlloc(size);609 CDirEntry *d_native=buf-offset(CDirEntry.start);610 Bool unlock_break;611 try {612 unlock_break=BreakLock;613 c=FileWrite(name,buf,size,0,RS_ATTR_DIR);614 d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS;615 StrCpy(d_native->name,name);616 d_native->clus=c;617 d_native->size=size;618 d_native->datetime=Now;619 d_native(U8 *)+=CDIR_SIZE;620 621 d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS;622 *d_native->name='.';623 d_native->name[1]='.';624 d_native->name[2]=0;625 d_native->clus=cur_dir_clus;626 d_native->size=0;627 d_native->datetime=Now;628 BlkWrite(dv,buf,c,1);629 Free(buf);630 if (unlock_break)631 BreakUnlock;632 } catch633 if (unlock_break)634 BreakUnlock;635 return TRUE;636}637 