2009-05-02 23:03:37 +02:00
|
|
|
/*
|
2009-05-02 23:53:27 +02:00
|
|
|
* Copyright (C) 2002-2004 The DOSBox Team
|
2009-05-02 23:03:37 +02:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2009-05-03 00:02:15 +02:00
|
|
|
* GNU General Public License for more details.
|
2009-05-02 23:03:37 +02:00
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
2009-05-03 00:08:43 +02:00
|
|
|
/* $Id: dos_files.cpp,v 1.59 2004/11/16 14:28:15 qbix79 Exp $ */
|
2009-05-02 23:43:00 +02:00
|
|
|
|
2009-05-02 23:03:37 +02:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
2009-05-02 23:12:18 +02:00
|
|
|
#include <time.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
2009-05-02 23:03:37 +02:00
|
|
|
#include "dosbox.h"
|
2009-05-02 23:35:44 +02:00
|
|
|
#include "bios.h"
|
2009-05-02 23:03:37 +02:00
|
|
|
#include "mem.h"
|
2009-05-02 23:43:00 +02:00
|
|
|
#include "regs.h"
|
2009-05-02 23:03:37 +02:00
|
|
|
#include "dos_inc.h"
|
|
|
|
#include "drives.h"
|
2009-05-02 23:12:18 +02:00
|
|
|
#include "cross.h"
|
2009-05-02 23:03:37 +02:00
|
|
|
|
|
|
|
#define DOS_FILESTART 4
|
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
#define FCB_SUCCESS 0
|
|
|
|
#define FCB_READ_NODATA 1
|
|
|
|
#define FCB_READ_PARTIAL 3
|
|
|
|
#define FCB_ERR_NODATA 1
|
|
|
|
#define FCB_ERR_EOF 3
|
|
|
|
#define FCB_ERR_WRITE 1
|
|
|
|
|
2009-05-02 23:03:37 +02:00
|
|
|
|
|
|
|
DOS_File * Files[DOS_FILES];
|
|
|
|
DOS_Drive * Drives[DOS_DRIVES];
|
|
|
|
|
|
|
|
Bit8u DOS_GetDefaultDrive(void) {
|
2009-05-02 23:20:05 +02:00
|
|
|
return dos.current_drive;
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void DOS_SetDefaultDrive(Bit8u drive) {
|
2009-05-02 23:20:05 +02:00
|
|
|
if (drive<=DOS_DRIVES) dos.current_drive=drive;
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool DOS_MakeName(char * name,char * fullname,Bit8u * drive) {
|
2009-05-02 23:53:27 +02:00
|
|
|
if(strlen(name) == 0) {
|
|
|
|
DOS_SetError(DOSERR_FILE_NOT_FOUND);
|
|
|
|
return false;
|
|
|
|
}
|
2009-05-03 00:08:43 +02:00
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
char tempdir[DOS_PATHLENGTH];
|
2009-05-02 23:03:37 +02:00
|
|
|
char upname[DOS_PATHLENGTH];
|
2009-05-02 23:20:05 +02:00
|
|
|
Bitu r,w;
|
|
|
|
*drive=dos.current_drive;
|
|
|
|
/* First get the drive */
|
|
|
|
if (name[1]==':') {
|
|
|
|
*drive=(name[0] | 0x20)-'a';
|
|
|
|
name+=2;
|
|
|
|
}
|
|
|
|
if (*drive>=DOS_DRIVES || !Drives[*drive]) {
|
|
|
|
DOS_SetError(DOSERR_PATH_NOT_FOUND);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
r=0;w=0;
|
2009-05-02 23:03:37 +02:00
|
|
|
while (name[r]!=0 && (r<DOS_PATHLENGTH)) {
|
|
|
|
Bit8u c=name[r++];
|
|
|
|
if ((c>='a') && (c<='z')) {upname[w++]=c-32;continue;}
|
|
|
|
if ((c>='A') && (c<='Z')) {upname[w++]=c;continue;}
|
|
|
|
if ((c>='0') && (c<='9')) {upname[w++]=c;continue;}
|
|
|
|
switch (c) {
|
|
|
|
case '/':
|
|
|
|
upname[w++]='\\';
|
|
|
|
break;
|
|
|
|
case ' ':
|
|
|
|
break;
|
|
|
|
case '\\': case '$': case '#': case '@': case '(': case ')':
|
|
|
|
case '!': case '%': case '{': case '}': case '`': case '~':
|
|
|
|
case '_': case '-': case '.': case '*': case '?': case '&':
|
2009-05-02 23:53:27 +02:00
|
|
|
case '\'': case '+': case '^':
|
2009-05-02 23:03:37 +02:00
|
|
|
upname[w++]=c;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DOS_SetError(DOSERR_PATH_NOT_FOUND);return false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-05-02 23:20:05 +02:00
|
|
|
if (r>=DOS_PATHLENGTH) { DOS_SetError(DOSERR_PATH_NOT_FOUND);return false; }
|
2009-05-02 23:03:37 +02:00
|
|
|
upname[w]=0;
|
|
|
|
/* Now parse the new file name to make the final filename */
|
|
|
|
if (upname[0]!='\\') strcpy(fullname,Drives[*drive]->curdir);
|
|
|
|
else fullname[0]=0;
|
|
|
|
Bit32u lastdir=0;Bit32u t=0;
|
|
|
|
while (fullname[t]!=0) {
|
|
|
|
if ((fullname[t]=='\\') && (fullname[t+1]!=0))lastdir=t;
|
|
|
|
t++;
|
|
|
|
};
|
|
|
|
r=0;w=0;
|
|
|
|
tempdir[0]=0;
|
|
|
|
bool stop=false;
|
|
|
|
while (!stop) {
|
|
|
|
if (upname[r]==0) stop=true;
|
|
|
|
if ((upname[r]=='\\') || (upname[r]==0)){
|
|
|
|
tempdir[w]=0;
|
|
|
|
if (tempdir[0]==0) { w=0;r++;continue;}
|
|
|
|
if (strcmp(tempdir,".")==0) {
|
|
|
|
tempdir[0]=0;
|
|
|
|
w=0;r++;
|
|
|
|
continue;
|
|
|
|
}
|
2009-05-02 23:43:00 +02:00
|
|
|
|
|
|
|
Bit32u iDown, cDots;
|
|
|
|
bool dots = true;
|
|
|
|
Bit32u templen =strlen(tempdir);
|
|
|
|
for(iDown=0;(iDown < templen) && dots;iDown++)
|
|
|
|
if(tempdir[iDown] != '.')
|
|
|
|
dots = false;
|
|
|
|
|
|
|
|
// only dots?
|
|
|
|
cDots = templen - 1;
|
|
|
|
if(dots && (cDots > 0))
|
|
|
|
{
|
|
|
|
for(iDown=strlen(fullname)-1;iDown>=0;iDown--)
|
|
|
|
{
|
|
|
|
if(fullname[iDown]=='\\' || iDown==0)
|
|
|
|
{
|
|
|
|
lastdir = iDown;
|
|
|
|
cDots--;
|
|
|
|
if(cDots==0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
fullname[lastdir]=0;
|
|
|
|
Bit32u t=0;lastdir=0;
|
|
|
|
while (fullname[t]!=0) {
|
|
|
|
if ((fullname[t]=='\\') && (fullname[t+1]!=0))lastdir=t;
|
|
|
|
t++;
|
|
|
|
}
|
|
|
|
tempdir[0]=0;
|
|
|
|
w=0;r++;
|
|
|
|
continue;
|
|
|
|
}
|
2009-05-02 23:43:00 +02:00
|
|
|
|
|
|
|
|
2009-05-02 23:03:37 +02:00
|
|
|
lastdir=strlen(fullname);
|
2009-05-02 23:43:00 +02:00
|
|
|
|
2009-05-02 23:03:37 +02:00
|
|
|
if (lastdir!=0) strcat(fullname,"\\");
|
2009-05-02 23:20:05 +02:00
|
|
|
char * ext=strchr(tempdir,'.');
|
|
|
|
if (ext) {
|
|
|
|
ext[4]=0;
|
|
|
|
if (strlen(tempdir)>12) memmove(tempdir+8,ext,5);
|
|
|
|
} else tempdir[8]=0;
|
2009-05-02 23:03:37 +02:00
|
|
|
strcat(fullname,tempdir);
|
|
|
|
tempdir[0]=0;
|
|
|
|
w=0;r++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
tempdir[w++]=upname[r++];
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-05-02 23:12:18 +02:00
|
|
|
bool DOS_GetCurrentDir(Bit8u drive,char * buffer) {
|
2009-05-02 23:03:37 +02:00
|
|
|
if (drive==0) drive=DOS_GetDefaultDrive();
|
|
|
|
else drive--;
|
|
|
|
if ((drive>DOS_DRIVES) || (!Drives[drive])) {
|
|
|
|
DOS_SetError(DOSERR_INVALID_DRIVE);
|
|
|
|
return false;
|
|
|
|
}
|
2009-05-02 23:12:18 +02:00
|
|
|
strcpy(buffer,Drives[drive]->curdir);
|
2009-05-02 23:03:37 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DOS_ChangeDir(char * dir) {
|
|
|
|
Bit8u drive;char fulldir[DOS_PATHLENGTH];
|
|
|
|
if (!DOS_MakeName(dir,fulldir,&drive)) return false;
|
2009-05-02 23:27:47 +02:00
|
|
|
|
2009-05-02 23:03:37 +02:00
|
|
|
if (Drives[drive]->TestDir(fulldir)) {
|
|
|
|
strcpy(Drives[drive]->curdir,fulldir);
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
DOS_SetError(DOSERR_PATH_NOT_FOUND);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DOS_MakeDir(char * dir) {
|
|
|
|
Bit8u drive;char fulldir[DOS_PATHLENGTH];
|
|
|
|
if (!DOS_MakeName(dir,fulldir,&drive)) return false;
|
|
|
|
return Drives[drive]->MakeDir(fulldir);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DOS_RemoveDir(char * dir) {
|
2009-05-03 00:08:43 +02:00
|
|
|
/* We need to do the test before the removal as can not rely on
|
|
|
|
* the host to forbid removal of the current directory.
|
|
|
|
* We never change directory. Everything happens in the drives.
|
|
|
|
*/
|
2009-05-02 23:03:37 +02:00
|
|
|
Bit8u drive;char fulldir[DOS_PATHLENGTH];
|
|
|
|
if (!DOS_MakeName(dir,fulldir,&drive)) return false;
|
2009-05-03 00:08:43 +02:00
|
|
|
/* Check if exists */
|
|
|
|
if(!Drives[drive]->TestDir(fulldir)) {
|
|
|
|
DOS_SetError(DOSERR_PATH_NOT_FOUND);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
/* See if it's current directory */
|
|
|
|
char currdir[DOS_PATHLENGTH]= { 0 };
|
|
|
|
DOS_GetCurrentDir(drive + 1 ,currdir);
|
|
|
|
if(strcmp(currdir,fulldir) == 0) {
|
|
|
|
DOS_SetError(DOSERR_REMOVE_CURRENT_DIRECTORY);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(Drives[drive]->RemoveDir(fulldir)) return true;
|
|
|
|
|
|
|
|
/* Failed. We know it exists and it's not the current dir */
|
|
|
|
/* Assume non empty */
|
|
|
|
DOS_SetError(DOSERR_ACCESS_DENIED);
|
|
|
|
return false;
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool DOS_Rename(char * oldname,char * newname) {
|
|
|
|
Bit8u driveold;char fullold[DOS_PATHLENGTH];
|
|
|
|
Bit8u drivenew;char fullnew[DOS_PATHLENGTH];
|
|
|
|
if (!DOS_MakeName(oldname,fullold,&driveold)) return false;
|
|
|
|
if (!DOS_MakeName(newname,fullnew,&drivenew)) return false;
|
|
|
|
//TODO Test for different drives maybe
|
|
|
|
if (Drives[drivenew]->Rename(fullold,fullnew)) return true;
|
|
|
|
DOS_SetError(DOSERR_FILE_NOT_FOUND);
|
|
|
|
return false;
|
2009-05-02 23:20:05 +02:00
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
bool DOS_FindFirst(char * search,Bit16u attr,bool fcb_findfirst) {
|
|
|
|
DOS_DTA dta(dos.dta());
|
2009-05-02 23:03:37 +02:00
|
|
|
Bit8u drive;char fullsearch[DOS_PATHLENGTH];
|
2009-05-02 23:20:05 +02:00
|
|
|
char dir[DOS_PATHLENGTH];char pattern[DOS_PATHLENGTH];
|
2009-05-02 23:03:37 +02:00
|
|
|
if (!DOS_MakeName(search,fullsearch,&drive)) return false;
|
2009-05-02 23:20:05 +02:00
|
|
|
/* Split the search in dir and pattern */
|
|
|
|
char * find_last;
|
|
|
|
find_last=strrchr(fullsearch,'\\');
|
|
|
|
if (!find_last) { /*No dir */
|
|
|
|
strcpy(pattern,fullsearch);
|
|
|
|
dir[0]=0;
|
|
|
|
} else {
|
|
|
|
*find_last=0;
|
|
|
|
strcpy(pattern,find_last+1);
|
|
|
|
strcpy(dir,fullsearch);
|
2009-05-03 00:08:43 +02:00
|
|
|
}
|
|
|
|
//check for devices. first part of filename before the dot
|
|
|
|
//can be the name of a device. like con.1
|
|
|
|
//if(findDevice(pattern) blah blah
|
|
|
|
// but leading subdirs must exist....
|
|
|
|
//
|
2009-05-02 23:20:05 +02:00
|
|
|
dta.SetupSearch(drive,(Bit8u)attr,pattern);
|
2009-05-03 00:02:15 +02:00
|
|
|
if (Drives[drive]->FindFirst(dir,dta,fcb_findfirst)) return true;
|
2009-05-02 23:43:00 +02:00
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
return false;
|
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
|
|
|
|
bool DOS_FindNext(void) {
|
2009-05-03 00:02:15 +02:00
|
|
|
DOS_DTA dta(dos.dta());
|
2009-05-02 23:20:05 +02:00
|
|
|
if (Drives[dta.GetSearchDrive()]->FindNext(dta)) return true;
|
|
|
|
return false;
|
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
|
|
|
|
|
|
|
|
bool DOS_ReadFile(Bit16u entry,Bit8u * data,Bit16u * amount) {
|
|
|
|
Bit32u handle=RealHandle(entry);
|
|
|
|
if (handle>=DOS_FILES) {
|
|
|
|
DOS_SetError(DOSERR_INVALID_HANDLE);
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
if (!Files[handle]) {
|
|
|
|
DOS_SetError(DOSERR_INVALID_HANDLE);
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
//TODO maybe another code :)
|
|
|
|
/*
|
|
|
|
if (!(Files[handle]->flags & OPEN_READ)) {
|
|
|
|
DOS_SetError(DOSERR_INVALID_HANDLE);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
Bit16u toread=*amount;
|
|
|
|
bool ret=Files[handle]->Read(data,&toread);
|
|
|
|
*amount=toread;
|
|
|
|
return ret;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool DOS_WriteFile(Bit16u entry,Bit8u * data,Bit16u * amount) {
|
|
|
|
Bit32u handle=RealHandle(entry);
|
|
|
|
if (handle>=DOS_FILES) {
|
|
|
|
DOS_SetError(DOSERR_INVALID_HANDLE);
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
if (!Files[handle]) {
|
|
|
|
DOS_SetError(DOSERR_INVALID_HANDLE);
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
//TODO maybe another code :)
|
|
|
|
/*
|
|
|
|
if (!(Files[handle]->flags & OPEN_WRITE)) {
|
|
|
|
DOS_SetError(DOSERR_INVALID_HANDLE);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
Bit16u towrite=*amount;
|
|
|
|
bool ret=Files[handle]->Write(data,&towrite);
|
|
|
|
*amount=towrite;
|
|
|
|
return ret;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool DOS_SeekFile(Bit16u entry,Bit32u * pos,Bit32u type) {
|
|
|
|
Bit32u handle=RealHandle(entry);
|
|
|
|
if (handle>=DOS_FILES) {
|
|
|
|
DOS_SetError(DOSERR_INVALID_HANDLE);
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
if (!Files[handle]) {
|
|
|
|
DOS_SetError(DOSERR_INVALID_HANDLE);
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
return Files[handle]->Seek(pos,type);
|
|
|
|
};
|
|
|
|
|
|
|
|
bool DOS_CloseFile(Bit16u entry) {
|
|
|
|
Bit32u handle=RealHandle(entry);
|
|
|
|
if (handle>=DOS_FILES) {
|
|
|
|
DOS_SetError(DOSERR_INVALID_HANDLE);
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
if (!Files[handle]) {
|
|
|
|
DOS_SetError(DOSERR_INVALID_HANDLE);
|
|
|
|
return false;
|
|
|
|
};
|
2009-05-03 00:08:43 +02:00
|
|
|
Files[handle]->Close();
|
|
|
|
DOS_PSP psp(dos.psp());
|
|
|
|
psp.SetFileHandle(entry,0xff);
|
|
|
|
if (Files[handle]->RemoveRef()<=0) {
|
|
|
|
delete Files[handle];
|
|
|
|
Files[handle]=0;
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DOS_CreateFile(char * name,Bit16u attributes,Bit16u * entry) {
|
2009-05-03 00:02:15 +02:00
|
|
|
// Creation of a device is the same as opening it
|
|
|
|
// Tc201 installer
|
2009-05-03 00:08:43 +02:00
|
|
|
if (DOS_FindDevice(name) != DOS_DEVICES)
|
2009-05-03 00:02:15 +02:00
|
|
|
return DOS_OpenFile(name, 0, entry);
|
|
|
|
|
2009-05-03 00:08:43 +02:00
|
|
|
LOG(LOG_FILES,LOG_NORMAL)("file create attributes %X file %s",attributes,name);
|
2009-05-02 23:03:37 +02:00
|
|
|
char fullname[DOS_PATHLENGTH];Bit8u drive;
|
2009-05-03 00:02:15 +02:00
|
|
|
DOS_PSP psp(dos.psp());
|
2009-05-02 23:03:37 +02:00
|
|
|
if (!DOS_MakeName(name,fullname,&drive)) return false;
|
|
|
|
/* Check for a free file handle */
|
|
|
|
Bit8u handle=DOS_FILES;Bit8u i;
|
|
|
|
for (i=0;i<DOS_FILES;i++) {
|
|
|
|
if (!Files[i]) {
|
|
|
|
handle=i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (handle==DOS_FILES) {
|
|
|
|
DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
/* We have a position in the main table now find one in the psp table */
|
2009-05-02 23:20:05 +02:00
|
|
|
*entry = psp.FindFreeFileEntry();
|
2009-05-02 23:03:37 +02:00
|
|
|
if (*entry==0xff) {
|
|
|
|
DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool foundit=Drives[drive]->FileCreate(&Files[handle],fullname,attributes);
|
|
|
|
if (foundit) {
|
2009-05-02 23:43:00 +02:00
|
|
|
Files[handle]->AddRef();
|
2009-05-02 23:20:05 +02:00
|
|
|
psp.SetFileHandle(*entry,handle);
|
2009-05-02 23:03:37 +02:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DOS_OpenFile(char * name,Bit8u flags,Bit16u * entry) {
|
|
|
|
/* First check for devices */
|
2009-05-02 23:43:00 +02:00
|
|
|
if (flags>2) LOG(LOG_FILES,LOG_ERROR)("Special file open command %X file %s",flags,name);
|
|
|
|
else LOG(LOG_FILES,LOG_NORMAL)("file open command %X file %s",flags,name);
|
2009-05-02 23:53:27 +02:00
|
|
|
|
2009-05-03 00:08:43 +02:00
|
|
|
Bit16u attr = 0;
|
2009-05-02 23:53:27 +02:00
|
|
|
if(DOS_GetFileAttr(name,&attr)){ //DON'T ALLOW directories to be openened
|
|
|
|
if((attr & DOS_ATTR_DIRECTORY) || (attr & DOS_ATTR_VOLUME)){
|
|
|
|
DOS_SetError(DOSERR_ACCESS_DENIED);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
DOS_PSP psp(dos.psp());
|
2009-05-03 00:08:43 +02:00
|
|
|
Bit8u devnum=DOS_DEVICES;
|
|
|
|
devnum=DOS_FindDevice((char *)name);
|
|
|
|
bool device=(devnum!=DOS_DEVICES);
|
|
|
|
char fullname[DOS_PATHLENGTH];Bit8u drive;Bit8u i;
|
|
|
|
|
2009-05-02 23:03:37 +02:00
|
|
|
/* First check if the name is correct */
|
2009-05-03 00:08:43 +02:00
|
|
|
if (!DOS_MakeName(name,fullname,&drive)) return false;
|
|
|
|
Bit8u handle=255;
|
|
|
|
/* Check for a free file handle */
|
|
|
|
for (i=0;i<DOS_FILES;i++) {
|
|
|
|
if (!Files[i]) {
|
|
|
|
handle=i;
|
|
|
|
break;
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
|
|
|
}
|
2009-05-03 00:08:43 +02:00
|
|
|
if (handle==255) {
|
|
|
|
DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES);
|
|
|
|
return false;
|
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
/* We have a position in the main table now find one in the psp table */
|
2009-05-02 23:20:05 +02:00
|
|
|
*entry = psp.FindFreeFileEntry();
|
2009-05-03 00:08:43 +02:00
|
|
|
|
2009-05-02 23:03:37 +02:00
|
|
|
if (*entry==0xff) {
|
|
|
|
DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool exists=false;
|
2009-05-03 00:08:43 +02:00
|
|
|
if (device) {
|
|
|
|
Files[handle]=new DOS_Device(*Devices[devnum]);
|
|
|
|
} else {
|
|
|
|
exists=Drives[drive]->FileOpen(&Files[handle],fullname,flags);
|
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
if (exists || device ) {
|
2009-05-02 23:43:00 +02:00
|
|
|
Files[handle]->AddRef();
|
2009-05-02 23:20:05 +02:00
|
|
|
psp.SetFileHandle(*entry,handle);
|
2009-05-02 23:03:37 +02:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
DOS_SetError(DOSERR_FILE_NOT_FOUND);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-02 23:43:00 +02:00
|
|
|
bool DOS_OpenFileExtended(char *name, Bit16u flags, Bit16u createAttr, Bit16u action, Bit16u *entry, Bit16u* status)
|
|
|
|
// FIXME: Not yet supported : Bit 13 of flags (int 0x24 on critical error
|
|
|
|
{
|
|
|
|
Bit16u result = 0;
|
|
|
|
if (DOS_OpenFile(name, (Bit8u)flags, entry)) {
|
|
|
|
// File already exists
|
|
|
|
switch (action & 0x0f) {
|
|
|
|
case 0x00 : return false; // failed
|
|
|
|
case 0x01 : result = 1; break; // file open (already done)
|
|
|
|
case 0x02 : DOS_CloseFile(*entry); // replace
|
|
|
|
if (!DOS_CreateFile(name, flags, entry)) return false;
|
|
|
|
result = 3;
|
|
|
|
break;
|
|
|
|
default : E_Exit("DOS: OpenFileExtended: Unknown action.");
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
// File doesnt exist
|
|
|
|
if ((action & 0xf0)==0) return false;
|
|
|
|
// Create File
|
|
|
|
if (!DOS_CreateFile(name, flags, entry)) return false;
|
|
|
|
result = 2;
|
|
|
|
};
|
|
|
|
*status = result;
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
2009-05-02 23:03:37 +02:00
|
|
|
bool DOS_UnlinkFile(char * name) {
|
|
|
|
char fullname[DOS_PATHLENGTH];Bit8u drive;
|
|
|
|
if (!DOS_MakeName(name,fullname,&drive)) return false;
|
2009-05-03 00:08:43 +02:00
|
|
|
if(Drives[drive]->FileUnlink(fullname)){
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
DOS_SetError(DOSERR_FILE_NOT_FOUND);
|
|
|
|
return false;
|
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool DOS_GetFileAttr(char * name,Bit16u * attr) {
|
|
|
|
char fullname[DOS_PATHLENGTH];Bit8u drive;
|
|
|
|
if (!DOS_MakeName(name,fullname,&drive)) return false;
|
|
|
|
if (Drives[drive]->GetFileAttr(fullname,attr)) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
DOS_SetError(DOSERR_FILE_NOT_FOUND);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-02 23:53:27 +02:00
|
|
|
bool DOS_SetFileAttr(char * name,Bit16u attr)
|
|
|
|
// this function does not change the file attributs
|
|
|
|
// it just does some tests if file is available
|
|
|
|
// returns false when using on cdrom (stonekeep)
|
|
|
|
{
|
|
|
|
Bit16u attrTemp;
|
|
|
|
char fullname[DOS_PATHLENGTH];Bit8u drive;
|
|
|
|
if (!DOS_MakeName(name,fullname,&drive)) return false;
|
|
|
|
if (strcmp(Drives[drive]->GetInfo(),"CDRom.")==0) {
|
|
|
|
DOS_SetError(DOSERR_ACCESS_DENIED);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return Drives[drive]->GetFileAttr(fullname,&attrTemp);
|
|
|
|
}
|
|
|
|
|
2009-05-02 23:12:18 +02:00
|
|
|
bool DOS_Canonicalize(char * name,char * big) {
|
2009-05-02 23:03:37 +02:00
|
|
|
//TODO Add Better support for devices and shit but will it be needed i doubt it :)
|
|
|
|
Bit8u drive;
|
|
|
|
char fullname[DOS_PATHLENGTH];
|
|
|
|
if (!DOS_MakeName(name,fullname,&drive)) return false;
|
|
|
|
big[0]=drive+'A';
|
|
|
|
big[1]=':';
|
|
|
|
big[2]='\\';
|
2009-05-02 23:12:18 +02:00
|
|
|
strcpy(&big[3],fullname);
|
2009-05-02 23:03:37 +02:00
|
|
|
return true;
|
2009-05-02 23:20:05 +02:00
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
|
2009-05-02 23:27:47 +02:00
|
|
|
bool DOS_GetFreeDiskSpace(Bit8u drive,Bit16u * bytes,Bit8u * sectors,Bit16u * clusters,Bit16u * free) {
|
2009-05-02 23:03:37 +02:00
|
|
|
if (drive==0) drive=DOS_GetDefaultDrive();
|
|
|
|
else drive--;
|
|
|
|
if ((drive>DOS_DRIVES) || (!Drives[drive])) {
|
|
|
|
DOS_SetError(DOSERR_INVALID_DRIVE);
|
|
|
|
return false;
|
|
|
|
}
|
2009-05-02 23:20:05 +02:00
|
|
|
return Drives[drive]->AllocationInfo(bytes,sectors,clusters,free);
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool DOS_DuplicateEntry(Bit16u entry,Bit16u * newentry) {
|
2009-05-02 23:43:00 +02:00
|
|
|
// Dont duplicate console handles
|
2009-05-03 00:08:43 +02:00
|
|
|
/* if (entry<=STDPRN) {
|
2009-05-02 23:43:00 +02:00
|
|
|
*newentry = entry;
|
|
|
|
return true;
|
|
|
|
};
|
2009-05-03 00:08:43 +02:00
|
|
|
*/
|
2009-05-02 23:03:37 +02:00
|
|
|
Bit8u handle=RealHandle(entry);
|
|
|
|
if (handle>=DOS_FILES) {
|
|
|
|
DOS_SetError(DOSERR_INVALID_HANDLE);
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
if (!Files[handle]) {
|
|
|
|
DOS_SetError(DOSERR_INVALID_HANDLE);
|
|
|
|
return false;
|
|
|
|
};
|
2009-05-03 00:02:15 +02:00
|
|
|
DOS_PSP psp(dos.psp());
|
2009-05-02 23:20:05 +02:00
|
|
|
*newentry = psp.FindFreeFileEntry();
|
2009-05-02 23:03:37 +02:00
|
|
|
if (*newentry==0xff) {
|
|
|
|
DOS_SetError(DOSERR_TOO_MANY_OPEN_FILES);
|
|
|
|
return false;
|
|
|
|
}
|
2009-05-02 23:43:00 +02:00
|
|
|
Files[handle]->AddRef();
|
2009-05-02 23:20:05 +02:00
|
|
|
psp.SetFileHandle(*newentry,handle);
|
2009-05-02 23:03:37 +02:00
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
2009-05-02 23:12:18 +02:00
|
|
|
bool DOS_ForceDuplicateEntry(Bit16u entry,Bit16u newentry) {
|
2009-05-02 23:43:00 +02:00
|
|
|
// Dont duplicate console handles
|
2009-05-03 00:08:43 +02:00
|
|
|
/* if (entry<=STDPRN) {
|
2009-05-02 23:43:00 +02:00
|
|
|
newentry = entry;
|
|
|
|
return true;
|
|
|
|
};
|
2009-05-03 00:08:43 +02:00
|
|
|
*/
|
2009-05-02 23:12:18 +02:00
|
|
|
Bit8u orig=RealHandle(entry);
|
|
|
|
if (orig>=DOS_FILES) {
|
|
|
|
DOS_SetError(DOSERR_INVALID_HANDLE);
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
if (!Files[orig]) {
|
|
|
|
DOS_SetError(DOSERR_INVALID_HANDLE);
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
Bit8u newone=RealHandle(newentry);
|
|
|
|
if (newone>=DOS_FILES) {
|
|
|
|
DOS_SetError(DOSERR_INVALID_HANDLE);
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
if (Files[newone]) {
|
|
|
|
DOS_CloseFile(newentry);
|
|
|
|
return false;
|
|
|
|
};
|
2009-05-03 00:02:15 +02:00
|
|
|
DOS_PSP psp(dos.psp());
|
2009-05-02 23:43:00 +02:00
|
|
|
Files[orig]->AddRef();
|
2009-05-02 23:20:05 +02:00
|
|
|
psp.SetFileHandle(newentry,(Bit8u)entry);
|
2009-05-02 23:12:18 +02:00
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-05-02 23:03:37 +02:00
|
|
|
|
|
|
|
bool DOS_CreateTempFile(char * name,Bit16u * entry) {
|
2009-05-02 23:20:05 +02:00
|
|
|
/* First add random crap to the end of the name and try to open */
|
2009-05-02 23:03:37 +02:00
|
|
|
/* Todo maybe check for euhm existence of the path name */
|
|
|
|
char * tempname;
|
|
|
|
tempname=name+strlen(name);
|
|
|
|
do {
|
|
|
|
Bit32u i;
|
|
|
|
for (i=0;i<8;i++) {
|
|
|
|
tempname[i]=(rand()%26)+'A';
|
|
|
|
}
|
|
|
|
tempname[8]='.';
|
|
|
|
for (i=9;i<12;i++) {
|
|
|
|
tempname[i]=(rand()%26)+'A';
|
|
|
|
}
|
2009-05-02 23:20:05 +02:00
|
|
|
tempname[12]=0;
|
2009-05-02 23:03:37 +02:00
|
|
|
} while (!DOS_CreateFile(name,0,entry));
|
|
|
|
return true;
|
|
|
|
}
|
2009-05-02 23:12:18 +02:00
|
|
|
|
|
|
|
#define FCB_SEP ":.;,=+"
|
|
|
|
#define ILLEGAL ":.;,=+ \t/\"[]<>|"
|
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
static bool isvalid(const char in){
|
2009-05-02 23:12:18 +02:00
|
|
|
const char ill[]=ILLEGAL;
|
2009-05-02 23:20:05 +02:00
|
|
|
return (Bit8u(in)>0x1F) && (!strchr(ill,in));
|
2009-05-02 23:12:18 +02:00
|
|
|
}
|
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
#define PARSE_SEP_STOP 0x01
|
|
|
|
#define PARSE_DFLT_DRIVE 0x02
|
|
|
|
#define PARSE_BLNK_FNAME 0x04
|
|
|
|
#define PARSE_BLNK_FEXT 0x08
|
|
|
|
|
|
|
|
#define PARSE_RET_NOWILD 0
|
|
|
|
#define PARSE_RET_WILD 1
|
|
|
|
#define PARSE_RET_BADDRIVE 0xff
|
|
|
|
|
2009-05-02 23:12:18 +02:00
|
|
|
Bit8u FCB_Parsename(Bit16u seg,Bit16u offset,Bit8u parser ,char *string, Bit8u *change){
|
2009-05-02 23:20:05 +02:00
|
|
|
|
|
|
|
char * string_begin=string;Bit8u ret=0;
|
2009-05-02 23:12:18 +02:00
|
|
|
DOS_FCB fcb(seg,offset);
|
2009-05-02 23:20:05 +02:00
|
|
|
bool hasdrive,hasname,hasext;
|
|
|
|
hasdrive=hasname=hasext=false;
|
|
|
|
Bitu index;bool finished;Bit8u fill;
|
|
|
|
/* First get the old data from the fcb */
|
2009-05-02 23:43:00 +02:00
|
|
|
#ifdef _MSC_VER
|
2009-05-02 23:20:05 +02:00
|
|
|
#pragma pack (1)
|
2009-05-02 23:43:00 +02:00
|
|
|
#endif
|
2009-05-02 23:20:05 +02:00
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
char drive[2];
|
|
|
|
char name[9];
|
|
|
|
char ext[4];
|
|
|
|
} part GCC_ATTRIBUTE (packed) ;
|
|
|
|
char full[DOS_FCBNAME];
|
|
|
|
} fcb_name;
|
2009-05-02 23:43:00 +02:00
|
|
|
#ifdef _MSC_VER
|
2009-05-02 23:20:05 +02:00
|
|
|
#pragma pack()
|
2009-05-02 23:43:00 +02:00
|
|
|
#endif
|
2009-05-02 23:20:05 +02:00
|
|
|
/* Get the old information from the previous fcb */
|
|
|
|
fcb.GetName(fcb_name.full);fcb_name.part.drive[1]=0;fcb_name.part.name[8]=0;fcb_name.part.ext[3]=0;
|
|
|
|
/* Strip of the leading sepetaror */
|
|
|
|
if((parser & PARSE_SEP_STOP) && *string) { //ignore leading seperator
|
|
|
|
char sep[] = FCB_SEP;char a[2];
|
|
|
|
a[0]= *string;a[1]='\0';
|
|
|
|
if (strcspn(a,sep)==0) string++;
|
|
|
|
}
|
|
|
|
/* strip leading spaces */
|
|
|
|
while((*string==' ')||(*string=='\t')) string++;
|
|
|
|
/* Check for a drive */
|
|
|
|
if (string[1]==':') {
|
|
|
|
fcb_name.part.drive[0]=0;
|
|
|
|
hasdrive=true;
|
|
|
|
if (isalpha(string[0]) && Drives[toupper(string[0])-'A']) {
|
|
|
|
fcb_name.part.drive[0]=toupper(string[0])-'A'+1;
|
|
|
|
} else ret=0xff;
|
|
|
|
string+=2;
|
|
|
|
}
|
|
|
|
/* Special checks for . and .. */
|
|
|
|
if (string[0]=='.') {
|
|
|
|
string++;
|
|
|
|
if (!string[0]) {
|
|
|
|
hasname=true;
|
|
|
|
ret=PARSE_RET_NOWILD;
|
|
|
|
strcpy(fcb_name.part.name,". ");
|
|
|
|
goto savefcb;
|
|
|
|
}
|
|
|
|
if (string[1]=='.' && !string[1]) {
|
|
|
|
string++;
|
|
|
|
hasname=true;
|
|
|
|
ret=PARSE_RET_NOWILD;
|
|
|
|
strcpy(fcb_name.part.name,".. ");
|
|
|
|
goto savefcb;
|
|
|
|
}
|
|
|
|
goto checkext;
|
|
|
|
}
|
|
|
|
/* Copy the name */
|
|
|
|
hasname=true;finished=false;fill=' ';index=0;
|
|
|
|
while (index<8) {
|
|
|
|
if (!finished) {
|
|
|
|
if (string[0]=='*') {fill='?';fcb_name.part.name[index]='?';if (!ret) ret=1;finished=true;}
|
|
|
|
else if (string[0]=='?') {fcb_name.part.name[index]='?';if (!ret) ret=1;}
|
|
|
|
else if (isvalid(string[0])) {fcb_name.part.name[index]=toupper(string[0]);}
|
|
|
|
else { finished=true;continue; }
|
|
|
|
string++;
|
|
|
|
} else {
|
|
|
|
fcb_name.part.name[index]=fill;
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
if (!(string[0]=='.')) goto savefcb;
|
|
|
|
string++;
|
|
|
|
checkext:
|
|
|
|
/* Copy the extension */
|
|
|
|
hasext=true;finished=false;fill=' ';index=0;
|
|
|
|
while (index<3) {
|
|
|
|
if (!finished) {
|
|
|
|
if (string[0]=='*') {fill='?';fcb_name.part.ext[index]='?';finished=true;}
|
|
|
|
else if (string[0]=='?') {fcb_name.part.ext[index]='?';if (!ret) ret=1;}
|
|
|
|
else if (isvalid(string[0])) {fcb_name.part.ext[index]=toupper(string[0]);}
|
|
|
|
else { finished=true;continue; }
|
|
|
|
string++;
|
|
|
|
} else {
|
|
|
|
fcb_name.part.ext[index]=fill;
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
savefcb:
|
|
|
|
if (!hasdrive & !(parser & PARSE_DFLT_DRIVE)) fcb_name.part.drive[0]=dos.current_drive+1;
|
|
|
|
if (!hasname & !(parser & PARSE_BLNK_FNAME)) strcpy(fcb_name.part.name," ");
|
|
|
|
if (!hasext & !(parser & PARSE_BLNK_FEXT)) strcpy(fcb_name.part.ext," ");
|
|
|
|
fcb.SetName(fcb_name.part.drive[0],fcb_name.part.name,fcb_name.part.ext);
|
|
|
|
*change=(Bit8u)(string-string_begin);
|
|
|
|
return ret;
|
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
static void DTAExtendName(char * name,char * filename,char * ext) {
|
|
|
|
char * find=strchr(name,'.');
|
|
|
|
if (find) {
|
|
|
|
strcpy(ext,find+1);
|
|
|
|
*find=0;
|
|
|
|
} else ext[0]=0;
|
|
|
|
strcpy(filename,name);
|
|
|
|
Bitu i;
|
|
|
|
for (i=strlen(name);i<8;i++) filename[i]=' ';filename[8]=0;
|
|
|
|
for (i=strlen(ext);i<3;i++) ext[i]=' ';ext[3]=0;
|
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
static void SaveFindResult(DOS_FCB & find_fcb) {
|
|
|
|
DOS_DTA find_dta(dos.tables.tempdta);
|
|
|
|
char name[DOS_NAMELENGTH_ASCII];Bit32u size;Bit16u date;Bit16u time;Bit8u attr;Bit8u drive;
|
|
|
|
char file_name[9];char ext[4];
|
|
|
|
find_dta.GetResult(name,size,date,time,attr);
|
2009-05-03 00:02:15 +02:00
|
|
|
drive=find_fcb.GetDrive()+1;
|
2009-05-02 23:20:05 +02:00
|
|
|
/* Create a correct file and extention */
|
|
|
|
DTAExtendName(name,file_name,ext);
|
2009-05-03 00:02:15 +02:00
|
|
|
DOS_FCB fcb(RealSeg(dos.dta()),RealOff(dos.dta()));//TODO
|
2009-05-02 23:20:05 +02:00
|
|
|
fcb.Create(find_fcb.Extended());
|
|
|
|
fcb.SetName(drive,file_name,ext);
|
2009-05-03 00:02:15 +02:00
|
|
|
fcb.SetAttr(attr); /* Only adds attribute if fcb is extended */
|
2009-05-02 23:20:05 +02:00
|
|
|
fcb.SetSizeDateTime(size,date,time);
|
2009-05-02 23:12:18 +02:00
|
|
|
}
|
2009-05-02 23:20:05 +02:00
|
|
|
|
2009-05-02 23:27:47 +02:00
|
|
|
bool DOS_FCBCreate(Bit16u seg,Bit16u offset) {
|
|
|
|
DOS_FCB fcb(seg,offset);
|
|
|
|
char shortname[DOS_FCBNAME];Bit16u handle;
|
|
|
|
fcb.GetName(shortname);
|
|
|
|
if (!DOS_CreateFile(shortname,2,&handle)) return false;
|
|
|
|
fcb.FileOpen((Bit8u)handle);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DOS_FCBOpen(Bit16u seg,Bit16u offset) {
|
2009-05-02 23:03:37 +02:00
|
|
|
DOS_FCB fcb(seg,offset);
|
2009-05-02 23:20:05 +02:00
|
|
|
char shortname[DOS_FCBNAME];Bit16u handle;
|
|
|
|
fcb.GetName(shortname);
|
2009-05-02 23:35:44 +02:00
|
|
|
|
|
|
|
/* First check if the name is correct */
|
|
|
|
Bit8u drive;
|
|
|
|
char fullname[DOS_PATHLENGTH];
|
|
|
|
if (!DOS_MakeName(shortname,fullname,&drive)) return false;
|
|
|
|
|
|
|
|
/* Check, if file is already opened */
|
2009-05-02 23:43:00 +02:00
|
|
|
for (Bit8u i=0;i<DOS_FILES;i++) {
|
2009-05-03 00:02:15 +02:00
|
|
|
DOS_PSP psp(dos.psp());
|
2009-05-02 23:35:44 +02:00
|
|
|
if (Files[i] && Files[i]->IsOpen() && Files[i]->IsName(fullname)) {
|
|
|
|
handle = psp.FindEntryByHandle(i);
|
|
|
|
if (handle==0xFF) {
|
|
|
|
// This shouldnt happen
|
2009-05-02 23:43:00 +02:00
|
|
|
LOG(LOG_FILES,LOG_ERROR)("DOS: File %s is opened but has no psp entry.",shortname);
|
2009-05-02 23:35:44 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
fcb.FileOpen((Bit8u)handle);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
if (!DOS_OpenFile(shortname,2,&handle)) return false;
|
|
|
|
fcb.FileOpen((Bit8u)handle);
|
|
|
|
return true;
|
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
bool DOS_FCBClose(Bit16u seg,Bit16u offset) {
|
|
|
|
DOS_FCB fcb(seg,offset);
|
|
|
|
Bit8u fhandle;
|
|
|
|
fcb.FileClose(fhandle);
|
|
|
|
DOS_CloseFile(fhandle);
|
|
|
|
return true;
|
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
bool DOS_FCBFindFirst(Bit16u seg,Bit16u offset) {
|
2009-05-02 23:20:05 +02:00
|
|
|
DOS_FCB fcb(seg,offset);
|
2009-05-03 00:02:15 +02:00
|
|
|
RealPt old_dta=dos.dta();dos.dta(dos.tables.tempdta);
|
2009-05-02 23:20:05 +02:00
|
|
|
char name[DOS_FCBNAME];fcb.GetName(name);
|
2009-05-03 00:02:15 +02:00
|
|
|
Bit8u attr = DOS_ATTR_ARCHIVE;
|
|
|
|
fcb.GetAttr(attr); /* Gets search attributes if extended */
|
|
|
|
bool ret=DOS_FindFirst(name,attr,true);
|
|
|
|
dos.dta(old_dta);
|
2009-05-02 23:20:05 +02:00
|
|
|
if (ret) SaveFindResult(fcb);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
bool DOS_FCBFindNext(Bit16u seg,Bit16u offset) {
|
2009-05-02 23:20:05 +02:00
|
|
|
DOS_FCB fcb(seg,offset);
|
2009-05-03 00:02:15 +02:00
|
|
|
RealPt old_dta=dos.dta();dos.dta(dos.tables.tempdta);
|
2009-05-02 23:20:05 +02:00
|
|
|
bool ret=DOS_FindNext();
|
2009-05-03 00:02:15 +02:00
|
|
|
dos.dta(old_dta);
|
2009-05-02 23:20:05 +02:00
|
|
|
if (ret) SaveFindResult(fcb);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bit8u DOS_FCBRead(Bit16u seg,Bit16u offset,Bit16u recno) {
|
|
|
|
DOS_FCB fcb(seg,offset);
|
|
|
|
Bit8u fhandle,cur_rec;Bit16u cur_block,rec_size;
|
|
|
|
fcb.GetSeqData(fhandle,rec_size);
|
|
|
|
fcb.GetRecord(cur_block,cur_rec);
|
|
|
|
Bit32u pos=((cur_block*128)+cur_rec)*rec_size;
|
|
|
|
if (!DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET)) return FCB_READ_NODATA;
|
|
|
|
Bit16u toread=rec_size;
|
|
|
|
if (!DOS_ReadFile(fhandle,dos_copybuf,&toread)) return FCB_READ_NODATA;
|
|
|
|
if (toread==0) return FCB_READ_NODATA;
|
|
|
|
if (toread<rec_size) {
|
2009-05-03 00:02:15 +02:00
|
|
|
PhysPt fill=Real2Phys(dos.dta())+toread;
|
2009-05-02 23:20:05 +02:00
|
|
|
Bitu i=rec_size-toread;
|
|
|
|
for (;i>0;i--) mem_writeb(fill++,0);
|
|
|
|
}
|
2009-05-03 00:02:15 +02:00
|
|
|
MEM_BlockWrite(Real2Phys(dos.dta())+recno*rec_size,dos_copybuf,rec_size);
|
2009-05-02 23:20:05 +02:00
|
|
|
if (++cur_rec>127) { cur_block++;cur_rec=0; }
|
|
|
|
fcb.SetRecord(cur_block,cur_rec);
|
|
|
|
if (toread==rec_size) return FCB_SUCCESS;
|
|
|
|
if (toread==0) return FCB_READ_NODATA;
|
|
|
|
return FCB_READ_PARTIAL;
|
|
|
|
}
|
|
|
|
|
2009-05-02 23:27:47 +02:00
|
|
|
Bit8u DOS_FCBWrite(Bit16u seg,Bit16u offset,Bit16u recno)
|
2009-05-02 23:20:05 +02:00
|
|
|
{
|
|
|
|
DOS_FCB fcb(seg,offset);
|
|
|
|
Bit8u fhandle,cur_rec;Bit16u cur_block,rec_size;
|
|
|
|
fcb.GetSeqData(fhandle,rec_size);
|
|
|
|
fcb.GetRecord(cur_block,cur_rec);
|
|
|
|
Bit32u pos=((cur_block*128)+cur_rec)*rec_size;
|
|
|
|
if (!DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET)) return FCB_ERR_WRITE;
|
2009-05-03 00:02:15 +02:00
|
|
|
MEM_BlockRead(Real2Phys(dos.dta())+recno*rec_size,dos_copybuf,rec_size);
|
2009-05-02 23:20:05 +02:00
|
|
|
Bit16u towrite=rec_size;
|
|
|
|
if (!DOS_WriteFile(fhandle,dos_copybuf,&towrite)) return FCB_ERR_WRITE;
|
|
|
|
Bit32u size;Bit16u date,time;
|
|
|
|
fcb.GetSizeDateTime(size,date,time);
|
|
|
|
if (pos+towrite>size) size=pos+towrite;
|
2009-05-02 23:35:44 +02:00
|
|
|
//time doesn't keep track of endofday
|
|
|
|
date = DOS_PackDate(dos.date.year,dos.date.month,dos.date.day);
|
|
|
|
Bit32u ticks = mem_readd(BIOS_TIMER);
|
|
|
|
Bit32u seconds = (ticks*10)/182;
|
|
|
|
Bit16u hour = (Bit16u)(seconds/3600);
|
|
|
|
Bit16u min = (Bit16u)((seconds % 3600)/60);
|
|
|
|
Bit16u sec = (Bit16u)(seconds % 60);
|
|
|
|
time = DOS_PackTime(hour,min,sec);
|
|
|
|
Bit8u temp=RealHandle(fhandle);
|
|
|
|
Files[temp]->time=time;
|
|
|
|
Files[temp]->date=date;
|
2009-05-02 23:20:05 +02:00
|
|
|
fcb.SetSizeDateTime(size,date,time);
|
|
|
|
if (++cur_rec>127) { cur_block++;cur_rec=0; }
|
|
|
|
fcb.SetRecord(cur_block,cur_rec);
|
|
|
|
return FCB_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bit8u DOS_FCBRandomRead(Bit16u seg,Bit16u offset,Bit16u numRec,bool restore) {
|
2009-05-02 23:27:47 +02:00
|
|
|
/* if restore is true :random read else random blok read.
|
|
|
|
* random read updates old block and old record to reflect the random data
|
|
|
|
* before the read!!!!!!!!! and the random data is not updated! (user must do this)
|
|
|
|
* Random block read updates these fields to reflect the state after the read!
|
|
|
|
*/
|
2009-05-02 23:20:05 +02:00
|
|
|
|
|
|
|
DOS_FCB fcb(seg,offset);
|
|
|
|
Bit32u random;Bit16u old_block;Bit8u old_rec;Bit8u error;
|
2009-05-02 23:27:47 +02:00
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
/* Set the correct record from the random data */
|
|
|
|
fcb.GetRandom(random);
|
|
|
|
fcb.SetRecord((Bit16u)(random / 128),(Bit8u)(random & 127));
|
2009-05-03 00:02:15 +02:00
|
|
|
if (restore) fcb.GetRecord(old_block,old_rec);//store this for after the read.
|
2009-05-02 23:20:05 +02:00
|
|
|
// Read records
|
|
|
|
for (int i=0; i<numRec; i++) {
|
|
|
|
error = DOS_FCBRead(seg,offset,i);
|
|
|
|
if (error!=0x00) break;
|
2009-05-02 23:12:18 +02:00
|
|
|
}
|
2009-05-02 23:20:05 +02:00
|
|
|
Bit16u new_block;Bit8u new_rec;
|
|
|
|
fcb.GetRecord(new_block,new_rec);
|
|
|
|
if (restore) fcb.SetRecord(old_block,old_rec);
|
2009-05-02 23:27:47 +02:00
|
|
|
/* Update the random record pointer with new position only when restore is false*/
|
2009-05-03 00:02:15 +02:00
|
|
|
if(!restore) fcb.SetRandom(new_block*128+new_rec);
|
|
|
|
return error;
|
2009-05-02 23:20:05 +02:00
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
|
2009-05-02 23:27:47 +02:00
|
|
|
Bit8u DOS_FCBRandomWrite(Bit16u seg,Bit16u offset,Bit16u numRec,bool restore) {
|
|
|
|
/* see FCB_RandomRead */
|
2009-05-02 23:20:05 +02:00
|
|
|
DOS_FCB fcb(seg,offset);
|
2009-05-02 23:27:47 +02:00
|
|
|
Bit32u random;Bit16u old_block;Bit8u old_rec;Bit8u error;
|
2009-05-02 23:20:05 +02:00
|
|
|
|
|
|
|
/* Set the correct record from the random data */
|
|
|
|
fcb.GetRandom(random);
|
|
|
|
fcb.SetRecord((Bit16u)(random / 128),(Bit8u)(random & 127));
|
2009-05-03 00:02:15 +02:00
|
|
|
if (restore) fcb.GetRecord(old_block,old_rec);
|
2009-05-02 23:20:05 +02:00
|
|
|
/* Write records */
|
|
|
|
for (int i=0; i<numRec; i++) {
|
2009-05-02 23:27:47 +02:00
|
|
|
error = DOS_FCBWrite(seg,offset,i);// dos_fcbwrite return 0 false when true...
|
|
|
|
if (error!=0x00) break;
|
2009-05-02 23:20:05 +02:00
|
|
|
}
|
|
|
|
Bit16u new_block;Bit8u new_rec;
|
|
|
|
fcb.GetRecord(new_block,new_rec);
|
|
|
|
if (restore) fcb.SetRecord(old_block,old_rec);
|
2009-05-02 23:27:47 +02:00
|
|
|
/* Update the random record pointer with new position only when restore is false */
|
2009-05-03 00:02:15 +02:00
|
|
|
if(!restore) fcb.SetRandom(new_block*128+new_rec);
|
2009-05-02 23:27:47 +02:00
|
|
|
return error;
|
2009-05-02 23:20:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool DOS_FCBGetFileSize(Bit16u seg,Bit16u offset,Bit16u numRec) {
|
|
|
|
char shortname[DOS_PATHLENGTH];Bit16u entry;Bit8u handle;Bit16u rec_size;
|
|
|
|
DOS_FCB fcb(seg,offset);
|
|
|
|
fcb.GetName(shortname);
|
|
|
|
if (!DOS_OpenFile(shortname,0,&entry)) return false;
|
|
|
|
handle=RealHandle(entry);
|
|
|
|
Bit32u size=Files[handle]->size;
|
|
|
|
DOS_CloseFile(entry);fcb.GetSeqData(handle,rec_size);
|
|
|
|
Bit32u random=(size/rec_size);
|
|
|
|
if (size % rec_size) random++;
|
|
|
|
fcb.SetRandom(random);
|
2009-05-02 23:12:18 +02:00
|
|
|
return true;
|
2009-05-02 23:20:05 +02:00
|
|
|
}
|
2009-05-02 23:12:18 +02:00
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
bool DOS_FCBDeleteFile(Bit16u seg,Bit16u offset){
|
2009-05-03 00:08:43 +02:00
|
|
|
/* FCB DELETE honours wildcards. it will return true if one or more
|
|
|
|
* files get deleted.
|
|
|
|
* To get this: the dta is set to temporary dta in which found files are
|
|
|
|
* stored. This can not be the tempdta as that one is used by fcbfindfirst
|
|
|
|
*/
|
|
|
|
RealPt old_dta=dos.dta();dos.dta(dos.tables.tempdta_fcbdelete);
|
|
|
|
DOS_FCB fcb(RealSeg(dos.dta()),RealOff(dos.dta()));
|
|
|
|
bool nextfile = false;
|
|
|
|
bool return_value = false;
|
|
|
|
nextfile = DOS_FCBFindFirst(seg,offset);
|
|
|
|
while(nextfile) {
|
|
|
|
char shortname[DOS_FCBNAME] = { 0 };
|
|
|
|
fcb.GetName(shortname);
|
|
|
|
bool res=DOS_UnlinkFile(shortname);
|
|
|
|
if(!return_value && res) return_value = true; //at least one file deleted
|
|
|
|
nextfile = DOS_FCBFindNext(seg,offset);
|
|
|
|
}
|
|
|
|
dos.dta(old_dta); /*Restore dta */
|
|
|
|
return return_value;
|
2009-05-02 23:20:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool DOS_FCBRenameFile(Bit16u seg, Bit16u offset){
|
|
|
|
DOS_FCB fcbold(seg,offset);
|
|
|
|
DOS_FCB fcbnew(seg,offset+16);
|
|
|
|
char oldname[DOS_FCBNAME];
|
|
|
|
char newname[DOS_FCBNAME];
|
|
|
|
fcbold.GetName(oldname);fcbnew.GetName(newname);
|
|
|
|
return DOS_Rename(oldname,newname);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DOS_FCBSetRandomRecord(Bit16u seg, Bit16u offset) {
|
|
|
|
DOS_FCB fcb(seg,offset);
|
|
|
|
Bit16u block;Bit8u rec;
|
|
|
|
fcb.GetRecord(block,rec);
|
|
|
|
fcb.SetRandom(block*128+rec);
|
2009-05-02 23:12:18 +02:00
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
|
|
|
|
|
|
|
|
bool DOS_FileExists(char * name) {
|
2009-05-02 23:12:18 +02:00
|
|
|
char fullname[DOS_PATHLENGTH];Bit8u drive;
|
|
|
|
if (!DOS_MakeName(name,fullname,&drive)) return false;
|
|
|
|
return Drives[drive]->FileExists(fullname);
|
2009-05-02 23:03:37 +02:00
|
|
|
}
|
|
|
|
|
2009-05-02 23:27:47 +02:00
|
|
|
bool DOS_GetAllocationInfo(Bit8u drive,Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters) {
|
2009-05-02 23:20:05 +02:00
|
|
|
if (!drive) drive=dos.current_drive;
|
|
|
|
else drive--;
|
|
|
|
if (!Drives[drive]) return false;
|
|
|
|
Bit16u _free_clusters;
|
|
|
|
Drives[drive]->AllocationInfo(_bytes_sector,_sectors_cluster,_total_clusters,&_free_clusters);
|
|
|
|
SegSet16(ds,RealSeg(dos.tables.mediaid));
|
|
|
|
reg_bx=RealOff(dos.tables.mediaid+drive);
|
|
|
|
return true;
|
|
|
|
}
|
2009-05-02 23:03:37 +02:00
|
|
|
|
|
|
|
bool DOS_SetDrive(Bit8u drive) {
|
|
|
|
if (Drives[drive]) {
|
|
|
|
DOS_SetDefaultDrive(drive);
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-05-02 23:20:05 +02:00
|
|
|
bool DOS_GetFileDate(Bit16u entry, Bit16u* otime, Bit16u* odate)
|
|
|
|
{
|
|
|
|
Bit32u handle=RealHandle(entry);
|
|
|
|
if (handle>=DOS_FILES) {
|
|
|
|
DOS_SetError(DOSERR_INVALID_HANDLE);
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
if (!Files[handle]) {
|
|
|
|
DOS_SetError(DOSERR_INVALID_HANDLE);
|
|
|
|
return false;
|
|
|
|
};
|
2009-05-03 00:02:15 +02:00
|
|
|
if (!Files[handle]->UpdateDateTimeFromHost()) {
|
2009-05-02 23:20:05 +02:00
|
|
|
DOS_SetError(DOSERR_INVALID_HANDLE);
|
|
|
|
return false;
|
|
|
|
}
|
2009-05-03 00:02:15 +02:00
|
|
|
*otime = Files[handle]->time;
|
|
|
|
*odate = Files[handle]->date;
|
2009-05-02 23:20:05 +02:00
|
|
|
return true;
|
|
|
|
};
|
2009-05-02 23:03:37 +02:00
|
|
|
|
|
|
|
void DOS_SetupFiles (void) {
|
|
|
|
/* Setup the File Handles */
|
|
|
|
Bit32u i;
|
|
|
|
for (i=0;i<DOS_FILES;i++) {
|
|
|
|
Files[i]=0;
|
|
|
|
}
|
|
|
|
/* Setup the Virtual Disk System */
|
|
|
|
for (i=0;i<DOS_DRIVES;i++) {
|
|
|
|
Drives[i]=0;
|
|
|
|
}
|
|
|
|
Drives[25]=new Virtual_Drive();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|