/****************************************/ /* MES/Copyleft Yukio Mituiwa,2005 */ /* */ /* 2005/2/14 first release */ /* */ /****************************************/ #include #include #include #include "mes.h" #include "fatdef.h" #define FAT12 1 #define FAT16 2 #define SECBUF 0 #define SECDAT 1 #define SECFAT 2 #define DISKNUM 6 static char *diskbuffer; #define EntDir 0x10 #define dfd file[fd].disk->diskfd #define topsec file[fd].disk->rsc typedef struct { char *buf; int ptr, wrote; } Cache; typedef struct { int rsc; int SecSize; int ClustSize; int ResvSec; int FatNum; int RootEnt; int TotalSec; int FatSec; int diskfd; int TopClust; int tailsec; char name[12]; char fatid; } DiskInfo; static volatile DiskInfo *disk; #define FATNUM 128 typedef struct { int id; int EntLba, EntClust, EntOffset, EntSize, EntClustOff; int fatindex, tailfat, fdopt; volatile DiskInfo *disk; volatile Cache cache[3]; Entry CurEnt; unsigned short fats[FATNUM]; char EntAttr; char Error; } FileInfo; static volatile FileInfo *file; extern char files; static int FILENUM; static int check_fd(unsigned int fd); static void FlushBuffer(int fd, int index, int addsec); static void WriteBuffer(int fd, int index, char *buf, int lba, int len); static void ReadBuffer(int fd, int index, int lba); static void FlushBuffers(int fd); static int AccessData(int fd, char *buf, int lba, int size, int option); static int AccessCData(int fd, int clust, char *buf, int off, int size, int option); static int GetFat(int fd, int index); static int FreeFat(int fd); static void SetFat(int fd, int index, int _data); static void AjustName2(char *data, char *name); static void AjustName(char *data, char *name); static int FindEntry(int fd, int clust, char *filename, int option); static int check_fd(unsigned int fd) { if(fd >= FILENUM) return -1; if(file[fd].disk == 0) return -1; return 0; } static void FlushBuffer(int fd, int index, int addsec) { int off, error; if(file[fd].Error) return; if(file[fd].cache[index].wrote) { off = (topsec + file[fd].cache[index].wrote) * SECSIZ; __seek(SuperTask, dfd, off); error = __write(SuperTask, dfd, file[fd].cache[index].buf, SECSIZ); if(error <= 0) { file[fd].Error = 1; return; } if(addsec != 0) { off = (topsec + addsec + file[fd].cache[index].wrote) * SECSIZ; __seek(SuperTask, dfd, off); error = __write(SuperTask, dfd, file[fd].cache[index].buf, SECSIZ); if(error <= 0) file[fd].Error = 1; } file[fd].cache[index].wrote = 0; } } static void WriteBuffer(int fd, int index, char *buf, int lba, int len) { int offset, fi; if(file[fd].Error) return; file[fd].cache[index].wrote = lba / SECSIZ; offset = lba - file[fd].cache[index].ptr; for(fi = 0;fi < FILENUM;fi++) { if(file[fi].disk != 0 && file[fi].cache[index].ptr == file[fd].cache[index].ptr) { memcpy(&file[fi].cache[index].buf[offset], buf, len); } } } static void ReadBuffer(int fd, int index, int lba) { int off, sec, error; if(file[fd].Error) return; sec = lba / SECSIZ; off = (topsec + sec) * SECSIZ; __seek(SuperTask, dfd, off); error = __read(SuperTask, dfd, file[fd].cache[index].buf, SECSIZ); if(error <= 0) file[fd].Error = 1; file[fd].cache[index].ptr = sec * SECSIZ; } static void FlushBuffers(int fd) { FlushBuffer(fd, SECBUF, 0); FlushBuffer(fd, SECDAT, 0); FlushBuffer(fd, SECFAT, file[fd].disk->FatSec); } static int AccessData(int fd, char *buf, int lba, int size, int option) { int offset, max, len; if(file[fd].Error) return -1; if(lba < file[fd].cache[SECBUF].ptr || lba >= (file[fd].cache[SECBUF].ptr + SECSIZ)){ FlushBuffer(fd, SECBUF, 0); ReadBuffer(fd, SECBUF, lba); } max = file[fd].cache[SECBUF].ptr + SECSIZ - lba; len = (size > max) ? max : size; offset = lba - file[fd].cache[SECBUF].ptr; if(option == OptRead) { memcpy(buf, &file[fd].cache[SECBUF].buf[offset], len); } else if(option == OptWrite) { WriteBuffer(fd, SECBUF, buf, lba, len); } return len; } static int AccessCData(int fd, int clust, char *buf, int off, int size, int option) { int lba, offset, max, len, total, maxlba, remain; if(file[fd].Error) return -1; total = 0; remain = size; maxlba = file[fd].disk->TopClust * SECSIZ + (clust - 2 + 1) * SECSIZ * file[fd].disk->ClustSize; do { lba = file[fd].disk->TopClust * SECSIZ + (clust - 2) * SECSIZ * file[fd].disk->ClustSize + off + total; if(lba >= maxlba) break; if(lba < file[fd].cache[SECDAT].ptr || lba >= (file[fd].cache[SECDAT].ptr + SECSIZ)){ FlushBuffer(fd, SECDAT, 0); ReadBuffer(fd, SECDAT, lba); } max = file[fd].cache[SECDAT].ptr + SECSIZ - lba; len = (remain > max) ? max : remain; offset = lba - file[fd].cache[SECDAT].ptr; if(option == OptRead) { memcpy(&buf[total], &file[fd].cache[SECDAT].buf[offset], len); } else if(option == OptWrite) { WriteBuffer(fd, SECDAT, &buf[total], lba, len); } total += len; remain -= len; } while(total < size); return total; } static int GetFat(int fd, int index) { int lba, offset, mod, siz, dword, ret; unsigned short word; char buf[3]; ret = 0; if(file[fd].Error) return -1; switch(file[fd].disk->fatid) { case FAT16: lba = file[fd].disk->ResvSec * SECSIZ + index * 2; if(lba < file[fd].cache[SECFAT].ptr || lba >= (file[fd].cache[SECFAT].ptr + SECSIZ)){ FlushBuffer(fd, SECFAT, file[fd].disk->FatSec); ReadBuffer(fd, SECFAT, lba); } offset = lba - file[fd].cache[SECFAT].ptr; memcpy((char*)&word, &file[fd].cache[SECFAT].buf[offset], 2); ret = le16toh(word); break; case FAT12: mod = index & 0x0001; lba = file[fd].disk->ResvSec * SECSIZ + (index >> 1) * 3; if(lba < file[fd].cache[SECFAT].ptr || lba >= (file[fd].cache[SECFAT].ptr + SECSIZ)){ FlushBuffer(fd, SECFAT, file[fd].disk->FatSec); ReadBuffer(fd, SECFAT, lba); } offset = lba - file[fd].cache[SECFAT].ptr; memcpy(buf, &file[fd].cache[SECFAT].buf[offset], 3); siz = offset - SECSIZ + 3; if(siz > 0) { FlushBuffer(fd, SECFAT, file[fd].disk->FatSec); lba = (lba / SECSIZ + 1) * SECSIZ; ReadBuffer(fd, SECFAT, lba); memcpy(&buf[3 - siz], &file[fd].cache[SECFAT].buf[0], siz); } dword = ((int)buf[2] << 16) & 0xff0000; dword += ((int)buf[1] << 8) & 0xff00; dword += (int)buf[0] & 0xff; if(mod == 1) { dword >>= 12; } else { dword &= 0x000fff; } ret = dword; break; } return ret; } static int FreeFat(int fd) { int i, j, n, fat; if(file[fd].Error) return -1; n = (file[fd].disk->TotalSec - file[fd].disk->TopClust) / file[fd].disk->ClustSize + 2; for(i = 2;i < n;i++) { fat = GetFat(fd, i); if(fat == 0) { for(j = 0;j <= file[fd].fatindex;j++) { if(i == file[fd].fats[j]) break; } if(j > file[fd].fatindex) return i; } } return 0; } int fat_status(int dd, int *total, int *count, char *name) { int i, n, c, lba, off; unsigned short *pfat; char buffer[SECSIZ]; if(dd >= DISKNUM) return -1; if(disk[dd].diskfd == 0) { *total = 0; return 0; } c = 0; n = (disk[dd].TotalSec - disk[dd].TopClust) / disk[dd].ClustSize + 2; lba = (disk[dd].rsc + disk[dd].ResvSec) * SECSIZ; __seek(SuperTask, disk[dd].diskfd, lba); __read(SuperTask, disk[dd].diskfd, buffer, SECSIZ); for(i = 2;i < n;i++) { off = (i * 2) % SECSIZ; if(off == 0) { __seek(SuperTask, disk[dd].diskfd, lba + i * 2); __read(SuperTask, disk[dd].diskfd, buffer, SECSIZ); } pfat = (unsigned short*)&buffer[off]; if(*pfat == 0) c++; } *count = c * disk[dd].ClustSize; *total = (n - 2) * disk[dd].ClustSize; strcpy(name, (char*)disk[dd].name); return 0; } static void SetFat(int fd, int index, int data) { int lba, offset, mod, siz; unsigned short word; char buf[3]; if(file[fd].Error) return; if(index < 2) return; switch(file[fd].disk->fatid) { case FAT16: lba = file[fd].disk->ResvSec * SECSIZ + index * 2; if(lba < file[fd].cache[SECFAT].ptr || lba >= (file[fd].cache[SECFAT].ptr + SECSIZ)){ FlushBuffer(fd, SECFAT, file[fd].disk->FatSec); ReadBuffer(fd, SECFAT, lba); } offset = lba - file[fd].cache[SECFAT].ptr; word = le16toh(data); WriteBuffer(fd, SECFAT, (char*)&word, lba, 2); break; case FAT12: mod = index & 0x0001; lba = file[fd].disk->ResvSec * SECSIZ + (index >> 1) * 3; if(lba < file[fd].cache[SECFAT].ptr || lba >= (file[fd].cache[SECFAT].ptr + SECSIZ)){ FlushBuffer(fd, SECFAT, file[fd].disk->FatSec); ReadBuffer(fd, SECFAT, lba); } offset = lba - file[fd].cache[SECFAT].ptr; memcpy(buf, &file[fd].cache[SECFAT].buf[offset], 3); if(mod == 1) { buf[2] = data >> 4; buf[1] = buf[1] & 0x0f; buf[1] |= (data << 4) & 0xf0; } else { buf[0] = data; buf[1] = buf[1] & 0xf0; buf[1] |= (data >> 8) & 0x0f; } siz = offset - SECSIZ + 3; WriteBuffer(fd, SECFAT, buf, lba, (siz > 0) ? 3 - siz : 3); if(siz > 0) { FlushBuffer(fd, SECFAT, file[fd].disk->FatSec); lba = (lba / SECSIZ + 1) * SECSIZ; ReadBuffer(fd, SECFAT, lba); memcpy(&buf[3 - siz], &file[fd].cache[SECFAT].buf[0], siz); if(mod == 1) { buf[2] = data >> 4; buf[1] = buf[1] & 0x0f; buf[1] |= (data << 4) & 0xf0; } else { buf[0] = data; buf[1] = buf[1] & 0xf0; buf[1] |= (data >> 8) & 0x0f; } WriteBuffer(fd, SECFAT, &buf[3 - siz], lba, siz); } break; } } static void AjustName2(char *data, char *name) { int i, p; if(memcmp(name, ".. ", 3) == 0) { strcpy(data, ".."); return; } p = 0; for(i = 0;i < 8;i++) { if(name[i] == ' ') break; data[p++] = tolower(name[i]); } data[p++] = '.'; for(i = 8;i < 11;i++) { if(name[i] == ' ') break; data[p++] = tolower(name[i]); } if(i == 8) p--; data[p] = 0; } static void AjustName(char *data, char *name) { int i, j; memset(data, ' ', 11); i = 0; if(memcmp(name, "..", 2) == 0) { memcpy(data, name, 2); i = 2; } for(;i < 8;i++) { if(name[i] == 0 || name[i] == '/' || name[i] == '\\') return; if(name[i] == '.') break; data[i] = toupper(name[i]); } if(name[i] != '.') return; j = i + 1; for(i = 0;i < 3;i++, j++) { if(name[j] == 0 || name[j] == '/' || name[j] == '\\') return; data[i + 8] = toupper(name[j]); } } static int FindEntry(int fd, int clust, char *filename, int option) { int lba, i, maxent, cur, next, ret, entnum; int freelba, fat, pfat, savelba, prevlba; char name[12], *path; Entry ent, prevent; cur = 0; if(clust == 0) { lba = (file[fd].disk->ResvSec + file[fd].disk->FatSec * 2) * SECSIZ; maxent = file[fd].disk->RootEnt; } else { lba = file[fd].disk->TopClust * SECSIZ + (clust - 2) * SECSIZ * file[fd].disk->ClustSize; maxent = (SECSIZ * file[fd].disk->ClustSize) / sizeof(Entry); cur = clust; } if(filename[0] == 0 && option == OptNone) { file[fd].EntLba = lba; file[fd].EntClust = 0; file[fd].EntSize = file[fd].disk->RootEnt * sizeof(Entry); file[fd].EntOffset = 0; file[fd].EntClustOff = 0; file[fd].EntAttr = 0x10; file[fd].Error = 0; return 0; } AjustName(name, filename); freelba = -1; prevlba = -1; savelba = -1; bzero((char*)&prevent, sizeof(Entry)); if(option == OptCreate || option == OptAdd) { file[fd].EntClust = 0; file[fd].EntSize = 0; file[fd].EntOffset = 0; file[fd].EntClustOff = 0; for(i = 0;i < FATNUM;i++) file[fd].fats[i] = 0; file[fd].tailfat = 0; file[fd].fatindex = 0; file[fd].Error = 0; } entnum = 0; for(i = 0;;i++) { if(i >= maxent) { if(clust == 0) { break; } else { next = GetFat(fd, cur); if((next & file[fd].disk->tailsec) == file[fd].disk->tailsec) break; cur = next; lba = file[fd].disk->TopClust * SECSIZ + (cur - 2) * SECSIZ * file[fd].disk->ClustSize; i = 0; } } memcpy((char*)&prevent, (char*)&ent, sizeof(Entry)); prevlba = savelba; AccessData(fd, (char*)&ent, lba, sizeof(Entry), OptRead); savelba = lba; lba += sizeof(Entry); if(ent.name[0] == 0xe5 || ent.name[0] == 0) { if(freelba == -1) freelba = savelba; continue; } if(ent.attr & 0x0e) continue; if(option == OptCount) { entnum++; continue; } if(memcmp(name, ent.name, 11) == 0) { if(ent.attr & 0x10) { path = strchr(filename, '/'); if(path == 0) path = strchr(filename, '\\'); if(path != 0) path++; if((path != 0 && *path != 0) || ent.top == 0) { ret = FindEntry(fd, le16toh(ent.top), path, option); return ret; } if(option == OptDelete || option == OptCreate) { entnum = FindEntry(fd, le16toh(ent.top), path, OptCount); if(entnum > 2) return -1; } } file[fd].EntLba = savelba; switch(option) { case OptNone: memcpy((char*)&file[fd].CurEnt, (char*)&ent, sizeof(Entry)); file[fd].EntClust = le16toh(ent.top); file[fd].EntSize = le32toh(ent.size); file[fd].EntAttr = ent.attr; file[fd].EntOffset = 0; file[fd].EntClustOff = 0; file[fd].Error = 0; return 0; case OptDelete: case OptCreate: ent.name[0] = 0xe5; AccessData(fd, (char*)&ent, savelba, sizeof(Entry), OptWrite); if(prevent.name[0] == 0x41 && prevent.attr == 0x0f) { prevent.name[0] = 0xe5; AccessData(fd, (char*)&prevent, prevlba, sizeof(Entry), OptWrite); } pfat = fat = le16toh(ent.top); while((fat & file[fd].disk->tailsec) != file[fd].disk->tailsec && fat != 0) { fat = GetFat(fd, fat); SetFat(fd, pfat, 0); pfat = fat; } FlushBuffers(fd); if(option == OptCreate) { memcpy((char*)file[fd].CurEnt.name, name, 11); file[fd].CurEnt.date = le16toh(0x4821); file[fd].CurEnt.win95 = le16toh(0x18); } return 0; case OptAdd: memcpy((char*)&file[fd].CurEnt, (char*)&ent, sizeof(Entry)); pfat = fat = le16toh(ent.top); while((fat & file[fd].disk->tailsec) != file[fd].disk->tailsec && fat != 0) { pfat = fat; fat = GetFat(fd, fat); } file[fd].fats[file[fd].fatindex] = pfat; file[fd].EntClust = le16toh(ent.top); file[fd].EntSize = le32toh(ent.size); file[fd].EntOffset = file[fd].EntSize; file[fd].EntAttr = ent.attr; file[fd].EntClustOff = file[fd].EntOffset % (SECSIZ * file[fd].disk->ClustSize); if(file[fd].EntClustOff == 0) file[fd].fatindex++; return 0; } } } if(option == OptCount) return entnum; if((option == OptCreate || option == OptAdd) && freelba != -1) { bzero((char*)&file[fd].CurEnt, sizeof(Entry)); memcpy((char*)file[fd].CurEnt.name, name, 11); file[fd].CurEnt.attr = 0x20; file[fd].CurEnt.date = le16toh(0x4821); file[fd].CurEnt.win95 = le16toh(0x18); file[fd].EntLba = freelba; return 0; } return -1; } int OpenFile(int id, char *_name, int option) { int ret, off, fd, dd, siz, max, error; char *filename, *name; siz = 0; max = strlen(_name); if(_name[0] != '/') max += strlen(__cwd(id)); if(max >= MAX_PATH_LEN) return -1; name = __malloc(SuperTask, MAX_PATH_LEN); if(name == 0) return -1; name[0] = 0; if(_name[0] != '/') strcat(name, __cwd(id)); strcat(name, _name); for(dd = 0;dd < DISKNUM;dd++) { if(disk[dd].diskfd == 0) continue; siz = strlen((char*)disk[dd].name); if(memcmp((char*)disk[dd].name, name, siz) == 0) break; } if(dd == DISKNUM) { if(name != _name) __free(SuperTask, name); return -1; } for(fd = 0;fd < FILENUM;fd++) { if(file[fd].disk == 0) break; } if(fd == FILENUM) { if(name != _name) __free(SuperTask, name); return -1; } file[fd].disk = &disk[dd]; filename = &name[siz]; file[fd].fdopt = option; file[fd].cache[SECBUF].wrote = 0; file[fd].cache[SECDAT].wrote = 0; file[fd].cache[SECFAT].wrote = 0; file[fd].cache[SECBUF].ptr = 0; file[fd].cache[SECDAT].ptr = 0; file[fd].cache[SECFAT].ptr = 0; file[fd].cache[SECDAT].ptr = file[fd].disk->TopClust * SECSIZ; off = (topsec + file[fd].disk->TopClust) * SECSIZ; __seek(SuperTask, dfd, off); error = __read(SuperTask, dfd, file[fd].cache[SECDAT].buf, SECSIZ); if(error <= 0){ file[fd].Error = 1; if(name != _name) __free(SuperTask, name); return -1; } ret = -1; switch(option) { case OptRead: ret = FindEntry(fd, 0, filename, OptNone); break; case OptWrite: ret = FindEntry(fd, 0, filename, OptCreate); break; case OptRemove: ret = FindEntry(fd, 0, filename, OptDelete); break; case OptAppend: ret = FindEntry(fd, 0, filename, OptAdd); file[fd].fdopt = OptWrite; break; default: ret = -1; } if(file[fd].Error) ret = -1; __free(SuperTask, name); if(ret == -1 || option == OptRemove) { file[fd].disk = 0; } else { ret = fd; } file[fd].id = id; return ret; } int FlushFile(int id, int fd) { int i, fat; if(file[fd].id != id) return -1; if(check_fd(fd) == -1) return -1; if(file[fd].Error) return -1; file[fd].CurEnt.size = htole32(file[fd].EntOffset); AccessData(fd, (char*)&file[fd].CurEnt, file[fd].EntLba, sizeof(Entry), OptWrite); if(file[fd].tailfat != 0 && file[fd].fats[0] != 0) SetFat(fd, file[fd].tailfat, file[fd].fats[0]); for(i = 0;i <= file[fd].fatindex;i++) { fat = file[fd].fats[i + 1]; if(fat == 0) fat = 0xffff; if(file[fd].fats[i] != 0) { file[fd].tailfat = file[fd].fats[i]; SetFat(fd, file[fd].fats[i], fat); } } FlushBuffers(fd); __ioctl(SuperTask, dfd, 0, DEV_FLUSH); if(file[fd].Error) return -1; return 0; } int CloseFile(int id, int fd) { if(file[fd].id != id) return -1; if(check_fd(fd) == -1) return -1; if(file[fd].fdopt == OptWrite) FlushFile(id, fd); file[fd].disk = 0; file[fd].Error = 0; return 0; } int ReadFile(int id, int fd, char *data, int siz) { int c, off, len, size, remain; if(file[fd].id != id) return -1; if(check_fd(fd) == -1) return -1; if(file[fd].Error) return -1; if(file[fd].fdopt == OptNone) return 0; size = siz; if(!(file[fd].CurEnt.attr & 0x10)) { if((file[fd].EntOffset + siz) >= file[fd].EntSize) { size = file[fd].EntSize - file[fd].EntOffset; } if(size == 0) return 0; } remain = size; do { c = file[fd].EntClust; if((c & file[fd].disk->tailsec) == file[fd].disk->tailsec) return 0; off = file[fd].EntOffset % (SECSIZ * file[fd].disk->ClustSize); len = AccessCData(fd, c, &data[size - remain], off, remain, OptRead); file[fd].EntOffset += len; file[fd].EntClustOff += len; remain -= len; if(file[fd].EntClustOff >= file[fd].disk->ClustSize * SECSIZ) { file[fd].EntClustOff = 0; file[fd].EntClust = GetFat(fd, file[fd].EntClust); } } while(remain > 0); if(file[fd].Error) return -1; return size; } int WriteFile(int id, int fd, char *data, int size) { int i, c, off, len, fat, remain; if(file[fd].id != id) return -1; if(check_fd(fd) == -1) return -1; if(file[fd].Error) return -1; if(file[fd].fdopt == OptNone) return 0; remain = size; do { if(file[fd].fats[file[fd].fatindex] == 0) { fat = FreeFat(fd); if(fat == 0) return 0; file[fd].fats[file[fd].fatindex] = fat; if(file[fd].EntOffset == 0) file[fd].CurEnt.top = le16toh(fat); } c = file[fd].fats[file[fd].fatindex]; off = file[fd].EntOffset % (SECSIZ * file[fd].disk->ClustSize); len = AccessCData(fd, c, &data[size - remain], off, remain, OptWrite); file[fd].EntOffset += len; file[fd].EntClustOff += len; remain -= len; if(file[fd].EntClustOff >= file[fd].disk->ClustSize * SECSIZ) { file[fd].EntClustOff = 0; file[fd].fatindex++; if(file[fd].fatindex >= (FATNUM - 1)) { FlushFile(id, fd); for(i = 0;i < FATNUM;i++) file[fd].fats[i] = 0; file[fd].fatindex = 0; } } } while(remain > 0); if(file[fd].Error) return -1; return size; } int SeekFile(int id, int fd, int pos) { int fat, pfat; if(file[fd].id != id) return -1; if(check_fd(fd) == -1) return -1; if(file[fd].Error) return -1; if(file[fd].fdopt != OptRead) return -1; pfat = fat = le16toh(file[fd].CurEnt.top); file[fd].EntOffset = 0; while((fat & file[fd].disk->tailsec) != file[fd].disk->tailsec && fat != 0) { pfat = fat; fat = GetFat(fd, fat); file[fd].EntClust = pfat; file[fd].EntOffset += file[fd].disk->ClustSize * SECSIZ; if(file[fd].EntOffset > pos) { file[fd].EntOffset = pos; file[fd].EntClustOff = file[fd].EntOffset % (SECSIZ * file[fd].disk->ClustSize); return 0; } } file[fd].EntOffset = file[fd].EntSize; file[fd].EntClustOff = file[fd].EntOffset % (SECSIZ * file[fd].disk->ClustSize); return 0; } int GetFileSize(int id, int _fd) { int fd; fd = _fd & FAT_MASK; if(file[fd].id != id) return -1; if(check_fd(fd) == -1) return -1; if(file[fd].Error) return -1; if(file[fd].fdopt == OptNone) return 0; if(file[fd].fdopt == OptWrite) FlushFile(id, fd); return le32toh(file[fd].CurEnt.size); } int GetFileId(int _fd) { int fd; fd = _fd & FAT_MASK; if(check_fd(fd) == -1) return -1; return file[fd].id; } int SetDirent(int id, char *name, DirEnt *entry) { int fd; fd = OpenFile(id, name, OptRead); if(fd == -1) return -1; if((file[fd].EntAttr & 0x10) == 0) { CloseFile(id, fd); return -1; } return fd | FATFD_MASK; } int NextRecord(int id, int _fd, DirEnt *entry) { int len, ret, fd; Entry ent; fd = _fd & FAT_MASK; if(file[fd].id != id) return -1; if(check_fd(fd) == -1) return -1; if(file[fd].Error) return -1; ret = -1; if(file[fd].EntClust == 0) { while(file[fd].EntOffset < file[fd].EntSize) { len = AccessData(fd, (char*)&ent, file[fd].EntLba, sizeof(Entry), OptRead); if(len == 0) break; file[fd].EntLba += sizeof(Entry); file[fd].EntOffset += sizeof(Entry); file[fd].EntClustOff += sizeof(Entry); if(ent.name[0] != 0xe5 && ent.name[0] != 0 && !(ent.attr & 0x0e)) { ret = 0; break; } } } else { do { len = ReadFile(id, fd, (char*)&ent, sizeof(Entry)); if(ent.name[0] != 0xe5 && ent.name[0] != 0 && !(ent.attr & 0x0e)) { ret = 0; break; } } while(len == sizeof(Entry)); } if(ret == 0) { entry->length = le32toh(ent.size); entry->attr = ent.attr; AjustName2(entry->name, ent.name); } return ret; } void fat_init(void) { int fd; FILENUM = files; diskbuffer = __malloc(SuperTask, SECSIZ * 3 * FILENUM); disk = (DiskInfo *)__malloc(SuperTask, sizeof(DiskInfo) * DISKNUM); file = (FileInfo *)__malloc(SuperTask, sizeof(FileInfo) * FILENUM); for(fd = 0;fd < FILENUM;fd++) { file[fd].cache[SECBUF].buf = &diskbuffer[fd * SECSIZ * 3]; file[fd].cache[SECDAT].buf = &(file[fd].cache[SECBUF].buf[SECSIZ]); file[fd].cache[SECFAT].buf = &(file[fd].cache[SECDAT].buf[SECSIZ]); } } int mount(char *devname) { unsigned char FdcArea[sizeof(FDC)]; unsigned char secbuf[SECSIZ]; FDC *fdc; int id, top, off, fd, dd, error, i; int params[2]; for(dd = 0;dd < DISKNUM;dd++) { if(disk[dd].diskfd == 0) { fd = __open(SuperTask, devname, 0); if(fd == -1) return -1; disk[dd].diskfd = fd; strcpy((char*)disk[dd].name, "/"); strcat((char*)disk[dd].name, devname); strcat((char*)disk[dd].name, "/"); __seek(SuperTask, disk[dd].diskfd, 0); __read(SuperTask, disk[dd].diskfd, secbuf, SECSIZ); __seek(SuperTask, disk[dd].diskfd, 0); //---------------------------------------------------------------- // __read(SuperTask, disk[dd].diskfd, secbuf, SECSIZ); error = __read(SuperTask, disk[dd].diskfd, secbuf, SECSIZ); if (error <= 0) { disk[dd].diskfd = 0; __close(SuperTask, fd); return -1; } //---------------------------------------------------------------- id = 4; disk[dd].rsc = 0; if(secbuf[0] != 0xeb || secbuf[0x1fe] != 0x55 || secbuf[0x1ff] != 0xaa) { id = secbuf[0x1c2]; //---------------------------------------------------------------- // disk[dd].rsc = secbuf[0x1c6]; for (i = 3; i >= 0; i--) { disk[dd].rsc <<= 8; // see mes25r19 file.c mount() disk[dd].rsc |= secbuf[0x1c6 + i]; } //---------------------------------------------------------------- off = disk[dd].rsc * SECSIZ; __seek(SuperTask, disk[dd].diskfd, off); //---------------------------------------------------------------- //__read(SuperTask, disk[dd].diskfd, secbuf, SECSIZ); //if(secbuf[0] != 0xeb || secbuf[0x1fe] != 0x55 || secbuf[0x1ff] != 0xaa) { error = __read(SuperTask, disk[dd].diskfd, secbuf, SECSIZ); // see mes25r19 file.c mount() if(secbuf[0] != 0xeb || secbuf[0x1fe] != 0x55 || secbuf[0x1ff] != 0xaa || error <= 0) { //---------------------------------------------------------------- disk[dd].diskfd = 0; __close(SuperTask, fd); return -1; } } memcpy(FdcArea, secbuf, sizeof(FDC)); fdc = (FDC*)FdcArea; disk[dd].SecSize = le16toh(fdc->ss); disk[dd].ClustSize = fdc->sc; disk[dd].ResvSec = le16toh(fdc->rsc); disk[dd].FatNum = fdc->fn; disk[dd].RootEnt = le16toh(fdc->rde); disk[dd].TotalSec = (fdc->ts == 0) ? le32toh(fdc->ts2) : le16toh(fdc->ts); disk[dd].FatSec = (fdc->sf == 0) ? le32toh(fdc->sf2) : le16toh(fdc->sf); top = (disk[dd].ResvSec + disk[dd].FatSec * 2) * SECSIZ + disk[dd].RootEnt * sizeof(Entry); disk[dd].TopClust = top / SECSIZ; params[0] = disk[dd].rsc + disk[dd].ResvSec + disk[dd].FatSec * 2; params[1] = (disk[dd].RootEnt * sizeof(Entry)) / SECSIZ; __ioctl(SuperTask, fd, (int)params, DISK_CACHE); switch(id) { case 4: case 6: case 14: case 20: case 22: case 30: disk[dd].fatid = FAT16; disk[dd].tailsec = 0xfff0; return dd; case 1: disk[dd].fatid = FAT12; disk[dd].tailsec = 0xfff; return dd; default: disk[dd].diskfd = 0; __close(SuperTask, fd); return -1; } } } return -1; } int eject(char *devname) { int dd, len, fd; len = strlen(devname); for(dd = 0;dd < DISKNUM;dd++) { if(disk[dd].diskfd == 0) continue; if(memcmp(devname, (char*)&disk[dd].name[1], len) == 0) { for(fd = 0;fd < FILENUM;fd++) { if(file[fd].disk->diskfd == disk[dd].diskfd) { if(file[fd].fdopt == OptWrite) FlushFile(file[fd].id, fd); file[fd].disk = 0; file[fd].Error = 0; } } __close(SuperTask, disk[dd].diskfd); disk[dd].diskfd = 0; return 0; } } return -1; } int format(char *devname) { int i, fd, n, sec, size, entsec, fatsec; char *buf; FDC *fdc; buf = __malloc(SuperTask, SECSIZ); if(buf == 0) return -1; fd = __open(SuperTask, devname, 0); if(fd == -1) return -1; size = __ioctl(SuperTask, fd, 0, MEDIA_SIZE); if(size == -1) { __close(SuperTask, fd); return -1; } bzero(buf, SECSIZ); fdc = (FDC*)buf; buf[0] = 0xeb; buf[0x1fe] = 0x55; buf[0x1ff] = 0xaa; fdc->ss = htole16(SECSIZ); fdc->rsc = htole16(1); fdc->fn = 2; sec = size / SECSIZ; n = ((sec * sizeof(Entry)) / (SECSIZ * 2)) * SECSIZ; if(n == 0) n = SECSIZ; n = n / sizeof(Entry); if(n > 0xf0) n = 0xf0; entsec = (n * sizeof(Entry)) / SECSIZ; fdc->rde = htole16(n); fdc->ts = htole16(sec); fdc->ident = 0; fatsec = (sec * 2) / SECSIZ; if(fatsec == 0) fatsec = 1; fdc->sc = 1; if(fatsec > 0x20) { fatsec = 0x20; fdc->sc = fatsec / 0x20; } fdc->sf = htole16(fatsec); __seek(SuperTask, fd, 0); if(__write(SuperTask, fd, buf, SECSIZ) <= 0) return -1; bzero(buf, SECSIZ); n = 1 + fatsec * 2 + entsec; for(i = 1;i < n;i++) { __seek(SuperTask, fd, i * SECSIZ); if(__write(SuperTask, fd, buf, SECSIZ) <= 0) return -1; } __free(SuperTask, buf); __close(SuperTask, fd); return 0; } int free_file(int id) { int fd; for(fd = 0;fd < FILENUM;fd++) { if(file[fd].id == id) { CloseFile(id, fd); } } return 0; }