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

📄 fs2.c

📁 支持nvram盘
💻 C
📖 第 1 页 / 共 5 页
字号:
		_set_errno(ENOTB);
	}
	else {
		_set_errno(0);
		if (((FS_b *)maplog)->seq != seq)
			_set_errno(EBADSEQ);
		if (name && ((FS_b *)maplog)->filenum != name)
			_set_errno(EBADFNUM);
		maplog += sizeof(FS_b) + offs;
		rc = lxd->d_size - offs;
		if (rc > len)
			rc = len;
		memcpy(buf, maplog, rc);
	}
		
#ifndef __TESTENV__
	#asm
	FS_RESTORE_XPC
	#endasm
#endif
	
	return rc;
	
}

#ifndef __TESTENV__
fs_nodebug root int fs_read_pbuf(FS_lxd * lxd, long dev_offs, word len)
{
	// This is a bit tricky since can't use root2xmem.  However, can
	// take advantage of the even number of bytes (<= 8k).
	// len must be > 1.  _fs.pbuf must be even aligned to avoid ldp
	// wrap problems.
	#asm
	FS_SAVE_XPC
	
c	FS_CALL_MAP(lxd, dev_offs);
	ld	ix,hl		; Address of mapped area in XPC window
	ld	hl,(sp+@sp+len)
	or	a
	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	iy,(_fs_pbuf)	; Dest physical address
	ld	a,(_fs_pbuf+2)
	ld de,2		; Increment amount (word)
loop:
	ld	hl,(ix)	; Get word
	add ix,de
	ldp (iy),hl	; Put word
	add iy,de
	adc a,0			; Update bits 16-23 if wrap
	djnz	loop	; Count units
	dec c
	jr	nz,loop	; Count multiples of 256
		
	FS_RESTORE_XPC
	#endasm
	return 0;
}
#endif

fs_nodebug int fs_verify_headers(FS_lxd * lxd, FS_w * w, FS_h * h)
{
	// Verify header(s) using the appropriate checksum.  Returns 0 for OK,
	// 1 for fail.  LSs starting with a bad block indicator always return
	// 0 since this will prevent reformatting attempts.
	auto FSchecksum chk;
	auto FS_b * b;
	
	chk = 0;
	if (lxd->wear_leveling) {
		if (w->magic == FSMAGIC_BAD)
			return 0;
		fs_checksum(&chk, w, sizeof(*w));
	}
	switch (h->magic) {
	case FSMAGIC_H:
		return fs_checksum(&chk, h, sizeof(*h));
	case FSMAGIC_B:
		b = (FS_b *)h;
		return fs_checksum(&chk, b, sizeof(*b));
	case FSMAGIC_BAD:
		return lxd->wear_leveling;	// Bad only if wear-leveling
	case FSMAGIC_F:
		// If h is all 0xFF, we return
		// OK since freshly erased sectors are acceptable.  Otherwise, we would
		// mark it as deleted, which would waste time and money.  Note that this
		// presumes that if the headers are 0xFF, then the rest of the LS is
		// also erased.
		return fs_checksum(NULL, h, sizeof(h));	// Returns OK if all 0xFF.
	}
	return 1;		
}

// Overall LS block classes - this determines the overall sorting order.
#define FSBCLASS_FREE	1
#define FSBCLASS_BAD		2
#define FSBCLASS_B		3
#define FSBCLASS_H		4
#define FSBCLASS_DEL		5		// "Deleted" class must be highest numerically

#ifdef FS_BENCHMARK
static int lv, lvmax;
static long ncomp, nqsort, tt;
#endif

