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

📄 fs2.c

📁 支持nvram盘
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (!skip_erase) {
		// Unerased byte.
#ifndef __TESTENV__
		#asm
		FS_RESTORE_XPC2
		#endasm
#endif
		
		w.magic = FSMAGIC_F;		// Set to erased value (F-block)
		if (wblock) {
			memcpy(&w.w, maplog, sizeof(w.w));	// Save WLU header
			pw = paddr(&w);
			len = sizeof(FS_w) + 1;
			if (w.w.magic == FSMAGIC_W) {
				// Existing valid W-block.  Update erase counts
				if (wearlevel) {
					w.w.wear = wearlevel;
					w.w.rwear = 0;
				}
				else {
					w.w.wear++;
					w.w.rwear++;
					if (!w.w.rwear)
						w.w.rwear--;
				}
			}
			else /* if (w.w.magic != FSMAGIC_BAD) */ {
				// Not a valid W-block.  Set it to nominated wear.
				w.w.magic = FSMAGIC_W;
				if (wearlevel)
					w.w.wear = wearlevel;
				else
					w.w.wear = 1;
				w.w.rwear = 0;
				w.w.wlo_num = lxd->high_wlo;
			}
		}
		else {
			pw = paddr(&w.magic);
			len = sizeof(w.magic);
		}
		
		if (FS_IS_SSW(lxd)) {
			// Small-sector devices don't really have pure "erase" function, however rewriting
			// a sector with 0xFF makes sense when initially formating, when completely
			// deleting a file, or when shifting a file.  Only the magic ID is set to 0xFF.
			rc = FS_CALL_WRITE(lxd, pw, len, maplog);
		}
		else {
			rc = FS_CALL_ERASE(lxd, maplog);
			if (!rc)
				rc = FS_CALL_ANDOVER(lxd, pw, len, maplog);
		}
	}
	
#ifndef __TESTENV__
	#asm
	FS_RESTORE_XPC
	#endasm
#endif
	
	if (rc)
		_set_errno(EIO);	// I/O error
	return rc;
}


fs_nodebug root int fs_erase_logical(FS_lxd * lxd, FSLSnum ls, char * erased)
{
	// Erase a logical sector in the given LX.  Since LSs may be less than or equal PSs
	// (in the case of BW device class), greater than or equal (for SSW), or don't care
	// (for NVRAM), we have to handle each case separately.
	// If PS == 0, must be NVRAM device.  Mark LS as erased by setting magic number to 0xFF.
	// If LS < PS, must be a BW device.  We AND out the B- or H-block magic byte to FSMAGIC_DEL.
	// This marks the LS as deleted, however no physical erase is performed since we don't want
	// other LSs on this PS to be erased.  These LSs will be reclaimed when necessary.
	// If LS >= PS, is either BW or SSW.  In either case, we perform a physical erase of all
	// PSs within this LS.
	// Note that this routine does _not_ alter any of the lstab chains.
	// *erased is set to 1 if the underlying PS(s) were actually erased, or 0 if this LS
	// was only marked for erasure because the PS size was larger than the LS.
	auto FSPSnum p, i;
	auto char * maplog;
	auto long offs;
	auto FSmagic mag;
	auto long pmag;
	auto int rc;
	
	if (lxd->ps_per_ls) {
		*erased = 1;
		for (p = ls * lxd->ps_per_ls, i = 0;
		     i < lxd->ps_per_ls;
		     p++, i++)
			if (fs_erase_physical(lxd, p, 0))
				return 1;
		return 0;
	}
	
	// Must be BW or NVRAM.  Flip some bits.
	offs = FS_LS2OFFSET(lxd, ls);
	if (lxd->ps_size)
		mag = FSMAGIC_DEL, *erased = 0;
	else
		mag = FSMAGIC_F, *erased = 1;
	pmag = paddr(&mag);
	
#ifndef __TESTENV__
	#asm
	FS_SAVE_XPC
	#endasm
#endif
	
	maplog = FS_CALL_MAP(lxd, offs);
	if (lxd->wear_leveling)
		maplog += sizeof(FS_w);		// Skip W-block if necessary
	
	rc = FS_CALL_ANDOVER(lxd, pmag, sizeof(mag), maplog);

#ifndef __TESTENV__
	#asm
	FS_RESTORE_XPC
	#endasm
#endif
	
	if (rc)
		_set_errno(EIO);
	return rc;
}

