8f079d6dd917984d13cf62ec9baad0eff40ba7d9
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

1) /*
2) 	DOSFS Embedded FAT-Compatible Filesystem
3) 	(C) 2005 Lewin A.R.W. Edwards (sysadm@zws.com)
4) 
5) 	You are permitted to modify and/or use this code in your own projects without
6) 	payment of royalty, regardless of the license(s) you choose for those projects.
7) 
8) 	You cannot re-copyright or restrict use of the code as released by Lewin Edwards.
9) */
10) 
11) #include <string.h>
12) #include <stdlib.h>
13) 
14) #include "dosfs.h"
15) 
16) /*
17) 	Get starting sector# of specified partition on drive #unit
18) 	NOTE: This code ASSUMES an MBR on the disk.
19) 	scratchsector should point to a SECTOR_SIZE scratch area
20) 	Returns 0xffffffff for any error.
21) 	If pactive is non-NULL, this function also returns the partition active flag.
22) 	If pptype is non-NULL, this function also returns the partition type.
23) 	If psize is non-NULL, this function also returns the partition size.
24) */
25) uint32_t DFS_GetPtnStart(uint8_t unit, uint8_t *scratchsector, uint8_t pnum, uint8_t *pactive, uint8_t *pptype, uint32_t *psize)
26) {
Stefan Schuermans bugfix patches from the for...

Stefan Schuermans authored 12 years ago

27) 	uint32_t result = 0;
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

28) 	PMBR mbr = (PMBR) scratchsector;
29) 
30) 	// DOS ptable supports maximum 4 partitions
31) 	if (pnum > 3)
32) 		return DFS_ERRMISC;
33) 
34) 	// Read MBR from target media
35) 	if (DFS_ReadSector(unit,scratchsector,0,1)) {
36) 		return DFS_ERRMISC;
37) 	}
38) 
39) 	result = (uint32_t) mbr->ptable[pnum].start_0 |
40) 	  (((uint32_t) mbr->ptable[pnum].start_1) << 8) |
41) 	  (((uint32_t) mbr->ptable[pnum].start_2) << 16) |
42) 	  (((uint32_t) mbr->ptable[pnum].start_3) << 24);
43) 
44) 	if (pactive)
45) 		*pactive = mbr->ptable[pnum].active;
46) 
47) 	if (pptype)
48) 		*pptype = mbr->ptable[pnum].type;
49) 
50) 	if (psize)
51) 		*psize = (uint32_t) mbr->ptable[pnum].size_0 |
52) 		  (((uint32_t) mbr->ptable[pnum].size_1) << 8) |
53) 		  (((uint32_t) mbr->ptable[pnum].size_2) << 16) |
54) 		  (((uint32_t) mbr->ptable[pnum].size_3) << 24);
55) 
56) 	return result;
57) }
58) 
59) 
60) /*
61) 	Retrieve volume info from BPB and store it in a VOLINFO structure
62) 	You must provide the unit and starting sector of the filesystem, and
63) 	a pointer to a sector buffer for scratch
64) 	Attempts to read BPB and glean information about the FS from that.
65) 	Returns 0 OK, nonzero for any error.
66) */
67) uint32_t DFS_GetVolInfo(uint8_t unit, uint8_t *scratchsector, uint32_t startsector, PVOLINFO volinfo)
68) {
69) 	PLBR lbr = (PLBR) scratchsector;
70) 	volinfo->unit = unit;
71) 	volinfo->startsector = startsector;
72) 
73) 	if(DFS_ReadSector(unit,scratchsector,startsector,1))
74) 		return DFS_ERRMISC;
75) 
76) // tag: OEMID, refer dosfs.h
77) //	strncpy(volinfo->oemid, lbr->oemid, 8);
78) //	volinfo->oemid[8] = 0;
79) 
80) 	volinfo->secperclus = lbr->bpb.secperclus;
81) 	volinfo->reservedsecs = (uint16_t) lbr->bpb.reserved_l |
82) 		  (((uint16_t) lbr->bpb.reserved_h) << 8);
83) 
84) 	volinfo->numsecs =  (uint16_t) lbr->bpb.sectors_s_l |
85) 		  (((uint16_t) lbr->bpb.sectors_s_h) << 8);
86) 
87) 	if (!volinfo->numsecs)
88) 		volinfo->numsecs = (uint32_t) lbr->bpb.sectors_l_0 |
89) 		  (((uint32_t) lbr->bpb.sectors_l_1) << 8) |
90) 		  (((uint32_t) lbr->bpb.sectors_l_2) << 16) |
91) 		  (((uint32_t) lbr->bpb.sectors_l_3) << 24);
92) 
93) 	// If secperfat is 0, we must be in a FAT32 volume; get secperfat
94) 	// from the FAT32 EBPB. The volume label and system ID string are also
95) 	// in different locations for FAT12/16 vs FAT32.
96) 	volinfo->secperfat =  (uint16_t) lbr->bpb.secperfat_l |
97) 		  (((uint16_t) lbr->bpb.secperfat_h) << 8);
98) 	if (!volinfo->secperfat) {
99) 		volinfo->secperfat = (uint32_t) lbr->ebpb.ebpb32.fatsize_0 |
100) 		  (((uint32_t) lbr->ebpb.ebpb32.fatsize_1) << 8) |
101) 		  (((uint32_t) lbr->ebpb.ebpb32.fatsize_2) << 16) |
102) 		  (((uint32_t) lbr->ebpb.ebpb32.fatsize_3) << 24);
103) 
104) 		memcpy(volinfo->label, lbr->ebpb.ebpb32.label, 11);
105) 		volinfo->label[11] = 0;
106) 	
107) // tag: OEMID, refer dosfs.h
108) //		memcpy(volinfo->system, lbr->ebpb.ebpb32.system, 8);
109) //		volinfo->system[8] = 0; 
110) 	}
111) 	else {
112) 		memcpy(volinfo->label, lbr->ebpb.ebpb.label, 11);
113) 		volinfo->label[11] = 0;
114) 	
115) // tag: OEMID, refer dosfs.h
116) //		memcpy(volinfo->system, lbr->ebpb.ebpb.system, 8);
117) //		volinfo->system[8] = 0; 
118) 	}
119) 
120) 	// note: if rootentries is 0, we must be in a FAT32 volume.
121) 	volinfo->rootentries =  (uint16_t) lbr->bpb.rootentries_l |
122) 		  (((uint16_t) lbr->bpb.rootentries_h) << 8);
123) 
124) 	// after extracting raw info we perform some useful precalculations
125) 	volinfo->fat1 = startsector + volinfo->reservedsecs;
126) 
127) 	// The calculation below is designed to round up the root directory size for FAT12/16
128) 	// and to simply ignore the root directory for FAT32, since it's a normal, expandable
129) 	// file in that situation.
130) 	if (volinfo->rootentries) {
131) 		volinfo->rootdir = volinfo->fat1 + (volinfo->secperfat * 2);
132) 		volinfo->dataarea = volinfo->rootdir + (((volinfo->rootentries * 32) + (SECTOR_SIZE - 1)) / SECTOR_SIZE);
133) 	}
134) 	else {
135) 		volinfo->dataarea = volinfo->fat1 + (volinfo->secperfat * 2);
136) 		volinfo->rootdir = (uint32_t) lbr->ebpb.ebpb32.root_0 |
137) 		  (((uint32_t) lbr->ebpb.ebpb32.root_1) << 8) |
138) 		  (((uint32_t) lbr->ebpb.ebpb32.root_2) << 16) |
139) 		  (((uint32_t) lbr->ebpb.ebpb32.root_3) << 24);
140) 	}
141) 
142) 	// Calculate number of clusters in data area and infer FAT type from this information.
143) 	volinfo->numclusters = (volinfo->numsecs - volinfo->dataarea) / volinfo->secperclus;
144) 	if (volinfo->numclusters < 4085)
145) 		volinfo->filesystem = FAT12;
146) 	else if (volinfo->numclusters < 65525)
147) 		volinfo->filesystem = FAT16;
148) 	else
149) 		volinfo->filesystem = FAT32;
150) 
151) 	return DFS_OK;
152) }
153) 
154) /*
155) 	Fetch FAT entry for specified cluster number
156) 	You must provide a scratch buffer for one sector (SECTOR_SIZE) and a populated VOLINFO
157) 	Returns a FAT32 BAD_CLUSTER value for any error, otherwise the contents of the desired
158) 	FAT entry.
159) 	scratchcache should point to a UINT32. This variable caches the physical sector number
160) 	last read into the scratch buffer for performance enhancement reasons.
161) */
162) uint32_t DFS_GetFAT(PVOLINFO volinfo, uint8_t *scratch, uint32_t *scratchcache, uint32_t cluster)
163) {
Stefan Schuermans bugfix patches from the for...

Stefan Schuermans authored 12 years ago

164) 	uint32_t offset = 0, sector = 0, result = 0;
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