fs_nodebug int fs_compare_ls(FS_lxd * lxd, FSLSnum a, FSLSnum b)
{
	auto FS_w wa, wb;
	auto FS_h ha, hb;
	auto int rc;
	auto int aclass, bclass;
	auto char erased;
	auto long wdiff;

#ifdef FS_BENCHMARK
	ncomp++;
#endif

	fs_get_headers(lxd, a, NULL, &ha, &wa);
	fs_get_headers(lxd, b, NULL, &hb, &wb);
	
#define FS_MAGIC2CLASS(mag, class, lxd) \
	switch (mag) { \
		default:				class = FSBCLASS_BAD; break; \
		case FSMAGIC_F:	class = FSBCLASS_FREE; break; \
		case FSMAGIC_DEL:	class = lxd->ps_size <= lxd->ls_size ? FSBCLASS_FREE : FSBCLASS_DEL; break; \
		case FSMAGIC_BAD:	class = FSBCLASS_BAD; break; \
		case FSMAGIC_B:	class = FSBCLASS_B; break; \
		case FSMAGIC_H:	class = FSBCLASS_H; break; \
	}
	
	FS_MAGIC2CLASS(ha.magic, aclass, lxd)
	FS_MAGIC2CLASS(hb.magic, bclass, lxd)

	if (aclass != bclass)
		rc = aclass - bclass;
	else switch (aclass) {
		case FSBCLASS_FREE: case FSBCLASS_DEL:
			if (lxd->wear_leveling) {
				wdiff = wa.wear - wb.wear;
				if (wdiff > 0) {
					rc = 1; break;
				}
				if (wdiff < 0) {
					rc = -1; break;
				}
			}
			// fall through
		default:
			rc = (int)(a - b);
			break;
		case FSBCLASS_B: case FSBCLASS_H:
			rc = (int)(ha.filenum - hb.filenum);
			if (rc) break;
			rc = (short)(ha.seq - hb.seq);			// This works with wrap-around too, assuming
																// number in sequence <= sequence-max-length / 2.
			if (rc) break;
			// We don't handle version wrap-around
			if (hb.version > ha.version)
				rc = 1;
			else if (hb.version == ha.version)
				rc = (int)(a - b);
			else
				rc = -1;
			break;
	}

	return rc;
}


fs_nodebug int fs_qsort(FS_lxd * lxd, long base, FSLSnum n)
{
	auto FSLSnum i, j, piv, lo, hi, atpiv, temp;
	auto long pivot, p2;

#ifdef FS_BENCHMARK
	lv++;
	nqsort++;
	if (lv > lvmax) lvmax = lv;
#endif

	lo = 0;
	hi = n - 1;
	if (n == 2) {
		// Sort 2 elements quickly
		pivot = FS_LS2TABENT(base, 0);
		atpiv = fs_lstabent(pivot);
		p2 = FS_LS2TABENT(base, 1);
		temp = fs_lstabent(p2);
		if (fs_compare_ls(lxd, atpiv, temp) > 0) {
			fs_set_lstabent(pivot, temp);
			fs_set_lstabent(p2, atpiv);
		}
#ifdef FS_BENCHMARK
		lv--;
#endif
		return 0;
	}
	//if (lo < hi)		// This test omitted: caller must set n >= 2!
	//{
		piv = (lo + hi) >> 1; // center pivot
		i = lo;
		j = hi;
		pivot = FS_LS2TABENT(base, piv);
		atpiv = fs_lstabent(pivot);
		while (i < j)
		{
			while (i < j && fs_compare_ls(lxd, fs_lstabent(FS_LS2TABENT(base, i)), atpiv) <= 0)
				++i;
			while (i < j && fs_compare_ls(lxd, fs_lstabent(FS_LS2TABENT(base, j)), atpiv) >= 0)
				--j;
			if (i < j) {
				// Swap entries i, j.
				temp = fs_lstabent(FS_LS2TABENT(base, j));
				fs_set_lstabent(FS_LS2TABENT(base, j), fs_lstabent(FS_LS2TABENT(base, i)));
				fs_set_lstabent(FS_LS2TABENT(base, i), temp);
				atpiv = fs_lstabent(pivot);
			}
		}
		if (piv < i && fs_compare_ls(lxd, fs_lstabent(FS_LS2TABENT(base, i)), atpiv) > 0)
			--i;
		// Swap i and pivot
		if (i != piv) {
			fs_set_lstabent(pivot, fs_lstabent(FS_LS2TABENT(base, i)));
			fs_set_lstabent(FS_LS2TABENT(base, i), atpiv);
		}
		
		if ((int)(i - lo) <= (int)(hi - i))
		{                    // control stack
			if ((temp = i - lo) > 1) 
				fs_qsort(lxd, FS_LS2TABENT(base, lo), temp);
			if ((temp = hi - i) > 1) 
				fs_qsort(lxd, FS_LS2TABENT(base, i+1), temp);
		}
		else
		{
			if ((temp = hi - i) > 1) 
				fs_qsort(lxd, FS_LS2TABENT(base, i+1), temp);
			if ((temp = i - lo) > 1) 
				fs_qsort(lxd, FS_LS2TABENT(base, lo), temp);
		}
	//}

#ifdef FS_BENCHMARK
	lv--;
#endif
	return 0;
}

