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 <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26 #include <errno.h>
27
28 #ifdef VITA
29 #include <psp2/io/stat.h>
30 #include <psp2/io/fcntl.h>
31 #endif
32
33 #include "dosbox.h"
34 #include "dos_inc.h"
35 #include "drives.h"
36 #include "support.h"
37 #include "cross.h"
38 #include "inout.h"
39
40 class localFile : public DOS_File {
41 public:
42 localFile(const char* name, FILE * handle);
43 bool Read(Bit8u * data,Bit16u * size);
44 bool Write(Bit8u * data,Bit16u * size);
45 bool Seek(Bit32u * pos,Bit32u type);
46 bool Close();
47 Bit16u GetInformation(void);
48 bool UpdateDateTimeFromHost(void);
49 void FlagReadOnlyMedium(void);
50 void Flush(void);
51 private:
52 FILE * fhandle;
53 bool read_only_medium;
54 enum { NONE,READ,WRITE } last_action;
55 };
56
57
FileCreate(DOS_File ** file,char * name,Bit16u)58 bool localDrive::FileCreate(DOS_File * * file,char * name,Bit16u /*attributes*/) {
59 //TODO Maybe care for attributes but not likely
60 char newname[CROSS_LEN];
61 strcpy(newname,basedir);
62 strcat(newname,name);
63 CROSS_FILENAME(newname);
64 char* temp_name = dirCache.GetExpandName(newname); //Can only be used in till a new drive_cache action is preformed */
65 /* Test if file exists (so we need to truncate it). don't add to dirCache then */
66 bool existing_file=false;
67
68 FILE * test=fopen(temp_name,"rb+");
69 if(test) {
70 fclose(test);
71 existing_file=true;
72
73 }
74
75 FILE * hand=fopen(temp_name,"wb+");
76 if (!hand){
77 LOG_MSG("Warning: file creation failed: %s",newname);
78 return false;
79 }
80
81 if(!existing_file) dirCache.AddEntry(newname, true);
82 /* Make the 16 bit device information */
83 *file=new localFile(name,hand);
84 (*file)->flags=OPEN_READWRITE;
85
86 return true;
87 }
88
FileOpen(DOS_File ** file,char * name,Bit32u flags)89 bool localDrive::FileOpen(DOS_File * * file,char * name,Bit32u flags) {
90 const char* type;
91 switch (flags&0xf) {
92 case OPEN_READ: type = "rb" ; break;
93 case OPEN_WRITE: type = "rb+"; break;
94 case OPEN_READWRITE: type = "rb+"; break;
95 case OPEN_READ_NO_MOD: type = "rb" ; break; //No modification of dates. LORD4.07 uses this
96 default:
97 DOS_SetError(DOSERR_ACCESS_CODE_INVALID);
98 return false;
99 }
100 char newname[CROSS_LEN];
101 strcpy(newname,basedir);
102 strcat(newname,name);
103 CROSS_FILENAME(newname);
104 dirCache.ExpandName(newname);
105
106 //Flush the buffer of handles for the same file. (Betrayal in Antara)
107 Bit8u i,drive=DOS_DRIVES;
108 localFile *lfp;
109 for (i=0;i<DOS_DRIVES;i++) {
110 if (Drives[i]==this) {
111 drive=i;
112 break;
113 }
114 }
115 for (i=0;i<DOS_FILES;i++) {
116 if (Files[i] && Files[i]->IsOpen() && Files[i]->GetDrive()==drive && Files[i]->IsName(name)) {
117 lfp=dynamic_cast<localFile*>(Files[i]);
118 if (lfp) lfp->Flush();
119 }
120 }
121
122 FILE * hand=fopen(newname,type);
123 // Bit32u err=errno;
124 if (!hand) {
125 if((flags&0xf) != OPEN_READ) {
126 FILE * hmm=fopen(newname,"rb");
127 if (hmm) {
128 fclose(hmm);
129 LOG_MSG("Warning: file %s exists and failed to open in write mode.\nPlease Remove write-protection",newname);
130 }
131 }
132 return false;
133 }
134
135 *file=new localFile(name,hand);
136 (*file)->flags=flags; //for the inheritance flag and maybe check for others.
137 // (*file)->SetFileName(newname);
138 return true;
139 }
140
GetSystemFilePtr(char const * const name,char const * const type)141 FILE * localDrive::GetSystemFilePtr(char const * const name, char const * const type) {
142
143 char newname[CROSS_LEN];
144 strcpy(newname,basedir);
145 strcat(newname,name);
146 CROSS_FILENAME(newname);
147 dirCache.ExpandName(newname);
148
149 return fopen(newname,type);
150 }
151
GetSystemFilename(char * sysName,char const * const dosName)152 bool localDrive::GetSystemFilename(char *sysName, char const * const dosName) {
153
154 strcpy(sysName, basedir);
155 strcat(sysName, dosName);
156 CROSS_FILENAME(sysName);
157 dirCache.ExpandName(sysName);
158 return true;
159 }
160
FileUnlink(char * name)161 bool localDrive::FileUnlink(char * name) {
162 char newname[CROSS_LEN];
163 strcpy(newname,basedir);
164 strcat(newname,name);
165 CROSS_FILENAME(newname);
166 char *fullname = dirCache.GetExpandName(newname);
167 if (unlink(fullname)) {
168 //Unlink failed for some reason try finding it.
169 struct stat buffer;
170 if(stat(fullname,&buffer)) return false; // File not found.
171
172 FILE* file_writable = fopen(fullname,"rb+");
173 if(!file_writable) return false; //No acces ? ERROR MESSAGE NOT SET. FIXME ?
174 fclose(file_writable);
175
176 //File exists and can technically be deleted, nevertheless it failed.
177 //This means that the file is probably open by some process.
178 //See if We have it open.
179 bool found_file = false;
180 for(Bitu i = 0;i < DOS_FILES;i++){
181 if(Files[i] && Files[i]->IsName(name)) {
182 Bitu max = DOS_FILES;
183 while(Files[i]->IsOpen() && max--) {
184 Files[i]->Close();
185 if (Files[i]->RemoveRef()<=0) break;
186 }
187 found_file=true;
188 }
189 }
190 if(!found_file) return false;
191 if (!unlink(fullname)) {
192 dirCache.DeleteEntry(newname);
193 return true;
194 }
195 return false;
196 } else {
197 dirCache.DeleteEntry(newname);
198 return true;
199 }
200 }
201
FindFirst(char * _dir,DOS_DTA & dta,bool fcb_findfirst)202 bool localDrive::FindFirst(char * _dir,DOS_DTA & dta,bool fcb_findfirst) {
203 char tempDir[CROSS_LEN];
204 strcpy(tempDir,basedir);
205 strcat(tempDir,_dir);
206 CROSS_FILENAME(tempDir);
207
208 for (unsigned int i=0;i<strlen(tempDir);i++) tempDir[i]=toupper(tempDir[i]);
209 if (allocation.mediaid==0xF0 ) {
210 EmptyCache(); //rescan floppie-content on each findfirst
211 }
212
213 char end[2]={CROSS_FILESPLIT,0};
214 if (tempDir[strlen(tempDir)-1]!=CROSS_FILESPLIT) strcat(tempDir,end);
215
216 Bit16u id;
217 if (!dirCache.FindFirst(tempDir,id)) {
218 DOS_SetError(DOSERR_PATH_NOT_FOUND);
219 return false;
220 }
221
222 strcpy(srchInfo[id].srch_dir,tempDir);
223 dta.SetDirID(id);
224
225 Bit8u sAttr;
226 dta.GetSearchParams(sAttr,tempDir,true);
227
228 if (this->isRemote() && this->isRemovable()) {
229 // cdroms behave a bit different than regular drives
230 if (sAttr == DOS_ATTR_VOLUME) {
231 dta.SetResult(dirCache.GetLabel(),dirCache.GetLabel(),0,0,0,DOS_ATTR_VOLUME);
232 return true;
233 }
234 } else {
235 if (sAttr == DOS_ATTR_VOLUME) {
236 if ( strcmp(dirCache.GetLabel(), "") == 0 ) {
237 // LOG(LOG_DOSMISC,LOG_ERROR)("DRIVELABEL REQUESTED: none present, returned NOLABEL");
238 // dta.SetResult("NO_LABEL",0,0,0,DOS_ATTR_VOLUME);
239 // return true;
240 DOS_SetError(DOSERR_NO_MORE_FILES);
241 return false;
242 }
243 dta.SetResult(dirCache.GetLabel(),dirCache.GetLabel(),0,0,0,DOS_ATTR_VOLUME);
244 return true;
245 } else if ((sAttr & DOS_ATTR_VOLUME) && (*_dir == 0) && !fcb_findfirst) {
246 //should check for a valid leading directory instead of 0
247 //exists==true if the volume label matches the searchmask and the path is valid
248 if (WildFileCmp(dirCache.GetLabel(),tempDir)) {
249 dta.SetResult(dirCache.GetLabel(),dirCache.GetLabel(),0,0,0,DOS_ATTR_VOLUME);
250 return true;
251 }
252 }
253 }
254 return FindNext(dta);
255 }
256
FindNext(DOS_DTA & dta)257 bool localDrive::FindNext(DOS_DTA & dta) {
258
259 char *dir_ent, *ldir_ent;
260 struct stat stat_block;
261 char full_name[CROSS_LEN];
262 char dir_entcopy[CROSS_LEN], ldir_entcopy[CROSS_LEN];
263
264 Bit8u srch_attr;char srch_pattern[LFN_NAMELENGTH+1];
265 Bit8u find_attr;
266
267 dta.GetSearchParams(srch_attr,srch_pattern,true);
268 Bit16u id = dta.GetDirID();
269
270 again:
271 if (!dirCache.FindNext(id,dir_ent,ldir_ent)) {
272 DOS_SetError(DOSERR_NO_MORE_FILES);
273 return false;
274 }
275 if(!WildFileCmp(dir_ent,srch_pattern)&&!LWildFileCmp(ldir_ent,srch_pattern)) goto again;
276
277 strcpy(full_name,srchInfo[id].srch_dir);
278 strcat(full_name,dir_ent);
279
280 //GetExpandName might indirectly destroy dir_ent (by caching in a new directory
281 //and due to its design dir_ent might be lost.)
282 //Copying dir_ent first
283 strcpy(dir_entcopy,dir_ent);
284 strcpy(ldir_entcopy,ldir_ent);
285 if (stat(dirCache.GetExpandName(full_name),&stat_block)!=0) {
286 goto again;//No symlinks and such
287 }
288
289 if(stat_block.st_mode & S_IFDIR) find_attr=DOS_ATTR_DIRECTORY;
290 else find_attr=DOS_ATTR_ARCHIVE;
291 if (~srch_attr & find_attr & (DOS_ATTR_DIRECTORY | DOS_ATTR_HIDDEN | DOS_ATTR_SYSTEM)) goto again;
292
293 /*file is okay, setup everything to be copied in DTA Block */
294 char find_name[DOS_NAMELENGTH_ASCII], *lfind_name=ldir_ent;
295 Bit16u find_date,find_time;Bit32u find_size;
296
297 if(strlen(dir_entcopy)<DOS_NAMELENGTH_ASCII){
298 strcpy(find_name,dir_entcopy);
299 upcase(find_name);
300 }
301 lfind_name[LFN_NAMELENGTH]=0;
302
303 find_size=(Bit32u) stat_block.st_size;
304 struct tm *time;
305 if((time=localtime((const time_t*)&stat_block.st_mtime))!=0){
306 find_date=DOS_PackDate((Bit16u)(time->tm_year+1900),(Bit16u)(time->tm_mon+1),(Bit16u)time->tm_mday);
307 find_time=DOS_PackTime((Bit16u)time->tm_hour,(Bit16u)time->tm_min,(Bit16u)time->tm_sec);
308 } else {
309 find_time=6;
310 find_date=4;
311 }
312 dta.SetResult(find_name,lfind_name,find_size,find_date,find_time,find_attr);
313 return true;
314 }
315
GetFileAttr(char * name,Bit16u * attr)316 bool localDrive::GetFileAttr(char * name,Bit16u * attr) {
317 char newname[CROSS_LEN];
318 strcpy(newname,basedir);
319 strcat(newname,name);
320 CROSS_FILENAME(newname);
321 dirCache.ExpandName(newname);
322
323 struct stat status;
324 if (stat(newname,&status)==0) {
325 *attr=DOS_ATTR_ARCHIVE;
326 if(status.st_mode & S_IFDIR) *attr|=DOS_ATTR_DIRECTORY;
327 return true;
328 }
329 *attr=0;
330 return false;
331 }
332
GetFileAttrEx(char * name,struct stat * status)333 bool localDrive::GetFileAttrEx(char* name, struct stat *status) {
334 char newname[CROSS_LEN];
335 strcpy(newname,basedir);
336 strcat(newname,name);
337 CROSS_FILENAME(newname);
338 dirCache.ExpandName(newname);
339 return !stat(newname,status);
340 }
341
GetCompressedSize(char * name)342 Bit32u localDrive::GetCompressedSize(char* name)
343 {
344 //win32 is not special
345 return 0;
346 /*
347 #if !defined (WIN32)
348 return 0;
349 #else
350 char newname[CROSS_LEN];
351 strcpy(newname,basedir);
352 strcat(newname,name);
353 CROSS_FILENAME(newname);
354 dirCache.ExpandName(newname);
355 Bit32u size = GetCompressedFileSize(newname, NULL);
356 if (size != INVALID_FILE_SIZE) {
357 if (size != 0 && size == GetFileSize(newname, NULL)) {
358 Bit32u sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters;
359 if (GetDiskFreeSpace(newname, §ors_per_cluster, &bytes_per_sector, &free_clusters, &total_clusters)) {
360 size = ((size - 1) | (sectors_per_cluster * bytes_per_sector - 1)) + 1;
361 }
362 }
363 return size;
364 } else {
365 DOS_SetError((Bit16u)GetLastError());
366 return -1;
367 }
368 #endif
369 */
370 }
371
CreateOpenFile(const char * name)372 void* localDrive::CreateOpenFile(const char* name)
373 {
374 char newname[CROSS_LEN];
375 strcpy(newname,basedir);
376 strcat(newname,name);
377 CROSS_FILENAME(newname);
378 dirCache.ExpandName(newname);
379 //win32 is not special
380 return NULL;
381 /*
382 #if defined (WIN32)
383 HANDLE handle=CreateFile(newname, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
384 if (handle==INVALID_HANDLE_VALUE)
385 DOS_SetError((Bit16u)GetLastError());
386 return handle;
387 #else
388 return NULL;
389 #endif
390 */
391 }
392
MakeDir(char * dir)393 bool localDrive::MakeDir(char * dir) {
394 char newdir[CROSS_LEN];
395 strcpy(newdir,basedir);
396 strcat(newdir,dir);
397 CROSS_FILENAME(newdir);
398 #if defined (WIN32) /* MS Visual C++ */
399 int temp=mkdir(dirCache.GetExpandName(newdir));
400 #elif defined(VITA)
401 int temp=sceIoMkdir(dirCache.GetExpandName(newdir), 0777);
402 #else
403 int temp=mkdir(dirCache.GetExpandName(newdir),0700);
404 #endif
405 if (temp==0) dirCache.CacheOut(newdir,true);
406
407 return (temp==0);// || ((temp!=0) && (errno==EEXIST));
408 }
409
RemoveDir(char * dir)410 bool localDrive::RemoveDir(char * dir) {
411 char newdir[CROSS_LEN];
412 strcpy(newdir,basedir);
413 strcat(newdir,dir);
414 CROSS_FILENAME(newdir);
415 #if defined (VITA)
416 int temp=sceIoRmdir(dirCache.GetExpandName(newdir));
417 #else
418 int temp=rmdir(dirCache.GetExpandName(newdir));
419 #endif
420 if (temp==0) dirCache.DeleteEntry(newdir,true);
421 return (temp==0);
422 }
423
424 #ifdef WII
access(const char * file,int type)425 int access (const char *file, int type)
426 {
427 struct stat stbuf;
428 gid_t gid;
429 uid_t uid;
430
431 if (file == NULL || (type & ~(R_OK|W_OK|X_OK|F_OK)) != 0) {
432 errno = EINVAL;
433 return -1;
434 }
435 if(stat(file, &stbuf) == -1)
436 return -1;
437
438 // No getgid() and getuid()? Well, we are God!
439
440 // gid = getgid();
441 // uid = getuid();
442 uid = stbuf.st_uid;
443 gid = stbuf.st_gid;
444
445 if(uid == stbuf.st_uid) {
446 if( ((type & R_OK) && !(stbuf.st_mode & S_IRUSR) ) ||
447 ((type & W_OK) && !(stbuf.st_mode & S_IWUSR) ) ||
448 ((type & X_OK) && !(stbuf.st_mode & S_IXUSR) ) ) {
449 errno = EACCES;
450 return -1;
451 }
452 }
453 else if(gid == stbuf.st_gid) {
454 if( ((type & R_OK) && !(stbuf.st_mode & S_IRGRP) ) ||
455 ((type & W_OK) && !(stbuf.st_mode & S_IWGRP) ) ||
456 ((type & X_OK) && !(stbuf.st_mode & S_IXGRP) ) ) {
457 errno = EACCES;
458 return -1;
459 }
460 }
461 else {
462 if( ((type & R_OK) && !(stbuf.st_mode & S_IROTH) ) ||
463 ((type & W_OK) && !(stbuf.st_mode & S_IWOTH) ) ||
464 ((type & X_OK) && !(stbuf.st_mode & S_IXOTH) ) ) {
465 errno = EACCES;
466 return -1;
467 }
468 }
469
470 return 0;
471
472 }
473 #endif
474
TestDir(char * dir)475 bool localDrive::TestDir(char * dir) {
476 char newdir[CROSS_LEN];
477 strcpy(newdir,basedir);
478 strcat(newdir,dir);
479 CROSS_FILENAME(newdir);
480 dirCache.ExpandName(newdir);
481 // Skip directory test, if "\"
482 size_t len = strlen(newdir);
483 if (len && (newdir[len-1]!='\\')) {
484 // It has to be a directory !
485 struct stat test;
486 if (stat(newdir,&test)) return false;
487 if ((test.st_mode & S_IFDIR)==0) return false;
488 };
489 int temp=access(newdir,F_OK);
490 return (temp==0);
491 }
492
Rename(char * oldname,char * newname)493 bool localDrive::Rename(char * oldname,char * newname) {
494 char newold[CROSS_LEN];
495 strcpy(newold,basedir);
496 strcat(newold,oldname);
497 CROSS_FILENAME(newold);
498 dirCache.ExpandName(newold);
499
500 char newnew[CROSS_LEN];
501 strcpy(newnew,basedir);
502 strcat(newnew,newname);
503 CROSS_FILENAME(newnew);
504 #ifdef VITA
505 int temp=sceIoRename(newold,dirCache.GetExpandName(newnew));
506 #else
507 int temp=rename(newold,dirCache.GetExpandName(newnew));
508 #endif
509 if (temp==0) dirCache.CacheOut(newnew);
510 return (temp==0);
511
512 }
513
AllocationInfo(Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters)514 bool localDrive::AllocationInfo(Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters) {
515 *_bytes_sector=allocation.bytes_sector;
516 *_sectors_cluster=allocation.sectors_cluster;
517 *_total_clusters=allocation.total_clusters;
518 *_free_clusters=allocation.free_clusters;
519 return true;
520 }
521
FileExists(const char * name)522 bool localDrive::FileExists(const char* name) {
523 char newname[CROSS_LEN];
524 strcpy(newname,basedir);
525 strcat(newname,name);
526 CROSS_FILENAME(newname);
527 dirCache.ExpandName(newname);
528 struct stat temp_stat;
529 if(stat(newname,&temp_stat)!=0) return false;
530 if(temp_stat.st_mode & S_IFDIR) return false;
531 return true;
532 }
533
FileStat(const char * name,FileStat_Block * const stat_block)534 bool localDrive::FileStat(const char* name, FileStat_Block * const stat_block) {
535 char newname[CROSS_LEN];
536 strcpy(newname,basedir);
537 strcat(newname,name);
538 CROSS_FILENAME(newname);
539 dirCache.ExpandName(newname);
540 struct stat temp_stat;
541 if(stat(newname,&temp_stat)!=0) return false;
542 /* Convert the stat to a FileStat */
543 struct tm *time;
544 if((time=localtime((const time_t*)&temp_stat.st_mtime))!=0) {
545 stat_block->time=DOS_PackTime((Bit16u)time->tm_hour,(Bit16u)time->tm_min,(Bit16u)time->tm_sec);
546 stat_block->date=DOS_PackDate((Bit16u)(time->tm_year+1900),(Bit16u)(time->tm_mon+1),(Bit16u)time->tm_mday);
547 } else {
548
549 }
550 stat_block->size=(Bit32u)temp_stat.st_size;
551 return true;
552 }
553
554
GetMediaByte(void)555 Bit8u localDrive::GetMediaByte(void) {
556 return allocation.mediaid;
557 }
558
isRemote(void)559 bool localDrive::isRemote(void) {
560 return false;
561 }
562
isRemovable(void)563 bool localDrive::isRemovable(void) {
564 return false;
565 }
566
UnMount(void)567 Bits localDrive::UnMount(void) {
568 delete this;
569 return 0;
570 }
571
localDrive(const char * startdir,Bit16u _bytes_sector,Bit8u _sectors_cluster,Bit16u _total_clusters,Bit16u _free_clusters,Bit8u _mediaid)572 localDrive::localDrive(const char * startdir,Bit16u _bytes_sector,Bit8u _sectors_cluster,Bit16u _total_clusters,Bit16u _free_clusters,Bit8u _mediaid) {
573 strcpy(basedir,startdir);
574 sprintf(info,"local directory %s",startdir);
575 allocation.bytes_sector=_bytes_sector;
576 allocation.sectors_cluster=_sectors_cluster;
577 allocation.total_clusters=_total_clusters;
578 allocation.free_clusters=_free_clusters;
579 allocation.mediaid=_mediaid;
580
581 dirCache.SetBaseDir(basedir);
582 }
583
584
585 //TODO Maybe use fflush, but that seemed to fuck up in visual c
Read(Bit8u * data,Bit16u * size)586 bool localFile::Read(Bit8u * data,Bit16u * size) {
587 if ((this->flags & 0xf) == OPEN_WRITE) { // check if file opened in write-only mode
588 DOS_SetError(DOSERR_ACCESS_DENIED);
589 return false;
590 }
591 if (last_action==WRITE) fseek(fhandle,ftell(fhandle),SEEK_SET);
592 last_action=READ;
593 *size=(Bit16u)fread(data,1,*size,fhandle);
594 /* Fake harddrive motion. Inspector Gadget with soundblaster compatible */
595 /* Same for Igor */
596 /* hardrive motion => unmask irq 2. Only do it when it's masked as unmasking is realitively heavy to emulate */
597 Bit8u mask = IO_Read(0x21);
598 if(mask & 0x4 ) IO_Write(0x21,mask&0xfb);
599 return true;
600 }
601
Write(Bit8u * data,Bit16u * size)602 bool localFile::Write(Bit8u * data,Bit16u * size) {
603 if ((this->flags & 0xf) == OPEN_READ) { // check if file opened in read-only mode
604 DOS_SetError(DOSERR_ACCESS_DENIED);
605 return false;
606 }
607 if (last_action==READ) fseek(fhandle,ftell(fhandle),SEEK_SET);
608 last_action=WRITE;
609 if(*size==0){
610 #ifdef VITA
611 return true;
612 #else
613 return (!ftruncate(fileno(fhandle),ftell(fhandle)));
614 #endif
615 }
616 else
617 {
618 *size=(Bit16u)fwrite(data,1,*size,fhandle);
619 return true;
620 }
621 }
622
Seek(Bit32u * pos,Bit32u type)623 bool localFile::Seek(Bit32u * pos,Bit32u type) {
624 int seektype;
625 switch (type) {
626 case DOS_SEEK_SET:seektype=SEEK_SET;break;
627 case DOS_SEEK_CUR:seektype=SEEK_CUR;break;
628 case DOS_SEEK_END:seektype=SEEK_END;break;
629 default:
630 //TODO Give some doserrorcode;
631 return false;//ERROR
632 }
633 int ret=fseek(fhandle,*reinterpret_cast<Bit32s*>(pos),seektype);
634 if (ret!=0) {
635 // Out of file range, pretend everythings ok
636 // and move file pointer top end of file... ?! (Black Thorne)
637 fseek(fhandle,0,SEEK_END);
638 };
639 #if 0
640 fpos_t temppos;
641 fgetpos(fhandle,&temppos);
642 Bit32u * fake_pos=(Bit32u*)&temppos;
643 *pos=*fake_pos;
644 #endif
645 *pos=(Bit32u)ftell(fhandle);
646 last_action=NONE;
647 return true;
648 }
649
Close()650 bool localFile::Close() {
651 // only close if one reference left
652 if (refCtr==1) {
653 if(fhandle) fclose(fhandle);
654 fhandle = 0;
655 open = false;
656 };
657 return true;
658 }
659
GetInformation(void)660 Bit16u localFile::GetInformation(void) {
661 return read_only_medium?0x40:0;
662 }
663
664
localFile(const char * _name,FILE * handle)665 localFile::localFile(const char* _name, FILE * handle) {
666 fhandle=handle;
667 open=true;
668 UpdateDateTimeFromHost();
669
670 attr=DOS_ATTR_ARCHIVE;
671 last_action=NONE;
672 read_only_medium=false;
673
674 name=0;
675 SetName(_name);
676 }
677
FlagReadOnlyMedium(void)678 void localFile::FlagReadOnlyMedium(void) {
679 read_only_medium = true;
680 }
681
UpdateDateTimeFromHost(void)682 bool localFile::UpdateDateTimeFromHost(void) {
683 if(!open) return false;
684 struct stat temp_stat;
685 fstat(fileno(fhandle),&temp_stat);
686 struct tm * ltime;
687 if((ltime=localtime((const time_t*)&temp_stat.st_mtime))!=0) {
688 time=DOS_PackTime((Bit16u)ltime->tm_hour,(Bit16u)ltime->tm_min,(Bit16u)ltime->tm_sec);
689 date=DOS_PackDate((Bit16u)(ltime->tm_year+1900),(Bit16u)(ltime->tm_mon+1),(Bit16u)ltime->tm_mday);
690 } else {
691 time=1;date=1;
692 }
693 return true;
694 }
695
Flush(void)696 void localFile::Flush(void) {
697 if (last_action==WRITE) {
698 fseek(fhandle,ftell(fhandle),SEEK_SET);
699 last_action=NONE;
700 }
701 }
702
703
704 // ********************************************
705 // CDROM DRIVE
706 // ********************************************
707
708 int MSCDEX_RemoveDrive(char driveLetter);
709 int MSCDEX_AddDrive(char driveLetter, const char* physicalPath, Bit8u& subUnit);
710 bool MSCDEX_HasMediaChanged(Bit8u subUnit);
711 bool MSCDEX_GetVolumeName(Bit8u subUnit, char* name);
712
713
cdromDrive(const char driveLetter,const char * startdir,Bit16u _bytes_sector,Bit8u _sectors_cluster,Bit16u _total_clusters,Bit16u _free_clusters,Bit8u _mediaid,int & error)714 cdromDrive::cdromDrive(const char driveLetter, const char * startdir,Bit16u _bytes_sector,Bit8u _sectors_cluster,Bit16u _total_clusters,Bit16u _free_clusters,Bit8u _mediaid, int& error)
715 :localDrive(startdir,_bytes_sector,_sectors_cluster,_total_clusters,_free_clusters,_mediaid) {
716 // Init mscdex
717 error = MSCDEX_AddDrive(driveLetter,startdir,subUnit);
718 strcpy(info, "CDRom ");
719 strcat(info, startdir);
720 this->driveLetter = driveLetter;
721 // Get Volume Label
722 char name[32];
723 if (MSCDEX_GetVolumeName(subUnit,name)) dirCache.SetLabel(name,true,true);
724 }
725
FileOpen(DOS_File ** file,char * name,Bit32u flags)726 bool cdromDrive::FileOpen(DOS_File * * file,char * name,Bit32u flags) {
727 if ((flags&0xf)==OPEN_READWRITE) {
728 flags &= ~OPEN_READWRITE;
729 } else if ((flags&0xf)==OPEN_WRITE) {
730 DOS_SetError(DOSERR_ACCESS_DENIED);
731 return false;
732 }
733 bool retcode = localDrive::FileOpen(file,name,flags);
734 if(retcode) (dynamic_cast<localFile*>(*file))->FlagReadOnlyMedium();
735 return retcode;
736 }
737
FileCreate(DOS_File **,char *,Bit16u)738 bool cdromDrive::FileCreate(DOS_File * * /*file*/,char * /*name*/,Bit16u /*attributes*/) {
739 DOS_SetError(DOSERR_ACCESS_DENIED);
740 return false;
741 }
742
FileUnlink(char *)743 bool cdromDrive::FileUnlink(char * /*name*/) {
744 DOS_SetError(DOSERR_ACCESS_DENIED);
745 return false;
746 }
747
RemoveDir(char *)748 bool cdromDrive::RemoveDir(char * /*dir*/) {
749 DOS_SetError(DOSERR_ACCESS_DENIED);
750 return false;
751 }
752
MakeDir(char *)753 bool cdromDrive::MakeDir(char * /*dir*/) {
754 DOS_SetError(DOSERR_ACCESS_DENIED);
755 return false;
756 }
757
Rename(char *,char *)758 bool cdromDrive::Rename(char * /*oldname*/,char * /*newname*/) {
759 DOS_SetError(DOSERR_ACCESS_DENIED);
760 return false;
761 }
762
GetFileAttr(char * name,Bit16u * attr)763 bool cdromDrive::GetFileAttr(char * name,Bit16u * attr) {
764 bool result = localDrive::GetFileAttr(name,attr);
765 if (result) *attr |= DOS_ATTR_READ_ONLY;
766 return result;
767 }
768
GetFileAttrEx(char * name,struct stat * status)769 bool cdromDrive::GetFileAttrEx(char* name, struct stat *status) {
770 return localDrive::GetFileAttrEx(name,status);
771 }
772
GetCompressedSize(char * name)773 Bit32u cdromDrive::GetCompressedSize(char* name) {
774 return localDrive::GetCompressedSize(name);
775 }
776
CreateOpenFile(const char * name)777 void* cdromDrive::CreateOpenFile(const char* name) {
778 return localDrive::CreateOpenFile(name);
779 }
780
FindFirst(char * _dir,DOS_DTA & dta,bool)781 bool cdromDrive::FindFirst(char * _dir,DOS_DTA & dta,bool /*fcb_findfirst*/) {
782 // If media has changed, reInit drivecache.
783 if (MSCDEX_HasMediaChanged(subUnit)) {
784 dirCache.EmptyCache();
785 // Get Volume Label
786 char name[32];
787 if (MSCDEX_GetVolumeName(subUnit,name)) dirCache.SetLabel(name,true,true);
788 }
789 return localDrive::FindFirst(_dir,dta);
790 }
791
SetDir(const char * path)792 void cdromDrive::SetDir(const char* path) {
793 // If media has changed, reInit drivecache.
794 if (MSCDEX_HasMediaChanged(subUnit)) {
795 dirCache.EmptyCache();
796 // Get Volume Label
797 char name[32];
798 if (MSCDEX_GetVolumeName(subUnit,name)) dirCache.SetLabel(name,true,true);
799 }
800 localDrive::SetDir(path);
801 }
802
isRemote(void)803 bool cdromDrive::isRemote(void) {
804 return true;
805 }
806
isRemovable(void)807 bool cdromDrive::isRemovable(void) {
808 return true;
809 }
810
UnMount(void)811 Bits cdromDrive::UnMount(void) {
812 if(MSCDEX_RemoveDrive(driveLetter)) {
813 delete this;
814 return 0;
815 }
816 return 2;
817 }
818