#ifndef __TESTENV__
fs_nodebug void fs_erase_pbuf(word len)
{
	// Set _fs.pbuf to all 0xFF to make it look "erased".  len must be even and > 0.
	#asm xmemok
	ld	hl,(sp+@sp+len)
	rr	hl			; Convert to words
	ld	b,l
	ld	c,h		; CB is counter
	ld	a,b
	or	a
	jr	z,noinc
	inc c			; Inc to exit loop properly
noinc:
	ld	ix,(_fs_pbuf)	; Dest physical address
	ld	a,(_fs_pbuf+2)
	ld de,2		; Increment amount (word)
	ld	hl,0FFFFh	; Data to store
loop:
	ldp (ix),hl	; Put word
	add ix,de
	adc a,0			; Update bits 16-23 if wrap
	djnz	loop	; Count units
	dec c
	jr	nz,loop	; Count multiples of 256
	#endasm
}
#endif

fs_nodebug int fs_purge_file(FS_ef * ef)
{
	// Delete this file by freeing all blocks in both metadata and data chains.
	// This routine is called during initialisation, where a file has unrecoverable
	// inconsistencies, such as missing data or metadata or bad sequencing.
	if (ef->datalx)
  		fs_erase_chain(FS_LXN2PTR(ef->datalx), paddr(&ef->first_dls), FS_REALLY_ERASE, 0, 0, NULL);
	if (ef->metalx)
  		fs_erase_chain(FS_LXN2PTR(ef->metalx), paddr(&ef->first_mls), FS_REALLY_ERASE, 0, 0, NULL);
	// Delete the EF and eftab entry
	ef->in_use = 0;
	_fs.eftab[ef->name] = 0;
	return 0;
}

fs_nodebug int fs_erase_chain(FS_lxd * lxd, long lsp, unsigned flags, int max_count, 
						 FSseq while_seq, FSLSnum * count)
{
	// Erase a chain of LSs.  Each erased LS is put on the list of free LSs.
	// The free LS list is maintained in order of increasing wear count.
	// After each LS is "erased", the LS is moved to the free or deleted list
	// as appropriate.
	// On entry, lsp is the paddr of the entry which indicates the first actual
	// LS in the chain to be erased.  This is necessary to allow the chain 
	// pointers to be updated properly.  lsp need not point into the lstab,
	// however subsequent entries are assumed to be in the lstab.
	// flags indicates the halt conditions (one or more of the FSHALT_* bits)
	// with following parameters giving the halt condition parameters.  If flags
	// is zero, then all LSs in the chain are erased.
	// If count is not NULL, then that counter is decremented for every LS erased.
	auto FSLSnum zapls;			// LS currently being zapped
	auto long zapp;				// Physical address (paddr) of above lstab entry
	auto FSLSnum nextls;
	auto long nextp;
	auto char erased;
	auto int num_erased;
	auto FS_h hdr;

	TRACE(("erase_chain: flags=%x, max_count=%d, while_seq=%u, count=%u\n",
			flags, max_count, while_seq, count ? *count : -1));
	
	// prime the pipeline
	zapp = lsp;
	nextls = fs_lstabent(zapp);
	num_erased = 0;
	
	for (;;) {
		zapls = nextls;
		if (zapls == FS_INVALID_LS)
			break;	// End of chain.
		if (flags & FSHALT_COUNT && num_erased >= max_count)
			break;
		if (flags & FSHALT_SEQ) {
			fs_get_headers(lxd, zapls, NULL, &hdr, NULL);
			if (hdr.seq != while_seq)
				break;
		}
		nextp = FS_LSTABPHYS(lxd, zapls);
		nextls = fs_lstabent(nextp);
		fs_set_lstabent(lsp, nextls);	// Remove zapls from head of chain
		TRACE(("  removed LS %u\n", zapls));
		if (count)
			(*count)--;
		if (fs_free_logical(lxd, zapp, zapls))
			return 1;	// Maybe I/O error
		if (FS_IS_SSW(lxd) && flags & FS_REALLY_ERASE)
			fs_erase_logical(lxd, zapls, &erased);
		zapp = nextp;
		num_erased++;
	}
	
	return 0;
}

