/* d80.c - simple midnight commander's extfs module for manipulating d80 diskette images comments, patches, improvements are welcome at: dusky at hq dot alert dot sk 2006 dusky */ #include #include #include #include #include #include #include #include #define SECSIZE 512 #define FATPOS 1 #define DIRPOS 6 #define FATSIZE 5 #define IMAGE_MDOS 1 #define IMAGE_MDOS3 2 //IllegalCharsShort: db """*+,./:;<=>?[\\]|" char *diskpath; int diskfd; int diskaccess; unsigned char fat[FATSIZE][SECSIZE]; int skip=0; char *ext="PCNB_SQ"; char *encode_filename(unsigned char *dentry) { static char outname[96]; char *ptr; int i, extra1, extra2; if (!dentry) return NULL; ptr=outname; for (i=1; i<11; i++) { if (!*(dentry+i)) continue; if (*(dentry+i)>126 || strchr("\"#*+.,/:;<=>?[\\]|{}", *(dentry+i))) { sprintf(ptr, "#%02X", *(dentry+i)); ptr+=2; } else *ptr=*(dentry+i); ptr++; } extra1=dentry[13]+256*dentry[14]; extra2=dentry[15]+256*dentry[16]; sprintf(ptr, ",#%04X,#%04X", extra1, extra2); ptr+=12; *ptr='.'; ptr++; if (*dentry>126 || strchr("\"#*+.,/:;<=>?[\\]|{}", *dentry)) { sprintf(ptr, "#%02X", *dentry); ptr+=2; } else { switch (*dentry) { case 'P': sprintf(ptr, "zx0"); break; case 'C': sprintf(ptr, "zx1"); break; case 'N': sprintf(ptr, "zx2"); break; case 'B': sprintf(ptr, "zx3"); break; case 'S': sprintf(ptr, "zx5"); break; case 'Q': sprintf(ptr, "zx6"); break; default: sprintf(ptr, "#%02X", *dentry); } ptr+=2; } ptr++; *ptr='\0'; return outname; } unsigned char *decode_filename(char *filename) { static unsigned char dentry[32]; char *ptr2; int i, extra1, extra2, len, ch, stage, j; if (!filename) return NULL; memset(dentry, 0xE5, 32); extra1=0; extra2=0; ptr2=filename; stage=0; j=1; for (i=0; i2) return NULL; dentry[13]=(extra1 & 0xff); dentry[14]=(extra1 >> 8) & 0xff; dentry[15]=(extra2 & 0xff); dentry[16]=(extra2 >> 8) & 0xff; stage=3; break; case ',': if (stage>1) return NULL; switch (stage) { case 0: len=sscanf(ptr2+1, "#%04X", &extra1); ptr2+=len*5; break; case 1: len=sscanf(ptr2+1, "#%04X", &extra2); ptr2+=len*5; break; default: return NULL; } stage++; break; case '#': if (stage==3) { len=sscanf(ptr2, "#%02X", &ch); ptr2+=len*2; while (j<11) { dentry[j]='\000'; j++; } dentry[0]=ch; stage++; } else if (j<11) { len=sscanf(ptr2, "#%02X", &ch); ptr2+=len*2; dentry[j]=ch; j++; } break; default: switch (stage) { case 0: if (j<11) { dentry[j]=*ptr2; j++; } break; case 1: case 2: return NULL; break; case 3: if (*ptr2!='z' || *(ptr2+1)!='x') return NULL; ch=*(ptr2+2); if ((ch<'0') || (ch>'6')) return NULL; while (j<11) { dentry[j]='\000'; j++; } dentry[0]=ext[ch-48]; ptr2+=2; } } ptr2++; } return dentry; } int image_type_guess() { unsigned char buff[SECSIZE]; if (diskfd==-1) { printf("Image is not opened.\n"); return -1; } lseek(diskfd, 0, SEEK_SET); read(diskfd, buff, SECSIZE); if (buff[0xCC]==0x53 && buff[0xCD]==0x44 && buff[0xCE]==0x4f && buff[0xCF]==0x53) return IMAGE_MDOS; read(diskfd, buff, SECSIZE); if (buff[0xCC]==0x53 && buff[0xCD]==0x44 && buff[0xCE]==0x4f && buff[0xCF]==0x53) return IMAGE_MDOS3; return -1; } void read_fat() { int i; if (diskfd==-1) { printf("Image is not opened.\n"); return; } lseek(diskfd, skip + FATPOS * SECSIZE, SEEK_SET); for (i=0;i=FATSIZE) return 0xDDD; if (s1&1) next = fat[s2][(s1/2)*3+2] + 256*((fat[s2][(s1/2)*3+1])&15); else next = fat[s2][(s1/2)*3] + 256*((fat[s2][(s1/2)*3+1])>>4); return next; } void set_fat_next(int sec, int next) { int s1,s2; s1=(sec % 341); s2=(sec / 341); if (s2>=FATSIZE) return; if (s1&1) { fat[s2][(s1/2)*3+2] = (next & 0xff); fat[s2][(s1/2)*3+1]&=0xf0; fat[s2][(s1/2)*3+1]|=((next >> 8) & 0x0f); } else { fat[s2][(s1/2)*3] = (next & 0xff); fat[s2][(s1/2)*3+1]&=0x0f; fat[s2][(s1/2)*3+1]|=((next >> 4) & 0xf0); } } int find_free_fat(int from) { int i; if (diskfd==-1) { printf("Image is not opened.\n"); return -1; } for (i=from;i<1705;i++) { if (get_fat_next(i)==0) return i; } return -1; } int check_space(int size) { int first,next,i; if ((first=find_free_fat(0))==-1) return -1; if (size==0) return first; next=first+1; for (i=1;i<((size+511)/512);i++) { if ((next=find_free_fat(next))==-1) return -1; next++; } return first; } int count_len(int sec) { int nsec=get_fat_next(sec); if (nsec==0xC00) return 0x000; if (nsec>0xE00) return nsec-0xE00; if (nsec==0xE00) return 0x200; if (nsec>0xC00) return 0x000; return 0x200+count_len(nsec); } int open_disk(char *fname) { int fd,type; if (!fname) { printf("Bad filename.\n"); return -1; } if (diskfd!=-1) { printf("Image (%s) is already opened.\n", diskpath); return -1; } diskaccess=-1; if ((fd=open(fname, O_RDWR))<0) { if ((fd=open(fname, O_RDONLY))<0) { printf("Can't open image (%s).\n", fname); return -1; } diskaccess++; } diskaccess++; diskfd=fd; switch (type=image_type_guess()) { case IMAGE_MDOS: skip=0; break; case IMAGE_MDOS3: skip=512; break; default: // printf("Unknown image type (%d).\n", type); close(fd); diskfd=-1; return -1; } diskpath=strdup(fname); return fd; } void close_disk() { if (diskfd==-1) { printf("Image is not opened.\n"); return; } if (diskpath) free(diskpath); diskpath=NULL; close(diskfd); diskfd=-1; } void list() { int i, len, fsec; unsigned char dentry[32]; if (diskfd==-1) { printf("Image is not opened.\n"); return; } lseek(diskfd, skip + DIRPOS * SECSIZE, SEEK_SET); for (i=0;i<128;i++) { read(diskfd, dentry, 32); if (dentry[0]==0xe5) continue; len=(unsigned char)dentry[11]+256*(unsigned char)dentry[12]+65536*(unsigned char)dentry[21]; fsec=(unsigned char)dentry[17]+256*(unsigned char)dentry[18]; printf("-rw-rw-rw- 1 0 0 %d 01-01-1970 01:00 ", len); printf("%s\n", encode_filename(dentry)); } } unsigned char *find_file(char *filename) { static unsigned char dentry[32], *dentry2; int i; dentry2=decode_filename(filename); lseek(diskfd, skip + DIRPOS * SECSIZE, SEEK_SET); for (i=0;i<128;i++) { read(diskfd, dentry, 32); if (dentry[0]==0xe5) continue; if (memcmp(dentry, dentry2, 11)) continue; return dentry; } /* for (i=0;i<11;i++) printf("%c",dentry2[i]); printf("\n"); sleep(5); */ return NULL; } int find_free_file() { static unsigned char dentry[32]; int i; lseek(diskfd, skip + DIRPOS * SECSIZE, SEEK_SET); for (i=0;i<128;i++) { read(diskfd, dentry, 32); if (dentry[0]==0xe5) { return i; } } return -1; } int copyout(char *filename, char *filename2) { int len, fsec, nsec; int ofd; unsigned char *dentry; unsigned char buff[SECSIZE]; read_fat(); if (!filename) { printf("Bad filename.\n"); return -1; } if (diskfd==-1) { printf("Image is not opened.\n"); return -1; } dentry=find_file(filename); if (!dentry) { printf("No such file (%s).\n", filename); return -1; } len=(unsigned char)dentry[11]+256*(unsigned char)dentry[12]+65536*(unsigned char)dentry[21]; fsec=(unsigned char)dentry[17]+256*(unsigned char)dentry[18]; ofd=open(filename2, O_WRONLY|O_CREAT|O_TRUNC, 0666); while ((nsec=get_fat_next(fsec))!=0xC00) { lseek(diskfd, skip + fsec*SECSIZE, SEEK_SET); read(diskfd, buff, SECSIZE); if (nsec>0xE00) { write(ofd, buff, nsec-0xE00); break; } if (nsec==0xE00) { write(ofd, buff, 0x200); break; } if (nsec>0xC00) break; write(ofd, buff, 0x200); fsec=nsec; } close(ofd); return 0; } int copyin(char *filename, char *filename2) { int len, fsec, nsec, nsec2; int ifd, dir, i; unsigned char *dentry; unsigned char buff[SECSIZE]; struct stat st; read_fat(); if (!filename || !filename2) { printf("Bad filename.\n"); return -1; } if (diskfd==-1) { printf("Image is not opened.\n"); return -1; } dentry=find_file(filename); if (dentry) { printf("File exist (%s).\n", filename); return -1; } if ((dir=find_free_file())==-1) { printf("Directory full.\n"); return -1; } stat(filename2, &st); len=st.st_size; fsec=check_space(len); if (fsec==-1) { printf("No enough free space (%d)\n", len); return -1; } if (len==0) { set_fat_next(fsec, 0xC00); } else { ifd=open(filename2, O_RDONLY); nsec=fsec; nsec2=nsec; for (i=1;i<((len+511)/512);i++) { nsec=find_free_fat(nsec2+1); set_fat_next(nsec2, nsec); read(ifd, buff, SECSIZE); lseek(diskfd, skip + nsec2*SECSIZE, SEEK_SET); write(diskfd, buff, SECSIZE); nsec2=nsec; } set_fat_next(nsec2, (len%512)+0xE00); read(ifd, buff, SECSIZE); lseek(diskfd, skip + nsec2*SECSIZE, SEEK_SET); write(diskfd, buff, SECSIZE); close(ifd); } dentry=decode_filename(filename); dentry[11]=len&0xFF; dentry[12]=(len >> 8)&0xFF; dentry[21]=(len >> 16)&0xFF; dentry[17]=fsec&0xFF; dentry[18]=(fsec >> 8)&0xFF; dentry[19]=0x00; dentry[20]=0x0F; write_fat(); lseek(diskfd, skip + DIRPOS*SECSIZE + dir*32, SEEK_SET); write(diskfd, dentry, 32); return 0; } void rm(char *filename) { int fsec, nsec; unsigned char *dentry; unsigned char buff[SECSIZE]; read_fat(); if (!filename) { printf("Bad filename.\n"); return; } if (diskfd==-1) { printf("Image is not opened.\n"); return; } dentry=find_file(filename); if (!dentry) { printf("No such file (%s).\n", filename); return; } lseek(diskfd, -32, SEEK_CUR); buff[0]=0xe5; write(diskfd, buff, 1); fsec=(unsigned char)dentry[17]+256*(unsigned char)dentry[18]; while ((nsec=get_fat_next(fsec))<0xC00) { if (!nsec) break; set_fat_next(fsec, 0x000); fsec=nsec; } if ((nsec>>8)!=0xd) set_fat_next(fsec, 0x000); write_fat(); } void fat_disk() { int i; if (diskfd==-1) { printf("Image is not opened.\n"); return; } for (i=0;i<64;i++) { printf("%03X: %03X\n",i, get_fat_next(i)); } } void test_fat() { read_fat(); fat_disk(); set_fat_next(0,666); fat_disk(); } int main(int argc, char **argv) { FILE *fp; int i,retval; diskpath=NULL; diskfd=-1; fp=fopen("/tmp/d80.log","a"); for (i=0;i