165) 
166) 	if (volinfo->filesystem == FAT12) {
167) 		offset = cluster + (cluster / 2);
168) 	}
169) 	else if (volinfo->filesystem == FAT16) {
170) 		offset = cluster * 2;
171) 	}
172) 	else if (volinfo->filesystem == FAT32) {
173) 		offset = cluster * 4;
174) 	}
175) 	else
176) 		return 0x0ffffff7;	// FAT32 bad cluster	
177) 
178) 	// at this point, offset is the BYTE offset of the desired sector from the start
179) 	// of the FAT. Calculate the physical sector containing this FAT entry.
180) 	sector = ldiv(offset, SECTOR_SIZE).quot + volinfo->fat1;
181) 
182) 	// If this is not the same sector we last read, then read it into RAM
183) 	if (sector != *scratchcache) {
184) 		if(DFS_ReadSector(volinfo->unit, scratch, sector, 1)) {
185) 			// avoid anyone assuming that this cache value is still valid, which
186) 			// might cause disk corruption
187) 			*scratchcache = 0;
188) 			return 0x0ffffff7;	// FAT32 bad cluster	
189) 		}
190) 		*scratchcache = sector;
191) 	}
192) 
193) 	// At this point, we "merely" need to extract the relevant entry.
194) 	// This is easy for FAT16 and FAT32, but a royal PITA for FAT12 as a single entry
195) 	// may span a sector boundary. The normal way around this is always to read two
196) 	// FAT sectors, but that luxury is (by design intent) unavailable to DOSFS.
197) 	offset = ldiv(offset, SECTOR_SIZE).rem;
198) 
199) 	if (volinfo->filesystem == FAT12) {
200) 		// Special case for sector boundary - Store last byte of current sector.
201) 		// Then read in the next sector and put the first byte of that sector into
202) 		// the high byte of result.
203) 		if (offset == SECTOR_SIZE - 1) {
204) 			result = (uint32_t) scratch[offset];
205) 			sector++;
206) 			if(DFS_ReadSector(volinfo->unit, scratch, sector, 1)) {
207) 				// avoid anyone assuming that this cache value is still valid, which
208) 				// might cause disk corruption
209) 				*scratchcache = 0;
210) 				return 0x0ffffff7;	// FAT32 bad cluster	
211) 			}
212) 			*scratchcache = sector;
213) 			// Thanks to Claudio Leonel for pointing out this missing line.
214) 			result |= ((uint32_t) scratch[0]) << 8;
215) 		}
216) 		else {
217) 			result = (uint32_t) scratch[offset] |
218) 			  ((uint32_t) scratch[offset+1]) << 8;
219) 		}
220) 		if (cluster & 1)
221) 			result = result >> 4;
222) 		else
223) 			result = result & 0xfff;
224) 	}
225) 	else if (volinfo->filesystem == FAT16) {
226) 		result = (uint32_t) scratch[offset] |
227) 		  ((uint32_t) scratch[offset+1]) << 8;
228) 	}
229) 	else if (volinfo->filesystem == FAT32) {
230) 		result = ((uint32_t) scratch[offset] |
231) 		  ((uint32_t) scratch[offset+1]) << 8 |
232) 		  ((uint32_t) scratch[offset+2]) << 16 |
233) 		  ((uint32_t) scratch[offset+3]) << 24) & 0x0fffffff;
234) 	}
235) 	else
236) 		result = 0x0ffffff7;	// FAT32 bad cluster	
237) 	return result;
238) }
239) 
240) 
241) /*
242) 	Set FAT entry for specified cluster number
243) 	You must provide a scratch buffer for one sector (SECTOR_SIZE) and a populated VOLINFO
244) 	Returns DFS_ERRMISC for any error, otherwise DFS_OK
245) 	scratchcache should point to a UINT32. This variable caches the physical sector number
246) 	last read into the scratch buffer for performance enhancement reasons.
247) 
248) 	NOTE: This code is HIGHLY WRITE-INEFFICIENT, particularly for flash media. Considerable
249) 	performance gains can be realized by caching the sector. However this is difficult to
250) 	achieve on FAT12 without requiring 2 sector buffers of scratch space, and it is a design
251) 	requirement of this code to operate on a single 512-byte scratch.
252) 
253) 	If you are operating DOSFS over flash, you are strongly advised to implement a writeback
254) 	cache in your physical I/O driver. This will speed up your code significantly and will
255) 	also conserve power and flash write life.
256) */
257) uint32_t DFS_SetFAT(PVOLINFO volinfo, uint8_t *scratch, uint32_t *scratchcache, uint32_t cluster, uint32_t new_contents)
258) {
Stefan Schuermans bugfix patches from the for...

Stefan Schuermans authored 12 years ago

259) 	uint32_t offset = 0, sector = 0, result = 0;
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

