1 /*
2  *  Copyright (C) 2002-2015  The DOSBox Team
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  *  Wengier: LFN support
19  */
20 
21 
22 #include <cctype>
23 #include <cstring>
24 #include "cdrom.h"
25 #include "dosbox.h"
26 #include "dos_system.h"
27 #include "support.h"
28 #include "drives.h"
29 
30 #define FLAGS1	((iso) ? de.fileFlags : de.timeZone)
31 #define FLAGS2	((iso) ? de->fileFlags : de->timeZone)
32 
33 using namespace std;
34 char fullname[LFN_NAMELENGTH];
35 
36 class isoFile : public DOS_File {
37 public:
38 	isoFile(isoDrive *drive, const char *name, FileStat_Block *stat, Bit32u offset);
39 	bool Read(Bit8u *data, Bit16u *size);
40 	bool Write(Bit8u *data, Bit16u *size);
41 	bool Seek(Bit32u *pos, Bit32u type);
42 	bool Close();
43 	Bit16u GetInformation(void);
44 private:
45 	isoDrive *drive;
46 	Bit8u buffer[ISO_FRAMESIZE];
47 	int cachedSector;
48 	Bit32u fileBegin;
49 	Bit32u filePos;
50 	Bit32u fileEnd;
51 	Bit16u info;
52 };
53 
isoFile(isoDrive * drive,const char * name,FileStat_Block * stat,Bit32u offset)54 isoFile::isoFile(isoDrive *drive, const char *name, FileStat_Block *stat, Bit32u offset) {
55 	this->drive = drive;
56 	time = stat->time;
57 	date = stat->date;
58 	attr = stat->attr;
59 	fileBegin = offset;
60 	filePos = fileBegin;
61 	fileEnd = fileBegin + stat->size;
62 	cachedSector = -1;
63 	open = true;
64 	this->name = NULL;
65 	SetName(name);
66 }
67 
Read(Bit8u * data,Bit16u * size)68 bool isoFile::Read(Bit8u *data, Bit16u *size) {
69 	if (filePos + *size > fileEnd)
70 		*size = (Bit16u)(fileEnd - filePos);
71 
72 	Bit16u nowSize = 0;
73 	int sector = filePos / ISO_FRAMESIZE;
74 	Bit16u sectorPos = (Bit16u)(filePos % ISO_FRAMESIZE);
75 
76 	if (sector != cachedSector) {
77 		if (drive->readSector(buffer, sector)) cachedSector = sector;
78 		else { *size = 0; cachedSector = -1; }
79 	}
80 	while (nowSize < *size) {
81 		Bit16u remSector = ISO_FRAMESIZE - sectorPos;
82 		Bit16u remSize = *size - nowSize;
83 		if(remSector < remSize) {
84 			memcpy(&data[nowSize], &buffer[sectorPos], remSector);
85 			nowSize += remSector;
86 			sectorPos = 0;
87 			sector++;
88 			cachedSector++;
89 			if (!drive->readSector(buffer, sector)) {
90 				*size = nowSize;
91 				cachedSector = -1;
92 			}
93 		} else {
94 			memcpy(&data[nowSize], &buffer[sectorPos], remSize);
95 			nowSize += remSize;
96 		}
97 
98 	}
99 
100 	*size = nowSize;
101 	filePos += *size;
102 	return true;
103 }
104 
Write(Bit8u *,Bit16u *)105 bool isoFile::Write(Bit8u* /*data*/, Bit16u* /*size*/) {
106 	return false;
107 }
108 
Seek(Bit32u * pos,Bit32u type)109 bool isoFile::Seek(Bit32u *pos, Bit32u type) {
110 	switch (type) {
111 		case DOS_SEEK_SET:
112 			filePos = fileBegin + *pos;
113 			break;
114 		case DOS_SEEK_CUR:
115 			filePos += *pos;
116 			break;
117 		case DOS_SEEK_END:
118 			filePos = fileEnd + *pos;
119 			break;
120 		default:
121 			return false;
122 	}
123 	if (filePos > fileEnd || filePos < fileBegin)
124 		filePos = fileEnd;
125 
126 	*pos = filePos - fileBegin;
127 	return true;
128 }
129 
Close()130 bool isoFile::Close() {
131 	if (refCtr == 1) open = false;
132 	return true;
133 }
134 
GetInformation(void)135 Bit16u isoFile::GetInformation(void) {
136 	return 0x40;		// read-only drive
137 }
138 
139 int  MSCDEX_RemoveDrive(char driveLetter);
140 int  MSCDEX_AddDrive(char driveLetter, const char* physicalPath, Bit8u& subUnit);
141 void MSCDEX_ReplaceDrive(CDROM_Interface* cdrom, Bit8u subUnit);
142 bool MSCDEX_HasDrive(char driveLetter);
143 bool MSCDEX_GetVolumeName(Bit8u subUnit, char* name);
144 
isoDrive(char driveLetter,const char * fileName,Bit8u mediaid,int & error)145 isoDrive::isoDrive(char driveLetter, const char *fileName, Bit8u mediaid, int &error) {
146 	nextFreeDirIterator = 0;
147 	memset(dirIterators, 0, sizeof(dirIterators));
148 	memset(sectorHashEntries, 0, sizeof(sectorHashEntries));
149 	memset(&rootEntry, 0, sizeof(isoDirEntry));
150 
151 	safe_strncpy(this->fileName, fileName, CROSS_LEN);
152 	error = UpdateMscdex(driveLetter, fileName, subUnit);
153 
154 	if (!error) {
155 		if (loadImage()) {
156 			strcpy(info, "isoDrive ");
157 			strcat(info, fileName);
158 			this->driveLetter = driveLetter;
159 			this->mediaid = mediaid;
160 			char buffer[32] = { 0 };
161 			if (!MSCDEX_GetVolumeName(subUnit, buffer)) strcpy(buffer, "");
162 			Set_Label(buffer,discLabel,true);
163 
164 		} else if (CDROM_Interface_Image::images[subUnit]->HasDataTrack() == false) { //Audio only cdrom
165 			strcpy(info, "isoDrive ");
166 			strcat(info, fileName);
167 			this->driveLetter = driveLetter;
168 			this->mediaid = mediaid;
169 			char buffer[32] = { 0 };
170 			strcpy(buffer, "Audio_CD");
171 			Set_Label(buffer,discLabel,true);
172 		} else error = 6; //Corrupt image
173 	}
174 }
175 
~isoDrive()176 isoDrive::~isoDrive() { }
177 
UpdateMscdex(char driveLetter,const char * path,Bit8u & subUnit)178 int isoDrive::UpdateMscdex(char driveLetter, const char* path, Bit8u& subUnit) {
179 	if (MSCDEX_HasDrive(driveLetter)) {
180 		CDROM_Interface_Image* oldCdrom = CDROM_Interface_Image::images[subUnit];
181 		CDROM_Interface* cdrom = new CDROM_Interface_Image(subUnit);
182 		char pathCopy[CROSS_LEN];
183 		safe_strncpy(pathCopy, path, CROSS_LEN);
184 		if (!cdrom->SetDevice(pathCopy, 0)) {
185 			CDROM_Interface_Image::images[subUnit] = oldCdrom;
186 			delete cdrom;
187 			return 3;
188 		}
189 		MSCDEX_ReplaceDrive(cdrom, subUnit);
190 		return 0;
191 	} else {
192 		return MSCDEX_AddDrive(driveLetter, path, subUnit);
193 	}
194 }
195 
Activate(void)196 void isoDrive::Activate(void) {
197 	UpdateMscdex(driveLetter, fileName, subUnit);
198 }
199 
FileOpen(DOS_File ** file,char * name,Bit32u flags)200 bool isoDrive::FileOpen(DOS_File **file, char *name, Bit32u flags) {
201 	if ((flags & 0x0f) == OPEN_WRITE) {
202 		DOS_SetError(DOSERR_ACCESS_DENIED);
203 		return false;
204 	}
205 
206 	isoDirEntry de;
207 	bool success = lookup(&de, name) && !IS_DIR(FLAGS1);
208 
209 	if (success) {
210 		FileStat_Block file_stat;
211 		file_stat.size = DATA_LENGTH(de);
212 		file_stat.attr = DOS_ATTR_ARCHIVE | DOS_ATTR_READ_ONLY;
213 		file_stat.date = DOS_PackDate(1900 + de.dateYear, de.dateMonth, de.dateDay);
214 		file_stat.time = DOS_PackTime(de.timeHour, de.timeMin, de.timeSec);
215 		*file = new isoFile(this, name, &file_stat, EXTENT_LOCATION(de) * ISO_FRAMESIZE);
216 		(*file)->flags = flags;
217 	}
218 	return success;
219 }
220 
FileCreate(DOS_File **,char *,Bit16u)221 bool isoDrive::FileCreate(DOS_File** /*file*/, char* /*name*/, Bit16u /*attributes*/) {
222 	DOS_SetError(DOSERR_ACCESS_DENIED);
223 	return false;
224 }
225 
FileUnlink(char *)226 bool isoDrive::FileUnlink(char* /*name*/) {
227 	DOS_SetError(DOSERR_ACCESS_DENIED);
228 	return false;
229 }
230 
RemoveDir(char *)231 bool isoDrive::RemoveDir(char* /*dir*/) {
232 	DOS_SetError(DOSERR_ACCESS_DENIED);
233 	return false;
234 }
235 
MakeDir(char *)236 bool isoDrive::MakeDir(char* /*dir*/) {
237 	DOS_SetError(DOSERR_ACCESS_DENIED);
238 	return false;
239 }
240 
TestDir(char * dir)241 bool isoDrive::TestDir(char *dir) {
242 	isoDirEntry de;
243 	return (lookup(&de, dir) && IS_DIR(FLAGS1));
244 }
245 
FindFirst(char * dir,DOS_DTA & dta,bool fcb_findfirst)246 bool isoDrive::FindFirst(char *dir, DOS_DTA &dta, bool fcb_findfirst) {
247 	isoDirEntry de;
248 	if (!lookup(&de, dir)) {
249 		DOS_SetError(DOSERR_PATH_NOT_FOUND);
250 		return false;
251 	}
252 
253 	// get a directory iterator and save its id in the dta
254 	int dirIterator = GetDirIterator(&de);
255 	bool isRoot = (*dir == 0);
256 	dirIterators[dirIterator].root = isRoot;
257 	dta.SetDirID((Bit16u)dirIterator);
258 
259 	Bit8u attr;
260 	char pattern[CROSS_LEN];
261 	dta.GetSearchParams(attr, pattern,true);
262 
263 	if (attr == DOS_ATTR_VOLUME) {
264 		dta.SetResult(discLabel, discLabel, 0, 0, 0, DOS_ATTR_VOLUME);
265 		return true;
266 	} else if ((attr & DOS_ATTR_VOLUME) && isRoot && !fcb_findfirst) {
267 		if (WildFileCmp(discLabel,pattern)) {
268 			// Get Volume Label (DOS_ATTR_VOLUME) and only in basedir and if it matches the searchstring
269 			dta.SetResult(discLabel, discLabel, 0, 0, 0, DOS_ATTR_VOLUME);
270 			return true;
271 		}
272 	}
273 
274 	return FindNext(dta);
275 }
276 
FindNext(DOS_DTA & dta)277 bool isoDrive::FindNext(DOS_DTA &dta) {
278 	Bit8u attr;
279 	char pattern[CROSS_LEN], findName[DOS_NAMELENGTH_ASCII], lfindName[ISO_MAXPATHNAME];
280 	dta.GetSearchParams(attr, pattern, true);
281 
282 	int dirIterator = dta.GetDirID();
283 	bool isRoot = dirIterators[dirIterator].root;
284 
285 	isoDirEntry de;
286 	while (GetNextDirEntry(dirIterator, &de)) {
287 		Bit8u findAttr = 0;
288 		if (IS_DIR(FLAGS1)) findAttr |= DOS_ATTR_DIRECTORY;
289 		else findAttr |= DOS_ATTR_ARCHIVE;
290 		if (IS_HIDDEN(FLAGS1)) findAttr |= DOS_ATTR_HIDDEN;
291 
292 		if (strcmp((char*)de.ident,(char*)fullname))
293 			strcpy(lfindName,fullname);
294 		else
295 			GetLongName((char*)de.ident,lfindName);
296 		if (!IS_ASSOC(FLAGS1) && !(isRoot && de.ident[0]=='.') && (WildFileCmp((char*)de.ident, pattern) || LWildFileCmp(lfindName, pattern))
297 			&& !(~attr & findAttr & (DOS_ATTR_DIRECTORY | DOS_ATTR_HIDDEN | DOS_ATTR_SYSTEM))) {
298 
299 			findName[0] = 0;
300 			/* file is okay, setup everything to be copied in DTA Block */
301 			if(strlen((char*)de.ident) < DOS_NAMELENGTH_ASCII) {
302 				strcpy(findName, (char*)de.ident);
303 				upcase(findName);
304 			}
305 			Bit32u findSize = DATA_LENGTH(de);
306 			Bit16u findDate = DOS_PackDate(1900 + de.dateYear, de.dateMonth, de.dateDay);
307 			Bit16u findTime = DOS_PackTime(de.timeHour, de.timeMin, de.timeSec);
308 			dta.SetResult(findName, lfindName, findSize, findDate, findTime, findAttr);
309 			return true;
310 		}
311 	}
312 	// after searching the directory, free the iterator
313 	FreeDirIterator(dirIterator);
314 
315 	DOS_SetError(DOSERR_NO_MORE_FILES);
316 	return false;
317 }
318 
Rename(char *,char *)319 bool isoDrive::Rename(char* /*oldname*/, char* /*newname*/) {
320 	DOS_SetError(DOSERR_ACCESS_DENIED);
321 	return false;
322 }
323 
GetFileAttr(char * name,Bit16u * attr)324 bool isoDrive::GetFileAttr(char *name, Bit16u *attr) {
325 	*attr = 0;
326 	isoDirEntry de;
327 	bool success = lookup(&de, name);
328 	if (success) {
329 		*attr = DOS_ATTR_ARCHIVE | DOS_ATTR_READ_ONLY;
330 		if (IS_HIDDEN(FLAGS1)) *attr |= DOS_ATTR_HIDDEN;
331 		if (IS_DIR(FLAGS1)) *attr |= DOS_ATTR_DIRECTORY;
332 	}
333 	return success;
334 }
335 
GetFileAttrEx(char * name,struct stat * status)336 bool isoDrive::GetFileAttrEx(char* name, struct stat *status) {
337 	return false;
338 }
339 
GetCompressedSize(char * name)340 Bit32u isoDrive::GetCompressedSize(char* name) {
341 	return 0;
342 }
343 
CreateOpenFile(const char * name)344 void* isoDrive::CreateOpenFile(const char* name) {
345 	DOS_SetError(1);
346 	return NULL;
347 }
348 
AllocationInfo(Bit16u * bytes_sector,Bit8u * sectors_cluster,Bit16u * total_clusters,Bit16u * free_clusters)349 bool isoDrive::AllocationInfo(Bit16u *bytes_sector, Bit8u *sectors_cluster, Bit16u *total_clusters, Bit16u *free_clusters) {
350 	*bytes_sector = 2048;
351 	*sectors_cluster = 1; // cluster size for cdroms ?
352 	*total_clusters = 65535;
353 	*free_clusters = 0;
354 	return true;
355 }
356 
FileExists(const char * name)357 bool isoDrive::FileExists(const char *name) {
358 	isoDirEntry de;
359 	return (lookup(&de, name) && !IS_DIR(FLAGS1));
360 }
361 
FileStat(const char * name,FileStat_Block * const stat_block)362 bool isoDrive::FileStat(const char *name, FileStat_Block *const stat_block) {
363 	isoDirEntry de;
364 	bool success = lookup(&de, name);
365 
366 	if (success) {
367 		stat_block->date = DOS_PackDate(1900 + de.dateYear, de.dateMonth, de.dateDay);
368 		stat_block->time = DOS_PackTime(de.timeHour, de.timeMin, de.timeSec);
369 		stat_block->size = DATA_LENGTH(de);
370 		stat_block->attr = DOS_ATTR_ARCHIVE | DOS_ATTR_READ_ONLY;
371 		if (IS_DIR(FLAGS1)) stat_block->attr |= DOS_ATTR_DIRECTORY;
372 	}
373 
374 	return success;
375 }
376 
GetMediaByte(void)377 Bit8u isoDrive::GetMediaByte(void) {
378 	return mediaid;
379 }
380 
isRemote(void)381 bool isoDrive::isRemote(void) {
382 	return true;
383 }
384 
isRemovable(void)385 bool isoDrive::isRemovable(void) {
386 	return true;
387 }
388 
UnMount(void)389 Bits isoDrive::UnMount(void) {
390 	if(MSCDEX_RemoveDrive(driveLetter)) {
391 		delete this;
392 		return 0;
393 	}
394 	return 2;
395 }
396 
GetDirIterator(const isoDirEntry * de)397 int isoDrive::GetDirIterator(const isoDirEntry* de) {
398 	int dirIterator = nextFreeDirIterator;
399 
400 	// get start and end sector of the directory entry (pad end sector if necessary)
401 	dirIterators[dirIterator].currentSector = EXTENT_LOCATION(*de);
402 	dirIterators[dirIterator].endSector =
403 		EXTENT_LOCATION(*de) + DATA_LENGTH(*de) / ISO_FRAMESIZE - 1;
404 	if (DATA_LENGTH(*de) % ISO_FRAMESIZE != 0)
405 		dirIterators[dirIterator].endSector++;
406 
407 	// reset position and mark as valid
408 	dirIterators[dirIterator].pos = 0;
409 	dirIterators[dirIterator].valid = true;
410 
411 	// advance to next directory iterator (wrap around if necessary)
412 	nextFreeDirIterator = (nextFreeDirIterator + 1) % MAX_OPENDIRS;
413 
414 	return dirIterator;
415 }
416 
GetNextDirEntry(const int dirIteratorHandle,isoDirEntry * de)417 bool isoDrive::GetNextDirEntry(const int dirIteratorHandle, isoDirEntry* de) {
418 	bool result = false;
419 	Bit8u* buffer = NULL;
420 	DirIterator& dirIterator = dirIterators[dirIteratorHandle];
421 	fullname[0]=0;
422 
423 	// check if the directory entry is valid
424 	if (dirIterator.valid && ReadCachedSector(&buffer, dirIterator.currentSector)) {
425 		// check if the next sector has to be read
426 		if ((dirIterator.pos >= ISO_FRAMESIZE)
427 		 || (buffer[dirIterator.pos] == 0)
428 		 || (dirIterator.pos + buffer[dirIterator.pos] > ISO_FRAMESIZE)) {
429 
430 			// check if there is another sector available
431 		 	if (dirIterator.currentSector < dirIterator.endSector) {
432 			 	dirIterator.pos = 0;
433 			 	dirIterator.currentSector++;
434 			 	if (!ReadCachedSector(&buffer, dirIterator.currentSector)) {
435 			 		return false;
436 			 	}
437 		 	} else {
438 		 		return false;
439 		 	}
440 		 }
441 		 // read sector and advance sector pointer
442 		 int length = readDirEntry(de, &buffer[dirIterator.pos]);
443 		 result = length >= 0;
444 		 dirIterator.pos += length;
445 	}
446 	return result;
447 }
448 
FreeDirIterator(const int dirIterator)449 void isoDrive::FreeDirIterator(const int dirIterator) {
450 	dirIterators[dirIterator].valid = false;
451 
452 	// if this was the last aquired iterator decrement nextFreeIterator
453 	if ((dirIterator + 1) % MAX_OPENDIRS == nextFreeDirIterator) {
454 		if (nextFreeDirIterator>0) {
455 			nextFreeDirIterator--;
456 		} else {
457 			nextFreeDirIterator = MAX_OPENDIRS-1;
458 		}
459 	}
460 }
461 
ReadCachedSector(Bit8u ** buffer,const Bit32u sector)462 bool isoDrive::ReadCachedSector(Bit8u** buffer, const Bit32u sector) {
463 	// get hash table entry
464 	int pos = sector % ISO_MAX_HASH_TABLE_SIZE;
465 	SectorHashEntry& he = sectorHashEntries[pos];
466 
467 	// check if the entry is valid and contains the correct sector
468 	if (!he.valid || he.sector != sector) {
469 		if (!CDROM_Interface_Image::images[subUnit]->ReadSector(he.data, false, sector)) {
470 			return false;
471 		}
472 		he.valid = true;
473 		he.sector = sector;
474 	}
475 
476 	*buffer = he.data;
477 	return true;
478 }
479 
readSector(Bit8u * buffer,Bit32u sector)480 inline bool isoDrive :: readSector(Bit8u *buffer, Bit32u sector) {
481 	return CDROM_Interface_Image::images[subUnit]->ReadSector(buffer, false, sector);
482 }
483 
readDirEntry(isoDirEntry * de,Bit8u * data)484 int isoDrive :: readDirEntry(isoDirEntry *de, Bit8u *data) {
485 	// copy data into isoDirEntry struct, data[0] = length of DirEntry
486 //	if (data[0] > sizeof(isoDirEntry)) return -1;//check disabled as isoDirentry is currently 258 bytes large. So it always fits
487 	memcpy(de, data, data[0]);//Perharps care about a zero at the end.
488 
489 	// xa not supported
490 	if (de->extAttrLength != 0) return -1;
491 	// interleaved mode not supported
492 	if (de->fileUnitSize != 0 || de->interleaveGapSize != 0) return -1;
493 
494 	// modify file identifier for use with dosbox
495 	if ((de->length < 33 + de->fileIdentLength)) return -1;
496 	if (IS_DIR(FLAGS2)) {
497 		if (de->fileIdentLength == 1 && de->ident[0] == 0) strcpy((char*)de->ident, ".");
498 		else if (de->fileIdentLength == 1 && de->ident[0] == 1) strcpy((char*)de->ident, "..");
499 		else {
500 			if (de->fileIdentLength > 200) return -1;
501 			de->ident[de->fileIdentLength] = 0;
502 		}
503 	} else {
504 		if (de->fileIdentLength > 200) return -1;
505 		de->ident[de->fileIdentLength] = 0;
506 		// remove any file version identifiers as there are some cdroms that don't have them
507 		strreplace((char*)de->ident, ';', 0);
508 		// if file has no extension remove the trailing dot
509 		size_t tmp = strlen((char*)de->ident);
510 		if (tmp > 0) {
511 			if (de->ident[tmp - 1] == '.') de->ident[tmp - 1] = 0;
512 		}
513 	}
514 	strcpy((char*)fullname,(char*)de->ident);
515 	char* dotpos = strchr((char*)de->ident, '.');
516 	if (dotpos!=NULL) {
517 		if (strlen(dotpos)>4) dotpos[4]=0;
518 		if (dotpos-(char*)de->ident>8) {
519 			strcpy((char*)(&de->ident[8]),dotpos);
520 		}
521 	} else if (strlen((char*)de->ident)>8) de->ident[8]=0;
522 	return de->length;
523 }
524 
loadImage()525 bool isoDrive :: loadImage() {
526 	Bit8u pvd[COOKED_SECTOR_SIZE];
527 	dataCD = false;
528 	readSector(pvd, ISO_FIRST_VD);
529 	if (pvd[0] == 1 && !strncmp((char*)(&pvd[1]), "CD001", 5) && pvd[6] == 1) iso = true;
530 	else if (pvd[8] == 1 && !strncmp((char*)(&pvd[9]), "CDROM", 5) && pvd[14] == 1) iso = false;
531 	else return false;
532 	Bit16u offset = iso ? 156 : 180;
533 	if (readDirEntry(&this->rootEntry, &pvd[offset])>0) {
534 		dataCD = true;
535 		return true;
536 	}
537 	return false;
538 }
539 
lookup(isoDirEntry * de,const char * path)540 bool isoDrive :: lookup(isoDirEntry *de, const char *path) {
541 	if (!dataCD) return false;
542 	*de = this->rootEntry;
543 	if (!strcmp(path, "")) return true;
544 
545 	char isoPath[ISO_MAXPATHNAME], longname[ISO_MAXPATHNAME];
546 	safe_strncpy(isoPath, path, ISO_MAXPATHNAME);
547 	strreplace(isoPath, '\\', '/');
548 
549 	// iterate over all path elements (name), and search each of them in the current de
550 	for(char* name = strtok(isoPath, "/"); NULL != name; name = strtok(NULL, "/")) {
551 
552 		bool found = false;
553 		// current entry must be a directory, abort otherwise
554 		if (IS_DIR(FLAGS2)) {
555 
556 			// remove the trailing dot if present
557 			size_t nameLength = strlen(name);
558 			if (nameLength > 0) {
559 				if (name[nameLength - 1] == '.') name[nameLength - 1] = 0;
560 			}
561 
562 			// look for the current path element
563 			int dirIterator = GetDirIterator(de);
564 			while (!found && GetNextDirEntry(dirIterator, de)) {
565 				GetLongName((char*)de->ident,longname);
566 				if (!IS_ASSOC(FLAGS2) && (0 == strncasecmp((char*) de->ident, name, ISO_MAX_FILENAME_LENGTH)) ||0 == strncasecmp((char*) longname, name, ISO_MAXPATHNAME)) {
567 					found = true;
568 				}
569 			}
570 			FreeDirIterator(dirIterator);
571 		}
572 		if (!found) return false;
573 	}
574 	return true;
575 }
576 
GetLongName(char * ident,char * lfindName)577 void isoDrive :: GetLongName(char *ident, char *lfindName) {
578 	char *c=ident+strlen(ident);
579 	int i,j=222-strlen(ident)-6;
580 	for (i=5;i<j;i++) {
581 		if (*(c+i)=='N'&&*(c+i+1)=='M'&&*(c+i+2)>0&&*(c+i+3)==1&&*(c+i+4)==0&&*(c+i+5)>0)
582 			break;
583 		}
584 	if (i<j&&strcmp(ident,".")&&strcmp(ident,"..")) {
585 		strncpy(lfindName,c+i+5,*(c+i+2)-5);
586 		lfindName[*(c+i+2)-5]=0;
587 	} else
588 		strcpy(lfindName,ident);
589 }
590