fs_nodebug FS_ef * fs_find_create_ef(FSfilenum name, FSLXnum mlx, FSLXnum dlx)
{
	// Find existing-file descriptor, or create if not found.  Returns NULL if
	// cannot create.  name is file number, mlx/dlx are LX numbers for metadata
	// and data respectively.  If either is zero, then anything matches.  If
	// the EF exists, but mlx/dlx disagree with the EF, return NULL.  For NULL
	// returns, errno will be set to EEXIST for mismatch with existing, or
	// ENFILE if no free entries remain.
	auto int i;
	auto FS_ef * ef;
	auto FSLXnum emlx, edlx;
	
	if (FS_EXISTS(name)) {
		ef = FS_EF_OF_FILE(name);
		_set_errno(EEXIST);
		emlx = ef->metalx;
		edlx = ef->datalx;
		if (mlx && emlx && emlx != mlx)
			return NULL;
		if (dlx && edlx && edlx != dlx)
			return NULL;
		if (!emlx)
			ef->metalx = mlx;
		if (!edlx)
			ef->datalx = dlx;
		return FS_EF_OF_FILE(name);
	}
	for (i = 1; i <= FS_MAX_FILES; i++) {
		ef = _fs.ef + i;
		if (!ef->in_use) {
			_fs.eftab[name] = (FSEFnum)i;
			memset(ef, 0, sizeof(*ef));
			ef->name = name;
			ef->in_use = 1;
			ef->metalx = mlx;
			ef->datalx = dlx;
			ef->attrs = 0xFF;	// FIXME: set appropriately
			ef->first_mls = FS_INVALID_LS;
			ef->first_dls = FS_INVALID_LS;
			return ef;
		} 
	}
	_set_errno(ENFILE);
	return NULL;
}