260) 	if (volinfo->filesystem == FAT12) {
261) 		offset = cluster + (cluster / 2);
262) 		new_contents &=0xfff;
263) 	}
264) 	else if (volinfo->filesystem == FAT16) {
265) 		offset = cluster * 2;
266) 		new_contents &=0xffff;
267) 	}
268) 	else if (volinfo->filesystem == FAT32) {
269) 		offset = cluster * 4;
270) 		new_contents &=0x0fffffff;	// FAT32 is really "FAT28"
271) 	}
272) 	else
273) 		return DFS_ERRMISC;	
274) 
275) 	// at this point, offset is the BYTE offset of the desired sector from the start
276) 	// of the FAT. Calculate the physical sector containing this FAT entry.
277) 	sector = ldiv(offset, SECTOR_SIZE).quot + volinfo->fat1;
278) 
279) 	// If this is not the same sector we last read, then read it into RAM
280) 	if (sector != *scratchcache) {
281) 		if(DFS_ReadSector(volinfo->unit, scratch, sector, 1)) {
282) 			// avoid anyone assuming that this cache value is still valid, which
283) 			// might cause disk corruption
284) 			*scratchcache = 0;
285) 			return DFS_ERRMISC;
286) 		}
287) 		*scratchcache = sector;
288) 	}
289) 
290) 	// At this point, we "merely" need to extract the relevant entry.
291) 	// This is easy for FAT16 and FAT32, but a royal PITA for FAT12 as a single entry
292) 	// may span a sector boundary. The normal way around this is always to read two
293) 	// FAT sectors, but that luxury is (by design intent) unavailable to DOSFS.
294) 	offset = ldiv(offset, SECTOR_SIZE).rem;
295) 
296) 	if (volinfo->filesystem == FAT12) {
297) 
298) 		// If this is an odd cluster, pre-shift the desired new contents 4 bits to
299) 		// make the calculations below simpler
300) 		if (cluster & 1)
301) 			new_contents = new_contents << 4;
302) 
303) 		// Special case for sector boundary
304) 		if (offset == SECTOR_SIZE - 1) {
305) 
306) 			// Odd cluster: High 12 bits being set
307) 			if (cluster & 1) {
308) 				scratch[offset] = (scratch[offset] & 0x0f) | (new_contents & 0xf0);
309) 			}
310) 			// Even cluster: Low 12 bits being set
311) 			else {
312) 				scratch[offset] = new_contents & 0xff;
313) 			}
314) 			result = DFS_WriteSector(volinfo->unit, scratch, *scratchcache, 1);
315) 			// mirror the FAT into copy 2
316) 			if (DFS_OK == result)
317) 				result = DFS_WriteSector(volinfo->unit, scratch, (*scratchcache)+volinfo->secperfat, 1);
318) 
319) 			// If we wrote that sector OK, then read in the subsequent sector
320) 			// and poke the first byte with the remainder of this FAT entry.
321) 			if (DFS_OK == result) {
322) 				scratchcache++;
323) 				result = DFS_ReadSector(volinfo->unit, scratch, *scratchcache, 1);
324) 				if (DFS_OK == result) {
325) 					// Odd cluster: High 12 bits being set
326) 					if (cluster & 1) {
327) 						scratch[0] = new_contents & 0xff00;
328) 					}
329) 					// Even cluster: Low 12 bits being set
330) 					else {
331) 						scratch[0] = (scratch[0] & 0xf0) | (new_contents & 0x0f);
332) 					}
333) 					result = DFS_WriteSector(volinfo->unit, scratch, *scratchcache, 1);
334) 					// mirror the FAT into copy 2
335) 					if (DFS_OK == result)
336) 						result = DFS_WriteSector(volinfo->unit, scratch, (*scratchcache)+volinfo->secperfat, 1);
337) 				}
338) 				else {
339) 					// avoid anyone assuming that this cache value is still valid, which
340) 					// might cause disk corruption
341) 					*scratchcache = 0;
342) 				}
343) 			}
344) 		} // if (offset == SECTOR_SIZE - 1)
345) 
346) 		// Not a sector boundary. But we still have to worry about if it's an odd
347) 		// or even cluster number.
348) 		else {
349) 			// Odd cluster: High 12 bits being set
350) 			if (cluster & 1) {
351) 				scratch[offset] = (scratch[offset] & 0x0f) | (new_contents & 0xf0);
352) 				scratch[offset+1] = new_contents & 0xff00;
353) 			}
354) 			// Even cluster: Low 12 bits being set
355) 			else {
356) 				scratch[offset] = new_contents & 0xff;
357) 				scratch[offset+1] = (scratch[offset+1] & 0xf0) | (new_contents & 0x0f);
358) 			}
359) 			result = DFS_WriteSector(volinfo->unit, scratch, *scratchcache, 1);
360) 			// mirror the FAT into copy 2
361) 			if (DFS_OK == result)
362) 				result = DFS_WriteSector(volinfo->unit, scratch, (*scratchcache)+volinfo->secperfat, 1);
363) 		}
364) 	}
365) 	else if (volinfo->filesystem == FAT16) {
366) 		scratch[offset] = (new_contents & 0xff);
367) 		scratch[offset+1] = (new_contents & 0xff00) >> 8;
368) 		result = DFS_WriteSector(volinfo->unit, scratch, *scratchcache, 1);
369) 		// mirror the FAT into copy 2
370) 		if (DFS_OK == result)
371) 			result = DFS_WriteSector(volinfo->unit, scratch, (*scratchcache)+volinfo->secperfat, 1);
372) 	}
373) 	else if (volinfo->filesystem == FAT32) {
374) 		scratch[offset] = (new_contents & 0xff);
375) 		scratch[offset+1] = (new_contents & 0xff00) >> 8;
376) 		scratch[offset+2] = (new_contents & 0xff0000) >> 16;
377) 		scratch[offset+3] = (scratch[offset+3] & 0xf0) | ((new_contents & 0x0f000000) >> 24);
378) 		// Note well from the above: Per Microsoft's guidelines we preserve the upper
379) 		// 4 bits of the FAT32 cluster value. It's unclear what these bits will be used
380) 		// for; in every example I've encountered they are always zero.
381) 		result = DFS_WriteSector(volinfo->unit, scratch, *scratchcache, 1);
Stefan Schuermans bugfix patches from the for...

Stefan Schuermans authored 12 years ago

382) 		// mirror the FAT into copy 2 - XXX
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

