⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fat_write.c

📁 索尼公司著名游戏机PS2使用的引导工具文件源代码,这是爱好者自编的工具,可以使用它来引导自己的程序,达到跳过原光驱启动执行自己制作的程序的目的,在windows上可以安装使用ps2的专用开发包,搭建c
💻 C
📖 第 1 页 / 共 5 页
字号:

							}

						} 

						deIdx = 0;

						//clear name strings

						dir.sname[0] = 0;

						dir.name[0] = 0;

					} else {

						record[j] = 3;

						deIdx = 0;

					}

					break;

				case 2: record[j] = 2; //long name

					deSec[deIdx] = theSector;

					deOfs[deIdx] = dirPos;

					deIdx++;

					break; 

				case 3: record[j] = 0; //empty

					deIdx = 0;

					break; 

			}

			dirPos += 32; //directory entry of size 32 bytes

			j++;

		}

	}

	//indicate inconsistency

	if (j>= maxRecord) {

		j++;

	}

	return j;

}



/*

  check wether the new direntries (note: one file have at least 2 direntries for 1 SFN and 1..n LFN)

  fit into the current directory space. 

  Enlarges the directory space if needed and possible (note: root dirspace can't be enlarged for fat12 and fat16)



  startCluster - valid start cluster of dirpace or 0 for the root directory

  entryCount   - number of direntries of the filename (at least 2)

  entryIndex   - index where to store new direntries  

  direntrySize - number of all direntries in the directory

*/



int enlargeDirentryClusterSpace(fat_bpb* bpb, unsigned int startCluster, int entryCount, int entryIndex, int direntrySize) {

	int ret;

	int dirSector;

	unsigned int startSector;

	int clusterMod;

	int i;

	int maxSector;

	int entriesPerSector;

	int chainSize;

	unsigned int currentCluster;

	unsigned int newCluster;

	

	i = entryIndex + direntrySize;

	XPRINTF("cur=%d ecount=%d \n", i, entryCount);

	//we don't need to enlarge directory cluster space

	if (i <= entryCount) return 0; //direntry fits into current space



	entriesPerSector = bpb->sectorSize / 32;

	maxSector = i / entriesPerSector; 

	if (i%entriesPerSector) {	

		maxSector++;

	}



	chainSize = fat_getDirentrySectorData(bpb, &startCluster, &startSector, &dirSector);



	XPRINTF("maxSector=%d  dirSector=%d\n", maxSector, dirSector);



	if (maxSector<=dirSector) return 0;



	//Root directory of FAT12 or FAT16 - space can't be enlarged!

	if (startCluster == 0 && bpb->fatType < FAT32) { 

		return -EMLINK; //too many direntries in the root directory

	}



	//in the cbuf we have the cluster chain

#ifdef DEBUG

	fat_dumpClusterChain(cbuf, chainSize, 0);

#endif 

	//get last cluster of the cluster chain

	currentCluster = cbuf[chainSize-1];

	XPRINTF("current (last) cluster=%d \n", currentCluster);



	//get 1 cluster from cluster stack and append the chain

	newCluster = fat_getFreeCluster(bpb, currentCluster);

	XPRINTF("new cluster=%d \n", newCluster);

	fat_invalidateLastChainResult(); //prevent to misuse current (now updated) cbuf

	//if new cluster cannot be allocated

	if (newCluster == 0) {

		return -ENOSPC;

	}



	// now clean the directory space

	startSector = fat_cluster2sector(bpb, newCluster);

	for (i = 0; i < bpb->clusterSize; i++) {

		ret = ALLOC_SECTOR(startSector + i, sbuf);

		memset(sbuf, 0 , bpb->sectorSize); //fill whole sector with zeros

		ret = WRITE_SECTOR(startSector + i);

		if (ret < 0) return -EIO;

	}

	return 1; // 1 cluster allocated

}





/*

  Create direntries of the long and short filename to the supplied buffer.



  lname     : long name

  sname     : short name

  directory : 0-file, 1-directory

  buffer    : start of the data buffer where to store direntries

  cluster   : start cluster of the file/directory



  returns the number of the direntries (3 means: 2 entries for long name + 1 entry for short name)

  note: the filesize set in the direntry is 0 (for both directory and file)

*/