fs_nodebug int fs_init_lstab(FS_lxd * lxd)
{
	// Initialise the lstab by reading the header blocks of each LS.  The lstab itself is
	// already allocated.  A temporary buffer of the same size is allocated for the
	// purpose of sorting the lstab.  The sort is performed in order:
	//   Free (available) LSs
	//   Bad
	//   B-blocks
	//   H-blocks
	//   Deleted (i.e. freed LSs within larger PSs)
	// For H- and B-blocks, the subsequence is in order of file number, sequence number
	// within file, then version number within sequence.
	// For F- and DEL- blocks, the subsequence is in order of increasing wear level if
	// applicable or by LS number if not.  Wear levels for LSs which are not the first
	// in their PS (i.e. have dummy W-blocks) take the wear level of the first LS in the PS.
	// An initial pass is performed to verify that the LSs to be sorted have consistent
	// checksums - any which do not are erased if possible.  Then they are placed at the 
	// end of the table (with the DEL entries), and not sorted further.
	auto FS_w w, w1;
	auto FS_h h;
	auto long ttab;
	auto long ttabsize;
	auto FSLSnum i;
	auto int pclass, kclass;
	auto long lphy;
	auto FSLSnum * counter;
	auto FS_ef * ef;
	auto int igchain;
	auto FSLSnum ls;
	auto FSfilenum pfile;
	auto FSversion pvers;
	auto char erased;
	auto FSLSnum num_to_sort;
	auto FSLSnum num_deleted;
	

	ttab = xalloc(ttabsize = (long)sizeof(FSLSnum) * lxd->num_ls);
	if (!ttab) {
		_set_errno(ENOMEM);
		return 1;
	}
	
	// Perform an initial pass through the LX.  Look for bad header checksums and
	// erase those LSs.  Also look for uninitialised wear blocks: if found, set them
	// to wear count 1.
#ifdef FS_BENCHMARK
	tt = MS_TIMER;
#endif
	num_to_sort = 0;
	num_deleted = 0;
	for (i = 0; i < lxd->num_ls; i++) {
		fs_get_headers(lxd, i, &w, &h, &w1);
		if (fs_verify_headers(lxd, &w, &h)) {
			// Bad header checksum.
			TRACE(("Bad hdr chk LS %u\n", i));
			if (fs_erase_logical(lxd, i, &erased) || !erased) {
				// Put unerasable or deleted LSs at end of table (speeds sort).
				num_deleted++;
				fs_set_lstabent(FS_LS2TABENT(ttab, lxd->num_ls - num_deleted), i);
				continue;
			}
		}
		fs_set_lstabent(FS_LS2TABENT(ttab, num_to_sort), i);
		num_to_sort++;
	}
#ifdef FS_BENCHMARK
	tt = MS_TIMER - tt;
	printf("Took %ld ms to scan\n", tt);
#endif
	
	num_to_sort += num_deleted;	// Sort everything
	
	// Specialised qsort algorithm.
#ifdef FS_BENCHMARK
	lv = 0;
	lvmax = 0;
	nqsort = 0;
	ncomp = 0;
	tt = MS_TIMER;
#endif
	
	if (num_to_sort > 1)
		fs_qsort(lxd, ttab, num_to_sort);
		
#ifdef FS_BENCHMARK
	tt = MS_TIMER - tt;
	printf("Max qsort levels = %d, qsort entry=%ld, comparisons=%ld, time=%ld ms\n", lvmax, nqsort, ncomp, tt);
#endif
	
	// Scan the generated list, looking for 'breaks'.  Initialise the lstab.  After
	// this, the lstab file chains may include multiple LSs with the same seq but
	// different version.  The most recent version with valid checksum will be retained.
	igchain = 1;
	pclass = 0;
	lxd->first_free = FS_INVALID_LS;
	lxd->first_deleted = FS_INVALID_LS;
	lxd->first_bad = FS_INVALID_LS;
	lxd->num_free = 0;
	lxd->num_deleted = 0;
	lxd->num_bad = 0;
	for (i = 0; i < lxd->num_ls; i++) {
		ls = fs_lstabent(FS_LS2TABENT(ttab, i));	// Get sorted LS number
		fs_get_headers(lxd, ls, &w, &h, NULL);
		if (i >= num_to_sort)
			kclass = FSBCLASS_DEL;	// deleted
		else
			FS_MAGIC2CLASS(h.magic, kclass, lxd)
		if (kclass != pclass || (kclass == FSBCLASS_H || kclass == FSBCLASS_B) && h.filenum != pfile) {
			// New list starting.  Finish old list, start new
			if (!igchain)
				fs_set_lstabent(lphy, FS_INVALID_LS);
			pclass = kclass;
			pfile = h.filenum;
			igchain = 0;
			switch (kclass) {
				case FSBCLASS_FREE: lphy = paddr(&lxd->first_free); counter = &lxd->num_free; break;
				case FSBCLASS_DEL: lphy = paddr(&lxd->first_deleted); counter = &lxd->num_deleted; break;
				default: lphy = paddr(&lxd->first_bad); counter = &lxd->num_bad; break;
				case FSBCLASS_B:	// Data LSs
					ef = fs_find_create_ef(h.filenum, 0, FS_PTR2LXN(lxd));

⌨️ 快捷键说明

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