2009-05-02 23:35:44 +02:00
|
|
|
|
|
|
|
/*
|
2009-05-03 00:28:34 +02:00
|
|
|
* Copyright (C) 2002-2007 The DOSBox Team
|
2009-05-02 23:35:44 +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:35:44 +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:37:32 +02:00
|
|
|
/* $Id: drive_cache.cpp,v 1.50 2007/06/12 20:22:08 c2woody Exp $ */
|
2009-05-02 23:43:00 +02:00
|
|
|
|
2009-05-02 23:35:44 +02:00
|
|
|
#include "drives.h"
|
|
|
|
#include "dos_inc.h"
|
|
|
|
#include "dirent.h"
|
|
|
|
#include "support.h"
|
|
|
|
|
|
|
|
// STL stuff
|
|
|
|
#include <vector>
|
|
|
|
#include <iterator>
|
|
|
|
#include <algorithm>
|
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
#if defined (WIN32) /* Win 32 */
|
|
|
|
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from
|
|
|
|
#include <windows.h>
|
|
|
|
#endif
|
|
|
|
|
2009-05-03 00:18:08 +02:00
|
|
|
#if defined (OS2)
|
|
|
|
#define INCL_DOSERRORS
|
|
|
|
#define INCL_DOSFILEMGR
|
|
|
|
#include <os2.h>
|
|
|
|
#endif
|
|
|
|
|
2009-05-02 23:53:27 +02:00
|
|
|
int fileInfoCounter = 0;
|
2009-05-02 23:35:44 +02:00
|
|
|
|
|
|
|
bool SortByName(DOS_Drive_Cache::CFileInfo* const &a, DOS_Drive_Cache::CFileInfo* const &b)
|
|
|
|
{
|
|
|
|
return strcmp(a->shortname,b->shortname)<0;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool SortByNameRev(DOS_Drive_Cache::CFileInfo* const &a, DOS_Drive_Cache::CFileInfo* const &b)
|
|
|
|
{
|
|
|
|
return strcmp(a->shortname,b->shortname)>0;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool SortByDirName(DOS_Drive_Cache::CFileInfo* const &a, DOS_Drive_Cache::CFileInfo* const &b)
|
|
|
|
{
|
|
|
|
// Directories first...
|
|
|
|
if (a->isDir!=b->isDir) return (a->isDir>b->isDir);
|
|
|
|
return strcmp(a->shortname,b->shortname)<0;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool SortByDirNameRev(DOS_Drive_Cache::CFileInfo* const &a, DOS_Drive_Cache::CFileInfo* const &b)
|
|
|
|
{
|
|
|
|
// Directories first...
|
|
|
|
if (a->isDir!=b->isDir) return (a->isDir>b->isDir);
|
|
|
|
return strcmp(a->shortname,b->shortname)>0;
|
|
|
|
};
|
|
|
|
|
|
|
|
DOS_Drive_Cache::DOS_Drive_Cache(void)
|
|
|
|
{
|
2009-05-03 00:02:15 +02:00
|
|
|
dirBase = new CFileInfo;
|
|
|
|
save_dir = 0;
|
|
|
|
srchNr = 0;
|
|
|
|
label[0] = 0;
|
|
|
|
nextFreeFindFirst = 0;
|
2009-05-02 23:43:00 +02:00
|
|
|
for (Bit32u i=0; i<MAX_OPENDIRS; i++) { dirSearch[i] = 0; free[i] = true; dirFindFirst[i] = 0; };
|
2009-05-02 23:35:44 +02:00
|
|
|
SetDirSort(DIRALPHABETICAL);
|
2009-05-03 00:08:43 +02:00
|
|
|
updatelabel = true;
|
2009-05-02 23:35:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
DOS_Drive_Cache::DOS_Drive_Cache(const char* path)
|
|
|
|
{
|
2009-05-03 00:02:15 +02:00
|
|
|
dirBase = new CFileInfo;
|
|
|
|
save_dir = 0;
|
|
|
|
srchNr = 0;
|
|
|
|
label[0] = 0;
|
|
|
|
nextFreeFindFirst = 0;
|
2009-05-02 23:43:00 +02:00
|
|
|
for (Bit32u i=0; i<MAX_OPENDIRS; i++) { dirSearch[i] = 0; free[i] = true; dirFindFirst[i] = 0; };
|
2009-05-02 23:35:44 +02:00
|
|
|
SetDirSort(DIRALPHABETICAL);
|
|
|
|
SetBaseDir(path);
|
2009-05-03 00:08:43 +02:00
|
|
|
updatelabel = true;
|
2009-05-02 23:35:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
DOS_Drive_Cache::~DOS_Drive_Cache(void)
|
|
|
|
{
|
|
|
|
Clear();
|
2009-05-02 23:43:00 +02:00
|
|
|
for (Bit32u i=0; i<MAX_OPENDIRS; i++) { delete dirFindFirst[i]; dirFindFirst[i]=0; };
|
2009-05-02 23:35:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
void DOS_Drive_Cache::Clear(void)
|
|
|
|
{
|
|
|
|
delete dirBase; dirBase = 0;
|
2009-05-03 00:02:15 +02:00
|
|
|
nextFreeFindFirst = 0;
|
2009-05-02 23:35:44 +02:00
|
|
|
for (Bit32u i=0; i<MAX_OPENDIRS; i++) dirSearch[i] = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
void DOS_Drive_Cache::EmptyCache(void)
|
|
|
|
{
|
|
|
|
// Empty Cache and reinit
|
|
|
|
Clear();
|
|
|
|
dirBase = new CFileInfo;
|
|
|
|
save_dir = 0;
|
|
|
|
srchNr = 0;
|
|
|
|
for (Bit32u i=0; i<MAX_OPENDIRS; i++) free[i] = true;
|
|
|
|
SetBaseDir(basePath);
|
|
|
|
};
|
|
|
|
|
2009-05-03 00:08:43 +02:00
|
|
|
void DOS_Drive_Cache::SetLabel(const char* vname,bool allowupdate)
|
2009-05-02 23:43:00 +02:00
|
|
|
{
|
2009-05-03 00:08:43 +02:00
|
|
|
/* allowupdate defaults to true. if mount sets a label then allowupdate is
|
|
|
|
* false and will this function return at once after the first call.
|
|
|
|
* The label will be set at the first call. */
|
|
|
|
|
|
|
|
if(!this->updatelabel) return;
|
|
|
|
this->updatelabel = allowupdate;
|
2009-05-02 23:43:00 +02:00
|
|
|
Bitu togo = 8;
|
|
|
|
Bitu vnamePos = 0;
|
|
|
|
Bitu labelPos = 0;
|
|
|
|
bool point = false;
|
|
|
|
while (togo>0) {
|
|
|
|
if (vname[vnamePos]==0) break;
|
|
|
|
if (!point && (vname[vnamePos]=='.')) { togo=4; point=true; }
|
2009-05-03 00:02:15 +02:00
|
|
|
label[labelPos] = toupper(vname[vnamePos]);
|
2009-05-02 23:43:00 +02:00
|
|
|
labelPos++; vnamePos++;
|
|
|
|
togo--;
|
|
|
|
if ((togo==0) && !point) {
|
|
|
|
if (vname[vnamePos]=='.') vnamePos++;
|
|
|
|
label[labelPos]='.'; labelPos++; point=true; togo=3;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
label[labelPos]=0;
|
2009-05-03 00:08:43 +02:00
|
|
|
//Remove trailing dot.
|
|
|
|
if((labelPos > 0) && (label[labelPos-1] == '.'))
|
|
|
|
label[labelPos-1]=0;
|
|
|
|
LOG(LOG_DOSMISC,LOG_NORMAL)("DIRCACHE: Set volume label to %s",label);
|
2009-05-02 23:43:00 +02:00
|
|
|
};
|
|
|
|
|
2009-05-02 23:35:44 +02:00
|
|
|
Bit16u DOS_Drive_Cache::GetFreeID(CFileInfo* dir)
|
|
|
|
{
|
2009-05-02 23:53:27 +02:00
|
|
|
for (Bit16u i=0; i<MAX_OPENDIRS; i++) if (free[i] || (dir==dirSearch[i])) return i;
|
2009-05-02 23:43:00 +02:00
|
|
|
LOG(LOG_FILES,LOG_NORMAL)("DIRCACHE: Too many open directories!");
|
2009-05-02 23:35:44 +02:00
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
void DOS_Drive_Cache::SetBaseDir(const char* baseDir)
|
|
|
|
{
|
|
|
|
Bit16u id;
|
|
|
|
strcpy(basePath,baseDir);
|
|
|
|
if (OpenDir(baseDir,id)) {
|
2009-05-02 23:53:27 +02:00
|
|
|
char* result = 0;
|
2009-05-02 23:35:44 +02:00
|
|
|
ReadDir(id,result);
|
|
|
|
};
|
2009-05-02 23:43:00 +02:00
|
|
|
// Get Volume Label
|
2009-05-03 00:18:08 +02:00
|
|
|
#if defined (WIN32) || defined (OS2)
|
2009-05-03 00:08:43 +02:00
|
|
|
char labellocal[256]={ 0 };
|
2009-05-02 23:43:00 +02:00
|
|
|
char drive[4] = "C:\\";
|
|
|
|
drive[0] = basePath[0];
|
2009-05-03 00:18:08 +02:00
|
|
|
#if defined (WIN32)
|
2009-05-03 00:08:43 +02:00
|
|
|
if (GetVolumeInformation(drive,labellocal,256,NULL,NULL,NULL,NULL,0)) {
|
2009-05-03 00:18:08 +02:00
|
|
|
#else // OS2
|
|
|
|
FSINFO fsinfo;
|
|
|
|
ULONG drivenumber = drive[0];
|
|
|
|
if (drivenumber > 26) { // drive letter was lowercase
|
|
|
|
drivenumber = drive[0] - 'a' + 1;
|
|
|
|
}
|
|
|
|
APIRET rc = DosQueryFSInfo(drivenumber, FSIL_VOLSER, &fsinfo, sizeof(FSINFO));
|
|
|
|
if (rc == NO_ERROR) {
|
|
|
|
#endif
|
2009-05-03 00:08:43 +02:00
|
|
|
/* Set label and allow being updated */
|
|
|
|
SetLabel(labellocal,true);
|
|
|
|
}
|
2009-05-02 23:43:00 +02:00
|
|
|
#endif
|
2009-05-02 23:35:44 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
void DOS_Drive_Cache::ExpandName(char* path)
|
|
|
|
{
|
|
|
|
strcpy(path,GetExpandName(path));
|
|
|
|
};
|
|
|
|
|
|
|
|
char* DOS_Drive_Cache::GetExpandName(const char* path)
|
|
|
|
{
|
2009-05-02 23:53:27 +02:00
|
|
|
static char work [CROSS_LEN] = { 0 };
|
2009-05-02 23:35:44 +02:00
|
|
|
char dir [CROSS_LEN];
|
|
|
|
|
|
|
|
work[0] = 0;
|
|
|
|
strcpy (dir,path);
|
|
|
|
|
2009-05-02 23:53:27 +02:00
|
|
|
const char* pos = strrchr(path,CROSS_FILESPLIT);
|
2009-05-02 23:35:44 +02:00
|
|
|
|
|
|
|
if (pos) dir[pos-path+1] = 0;
|
|
|
|
CFileInfo* dirInfo = FindDirInfo(dir, work);
|
|
|
|
|
|
|
|
if (pos) {
|
|
|
|
// Last Entry = File
|
|
|
|
strcpy(dir,pos+1);
|
|
|
|
GetLongName(dirInfo, dir);
|
|
|
|
strcat(work,dir);
|
|
|
|
}
|
2009-05-03 00:02:15 +02:00
|
|
|
|
|
|
|
if(work && *work) {
|
|
|
|
size_t len = strlen(work);
|
|
|
|
#if defined (WIN32)
|
|
|
|
if((work[len-1] == CROSS_FILESPLIT ) && (len >= 2) && (work[len-2] != ':')) {
|
|
|
|
#else
|
|
|
|
if((len > 1) && (work[len-1] == CROSS_FILESPLIT )) {
|
|
|
|
#endif
|
|
|
|
work[len-1] = 0; // Remove trailing slashes except when in root
|
|
|
|
}
|
|
|
|
}
|
2009-05-02 23:35:44 +02:00
|
|
|
return work;
|
|
|
|
};
|
|
|
|
|
|
|
|
void DOS_Drive_Cache::AddEntry(const char* path, bool checkExists)
|
|
|
|
{
|
|
|
|
// Get Last part...
|
|
|
|
char file [CROSS_LEN];
|
|
|
|
char expand [CROSS_LEN];
|
|
|
|
|
|
|
|
CFileInfo* dir = FindDirInfo(path,expand);
|
2009-05-02 23:53:27 +02:00
|
|
|
const char* pos = strrchr(path,CROSS_FILESPLIT);
|
2009-05-02 23:35:44 +02:00
|
|
|
|
|
|
|
if (pos) {
|
|
|
|
strcpy(file,pos+1);
|
|
|
|
// Check if file already exists, then dont add new entry...
|
|
|
|
if (checkExists && (GetLongName(dir,file)>=0)) return;
|
|
|
|
|
|
|
|
CreateEntry(dir,file);
|
|
|
|
// Sort Lists - filelist has to be alphabetically sorted
|
|
|
|
std::sort(dir->fileList.begin(), dir->fileList.end(), SortByName);
|
2009-05-02 23:43:00 +02:00
|
|
|
Bits index = GetLongName(dir,file);
|
2009-05-02 23:35:44 +02:00
|
|
|
if (index>=0) {
|
|
|
|
Bit32u i;
|
|
|
|
// Check if there are any open search dir that are affected by this...
|
|
|
|
if (dir) for (i=0; i<MAX_OPENDIRS; i++) {
|
2009-05-03 00:37:32 +02:00
|
|
|
if ((dirSearch[i]==dir) && ((Bit32u)index<=dirSearch[i]->nextEntry))
|
2009-05-02 23:35:44 +02:00
|
|
|
dirSearch[i]->nextEntry++;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// LOG_DEBUG("DIR: Added Entry %s",path);
|
|
|
|
} else {
|
|
|
|
// LOG_DEBUG("DIR: Error: Failed to add %s",path);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
void DOS_Drive_Cache::DeleteEntry(const char* path, bool ignoreLastDir)
|
|
|
|
{
|
|
|
|
CacheOut(path,ignoreLastDir);
|
2009-05-02 23:53:27 +02:00
|
|
|
if (dirSearch[srchNr] && (dirSearch[srchNr]->nextEntry>0)) dirSearch[srchNr]->nextEntry--;
|
2009-05-02 23:35:44 +02:00
|
|
|
|
|
|
|
if (!ignoreLastDir) {
|
|
|
|
// Check if there are any open search dir that are affected by this...
|
|
|
|
Bit32u i;
|
|
|
|
char expand [CROSS_LEN];
|
|
|
|
CFileInfo* dir = FindDirInfo(path,expand);
|
|
|
|
if (dir) for (i=0; i<MAX_OPENDIRS; i++) {
|
|
|
|
if ((dirSearch[i]==dir) && (dirSearch[i]->nextEntry>0))
|
|
|
|
dirSearch[i]->nextEntry--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void DOS_Drive_Cache::CacheOut(const char* path, bool ignoreLastDir)
|
|
|
|
{
|
|
|
|
char expand[CROSS_LEN] = { 0 };
|
|
|
|
CFileInfo* dir;
|
|
|
|
|
|
|
|
if (ignoreLastDir) {
|
|
|
|
char tmp[CROSS_LEN] = { 0 };
|
|
|
|
Bit32s len = strrchr(path,CROSS_FILESPLIT) - path;
|
|
|
|
if (len>0) {
|
2009-05-03 00:18:08 +02:00
|
|
|
safe_strncpy(tmp,path,len+1);
|
2009-05-02 23:35:44 +02:00
|
|
|
} else {
|
|
|
|
strcpy(tmp,path);
|
|
|
|
}
|
|
|
|
dir = FindDirInfo(tmp,expand);
|
|
|
|
} else {
|
|
|
|
dir = FindDirInfo(path,expand);
|
|
|
|
}
|
|
|
|
|
|
|
|
// LOG_DEBUG("DIR: Caching out %s : dir %s",expand,dir->orgname);
|
|
|
|
// delete file objects...
|
2009-05-02 23:53:27 +02:00
|
|
|
for(Bit32u i=0; i<dir->fileList.size(); i++) {
|
|
|
|
if (dirSearch[srchNr]==dir->fileList[i]) dirSearch[srchNr] = 0;
|
|
|
|
delete dir->fileList[i]; dir->fileList[i] = 0;
|
|
|
|
}
|
2009-05-02 23:35:44 +02:00
|
|
|
// clear lists
|
|
|
|
dir->fileList.clear();
|
|
|
|
dir->longNameList.clear();
|
|
|
|
save_dir = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool DOS_Drive_Cache::IsCachedIn(CFileInfo* curDir)
|
|
|
|
{
|
|
|
|
return (curDir->fileList.size()>0);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
bool DOS_Drive_Cache::GetShortName(const char* fullname, char* shortname)
|
|
|
|
{
|
|
|
|
// Get Dir Info
|
|
|
|
char expand[CROSS_LEN] = {0};
|
|
|
|
CFileInfo* curDir = FindDirInfo(fullname,expand);
|
|
|
|
|
2009-05-02 23:43:00 +02:00
|
|
|
Bits low = 0;
|
|
|
|
Bits high = curDir->longNameList.size()-1;
|
|
|
|
Bits mid, res;
|
2009-05-02 23:35:44 +02:00
|
|
|
|
|
|
|
while (low<=high) {
|
|
|
|
mid = (low+high)/2;
|
|
|
|
res = strcmp(fullname,curDir->longNameList[mid]->orgname);
|
|
|
|
if (res>0) low = mid+1; else
|
|
|
|
if (res<0) high = mid-1;
|
|
|
|
else {
|
|
|
|
strcpy(shortname,curDir->longNameList[mid]->shortname);
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2009-05-02 23:53:27 +02:00
|
|
|
int DOS_Drive_Cache::CompareShortname(const char* compareName, const char* shortName)
|
|
|
|
{
|
2009-05-03 00:18:08 +02:00
|
|
|
char const* cpos = strchr(shortName,'~');
|
2009-05-02 23:53:27 +02:00
|
|
|
if (cpos) {
|
2009-05-03 00:18:08 +02:00
|
|
|
/* the following code is replaced as it's not safe when char* is 64 bits */
|
|
|
|
/* Bits compareCount1 = (int)cpos - (int)shortName;
|
2009-05-02 23:53:27 +02:00
|
|
|
char* endPos = strchr(cpos,'.');
|
|
|
|
Bitu numberSize = endPos ? int(endPos)-int(cpos) : strlen(cpos);
|
|
|
|
|
|
|
|
char* lpos = strchr(compareName,'.');
|
|
|
|
Bits compareCount2 = lpos ? int(lpos)-int(compareName) : strlen(compareName);
|
|
|
|
if (compareCount2>8) compareCount2 = 8;
|
|
|
|
|
|
|
|
compareCount2 -= numberSize;
|
|
|
|
if (compareCount2>compareCount1) compareCount1 = compareCount2;
|
2009-05-03 00:18:08 +02:00
|
|
|
*/
|
|
|
|
size_t compareCount1 = strcspn(shortName,"~");
|
|
|
|
size_t numberSize = strcspn(cpos,".");
|
|
|
|
size_t compareCount2 = strcspn(compareName,".");
|
|
|
|
if(compareCount2 > 8) compareCount2 = 8;
|
|
|
|
/* We want
|
|
|
|
* compareCount2 -= numberSize;
|
|
|
|
* if (compareCount2>compareCount1) compareCount1 = compareCount2;
|
|
|
|
* but to prevent negative numbers:
|
|
|
|
*/
|
|
|
|
if(compareCount2 > compareCount1 + numberSize)
|
|
|
|
compareCount1 = compareCount2 - numberSize;
|
2009-05-02 23:53:27 +02:00
|
|
|
return strncmp(compareName,shortName,compareCount1);
|
|
|
|
}
|
|
|
|
return strcmp(compareName,shortName);
|
|
|
|
};
|
|
|
|
|
2009-05-02 23:35:44 +02:00
|
|
|
Bit16u DOS_Drive_Cache::CreateShortNameID(CFileInfo* curDir, const char* name)
|
|
|
|
{
|
2009-05-02 23:43:00 +02:00
|
|
|
Bits foundNr = 0;
|
|
|
|
Bits low = 0;
|
|
|
|
Bits high = curDir->longNameList.size()-1;
|
|
|
|
Bits mid, res;
|
2009-05-02 23:35:44 +02:00
|
|
|
|
|
|
|
while (low<=high) {
|
|
|
|
mid = (low+high)/2;
|
2009-05-02 23:53:27 +02:00
|
|
|
res = CompareShortname(name,curDir->longNameList[mid]->shortname);
|
|
|
|
|
2009-05-02 23:35:44 +02:00
|
|
|
if (res>0) low = mid+1; else
|
|
|
|
if (res<0) high = mid-1;
|
|
|
|
else {
|
|
|
|
// any more same x chars in next entries ?
|
|
|
|
do {
|
|
|
|
foundNr = curDir->longNameList[mid]->shortNr;
|
|
|
|
mid++;
|
2009-05-03 00:37:32 +02:00
|
|
|
} while((Bitu)mid<curDir->longNameList.size() && (CompareShortname(name,curDir->longNameList[mid]->shortname)==0));
|
2009-05-02 23:35:44 +02:00
|
|
|
break;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
return foundNr+1;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool DOS_Drive_Cache::RemoveTrailingDot(char* shortname)
|
|
|
|
// remove trailing '.' if no extension is available (Linux compatibility)
|
|
|
|
{
|
|
|
|
Bitu len = strlen(shortname);
|
|
|
|
if (len && (shortname[len-1]=='.')) {
|
|
|
|
if (len==1) return false;
|
|
|
|
if ((len==2) && (shortname[0]=='.')) return false;
|
|
|
|
shortname[len-1] = 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2009-05-02 23:43:00 +02:00
|
|
|
Bits DOS_Drive_Cache::GetLongName(CFileInfo* curDir, char* shortName)
|
2009-05-02 23:35:44 +02:00
|
|
|
{
|
|
|
|
// Remove dot, if no extension...
|
|
|
|
RemoveTrailingDot(shortName);
|
|
|
|
// Search long name and return array number of element
|
2009-05-02 23:43:00 +02:00
|
|
|
Bits low = 0;
|
|
|
|
Bits high = curDir->fileList.size()-1;
|
|
|
|
Bits mid,res;
|
2009-05-02 23:35:44 +02:00
|
|
|
while (low<=high) {
|
|
|
|
mid = (low+high)/2;
|
|
|
|
res = strcmp(shortName,curDir->fileList[mid]->shortname);
|
|
|
|
if (res>0) low = mid+1; else
|
|
|
|
if (res<0) high = mid-1; else
|
|
|
|
{ // Found
|
|
|
|
strcpy(shortName,curDir->fileList[mid]->orgname);
|
|
|
|
return mid;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
// not available
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool DOS_Drive_Cache::RemoveSpaces(char* str)
|
|
|
|
// Removes all spaces
|
|
|
|
{
|
|
|
|
char* curpos = str;
|
|
|
|
char* chkpos = str;
|
|
|
|
while (*chkpos!=0) {
|
|
|
|
if (*chkpos==' ') chkpos++; else *curpos++ = *chkpos++;
|
|
|
|
}
|
|
|
|
*curpos = 0;
|
|
|
|
return (curpos!=chkpos);
|
|
|
|
};
|
|
|
|
|
|
|
|
void DOS_Drive_Cache::CreateShortName(CFileInfo* curDir, CFileInfo* info)
|
|
|
|
{
|
2009-05-02 23:43:00 +02:00
|
|
|
Bits len = 0;
|
|
|
|
Bits lenExt = 0;
|
2009-05-02 23:35:44 +02:00
|
|
|
bool createShort = false;
|
|
|
|
|
|
|
|
char tmpNameBuffer[CROSS_LEN];
|
|
|
|
|
|
|
|
char* tmpName = tmpNameBuffer;
|
|
|
|
|
|
|
|
// Remove Spaces
|
|
|
|
strcpy(tmpName,info->orgname);
|
|
|
|
upcase(tmpName);
|
|
|
|
createShort = RemoveSpaces(tmpName);
|
|
|
|
|
|
|
|
// Get Length of filename
|
|
|
|
char* pos = strchr(tmpName,'.');
|
|
|
|
if (pos) {
|
|
|
|
// Get Length of extension
|
|
|
|
lenExt = strlen(pos)-1;
|
|
|
|
// ignore preceding '.' if extension is longer than "3"
|
|
|
|
if (lenExt>3) {
|
|
|
|
while (*tmpName=='.') tmpName++;
|
|
|
|
createShort = true;
|
|
|
|
};
|
|
|
|
pos = strchr(tmpName,'.');
|
|
|
|
if (pos) len = (Bit16u)(pos - tmpName);
|
|
|
|
else len = strlen(tmpName);
|
|
|
|
|
|
|
|
} else
|
|
|
|
len = strlen(tmpName);
|
|
|
|
|
|
|
|
// Should shortname version be created ?
|
|
|
|
createShort = createShort || (len>8);
|
|
|
|
if (!createShort) {
|
|
|
|
char buffer[CROSS_LEN];
|
|
|
|
strcpy(buffer,tmpName);
|
|
|
|
createShort = (GetLongName(curDir,buffer)>=0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (createShort) {
|
|
|
|
// Create number
|
|
|
|
char buffer[8];
|
|
|
|
info->shortNr = CreateShortNameID(curDir,tmpName);
|
|
|
|
sprintf(buffer,"%d",info->shortNr);
|
|
|
|
// Copy first letters
|
2009-05-03 00:18:08 +02:00
|
|
|
Bit16u tocopy = 0;
|
2009-05-02 23:35:44 +02:00
|
|
|
if (len+strlen(buffer)+1>8) tocopy = 8 - strlen(buffer) - 1;
|
|
|
|
else tocopy = len;
|
2009-05-03 00:18:08 +02:00
|
|
|
safe_strncpy(info->shortname,tmpName,tocopy+1);
|
2009-05-02 23:35:44 +02:00
|
|
|
// Copy number
|
|
|
|
strcat(info->shortname,"~");
|
|
|
|
strcat(info->shortname,buffer);
|
|
|
|
// Add (and cut) Extension, if available
|
|
|
|
if (pos) {
|
|
|
|
// Step to last extension...
|
|
|
|
pos = strrchr(tmpName, '.');
|
|
|
|
// add extension
|
|
|
|
strncat(info->shortname,pos,4);
|
|
|
|
info->shortname[DOS_NAMELENGTH] = 0;
|
|
|
|
};
|
|
|
|
// Put it in longname list...
|
|
|
|
curDir->longNameList.push_back(info);
|
|
|
|
std::sort(curDir->longNameList.begin(), curDir->longNameList.end(), SortByName);
|
|
|
|
} else {
|
|
|
|
strcpy(info->shortname,tmpName);
|
|
|
|
}
|
|
|
|
RemoveTrailingDot(info->shortname);
|
|
|
|
};
|
|
|
|
|
|
|
|
DOS_Drive_Cache::CFileInfo* DOS_Drive_Cache::FindDirInfo(const char* path, char* expandedPath)
|
|
|
|
{
|
|
|
|
// statics
|
|
|
|
static char split[2] = { CROSS_FILESPLIT,0 };
|
|
|
|
|
|
|
|
char dir [CROSS_LEN];
|
|
|
|
char work [CROSS_LEN];
|
2009-05-02 23:43:00 +02:00
|
|
|
const char* start = path;
|
2009-05-02 23:53:27 +02:00
|
|
|
const char* pos;
|
2009-05-02 23:35:44 +02:00
|
|
|
CFileInfo* curDir = dirBase;
|
|
|
|
Bit16u id;
|
|
|
|
|
|
|
|
if (save_dir && (strcmp(path,save_path)==0)) {
|
|
|
|
strcpy(expandedPath,save_expanded);
|
|
|
|
return save_dir;
|
|
|
|
};
|
|
|
|
|
|
|
|
// LOG_DEBUG("DIR: Find %s",path);
|
|
|
|
|
|
|
|
// Remove base dir path
|
|
|
|
start += strlen(basePath);
|
|
|
|
strcpy(expandedPath,basePath);
|
|
|
|
|
|
|
|
// hehe, baseDir should be cached in...
|
|
|
|
if (!IsCachedIn(curDir)) {
|
|
|
|
strcpy(work,basePath);
|
|
|
|
if (OpenDir(curDir,work,id)) {
|
|
|
|
char buffer[CROSS_LEN];
|
2009-05-02 23:53:27 +02:00
|
|
|
char* result = 0;
|
2009-05-02 23:35:44 +02:00
|
|
|
strcpy(buffer,dirPath);
|
|
|
|
ReadDir(id,result);
|
|
|
|
strcpy(dirPath,buffer);
|
|
|
|
free[id] = true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
do {
|
|
|
|
// bool errorcheck = false;
|
|
|
|
pos = strchr(start,CROSS_FILESPLIT);
|
2009-05-03 00:18:08 +02:00
|
|
|
if (pos) { safe_strncpy(dir,start,pos-start+1); /*errorcheck = true;*/ }
|
2009-05-02 23:35:44 +02:00
|
|
|
else { strcpy(dir,start); };
|
|
|
|
|
|
|
|
// Path found
|
2009-05-02 23:43:00 +02:00
|
|
|
Bits nextDir = GetLongName(curDir,dir);
|
2009-05-02 23:35:44 +02:00
|
|
|
strcat(expandedPath,dir);
|
|
|
|
|
|
|
|
// Error check
|
|
|
|
/* if ((errorcheck) && (nextDir<0)) {
|
|
|
|
LOG_DEBUG("DIR: Error: %s not found.",expandedPath);
|
|
|
|
};
|
|
|
|
*/
|
|
|
|
// Follow Directory
|
|
|
|
if ((nextDir>=0) && curDir->fileList[nextDir]->isDir) {
|
|
|
|
curDir = curDir->fileList[nextDir];
|
|
|
|
strcpy (curDir->orgname,dir);
|
|
|
|
if (!IsCachedIn(curDir)) {
|
2009-05-02 23:43:00 +02:00
|
|
|
if (OpenDir(curDir,expandedPath,id)) {
|
2009-05-02 23:35:44 +02:00
|
|
|
char buffer[CROSS_LEN];
|
2009-05-02 23:53:27 +02:00
|
|
|
char* result = 0;
|
2009-05-02 23:35:44 +02:00
|
|
|
strcpy(buffer,dirPath);
|
|
|
|
ReadDir(id,result);
|
|
|
|
strcpy(dirPath,buffer);
|
|
|
|
free[id] = true;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if (pos) {
|
|
|
|
strcat(expandedPath,split);
|
|
|
|
start = pos+1;
|
|
|
|
}
|
|
|
|
} while (pos);
|
|
|
|
|
|
|
|
// Save last result for faster access next time
|
|
|
|
strcpy(save_path,path);
|
|
|
|
strcpy(save_expanded,expandedPath);
|
|
|
|
save_dir = curDir;
|
|
|
|
|
|
|
|
return curDir;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool DOS_Drive_Cache::OpenDir(const char* path, Bit16u& id)
|
|
|
|
{
|
|
|
|
char expand[CROSS_LEN] = {0};
|
|
|
|
CFileInfo* dir = FindDirInfo(path,expand);
|
|
|
|
if (OpenDir(dir,expand,id)) {
|
|
|
|
dirSearch[id]->nextEntry = 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2009-05-02 23:43:00 +02:00
|
|
|
bool DOS_Drive_Cache::OpenDir(CFileInfo* dir, const char* expand, Bit16u& id)
|
2009-05-02 23:35:44 +02:00
|
|
|
{
|
|
|
|
id = GetFreeID(dir);
|
|
|
|
dirSearch[id] = dir;
|
2009-05-02 23:43:00 +02:00
|
|
|
char expandcopy [CROSS_LEN];
|
|
|
|
strcpy(expandcopy,expand);
|
2009-05-02 23:35:44 +02:00
|
|
|
// Add "/"
|
|
|
|
char end[2]={CROSS_FILESPLIT,0};
|
2009-05-02 23:43:00 +02:00
|
|
|
if (expandcopy[strlen(expandcopy)-1]!=CROSS_FILESPLIT) strcat(expandcopy,end);
|
2009-05-02 23:35:44 +02:00
|
|
|
// open dir
|
|
|
|
if (dirSearch[id]) {
|
|
|
|
// open dir
|
2009-05-02 23:43:00 +02:00
|
|
|
DIR* dirp = opendir(expandcopy);
|
2009-05-02 23:35:44 +02:00
|
|
|
if (dirp) {
|
|
|
|
// Reset it..
|
|
|
|
closedir(dirp);
|
2009-05-02 23:43:00 +02:00
|
|
|
strcpy(dirPath,expandcopy);
|
2009-05-02 23:35:44 +02:00
|
|
|
free[id] = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
|
|
|
void DOS_Drive_Cache::CreateEntry(CFileInfo* dir, const char* name)
|
|
|
|
{
|
|
|
|
struct stat status;
|
|
|
|
CFileInfo* info = new CFileInfo;
|
|
|
|
strcpy(info->orgname ,name);
|
|
|
|
info->shortNr = 0;
|
|
|
|
// Read and copy file stats
|
|
|
|
char buffer[CROSS_LEN];
|
|
|
|
strcpy(buffer,dirPath);
|
|
|
|
strcat(buffer,info->orgname);
|
|
|
|
if (stat(buffer,&status)==0) info->isDir = (S_ISDIR(status.st_mode)>0);
|
|
|
|
else info->isDir = false;
|
|
|
|
// Check for long filenames...
|
|
|
|
CreateShortName(dir, info);
|
|
|
|
// Put file in lists
|
|
|
|
dir->fileList.push_back(info);
|
|
|
|
};
|
|
|
|
|
|
|
|
bool DOS_Drive_Cache::ReadDir(Bit16u id, char* &result)
|
|
|
|
{
|
|
|
|
// shouldnt happen...
|
|
|
|
if (id>MAX_OPENDIRS) return false;
|
|
|
|
|
|
|
|
if (!IsCachedIn(dirSearch[id])) {
|
|
|
|
// Try to open directory
|
|
|
|
DIR* dirp = opendir(dirPath);
|
|
|
|
if (!dirp) {
|
|
|
|
free[id] = true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Read complete directory
|
|
|
|
struct dirent* tmpres;
|
|
|
|
while ((tmpres = readdir(dirp))!=NULL) {
|
|
|
|
CreateEntry(dirSearch[id],tmpres->d_name);
|
|
|
|
// Sort Lists - filelist has to be alphabetically sorted, even in between (for finding double file names)
|
|
|
|
// hmpf.. bit slow probably...
|
|
|
|
std::sort(dirSearch[id]->fileList.begin(), dirSearch[id]->fileList.end(), SortByName);
|
|
|
|
}
|
|
|
|
// close dir
|
|
|
|
closedir(dirp);
|
|
|
|
// Info
|
|
|
|
/* if (!dirp) {
|
|
|
|
LOG_DEBUG("DIR: Error Caching in %s",dirPath);
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
char buffer[128];
|
|
|
|
sprintf(buffer,"DIR: Caching in %s (%d Files)",dirPath,dirSearch[srchNr]->fileList.size());
|
|
|
|
LOG_DEBUG(buffer);
|
|
|
|
};*/
|
|
|
|
};
|
|
|
|
if (SetResult(dirSearch[id], result, dirSearch[id]->nextEntry)) return true;
|
|
|
|
free[id] = true;
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool DOS_Drive_Cache::SetResult(CFileInfo* dir, char* &result, Bit16u entryNr)
|
|
|
|
{
|
2009-05-02 23:53:27 +02:00
|
|
|
static char res[CROSS_LEN] = { 0 };
|
2009-05-02 23:35:44 +02:00
|
|
|
|
|
|
|
result = res;
|
2009-05-02 23:43:00 +02:00
|
|
|
if (entryNr>=dir->fileList.size()) return false;
|
|
|
|
CFileInfo* info = dir->fileList[entryNr];
|
2009-05-02 23:35:44 +02:00
|
|
|
// copy filename, short version
|
|
|
|
strcpy(res,info->shortname);
|
|
|
|
// Set to next Entry
|
|
|
|
dir->nextEntry = entryNr+1;
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
2009-05-02 23:43:00 +02:00
|
|
|
// FindFirst / FindNext
|
2009-05-03 00:02:15 +02:00
|
|
|
bool DOS_Drive_Cache::FindFirst(char* path, Bitu& id)
|
2009-05-02 23:43:00 +02:00
|
|
|
{
|
|
|
|
Bit16u dirID;
|
2009-05-03 00:28:34 +02:00
|
|
|
Bitu dirFindFirstID = this->nextFreeFindFirst;
|
2009-05-02 23:53:27 +02:00
|
|
|
|
2009-05-02 23:43:00 +02:00
|
|
|
// Cache directory in
|
|
|
|
if (!OpenDir(path,dirID)) return false;
|
2009-05-03 00:02:15 +02:00
|
|
|
|
2009-05-03 00:28:34 +02:00
|
|
|
this->nextFreeFindFirst++; //increase it for the next search
|
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
if (dirFindFirstID == MAX_OPENDIRS) {
|
2009-05-02 23:43:00 +02:00
|
|
|
// no free slot found...
|
2009-05-03 00:02:15 +02:00
|
|
|
LOG(LOG_MISC,LOG_ERROR)("DIRCACHE: FindFirst/Next: All slots full. Resetting");
|
|
|
|
// Clear the internal list then.
|
2009-05-02 23:43:00 +02:00
|
|
|
dirFindFirstID = 0;
|
2009-05-03 00:02:15 +02:00
|
|
|
this->nextFreeFindFirst = 1; //the next free one after this search
|
|
|
|
for(Bitu n=0; n<MAX_OPENDIRS;n++) {
|
|
|
|
// Clear and reuse slot
|
|
|
|
delete dirFindFirst[n];
|
|
|
|
dirFindFirst[n]=0;
|
|
|
|
}
|
|
|
|
|
2009-05-02 23:43:00 +02:00
|
|
|
}
|
|
|
|
dirFindFirst[dirFindFirstID] = new CFileInfo();
|
|
|
|
dirFindFirst[dirFindFirstID]-> nextEntry = 0;
|
|
|
|
|
|
|
|
// Copy entries to use with FindNext
|
|
|
|
for (Bitu i=0; i<dirSearch[dirID]->fileList.size(); i++) {
|
|
|
|
CreateEntry(dirFindFirst[dirFindFirstID],dirSearch[dirID]->fileList[i]->orgname);
|
|
|
|
// Sort Lists - filelist has to be alphabetically sorted, even in between (for finding double file names)
|
|
|
|
std::sort(dirFindFirst[dirFindFirstID]->fileList.begin(), dirFindFirst[dirFindFirstID]->fileList.end(), SortByName);
|
|
|
|
};
|
|
|
|
// Now re-sort the fileList accordingly to output
|
|
|
|
switch (sortDirType) {
|
|
|
|
case ALPHABETICAL : std::sort(dirFindFirst[dirFindFirstID]->fileList.begin(), dirFindFirst[dirFindFirstID]->fileList.end(), SortByName); break;
|
|
|
|
case DIRALPHABETICAL : std::sort(dirFindFirst[dirFindFirstID]->fileList.begin(), dirFindFirst[dirFindFirstID]->fileList.end(), SortByDirName); break;
|
|
|
|
case ALPHABETICALREV : std::sort(dirFindFirst[dirFindFirstID]->fileList.begin(), dirFindFirst[dirFindFirstID]->fileList.end(), SortByNameRev); break;
|
|
|
|
case DIRALPHABETICALREV : std::sort(dirFindFirst[dirFindFirstID]->fileList.begin(), dirFindFirst[dirFindFirstID]->fileList.end(), SortByDirNameRev); break;
|
|
|
|
case NOSORT : break;
|
|
|
|
};
|
|
|
|
|
|
|
|
// LOG(LOG_MISC,LOG_ERROR)("DIRCACHE: FindFirst : %s (ID:%02X)",path,dirFindFirstID);
|
|
|
|
id = dirFindFirstID;
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
bool DOS_Drive_Cache::FindNext(Bitu id, char* &result)
|
|
|
|
{
|
|
|
|
// out of range ?
|
|
|
|
if ((id>=MAX_OPENDIRS) || !dirFindFirst[id]) {
|
|
|
|
LOG(LOG_MISC,LOG_ERROR)("DIRCACHE: FindFirst/Next failure : ID out of range: %04X",id);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!SetResult(dirFindFirst[id], result, dirFindFirst[id]->nextEntry)) {
|
|
|
|
// free slot
|
|
|
|
delete dirFindFirst[id]; dirFindFirst[id] = 0;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|