fs_nodebug int fs_expurgate(FS_lxd * lxd, FSfilenum fn)
{
	// This is only called when files on a SSW LX are deleted.  It scans the free
	// chain looking for LSs which used to belong to this file.  These LSs are
	// physically erased so that they won't get confused with blocks that belong
	// to the same file number (should it be re-created).  This is an unfortunate
	// necessity of our "lazy erase" strategy for SSW devices, however it is much
	// better than always physically erasing for any update.
	auto FSLSnum nextls;
	auto long nextp;
	auto char erased;
	auto FS_h hdr;

	TRACE(("fs_expurgate: lxn=%d fn=%d", (int)lxd->this, (int)fn));
	
	// prime the pipeline
	nextls = lxd->first_free;
	
	for (;;) {
		if (nextls == FS_INVALID_LS)
			break;	// End of chain.
		fs_get_headers(lxd, nextls, NULL, &hdr, NULL);
		if (hdr.filenum == fn)
			fs_erase_logical(lxd, nextls, &erased);
		nextp = FS_LSTABPHYS(lxd, nextls);
		nextls = fs_lstabent(nextp);
	}
	
	return 0;
}

fs_nodebug int fs_free_logical(FS_lxd * lxd, long lstabp, FSLSnum ls)
{
	// Send a logical sector to the free (or del) chain.
	// For SSW devices, we don't really need to erase the sector, since the version
	// number in the updated LS will be higher than this LS -- this is picked up
	// at fs_init time.  So, to save wear, we just put the LS on the free list without
	// really erasing it.
	auto char erased;
	
	TRACE(("fs_free_logical: ls=%d\n", (int)ls));
	
	if (FS_IS_SSW(lxd))
		erased = 1;	// Fake it
	else
		if (fs_erase_logical(lxd, ls, &erased))	
			return 1;
	if (erased) {
		fs_insert_chain(lxd, paddr(&lxd->first_free), ls);
		lxd->num_free++;
	}
	else {
		// Deleted, not erased, because this LS part of larger PS.
		fs_insert_chain(lxd, paddr(&lxd->first_deleted), ls);
		lxd->num_deleted++;
	}
	return 0;
}


/*** BeginHeader fs_verify_data, fs_get_meta, fs_read_data, fs_read_pbuf,
		fs_verify_headers, fs_compare_ls, fs_qsort, fs_find_create_ef, fs_init_lstab, fs_scan_file,
		fs_open, fs_locate */
root int fs_verify_data(FS_lxd * lxd, FSLSnum ls);
root FSoffset fs_get_meta(FS_lxd * lxd, FSLSnum ls, FS_h * hdr);
root int fs_read_data(FS_lxd * lxd, FSLSnum ls, FSoffset offs, char * buf, int len, 
							FSseq seq, FSfilenum name);
root int fs_read_pbuf(FS_lxd * lxd, long dev_offs, word len);
int fs_verify_headers(FS_lxd * lxd, FS_w * w, FS_h * h);
int fs_compare_ls(FS_lxd * lxd, FSLSnum a, FSLSnum b);
int fs_qsort(FS_lxd * lxd, long base, FSLSnum n);
FS_ef * fs_find_create_ef(FSfilenum name, FSLXnum mlx, FSLXnum dlx);
int fs_init_lstab(FS_lxd * lxd);
int fs_scan_file(FS_ef * ef);
int fs_open(File * f, FileNumber name);
int fs_locate(FS_ef * ef, long pos, FSLSnum * ls, FSoffset * offs, 
					long * lstabpp, FSseq * seq, FSLSnum * prevlsp);