int createDirentry(unsigned char* lname, unsigned char* sname, char directory, unsigned int cluster, unsigned char* buffer) {

	int i;

	int lsize;

	int nameSize;

	unsigned char chsum;



	lsize = getDirentrySize(lname) - 1;

	chsum = computeNameChecksum(sname);

	nameSize = strlen((const char*) lname);

	//if the long name is longer than 8.3 chars then more than 1 lfn direntry have to be made

	for (i = 0; i <= lsize; i++) {

		setLfnEntry(lname, nameSize, chsum, buffer, lsize-i, lsize);

	}

	lsize++;

	//now create direntry of the short name right behind the long name direntries

	setSfnEntry(sname, directory, buffer + (lsize * 32), cluster);

	return lsize + 1;

}



/*

  Create empty directory space with two SFN direntries:

  1) current directory "."

  2) parent directory  ".."



*/

int createDirectorySpace(fat_bpb* bpb, unsigned int dirCluster, unsigned int parentDirCluster) {

	int i,j;

	int ret;

	unsigned int startSector;

	unsigned char name[11];



	//we do not mess with root directory

	if (dirCluster < 2) {

		return -EFAULT;

	}



	for (i = 0; i< 11; i++) name[i] = 32;

	name[0] = '.';

	setSfnEntry(name, 1, tbuf, dirCluster);

	name[1] = '.';

	setSfnEntry(name, 1, tbuf + 32, parentDirCluster);



#ifdef DEBUG

	fat_dumpSectorHex(tbuf, 64);

#endif





	//we create directory space inside one cluster. No need to worry about 

	//large dir space spread on multiple clusters

	startSector = fat_cluster2sector(bpb, dirCluster);

	XPRINTF("I: create dir space: cluster=%d sector=%d (%d) \n", dirCluster, startSector, startSector * bpb->sectorSize);



	//go through all sectors of the cluster

	for (i = 0; i < bpb->clusterSize; i++) {

		ret = READ_SECTOR(startSector + i, sbuf); 

		if (ret < 0) {

			printf("FAT writer: read directory sector failed ! sector=%i\n", startSector + i);

			return -EIO;

		}

		memset(sbuf, 0, bpb->sectorSize); //clean the sector

		if (i == 0) {

			memcpy(sbuf, tbuf, 64);

		}

		ret = WRITE_SECTOR(startSector + i); 

		if (ret < 0) {

			printf("FAT writer: write directory sector failed ! sector=%i\n", startSector + i);

			return -EIO;

		}

	}

	

}





/*

  save direntries stored in dbuf to the directory space on the disk

 

  startCluster - start cluster of the directory space

  dbuf         - direntry buffer

  entrySize    - number of direntries stored in the dbuf

  entryIndex   - index of the direntry start in the directory space



  retSector    - contains sector number of the direntry (output)

  retOffset    - contains byte offse of the SFN direntry from start of the sector (output)

  the reason is to speed up modification of the SFN (size of the file)



*/

