/* Get starting sector# of specified partition on drive #unit NOTE: This code ASSUMES an MBR on the disk. scratchsector should point to a SECTOR_SIZE scratch area Returns 0xffffffff for any error. If pactive is non-NULL, this function also returns the partition active flag. If pptype is non-NULL, this function also returns the partition type. If psize is non-NULL, this function also returns the partition size. */ uint32_t DFS_GetPtnStart(uint8_t unit, uint8_t *scratchsector, uint8_t pnum, uint8_t *pactive, uint8_t *pptype, uint32_t *psize) { uint32_t result; PMBR mbr = (PMBR) scratchsector; // DOS ptable supports maximum 4 partitions if (pnum > 3) return DFS_ERRMISC; // Read MBR from target media if (DFS_ReadSector(unit,scratchsector,0,1)) { return DFS_ERRMISC; } result = (uint32_t) mbr->ptable[pnum].start_0 | (((uint32_t) mbr->ptable[pnum].start_1) << 8) | (((uint32_t) mbr->ptable[pnum].start_2) << 16) | (((uint32_t) mbr->ptable[pnum].start_3) << 24); if (pactive) *pactive = mbr->ptable[pnum].active; if (pptype) *pptype = mbr->ptable[pnum].type; if (psize) *psize = (uint32_t) mbr->ptable[pnum].size_0 | (((uint32_t) mbr->ptable[pnum].size_1) << 8) | (((uint32_t) mbr->ptable[pnum].size_2) << 16) | (((uint32_t) mbr->ptable[pnum].size_3) << 24); return result; }
uint32_t mount_complete(void) { int retval, sector; strcpy(dfs_currdir, "/"); // Start up the low-level file I/O driver if ((retval = DFS_InitFileIO()) != DFS_OK) return retval; // Find the first sector of the volume if ((retval = DFS_ReadSector(0, dfs_scratch, 0, 1)) != DFS_OK) return retval; if (!strncmp((char *)dfs_scratch+0x36, "FAT16", 5) || !strncmp((char *)dfs_scratch+0x52, "FAT32", 5)) sector = 0; else memcpy(§or, &dfs_scratch[0x1c6], 4); // Get the volume information retval = DFS_GetVolInfo(0, dfs_scratch, sector, &dfs_volinfo); dfs_mountflag = (retval == DFS_OK); return retval; }
void telnet_sddump( file_handle_t handle, char** argv, unsigned int argc ) { unsigned long sector = 0; char tmp[8]; char* parseend; if( argc != 2) { file_puts("sddump [sector]\r\n", telnet_handle); return; } sector = strtoul( argv[1], &parseend, 0); unsigned char* data = malloc( SECTOR_SIZE ); unsigned char result = DFS_ReadSector(0, data, sector, 1); if( result == 0 ) { memdump( handle, data, data + SECTOR_SIZE); } else { file_puts("Error reading sector. Response code:", handle ); sprintf(tmp,"%02hhx", result ); file_puts(tmp, handle); file_puts(CRLF, handle); } free(data); return; }
/* Fetch FAT entry for specified cluster number You must provide a scratch buffer for one sector (SECTOR_SIZE) and a populated VOLINFO Returns a FAT32 BAD_CLUSTER value for any error, otherwise the contents of the desired FAT entry. scratchcache should point to a UINT32. This variable caches the physical sector number last read into the scratch buffer for performance enhancement reasons. */ uint32_t DFS_GetFAT(PVOLINFO volinfo, uint8_t *scratch, uint32_t *scratchcache, uint32_t cluster) { uint32_t offset, sector, result; if (volinfo->filesystem == FAT12) { offset = cluster + (cluster / 2); } else if (volinfo->filesystem == FAT16) { offset = cluster * 2; } else if (volinfo->filesystem == FAT32) { offset = cluster * 4; } else return 0x0ffffff7; // FAT32 bad cluster // at this point, offset is the BYTE offset of the desired sector from the start // of the FAT. Calculate the physical sector containing this FAT entry. sector = ldiv(offset, SECTOR_SIZE).quot + volinfo->fat1; // If this is not the same sector we last read, then read it into RAM if (sector != *scratchcache) { if(DFS_ReadSector(volinfo->unit, scratch, sector, 1)) { // avoid anyone assuming that this cache value is still valid, which // might cause disk corruption *scratchcache = 0; return 0x0ffffff7; // FAT32 bad cluster } *scratchcache = sector; } // At this point, we "merely" need to extract the relevant entry. // This is easy for FAT16 and FAT32, but a royal PITA for FAT12 as a single entry // may span a sector boundary. The normal way around this is always to read two // FAT sectors, but that luxury is (by design intent) unavailable to DOSFS. offset = ldiv(offset, SECTOR_SIZE).rem; if (volinfo->filesystem == FAT12) { // Special case for sector boundary - Store last byte of current sector. // Then read in the next sector and put the first byte of that sector into // the high byte of result. if (offset == SECTOR_SIZE - 1) { result = (uint32_t) scratch[offset]; sector++; if(DFS_ReadSector(volinfo->unit, scratch, sector, 1)) { // avoid anyone assuming that this cache value is still valid, which // might cause disk corruption *scratchcache = 0; return 0x0ffffff7; // FAT32 bad cluster } *scratchcache = sector; // Thanks to Claudio Leonel for pointing out this missing line. result |= ((uint32_t) scratch[0]) << 8; } else { result = (uint32_t) scratch[offset] | ((uint32_t) scratch[offset+1]) << 8; } if (cluster & 1) result = result >> 4; else result = result & 0xfff; }
/* Retrieve volume info from BPB and store it in a VOLINFO structure You must provide the unit and starting sector of the filesystem, and a pointer to a sector buffer for scratch Attempts to read BPB and glean information about the FS from that. Returns 0 OK, nonzero for any error. */ uint32_t DFS_GetVolInfo(uint8_t unit, uint8_t *scratchsector, uint32_t startsector, PVOLINFO volinfo) { PLBR lbr = (PLBR) scratchsector; volinfo->unit = unit; volinfo->startsector = startsector; if(DFS_ReadSector(unit,scratchsector,startsector,1)) return DFS_ERRMISC; // tag: OEMID, refer dosfs.h // strncpy(volinfo->oemid, lbr->oemid, 8); // volinfo->oemid[8] = 0; volinfo->secperclus = lbr->bpb.secperclus; volinfo->reservedsecs = (uint16_t) lbr->bpb.reserved_l | (((uint16_t) lbr->bpb.reserved_h) << 8); volinfo->numsecs = (uint16_t) lbr->bpb.sectors_s_l | (((uint16_t) lbr->bpb.sectors_s_h) << 8); if (!volinfo->numsecs) volinfo->numsecs = (uint32_t) lbr->bpb.sectors_l_0 | (((uint32_t) lbr->bpb.sectors_l_1) << 8) | (((uint32_t) lbr->bpb.sectors_l_2) << 16) | (((uint32_t) lbr->bpb.sectors_l_3) << 24); // If secperfat is 0, we must be in a FAT32 volume; get secperfat // from the FAT32 EBPB. The volume label and system ID string are also // in different locations for FAT12/16 vs FAT32. volinfo->secperfat = (uint16_t) lbr->bpb.secperfat_l | (((uint16_t) lbr->bpb.secperfat_h) << 8); if (!volinfo->secperfat) { volinfo->secperfat = (uint32_t) lbr->ebpb.ebpb32.fatsize_0 | (((uint32_t) lbr->ebpb.ebpb32.fatsize_1) << 8) | (((uint32_t) lbr->ebpb.ebpb32.fatsize_2) << 16) | (((uint32_t) lbr->ebpb.ebpb32.fatsize_3) << 24); memcpy(volinfo->label, lbr->ebpb.ebpb32.label, 11); volinfo->label[11] = 0; // tag: OEMID, refer dosfs.h // memcpy(volinfo->system, lbr->ebpb.ebpb32.system, 8); // volinfo->system[8] = 0; } else { memcpy(volinfo->label, lbr->ebpb.ebpb.label, 11); volinfo->label[11] = 0; // tag: OEMID, refer dosfs.h // memcpy(volinfo->system, lbr->ebpb.ebpb.system, 8); // volinfo->system[8] = 0; } // note: if rootentries is 0, we must be in a FAT32 volume. volinfo->rootentries = (uint16_t) lbr->bpb.rootentries_l | (((uint16_t) lbr->bpb.rootentries_h) << 8); // after extracting raw info we perform some useful precalculations volinfo->fat1 = startsector + volinfo->reservedsecs; // The calculation below is designed to round up the root directory size for FAT12/16 // and to simply ignore the root directory for FAT32, since it's a normal, expandable // file in that situation. if (volinfo->rootentries) { volinfo->rootdir = volinfo->fat1 + (volinfo->secperfat * 2); volinfo->dataarea = volinfo->rootdir + (((volinfo->rootentries * 32) + (SECTOR_SIZE - 1)) / SECTOR_SIZE); } else { volinfo->dataarea = volinfo->fat1 + (volinfo->secperfat * 2); volinfo->rootdir = (uint32_t) lbr->ebpb.ebpb32.root_0 | (((uint32_t) lbr->ebpb.ebpb32.root_1) << 8) | (((uint32_t) lbr->ebpb.ebpb32.root_2) << 16) | (((uint32_t) lbr->ebpb.ebpb32.root_3) << 24); } // Calculate number of clusters in data area and infer FAT type from this information. volinfo->numclusters = (volinfo->numsecs - volinfo->dataarea) / volinfo->secperclus; if (volinfo->numclusters < 4085) volinfo->filesystem = FAT12; else if (volinfo->numclusters < 65525) volinfo->filesystem = FAT16; else volinfo->filesystem = FAT32; return DFS_OK; }