383) 		if (DFS_OK == result)
384) 			result = DFS_WriteSector(volinfo->unit, scratch, (*scratchcache)+volinfo->secperfat, 1);
385) 	}
386) 	else
387) 		result = DFS_ERRMISC;
388) 
389) 	return result;
390) }
391) 
392) /*
393) 	Convert a filename element from canonical (8.3) to directory entry (11) form
394) 	src must point to the first non-separator character.
395) 	dest must point to a 12-byte buffer.
396) */
397) uint8_t *DFS_CanonicalToDir(uint8_t *dest, uint8_t *src)
398) {
399) 	uint8_t *destptr = dest;
400) 
401) 	memset(dest, ' ', 11);
402) 	dest[11] = 0;
403) 
404) 	while (*src && (*src != DIR_SEPARATOR) && (destptr - dest < 11)) {
405) 		if (*src >= 'a' && *src <='z') {
406) 			*destptr++ = (*src - 'a') + 'A';
407) 			src++;
408) 		}
409) 		else if (*src == '.') {
410) 			src++;
411) 			destptr = dest + 8;
412) 		}
413) 		else {
414) 			*destptr++ = *src++;
415) 		}
416) 	}
417) 
418) 	return dest;
419) }
420) 
421) /*
422) 	Find the first unused FAT entry
423) 	You must provide a scratch buffer for one sector (SECTOR_SIZE) and a populated VOLINFO
424) 	Returns a FAT32 BAD_CLUSTER value for any error, otherwise the contents of the desired
425) 	FAT entry.
426) 	Returns FAT32 bad_sector (0x0ffffff7) if there is no free cluster available
427) */
428) uint32_t DFS_GetFreeFAT(PVOLINFO volinfo, uint8_t *scratch)
429) {
430) 	uint32_t i, result = 0xffffffff, scratchcache = 0;
431) 	
432) 	// Search starts at cluster 2, which is the first usable cluster
433) 	// NOTE: This search can't terminate at a bad cluster, because there might
434) 	// legitimately be bad clusters on the disk.
435) 	for (i=2; i < volinfo->numclusters; i++) {
436) 		result = DFS_GetFAT(volinfo, scratch, &scratchcache, i);
437) 		if (!result) {
438) 			return i;
439) 		}
440) 	}
441) 	return 0x0ffffff7;		// Can't find a free cluster
442) }
443) 
444) 
445) /*
446) 	Open a directory for enumeration by DFS_GetNextDirEnt
447) 	You must supply a populated VOLINFO (see DFS_GetVolInfo)
448) 	The empty string or a string containing only the directory separator are
449) 	considered to be the root directory.
450) 	Returns 0 OK, nonzero for any error.
451) */
452) uint32_t DFS_OpenDir(PVOLINFO volinfo, uint8_t *dirname, PDIRINFO dirinfo)
453) {
454) 	// Default behavior is a regular search for existing entries
455) 	dirinfo->flags = 0;
456) 
457) 	if (!strlen((char *) dirname) || (strlen((char *) dirname) == 1 && dirname[0] == DIR_SEPARATOR)) {
458) 		if (volinfo->filesystem == FAT32) {
459) 			dirinfo->currentcluster = volinfo->rootdir;
460) 			dirinfo->currentsector = 0;
461) 			dirinfo->currententry = 0;
462) 
463) 			// read first sector of directory
464) 			return DFS_ReadSector(volinfo->unit, dirinfo->scratch, volinfo->dataarea + ((volinfo->rootdir - 2) * volinfo->secperclus), 1);
465) 		}
466) 		else {
467) 			dirinfo->currentcluster = 0;
468) 			dirinfo->currentsector = 0;
469) 			dirinfo->currententry = 0;
470) 
471) 			// read first sector of directory
472) 			return DFS_ReadSector(volinfo->unit, dirinfo->scratch, volinfo->rootdir, 1);
473) 		}
474) 	}
475) 
476) 	// This is not the root directory. We need to find the start of this subdirectory.
477) 	// We do this by devious means, using our own companion function DFS_GetNext.
478) 	else {
479) 		uint8_t tmpfn[12];
480) 		uint8_t *ptr = dirname;
481) 		uint32_t result;
482) 		DIRENT de;
483) 
484) 		if (volinfo->filesystem == FAT32) {
485) 			dirinfo->currentcluster = volinfo->rootdir;
486) 			dirinfo->currentsector = 0;
487) 			dirinfo->currententry = 0;
488) 
489) 			// read first sector of directory
490) 			if (DFS_ReadSector(volinfo->unit, dirinfo->scratch, volinfo->dataarea + ((volinfo->rootdir - 2) * volinfo->secperclus), 1))
491) 				return DFS_ERRMISC;
492) 		}
493) 		else {
494) 			dirinfo->currentcluster = 0;
495) 			dirinfo->currentsector = 0;
496) 			dirinfo->currententry = 0;
497) 
498) 			// read first sector of directory
499) 			if (DFS_ReadSector(volinfo->unit, dirinfo->scratch, volinfo->rootdir, 1))
500) 				return DFS_ERRMISC;
501) 		}
502) 
503) 		// skip leading path separators
504) 		while (*ptr == DIR_SEPARATOR && *ptr)
505) 			ptr++;
506) 
507) 		// Scan the path from left to right, finding the start cluster of each entry
508) 		// Observe that this code is inelegant, but obviates the need for recursion.
509) 		while (*ptr) {
510) 			DFS_CanonicalToDir(tmpfn, ptr);
511) 
512) 			de.name[0] = 0;
513) 
514) 			do {
515) 				result = DFS_GetNext(volinfo, dirinfo, &de);
516) 			} while (!result && memcmp(de.name, tmpfn, 11));
517) 
518) 			if (!memcmp(de.name, tmpfn, 11) && ((de.attr & ATTR_DIRECTORY) == ATTR_DIRECTORY)) {
519) 				if (volinfo->filesystem == FAT32) {
520) 					dirinfo->currentcluster = (uint32_t) de.startclus_l_l |
521) 					  ((uint32_t) de.startclus_l_h) << 8 |
522) 					  ((uint32_t) de.startclus_h_l) << 16 |
523) 					  ((uint32_t) de.startclus_h_h) << 24;
524) 				}
525) 				else {
526) 					dirinfo->currentcluster = (uint32_t) de.startclus_l_l |
527) 					  ((uint32_t) de.startclus_l_h) << 8;
528) 				}
529) 				dirinfo->currentsector = 0;
530) 				dirinfo->currententry = 0;
531) 
532) 				if (DFS_ReadSector(volinfo->unit, dirinfo->scratch, volinfo->dataarea + ((dirinfo->currentcluster - 2) * volinfo->secperclus), 1))
533) 					return DFS_ERRMISC;
534) 			}
535) 			else if (!memcmp(de.name, tmpfn, 11) && !(de.attr & ATTR_DIRECTORY))
536) 				return DFS_NOTFOUND;
537) 
538) 			// seek to next item in list
539) 			while (*ptr != DIR_SEPARATOR && *ptr)
540) 				ptr++;
541) 			if (*ptr == DIR_SEPARATOR)
542) 				ptr++;
543) 		}
544) 
545) 		if (!dirinfo->currentcluster)
546) 			return DFS_NOTFOUND;
547) 	}
548) 	return DFS_OK;
549) }
550) 
551) /*
552) 	Get next entry in opened directory structure. Copies fields into the dirent
553) 	structure, updates dirinfo. Note that it is the _caller's_ responsibility to
554) 	handle the '.' and '..' entries.
555) 	A deleted file will be returned as a NULL entry (first char of filename=0)
556) 	by this code. Filenames beginning with 0x05 will be translated to 0xE5
557) 	automatically. Long file name entries will be returned as NULL.
558) 	returns DFS_EOF if there are no more entries, DFS_OK if this entry is valid,
559) 	or DFS_ERRMISC for a media error
560) */
561) uint32_t DFS_GetNext(PVOLINFO volinfo, PDIRINFO dirinfo, PDIRENT dirent)
562) {
563) 	uint32_t tempint;	// required by DFS_GetFAT
564) 
565) 	// Do we need to read the next sector of the directory?
566) 	if (dirinfo->currententry >= SECTOR_SIZE / sizeof(DIRENT)) {
567) 		dirinfo->currententry = 0;
568) 		dirinfo->currentsector++;
569) 
570) 		// Root directory; special case handling 
571) 		// Note that currentcluster will only ever be zero if both:
572) 		// (a) this is the root directory, and
573) 		// (b) we are on a FAT12/16 volume, where the root dir can't be expanded
574) 		if (dirinfo->currentcluster == 0) {
575) 			// Trying to read past end of root directory?
576) 			if (dirinfo->currentsector * (SECTOR_SIZE / sizeof(DIRENT)) >= volinfo->rootentries)
577) 				return DFS_EOF;
578) 
579) 			// Otherwise try to read the next sector
580) 			if (DFS_ReadSector(volinfo->unit, dirinfo->scratch, volinfo->rootdir + dirinfo->currentsector, 1))
581) 				return DFS_ERRMISC;
582) 		}
583) 
584) 		// Normal handling
585) 		else {
586) 			if (dirinfo->currentsector >= volinfo->secperclus) {
587) 				dirinfo->currentsector = 0;
588) 				if ((dirinfo->currentcluster >= 0xff7 &&  volinfo->filesystem == FAT12) ||
589) 				  (dirinfo->currentcluster >= 0xfff7 &&  volinfo->filesystem == FAT16) ||
590) 				  (dirinfo->currentcluster >= 0x0ffffff7 &&  volinfo->filesystem == FAT32)) {
591) 				  
592) 				  	// We are at the end of the directory chain. If this is a normal
593) 				  	// find operation, we should indicate that there is nothing more
594) 				  	// to see.
595) 				  	if (!(dirinfo->flags & DFS_DI_BLANKENT))
596) 						return DFS_EOF;
597) 					
598) 					// On the other hand, if this is a "find free entry" search,
599) 					// we need to tell the caller to allocate a new cluster
600) 					else
601) 						return DFS_ALLOCNEW;
602) 				}
603) 				dirinfo->currentcluster = DFS_GetFAT(volinfo, dirinfo->scratch, &tempint, dirinfo->currentcluster);
604) 			}
605) 			if (DFS_ReadSector(volinfo->unit, dirinfo->scratch, volinfo->dataarea + ((dirinfo->currentcluster - 2) * volinfo->secperclus) + dirinfo->currentsector, 1))
606) 				return DFS_ERRMISC;
607) 		}
608) 	}
609) 
610) 	memcpy(dirent, &(((PDIRENT) dirinfo->scratch)[dirinfo->currententry]), sizeof(DIRENT));
611) 
612) 	if (dirent->name[0] == 0) {		// no more files in this directory
613) 		// If this is a "find blank" then we can reuse this name.
614) 		if (dirinfo->flags & DFS_DI_BLANKENT)
615) 			return DFS_OK;
616) 		else
617) 			return DFS_EOF;
618) 	}
619) 
620) 	if (dirent->name[0] == 0xe5)	// handle deleted file entries
621) 		dirent->name[0] = 0;
622) 	else if ((dirent->attr & ATTR_LONG_NAME) == ATTR_LONG_NAME)
623) 		dirent->name[0] = 0;
624) 	else if (dirent->name[0] == 0x05)	// handle kanji filenames beginning with 0xE5
625) 		dirent->name[0] = 0xe5;
626) 
627) 	dirinfo->currententry++;
628) 
629) 	return DFS_OK;
630) }
631) 
632) /*
633) 	INTERNAL
634) 	Find a free directory entry in the directory specified by path
635) 	This function MAY cause a disk write if it is necessary to extend the directory
636) 	size.
637) 	Note - di.scratch must be preinitialized to point to a sector scratch buffer
638) 	de is a scratch structure
639) 	Returns DFS_ERRMISC if a new entry could not be located or created
640) 	de is updated with the same return information you would expect from DFS_GetNext
641) */
642) uint32_t DFS_GetFreeDirEnt(PVOLINFO volinfo, uint8_t *path, PDIRINFO di, PDIRENT de)
643) {
Stefan Schuermans bugfix patches from the for...

Stefan Schuermans authored 12 years ago

644) 	uint32_t tempclus = 0, i = 0;
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