int saveDirentry(fat_bpb* bpb, unsigned int startCluster, unsigned char * dbuf, int entrySize, int entryIndex, unsigned int* retSector, int* retOffset) {

	int i, j;

	int dirSector;

	unsigned int startSector;

	unsigned int theSector;

	int cont;

	int ret;

	int dirPos;

	int clusterMod;

	int entryEndIndex;

	int writeFlag;



	cont = 1;

	clusterMod = bpb->clusterSize - 1;

	//clear name strings

	entryEndIndex = entryIndex + entrySize;



	j = 0;



	fat_getDirentrySectorData(bpb, &startCluster, &startSector, &dirSector);



	XPRINTF("dirCluster=%i startSector=%i (%i) dirSector=%i \n", startCluster, startSector, startSector * Size_Sector, dirSector);



	//go through first directory sector till the max number of directory sectors

	//or stop when no more direntries detected

	for (i = 0; i < dirSector && cont; i++) {

		theSector = startSector + i;

		ret = READ_SECTOR(theSector, sbuf); 

		if (ret < 0) {

			printf("FAT writer: read directory sector failed ! sector=%i\n", theSector);

			return -EIO;

		}

		XPRINTF("read sector ok, scanning sector for direntries...\n");

		

		//prepare next sector: get correct sector from cluster chain buffer

		if ((startCluster != 0) && (i % bpb->clusterSize == clusterMod)) {

			startSector = fat_cluster2sector(bpb, cbuf[(i / bpb->clusterSize) +  1]);

			startSector -= (i+1);

		}

		dirPos = 0;

		writeFlag = 0;

		// go through start of the sector till the end of sector

		while (dirPos < bpb->sectorSize) {

			if (j >=entryIndex && j < entryEndIndex) {

				memcpy(sbuf + dirPos, dbuf + ((j-entryIndex)*32), 32);

				writeFlag++;

				//SFN is stored

				if (j == entryEndIndex-1) {

					*retSector = theSector;

					*retOffset = dirPos;

				}

			}

			//sbuf + dirPos

			dirPos += 32; //directory entry of size 32 bytes

			j++;

		}

		//store modified sector

		if (writeFlag) {

			ret = WRITE_SECTOR(theSector);

			if (ret < 0) {

				printf("FAT writer: write directory sector failed ! sector=%i\n", theSector);

				return -EIO;

			}

		}

		if (j >= entryEndIndex) {

			cont = 0; //do not continue

		}

	}

	return j;

}





/*

  - create/convert long name to short name

  - analyse directory space

  - enlarge directory space

  - save direntries



  lname         - long name

  directory     - 0-> create file  1->create directory

  escapeNoExist - 0->allways create file  1->early exit if file doesn't exist

  startCluster  - directory space start cluster (set to zero for root directory)

  retSector     - SFN sector - sector of the SFN direntry (output)

  retOffset     - byte offset of the SFN direntry counting from the start of the sector (output)

*/