/*** EndHeader */

fs_nodebug root int fs_verify_data(FS_lxd * lxd, FSLSnum ls)
{
	// Read the specified data LS then verify the final checksum.  This
	// function should only be called for B-blocks which are complete (i.e.
	// not the last in a file).
	// Returns 0 if OK, 1 if failed.
	auto char * maplog;
	auto FS_h * h;
	auto int rc;
#ifdef FS_DEBUG
	auto FSchecksum chk;
#endif
	
#ifndef __TESTENV__
	#asm
	FS_SAVE_XPC
	#endasm
#endif
	
	maplog = FS_CALL_MAP(lxd, FS_LS2OFFSET(lxd, ls));
	rc = fs_checksum(NULL, maplog, lxd->ls_size);

#ifdef FS_DEBUG
	if (rc) {
		chk = 0;
		fs_checksum(&chk, maplog, lxd->ls_size);
		printf("Bad complete data checksum: %x\n", chk);
	}
#endif
		
#ifndef __TESTENV__
	#asm
	FS_RESTORE_XPC
	#endasm
#endif
	
	return rc;
}

fs_nodebug root FSoffset fs_get_meta(FS_lxd * lxd, FSLSnum ls, FS_h * hdr)
{
	// Extract results from metadata LS.  *hdr is set up with initial H-block, then
	// the first_offs, first_seq, last_offs and last_chk are updated with the most recent
	// valid log entry.
	// Returns the next available offset in the metadata log.
	auto char * maplog;
	auto FS_l * lastlog;
	auto int rc;
	auto FS_l * log;
	auto FSoffset offs;
	
#ifndef __TESTENV__
	#asm
	FS_SAVE_XPC
	#endasm
#endif
	
	maplog = FS_CALL_MAP(lxd, FS_LS2OFFSET(lxd, ls));
	if (lxd->wear_leveling)
		maplog += sizeof(FS_w);
	memcpy(hdr, maplog, sizeof(*hdr));
	maplog += sizeof(*hdr);
	log = (FS_l *)maplog;
	lastlog = log + (lxd->d_size - FS_INIT_LOGOFFS) / sizeof(FS_l);
	while (log < lastlog) {
		if (log->log_chk == FS_INVALID_CHK || fs_checksum(NULL, log, sizeof(*log)))
			break;	// Bad entry checksum
		offs = log->new_offs & FS_OFFS_MASK;
		if (log->new_offs & FS_LOG_DEL) {
			hdr->first_offs = offs;
			hdr->first_seq = log->log_data;
		}
		else {
			hdr->last_offs = offs;
			hdr->last_chk = log->log_data;
		}
		log++;
	}
	
#ifndef __TESTENV__
	#asm
	FS_RESTORE_XPC
	#endasm
#endif
	
	return (FSoffset)((char *)log - maplog + FS_INIT_LOGOFFS);
}

fs_nodebug root int fs_read_data(FS_lxd * lxd, FSLSnum ls, FSoffset offs,
			char * buf, int len, FSseq seq, FSfilenum name)
{
	// Read given LS, starting at local offset, into buf of given length.
	// Returns actual number of chars read, which will be the lesser of len
	// and lxd->d_size - offs, or 0 if error.  buf must _not_ point into XPC window.
	// seq is the expected sequence number of ls.  If there is a mismatch, the read
	// 'works' but EBADSEQ will be set.  Similarly for the file number.
	auto char * maplog;
	auto int rc;
	
#ifndef __TESTENV__
	#asm
	FS_SAVE_XPC
	#endasm
#endif
	
	maplog = FS_CALL_MAP(lxd, FS_LS2OFFSET(lxd, ls));
	if (lxd->wear_leveling)
		maplog += sizeof(FS_w);
	
	if ((FSmagic)*maplog != FSMAGIC_B) {
		rc = 0;

⌨️ 快捷键说明

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