645) 
646) 	if (DFS_OpenDir(volinfo, path, di))
647) 		return DFS_NOTFOUND;
648) 
649) 	// Set "search for empty" flag so DFS_GetNext knows what we're doing
650) 	di->flags |= DFS_DI_BLANKENT;
651) 
652) 	// We seek through the directory looking for an empty entry
653) 	// Note we are reusing tempclus as a temporary result holder.
654) 	tempclus = 0;	
655) 	do {
656) 		tempclus = DFS_GetNext(volinfo, di, de);
657) 
658) 		// Empty entry found
659) 		if (tempclus == DFS_OK && (!de->name[0])) {
660) 			return DFS_OK;
661) 		}
662) 
663) 		// End of root directory reached
664) 		else if (tempclus == DFS_EOF)
665) 			return DFS_ERRMISC;
666) 			
667) 		else if (tempclus == DFS_ALLOCNEW) {
668) 			tempclus = DFS_GetFreeFAT(volinfo, di->scratch);
669) 			if (tempclus == 0x0ffffff7)
670) 				return DFS_ERRMISC;
671) 
672) 			// write out zeroed sectors to the new cluster
673) 			memset(di->scratch, 0, SECTOR_SIZE);
674) 			for (i=0;i<volinfo->secperclus;i++) {
675) 				if (DFS_WriteSector(volinfo->unit, di->scratch, volinfo->dataarea + ((tempclus - 2) * volinfo->secperclus) + i, 1))
676) 					return DFS_ERRMISC;
677) 			}
678) 			// Point old end cluster to newly allocated cluster
679) 			i = 0;
680) 			DFS_SetFAT(volinfo, di->scratch, &i, di->currentcluster, tempclus);
681) 
682) 			// Update DIRINFO so caller knows where to place the new file			
683) 			di->currentcluster = tempclus;
684) 			di->currentsector = 0;
685) 			di->currententry = 1;	// since the code coming after this expects to subtract 1
686) 			
687) 			// Mark newly allocated cluster as end of chain			
688) 			switch(volinfo->filesystem) {
689) 				case FAT12:		tempclus = 0xff8;	break;
690) 				case FAT16:		tempclus = 0xfff8;	break;
691) 				case FAT32:		tempclus = 0x0ffffff8;	break;
692) 				default:		return DFS_ERRMISC;
693) 			}
694) 			DFS_SetFAT(volinfo, di->scratch, &i, di->currentcluster, tempclus);
695) 		}
696) 	} while (!tempclus);
697) 
698) 	// We shouldn't get here
699) 	return DFS_ERRMISC;
700) }
701) 
702) /*
703) 	Open a file for reading or writing. You supply populated VOLINFO, a path to the file,
704) 	mode (DFS_READ or DFS_WRITE) and an empty fileinfo structure. You also need to
705) 	provide a pointer to a sector-sized scratch buffer.
706) 	Returns various DFS_* error states. If the result is DFS_OK, fileinfo can be used
707) 	to access the file from this point on.
708) */
709) uint32_t DFS_OpenFile(PVOLINFO volinfo, uint8_t *path, uint8_t mode, uint8_t *scratch, PFILEINFO fileinfo)
710) {
711) 	uint8_t tmppath[MAX_PATH];
712) 	uint8_t filename[12];
713) 	uint8_t *p;
714) 	DIRINFO di;
715) 	DIRENT de;
716) 
717) 	// larwe 2006-09-16 +1 zero out file structure
718) 	memset(fileinfo, 0, sizeof(FILEINFO));
719) 
720) 	// save access mode
721) 	fileinfo->mode = mode;
722) 
723) 	// Get a local copy of the path. If it's longer than MAX_PATH, abort.
724) 	strncpy((char *) tmppath, (char *) path, MAX_PATH);
725) 	tmppath[MAX_PATH - 1] = 0;
726) 	if (strcmp((char *) path,(char *) tmppath)) {
727) 		return DFS_PATHLEN;
728) 	}
729) 
730) 	// strip leading path separators
731) 	while (tmppath[0] == DIR_SEPARATOR)
732) 		strcpy((char *) tmppath, (char *) tmppath + 1);
733) 
734) 	// Parse filename off the end of the supplied path
735) 	p = tmppath;
736) 	while (*(p++));
737) 
738) 	p--;
739) 	while (p > tmppath && *p != DIR_SEPARATOR) // larwe 9/16/06 ">=" to ">" bugfix
740) 		p--;
741) 	if (*p == DIR_SEPARATOR)
742) 		p++;
743) 
744) 	DFS_CanonicalToDir(filename, p);
745) 
746) 	if (p > tmppath)
747) 		p--;
748) 	if (*p == DIR_SEPARATOR || p == tmppath) // larwe 9/16/06 +"|| p == tmppath" bugfix
749) 		*p = 0;
750) 
751) 	// At this point, if our path was MYDIR/MYDIR2/FILE.EXT, filename = "FILE    EXT" and
752) 	// tmppath = "MYDIR/MYDIR2".
753) 	di.scratch = scratch;
754) 	if (DFS_OpenDir(volinfo, tmppath, &di))
755) 		return DFS_NOTFOUND;
756) 
757) 	while (!DFS_GetNext(volinfo, &di, &de)) {
758) 		if (!memcmp(de.name, filename, 11)) {
759) 			// You can't use this function call to open a directory.
760) 			if (de.attr & ATTR_DIRECTORY)
761) 				return DFS_NOTFOUND;
762) 
763) 			fileinfo->volinfo = volinfo;
764) 			fileinfo->pointer = 0;
765) 			// The reason we store this extra info about the file is so that we can
766) 			// speedily update the file size, modification date, etc. on a file that is
767) 			// opened for writing.
768) 			if (di.currentcluster == 0)
769) 				fileinfo->dirsector = volinfo->rootdir + di.currentsector;
770) 			else
771) 				fileinfo->dirsector = volinfo->dataarea + ((di.currentcluster - 2) * volinfo->secperclus) + di.currentsector;
772) 			fileinfo->diroffset = di.currententry - 1;
773) 			if (volinfo->filesystem == FAT32) {
774) 				fileinfo->cluster = (uint32_t) de.startclus_l_l |
775) 				  ((uint32_t) de.startclus_l_h) << 8 |
776) 				  ((uint32_t) de.startclus_h_l) << 16 |
777) 				  ((uint32_t) de.startclus_h_h) << 24;
778) 			}
779) 			else {
780) 				fileinfo->cluster = (uint32_t) de.startclus_l_l |
781) 				  ((uint32_t) de.startclus_l_h) << 8;
782) 			}
783) 			fileinfo->firstcluster = fileinfo->cluster;
784) 			fileinfo->filelen = (uint32_t) de.filesize_0 |
785) 			  ((uint32_t) de.filesize_1) << 8 |
786) 			  ((uint32_t) de.filesize_2) << 16 |
787) 			  ((uint32_t) de.filesize_3) << 24;
788) 
789) 			return DFS_OK;
790) 		}
791) 	}
792) 
793) 	// At this point, we KNOW the file does not exist. If the file was opened
794) 	// with write access, we can create it.
795) 	if (mode & DFS_WRITE) {
796) 		uint32_t cluster, temp;
797) 
798) 		// Locate or create a directory entry for this file
799) 		if (DFS_OK != DFS_GetFreeDirEnt(volinfo, tmppath, &di, &de))
800) 			return DFS_ERRMISC;
801) 
802) 		// put sane values in the directory entry
803) 		memset(&de, 0, sizeof(de));
804) 		memcpy(de.name, filename, 11);
805) 		de.crttime_l = 0x20;	// 01:01:00am, Jan 1, 2006.
806) 		de.crttime_h = 0x08;
807) 		de.crtdate_l = 0x11;
808) 		de.crtdate_h = 0x34;
809) 		de.lstaccdate_l = 0x11;
810) 		de.lstaccdate_h = 0x34;
811) 		de.wrttime_l = 0x20;
812) 		de.wrttime_h = 0x08;
813) 		de.wrtdate_l = 0x11;
814) 		de.wrtdate_h = 0x34;
815) 
816) 		// allocate a starting cluster for the directory entry
817) 		cluster = DFS_GetFreeFAT(volinfo, scratch);
818) 
819) 		de.startclus_l_l = cluster & 0xff;
820) 		de.startclus_l_h = (cluster & 0xff00) >> 8;
821) 		de.startclus_h_l = (cluster & 0xff0000) >> 16;
822) 		de.startclus_h_h = (cluster & 0xff000000) >> 24;
823) 
824) 		// update FILEINFO for our caller's sake
825) 		fileinfo->volinfo = volinfo;
826) 		fileinfo->pointer = 0;
827) 		// The reason we store this extra info about the file is so that we can
828) 		// speedily update the file size, modification date, etc. on a file that is
829) 		// opened for writing.
830) 		if (di.currentcluster == 0)
831) 			fileinfo->dirsector = volinfo->rootdir + di.currentsector;
832) 		else
833) 			fileinfo->dirsector = volinfo->dataarea + ((di.currentcluster - 2) * volinfo->secperclus) + di.currentsector;
834) 		fileinfo->diroffset = di.currententry - 1;
835) 		fileinfo->cluster = cluster;
836) 		fileinfo->firstcluster = cluster;
837) 		fileinfo->filelen = 0;
838) 		
839) 		// write the directory entry
840) 		// note that we no longer have the sector containing the directory entry,
841) 		// tragically, so we have to re-read it
842) 		if (DFS_ReadSector(volinfo->unit, scratch, fileinfo->dirsector, 1))
843) 			return DFS_ERRMISC;
844) 		memcpy(&(((PDIRENT) scratch)[di.currententry-1]), &de, sizeof(DIRENT));
845) 		if (DFS_WriteSector(volinfo->unit, scratch, fileinfo->dirsector, 1))
846) 			return DFS_ERRMISC;
847) 
848) 		// Mark newly allocated cluster as end of chain			
849) 		switch(volinfo->filesystem) {
850) 			case FAT12:		cluster = 0xff8;	break;
851) 			case FAT16:		cluster = 0xfff8;	break;
852) 			case FAT32:		cluster = 0x0ffffff8;	break;
853) 			default:		return DFS_ERRMISC;
854) 		}
855) 		temp = 0;
856) 		DFS_SetFAT(volinfo, scratch, &temp, fileinfo->cluster, cluster);
857) 
858) 		return DFS_OK;
859) 	}
860) 
861) 	return DFS_NOTFOUND;
862) }
863) 
864) /*
865) 	Read an open file
866) 	You must supply a prepopulated FILEINFO as provided by DFS_OpenFile, and a
867) 	pointer to a SECTOR_SIZE scratch buffer.
868) 	Note that returning DFS_EOF is not an error condition. This function updates the
869) 	successcount field with the number of bytes actually read.
870) */
871) uint32_t DFS_ReadFile(PFILEINFO fileinfo, uint8_t *scratch, uint8_t *buffer, uint32_t *successcount, uint32_t len)
872) {
Stefan Schuermans bugfix patches from the for...

Stefan Schuermans authored 12 years ago

873) 	uint32_t remain = 0;
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

874) 	uint32_t result = DFS_OK;
Stefan Schuermans bugfix patches from the for...

Stefan Schuermans authored 12 years ago

875) 	uint32_t sector = 0;
876) 	uint32_t bytesread = 0;
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

877) 
878) 	// Don't try to read past EOF
879) 	if (len > fileinfo->filelen - fileinfo->pointer)
880) 		len = fileinfo->filelen - fileinfo->pointer;
881) 
882) 	remain = len;
883) 	*successcount = 0;
884) 
885) 	while (remain && result == DFS_OK) {
886) 		// This is a bit complicated. The sector we want to read is addressed at a cluster
887) 		// granularity by the fileinfo->cluster member. The file pointer tells us how many
888) 		// extra sectors to add to that number.
889) 		sector = fileinfo->volinfo->dataarea +
890) 		  ((fileinfo->cluster - 2) * fileinfo->volinfo->secperclus) +
Stefan Schuermans replace all div() calls wit...

Stefan Schuermans authored 12 years ago

891) 		  ldiv(ldiv(fileinfo->pointer,fileinfo->volinfo->secperclus * SECTOR_SIZE).rem, SECTOR_SIZE).quot;
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

892) 
893) 		// Case 1 - File pointer is not on a sector boundary
Stefan Schuermans replace all div() calls wit...

Stefan Schuermans authored 12 years ago

894) 		if (ldiv(fileinfo->pointer, SECTOR_SIZE).rem) {
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

895) 			uint16_t tempreadsize;
896) 
897) 			// We always have to go through scratch in this case
898) 			result = DFS_ReadSector(fileinfo->volinfo->unit, scratch, sector, 1);
899) 
900) 			// This is the number of bytes that we actually care about in the sector
901) 			// just read.
Stefan Schuermans replace all div() calls wit...

Stefan Schuermans authored 12 years ago

902) 			tempreadsize = SECTOR_SIZE - (ldiv(fileinfo->pointer, SECTOR_SIZE).rem);
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

903) 					
904) 			// Case 1A - We want the entire remainder of the sector. After this
905) 			// point, all passes through the read loop will be aligned on a sector
906) 			// boundary, which allows us to go through the optimal path 2A below.
907) 		   	if (remain >= tempreadsize) {
908) 				memcpy(buffer, scratch + (SECTOR_SIZE - tempreadsize), tempreadsize);
909) 				bytesread = tempreadsize;
910) 				buffer += tempreadsize;
911) 				fileinfo->pointer += tempreadsize;
912) 				remain -= tempreadsize;
913) 			}
914) 			// Case 1B - This read concludes the file read operation
915) 			else {
916) 				memcpy(buffer, scratch + (SECTOR_SIZE - tempreadsize), remain);
917) 
918) 				buffer += remain;
919) 				fileinfo->pointer += remain;
920) 				bytesread = remain;
921) 				remain = 0;
922) 			}
923) 		}
924) 		// Case 2 - File pointer is on sector boundary
925) 		else {
926) 			// Case 2A - We have at least one more full sector to read and don't have
927) 			// to go through the scratch buffer. You could insert optimizations here to
928) 			// read multiple sectors at a time, if you were thus inclined (note that
929) 			// the maximum multi-read you could perform is a single cluster, so it would
930) 			// be advantageous to have code similar to case 1A above that would round the
931) 			// pointer to a cluster boundary the first pass through, so all subsequent
932) 			// [large] read requests would be able to go a cluster at a time).
933) 			if (remain >= SECTOR_SIZE) {
934) 				result = DFS_ReadSector(fileinfo->volinfo->unit, buffer, sector, 1);
935) 				remain -= SECTOR_SIZE;
936) 				buffer += SECTOR_SIZE;
937) 				fileinfo->pointer += SECTOR_SIZE;
938) 				bytesread = SECTOR_SIZE;
939) 			}
940) 			// Case 2B - We are only reading a partial sector
941) 			else {
942) 				result = DFS_ReadSector(fileinfo->volinfo->unit, scratch, sector, 1);
943) 				memcpy(buffer, scratch, remain);
944) 				buffer += remain;
945) 				fileinfo->pointer += remain;
946) 				bytesread = remain;
947) 				remain = 0;
948) 			}
949) 		}
950) 
951) 		*successcount += bytesread;
952) 
953) 		// check to see if we stepped over a cluster boundary
Stefan Schuermans replace all div() calls wit...

Stefan Schuermans authored 12 years ago

954) 		if (ldiv(fileinfo->pointer - bytesread, fileinfo->volinfo->secperclus * SECTOR_SIZE).quot !=
955) 		  ldiv(fileinfo->pointer, fileinfo->volinfo->secperclus * SECTOR_SIZE).quot) {
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

956) 			// An act of minor evil - we use bytesread as a scratch integer, knowing that
957) 			// its value is not used after updating *successcount above
958) 			bytesread = 0;
959) 			if (((fileinfo->volinfo->filesystem == FAT12) && (fileinfo->cluster >= 0xff8)) ||
960) 			  ((fileinfo->volinfo->filesystem == FAT16) && (fileinfo->cluster >= 0xfff8)) ||
961) 			  ((fileinfo->volinfo->filesystem == FAT32) && (fileinfo->cluster >= 0x0ffffff8)))
962) 				result = DFS_EOF;
963) 			else
964) 				fileinfo->cluster = DFS_GetFAT(fileinfo->volinfo, scratch, &bytesread, fileinfo->cluster);
965) 		}
966) 	}
967) 	
968) 	return result;
969) }
970) 
971) /*
972) 	Seek file pointer to a given position
973) 	This function does not return status - refer to the fileinfo->pointer value
974) 	to see where the pointer wound up.
975) 	Requires a SECTOR_SIZE scratch buffer
976) */
977) void DFS_Seek(PFILEINFO fileinfo, uint32_t offset, uint8_t *scratch)
978) {
Stefan Schuermans bugfix patches from the for...

Stefan Schuermans authored 12 years ago

979) 	uint32_t tempint = 0;
980)         uint16_t endcluster = 0;
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

981) 
982) 	// larwe 9/16/06 bugfix split case 0a/0b and changed fallthrough handling
983) 	// Case 0a - Return immediately for degenerate case
984) 	if (offset == fileinfo->pointer) {
985) 		return;
986) 	}
987) 	
988) 	// Case 0b - Don't allow the user to seek past the end of the file
989) 	if (offset > fileinfo->filelen) {
990) 		offset = fileinfo->filelen;
991) 		// NOTE NO RETURN HERE!
992) 	}
993) 
994) 	// Case 1 - Simple rewind to start
995) 	// Note _intentional_ fallthrough from Case 0b above
996) 	if (offset == 0) {
997) 		fileinfo->cluster = fileinfo->firstcluster;
998) 		fileinfo->pointer = 0;
999) 		return;		// larwe 9/16/06 +1 bugfix
1000) 	}
1001) 	// Case 2 - Seeking backwards. Need to reset and seek forwards
1002) 	else if (offset < fileinfo->pointer) {
1003) 		fileinfo->cluster = fileinfo->firstcluster;
1004) 		fileinfo->pointer = 0;
1005) 		// NOTE NO RETURN HERE!
1006) 	}
1007) 
1008) 	// Case 3 - Seeking forwards
1009) 	// Note _intentional_ fallthrough from Case 2 above
1010) 
1011) 	// Case 3a - Seek size does not cross cluster boundary - 
1012) 	// very simple case
1013) 	// larwe 9/16/06 changed .rem to .quot in both div calls, bugfix
Stefan Schuermans replace all div() calls wit...

Stefan Schuermans authored 12 years ago

1014) 	if (ldiv(fileinfo->pointer, fileinfo->volinfo->secperclus * SECTOR_SIZE).quot ==
1015) 	  ldiv(fileinfo->pointer + offset, fileinfo->volinfo->secperclus * SECTOR_SIZE).quot) {
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

1016) 		fileinfo->pointer = offset;
1017) 	}
1018) 	// Case 3b - Seeking across cluster boundary(ies)
1019) 	else {
1020) 		// round file pointer down to cluster boundary
Stefan Schuermans replace all div() calls wit...

Stefan Schuermans authored 12 years ago

1021) 		fileinfo->pointer = ldiv(fileinfo->pointer, fileinfo->volinfo->secperclus * SECTOR_SIZE).quot *
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

1022) 		  fileinfo->volinfo->secperclus * SECTOR_SIZE;
1023) 
1024) 		// seek by clusters
Stefan Schuermans bugfix patches from the for...

Stefan Schuermans authored 12 years ago

1025) 		// canny/reza 5/7  added endcluster related code
Stefan Schuermans replace all div() calls wit...

Stefan Schuermans authored 12 years ago

1026) 		endcluster = ldiv(offset, fileinfo->volinfo->secperclus * SECTOR_SIZE).quot;
1027) 		while (ldiv(fileinfo->pointer, fileinfo->volinfo->secperclus * SECTOR_SIZE).quot != endcluster) {
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

1028) 			fileinfo->cluster = DFS_GetFAT(fileinfo->volinfo, scratch, &tempint, fileinfo->cluster);
1029) 			// Abort if there was an error
1030) 			if (fileinfo->cluster == 0x0ffffff7) {
1031) 				fileinfo->pointer = 0;
1032) 				fileinfo->cluster = fileinfo->firstcluster;
1033) 				return;
1034) 			}
1035) 			fileinfo->pointer += SECTOR_SIZE * fileinfo->volinfo->secperclus;
1036) 		}
1037) 
1038) 		// since we know the cluster is right, we have no more work to do
1039) 		fileinfo->pointer = offset;
1040) 	}
1041) }
1042) 
1043) /*
1044) 	Delete a file
1045) 	scratch must point to a sector-sized buffer
1046) */
1047) uint32_t DFS_UnlinkFile(PVOLINFO volinfo, uint8_t *path, uint8_t *scratch)
1048) {
1049) 	FILEINFO fi;
1050) 	uint32_t cache = 0;
Stefan Schuermans bugfix patches from the for...

Stefan Schuermans authored 12 years ago

1051) 	uint32_t tempclus = 0;
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

1052) 
1053) 	// DFS_OpenFile gives us all the information we need to delete it
1054) 	if (DFS_OK != DFS_OpenFile(volinfo, path, DFS_READ, scratch, &fi))
1055) 		return DFS_NOTFOUND;
1056) 
1057) 	// First, read the directory sector and delete that entry
1058) 	if (DFS_ReadSector(volinfo->unit, scratch, fi.dirsector, 1))
1059) 		return DFS_ERRMISC;
1060) 	((PDIRENT) scratch)[fi.diroffset].name[0] = 0xe5;
1061) 	if (DFS_WriteSector(volinfo->unit, scratch, fi.dirsector, 1))
1062) 		return DFS_ERRMISC;
1063) 
1064) 	// Now follow the cluster chain to free the file space
1065) 	while (!((volinfo->filesystem == FAT12 && fi.firstcluster >= 0x0ff7) ||
1066) 	  (volinfo->filesystem == FAT16 && fi.firstcluster >= 0xfff7) ||
1067) 	  (volinfo->filesystem == FAT32 && fi.firstcluster >= 0x0ffffff7))) {
1068) 		tempclus = fi.firstcluster;
1069) 
1070) 		fi.firstcluster = DFS_GetFAT(volinfo, scratch, &cache, fi.firstcluster);
1071) 		DFS_SetFAT(volinfo, scratch, &cache, tempclus, 0);
1072) 
1073) 	}
1074) 	return DFS_OK;
1075) }
1076) 
1077) 
1078) /*
1079) 	Write an open file
1080) 	You must supply a prepopulated FILEINFO as provided by DFS_OpenFile, and a
1081) 	pointer to a SECTOR_SIZE scratch buffer.
1082) 	This function updates the successcount field with the number of bytes actually written.
1083) */
1084) uint32_t DFS_WriteFile(PFILEINFO fileinfo, uint8_t *scratch, uint8_t *buffer, uint32_t *successcount, uint32_t len)
1085) {
Stefan Schuermans bugfix patches from the for...

Stefan Schuermans authored 12 years ago

1086) 	uint32_t remain = 0;
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

1087) 	uint32_t result = DFS_OK;
Stefan Schuermans bugfix patches from the for...

Stefan Schuermans authored 12 years ago

1088) 	uint32_t sector = 0;
1089) 	uint32_t byteswritten = 0;
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

1090) 
1091) 	// Don't allow writes to a file that's open as readonly
1092) 	if (!(fileinfo->mode & DFS_WRITE))
1093) 		return DFS_ERRMISC;
1094) 
1095) 	remain = len;
1096) 	*successcount = 0;
1097) 
1098) 	while (remain && result == DFS_OK) {
1099) 		// This is a bit complicated. The sector we want to read is addressed at a cluster
1100) 		// granularity by the fileinfo->cluster member. The file pointer tells us how many
1101) 		// extra sectors to add to that number.
1102) 		sector = fileinfo->volinfo->dataarea +
1103) 		  ((fileinfo->cluster - 2) * fileinfo->volinfo->secperclus) +
Stefan Schuermans replace all div() calls wit...

Stefan Schuermans authored 12 years ago

1104) 		  ldiv(ldiv(fileinfo->pointer,fileinfo->volinfo->secperclus * SECTOR_SIZE).rem, SECTOR_SIZE).quot;
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

1105) 
1106) 		// Case 1 - File pointer is not on a sector boundary
Stefan Schuermans replace all div() calls wit...

Stefan Schuermans authored 12 years ago

1107) 		if (ldiv(fileinfo->pointer, SECTOR_SIZE).rem) {
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

1108) 			uint16_t tempsize;
1109) 
1110) 			// We always have to go through scratch in this case
1111) 			result = DFS_ReadSector(fileinfo->volinfo->unit, scratch, sector, 1);
1112) 
1113) 			// This is the number of bytes that we don't want to molest in the
1114) 			// scratch sector just read.
Stefan Schuermans replace all div() calls wit...

Stefan Schuermans authored 12 years ago

1115) 			tempsize = ldiv(fileinfo->pointer, SECTOR_SIZE).rem;
Stefan Schuermans added dosfs code to read FA...

Stefan Schuermans authored 12 years ago

1116) 					
1117) 			// Case 1A - We are writing the entire remainder of the sector. After
1118) 			// this point, all passes through the read loop will be aligned on a
1119) 			// sector boundary, which allows us to go through the optimal path
1120) 			// 2A below.
1121) 		   	if (remain >= SECTOR_SIZE - tempsize) {
1122) 				memcpy(scratch + tempsize, buffer, SECTOR_SIZE - tempsize);
1123) 				if (!result)
1124) 					result = DFS_WriteSector(fileinfo->volinfo->unit, scratch, sector, 1);
1125) 
1126) 				byteswritten = SECTOR_SIZE - tempsize;
1127) 				buffer += SECTOR_SIZE - tempsize;
1128) 				fileinfo->pointer += SECTOR_SIZE - tempsize;
1129) 				if (fileinfo->filelen < fileinfo->pointer) {
1130) 					fileinfo->filelen = fileinfo->pointer;
1131) 				}
1132) 				remain -= SECTOR_SIZE - tempsize;
1133) 			}
1134) 			// Case 1B - This concludes the file write operation
1135) 			else {
1136) 				memcpy(scratch + tempsize, buffer, remain);
1137) 				if (!result)
1138) 					result = DFS_WriteSector(fileinfo->volinfo->unit, scratch, sector, 1);
1139) 
1140) 				buffer += remain;
1141) 				fileinfo->pointer += remain;
1142) 				if (fileinfo->filelen < fileinfo->pointer) {
1143) 					fileinfo->filelen = fileinfo->pointer;
1144) 				}
1145) 				byteswritten = remain;
1146) 				remain = 0;
1147) 			}
1148) 		} // case 1
1149) 		// Case 2 - File pointer is on sector boundary
1150) 		else {
1151) 			// Case 2A - We have at least one more full sector to write and don't have
1152) 			// to go through the scratch buffer. You could insert optimizations here to
1153) 			// write multiple sectors at a time, if you were thus inclined. Refer to
1154) 			// similar notes in DFS_ReadFile.
1155) 			if (remain >= SECTOR_SIZE) {
1156) 				result = DFS_WriteSector(fileinfo->volinfo->unit, buffer, sector, 1);
1157) 				remain -= SECTOR_SIZE;
1158) 				buffer += SECTOR_SIZE;
1159) 				fileinfo->pointer += SECTOR_SIZE;
1160) 				if (fileinfo->filelen < fileinfo->pointer) {
1161) 					fileinfo->filelen = fileinfo->pointer;
1162) 				}
1163) 				byteswritten = SECTOR_SIZE;
1164) 			}
1165) 			// Case 2B - We are only writing a partial sector and potentially need to
1166) 			// go through the scratch buffer.
1167) 			else {
1168) 				// If the current file pointer is not yet at or beyond the file
1169) 				// length, we are writing somewhere in the middle of the file and
1170) 				// need to load the original sector to do a read-modify-write.
1171) 				if (fileinfo->pointer < fileinfo->filelen) {
1172) 					result = DFS_ReadSector(fileinfo->volinfo->unit, scratch, sector, 1);
1173) 					if (!result) {
1174) 						memcpy(scratch, buffer, remain);
1175) 						result = DFS_WriteSector(fileinfo->volinfo->unit, scratch, sector, 1);
1176) 					}
1177) 				}
1178) 				else {
1179) 					result = DFS_WriteSector(fileinfo->volinfo->unit, buffer, sector, 1);
1180) 				}
1181) 
1182) 				buffer += remain;
1183) 				fileinfo->pointer += remain;
1184) 				if (fileinfo->filelen < fileinfo->pointer) {
1185) 					fileinfo->filelen = fileinfo->pointer;
1186) 				}
1187) 				byteswritten = remain;
1188) 				remain = 0;
1189) 			}
1190) 		}
1191) 
1192) 		*successcount += byteswritten;
1193) 
1194) 		// check to see if we stepped over a cluster boundary
Stefan Schuermans replace all div() calls wit...

Stefan Schuermans authored 12 years ago

1195) 		if (ldiv(fileinfo->pointer - byteswritten, fileinfo->volinfo->secperclus * SECTOR_SIZE).quot !=
1196) 		  ldiv(fileinfo->pointer, fileinfo->volinfo->secperclus * SECTOR_SIZE).quot) {