int fat_modifyDirSpace(fat_bpb* bpb, unsigned char* lname, char directory, char escapeNotExist, unsigned int* startCluster, unsigned int* retSector, int* retOffset) {
	int ret;
	int i;
	unsigned char sname[12]; //short name 8+3 + terminator
	unsigned int newCluster;
	int entryCount;
	int compressShortName;
	int entryIndex;
	int direntrySize;

	//memo buffer for each direntry - up to 1024 entries in directory
	// 7 6 5 4 3 2 | 1 0
	// ------------+-----   
	// SEQ HI/LO   | ID
	// ------------------
	// ID : 0 - entry is empty or deleted 
	//      1 - sfn entry
	//      2 - lfn entry
	//      3 - other entry (volume label etc.)
	// SEQ: sequence number of the short filename.
	// if our long filename is "Quitelongname.txt" then
	// seq for existing entry:
	// ABCD.TXT     seq = 0 (no sequence number in name and name doesn't match)
	// ABCDEF~1.TXT seq = 0 (because the short names doesn't match)
	// QUITELON.TXT seq = 0 (again the short name doesn't match)
	// QUITEL~1.JPG seq = 0 (name match but extension desn't match)
	// QUITEL~1.TXT seq = 1 (both name and extension match - sequence number 1)
	// QUITE~85.TXT seq = 85 ( dtto. ^^^^)
	
	// If the sfn has sequence it means the filename should be long
	// and preceeding entry should be lfn. In this case the preceeding (lfn)
	// entry seq holds the high 6 bites of the whole sequence. If preceding 
	// entry is another sfn direntry then we report error (even if it might be
	// (in some rare occasions) correct directory structure).

	unsigned char entry[DIRENTRY_COUNT]; 
	memset(entry, 0, DIRENTRY_COUNT);
	sname[11] = 0;

	//create short name from long name
	ret = createShortNameMask(lname,sname);
	if (ret < 0) {
		XPRINTF("E: short name invalid!\n");
		return ret;
	}
	compressShortName = ret;
#ifdef DEBUG
	printf("compressShortName = %i\n", compressShortName);
#endif

	//get information about existing direntries (palcement of the empty/reusable direntries)
	//and sequence nubers of the short filenames
	ret = fat_fillDirentryInfo(bpb, lname, sname, directory, startCluster, entry, DIRENTRY_COUNT, retSector, retOffset);
	if (ret < 0) {
		XPRINTF("E: direntry data invalid!\n");
		return ret;
	}
	//ret 0 means that exact filename/directory already exist
	if (ret == 0) {
		return ret;		
	}

	//exact filename not exist and we want to report it
	if (escapeNotExist) {
		return -ENOENT;
	}

	if (ret > DIRENTRY_COUNT) {
		XPRINTF("W: Direntry count is larger than number of records!\n");
		ret = DIRENTRY_COUNT;
	}
	entryCount = ret;
	XPRINTF("I: direntry count=%d\n", entryCount);

#ifdef DEBUG
	for (i = 0; i < entryCount; i++) printf("%d ", entry[i]);
	printf("\n");
#endif

	if (compressShortName) {
		setShortNameSequence(entry, entryCount, sname);
	}
	XPRINTF("I: new short name='%s' \n", sname);

	//find the offset (index) of the direntry space where to put this direntry
	entryIndex = getDirentryStoreOffset(entry, entryCount, lname, &direntrySize);
	XPRINTF("I: direntry store offset=%d\n", entryIndex);

	//if the direntry offset excede current space of directory clusters
	//we have to add one cluster to directory space
	ret = enlargeDirentryClusterSpace(bpb, *startCluster, entryCount, entryIndex, direntrySize);
	XPRINTF("I: enlarge direntry cluster space ret=%d\n", ret);
	if (ret < 0) {
		return ret;
	}

	//get new cluster for file/directory
	newCluster = fat_getFreeCluster(bpb, 0);
	if (newCluster == 0) {
		return -EFAULT;
	}
	XPRINTF("I: new file/dir cluster=%d\n", newCluster);	

	//create direntry data to temporary buffer
	ret = createDirentry(lname, sname, directory, newCluster, tbuf);
	XPRINTF("I: create direntry to buf ret=%d\n", ret);
	if (ret < 0) {
		return ret;
	}
	direntrySize = ret;

#ifdef DEBUG
	fat_dumpSectorHex(tbuf, direntrySize * 32);
#endif

//	return -1;

	//now store direntries into the directory space
	ret = saveDirentry(bpb, *startCluster, tbuf, direntrySize, entryIndex, retSector, retOffset);
	XPRINTF("I: save direntry ret=%d\n", ret);
	if (ret < 0) {
		return ret;
	}

	//create empty directory structure 
	if (directory) {
		ret = createDirectorySpace(bpb, newCluster, *startCluster);
		XPRINTF("I: create directory space ret=%d\n", ret);
		if (ret < 0) {
			return ret;
		}
	}
	
	return 1;
}





/*

   Check wether directory space contain any file or directory



   startCluster - start cluster of the directory space



   returns: 0 - false - directory space contains files or directories (except '.' and '..')

            1 - true  - directory space is empty or contains deleted entries

           -X - error

*/

int checkDirspaceEmpty(fat_bpb* bpb, unsigned int startCluster, unsigned char* entry) {

	int ret;

	int i;

	unsigned char sname[12]; //short name 8+3 + terminator

	int entryCount;

//	int entryIndex;

	int direntrySize;



	unsigned int retSector;

	int retOffset;



	XPRINTF("I: checkDirspaceEmpty  directory cluster=%d \n", startCluster);

	if (startCluster < 2) {  // do not check root directory!

		return -EFAULT;

	}



	memset(entry, 0, DIRENTRY_COUNT);

	sname[0] = 0;

	



	ret = fat_fillDirentryInfo(bpb, sname, sname, 1, &startCluster, entry, DIRENTRY_COUNT, &retSector, &retOffset);

	if (ret > DIRENTRY_COUNT) {

		XPRINTF("W: Direntry count is larger than number of records! directory space cluster =%d maxRecords=%d\n", startCluster, DIRENTRY_COUNT);

		ret = DIRENTRY_COUNT;

	} 

	entryCount = ret;	



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -