3 * NOV 1993 Erik Bos <erik@xs4all.nl>
5 * FindFile by Bob, hacked for dos & unixpaths by Erik.
7 * Bugfix by dash@ifi.uio.no: ToUnix() was called to often
20 #if defined(__linux__) || defined(sun)
23 #if defined(__NetBSD__) || defined(__FreeBSD__)
24 #include <sys/param.h>
25 #include <sys/mount.h>
38 #define WINE_INI_USER "~/.winerc"
39 #define MAX_DOS_DRIVES 26
41 extern char WindowsDirectory
[256], SystemDirectory
[256],TempDirectory
[256];
43 char WindowsPath
[256];
45 static int max_open_dirs
= 0;
46 static int CurrentDrive
= 2;
48 struct DosDriveStruct
{ /* eg: */
49 char *rootdir
; /* /usr/windows */
50 char cwd
[256]; /* / */
51 char label
[13]; /* DRIVE-A */
52 unsigned int serialnumber
; /* ABCD5678 */
56 static struct DosDriveStruct DosDrives
[MAX_DOS_DRIVES
];
57 static struct dosdirent
*DosDirs
=NULL
;
59 static void ExpandTildeString(char *s
)
62 char temp
[1024], *ptr
= temp
;
76 if ( (entry
= getpwuid(getuid())) == NULL
)
81 strcpy(s
, entry
->pw_dir
);
82 s
+= strlen(entry
->pw_dir
);
87 /* Simplify the path in "name" by removing "//"'s and
88 ".."'s in names like "/usr/bin/../lib/test" */
89 static void DOS_SimplifyPath(char *name
)
94 dprintf_dosfs(stddeb
,"SimplifyPath: Before %s\n",name
);
97 while ((l
= strstr(name
,"//"))) {
98 strcpy(l
,l
+1); changed
= TRUE
;
100 while ((l
= strstr(name
,"/../"))) {
102 p
= strrchr(name
,'/');
103 if (p
== NULL
) p
= name
;
108 dprintf_dosfs(stddeb
,"SimplifyPath: After %s\n",name
);
112 /* ChopOffSlash takes care to strip directory slashes from the
113 * end off the path name, but leaves a single slash. Multiple
114 * slashes at the end of a path are all removed.
117 void ChopOffSlash(char *path
)
119 char *p
= path
+ strlen(path
) - 1;
120 while ((*p
== '\\') && (p
> path
)) *p
-- = '\0';
126 if (*s
== '\\') *s
= '/';
127 *s
=tolower(*s
); /* umsdos fs can't read files without :( */
135 if (*s
== '/') *s
= '\\';
140 void DOS_InitFS(void)
143 char drive
[2], temp
[256];
145 GetPrivateProfileString("wine", "windows", "c:\\windows",
146 WindowsDirectory
, sizeof(WindowsDirectory
), WINE_INI
);
148 GetPrivateProfileString("wine", "system", "c:\\windows\\system",
149 SystemDirectory
, sizeof(SystemDirectory
), WINE_INI
);
151 GetPrivateProfileString("wine", "temp", "c:\\windows",
152 TempDirectory
, sizeof(TempDirectory
), WINE_INI
);
154 GetPrivateProfileString("wine", "path", "c:\\windows;c:\\windows\\system",
155 WindowsPath
, sizeof(WindowsPath
), WINE_INI
);
157 ChopOffSlash(WindowsDirectory
);
158 ToDos(WindowsDirectory
);
160 ChopOffSlash(SystemDirectory
);
161 ToDos(SystemDirectory
);
163 ChopOffSlash(TempDirectory
);
164 ToDos(TempDirectory
);
167 ExpandTildeString(WindowsPath
);
169 for (x
=0; x
!=MAX_DOS_DRIVES
; x
++) {
170 DosDrives
[x
].serialnumber
= (0xEB0500L
| x
);
174 GetPrivateProfileString("drives", drive
, "*", temp
, sizeof(temp
), WINE_INI
);
175 if (!strcmp(temp
, "*") || *temp
== '\0') {
176 DosDrives
[x
].rootdir
= NULL
;
177 DosDrives
[x
].cwd
[0] = '\0';
178 DosDrives
[x
].label
[0] = '\0';
179 DosDrives
[x
].disabled
= 1;
182 ExpandTildeString(temp
);
184 DosDrives
[x
].rootdir
= strdup(temp
);
185 strcpy(DosDrives
[x
].rootdir
, temp
);
186 strcpy(DosDrives
[x
].cwd
, "/windows/");
187 strcpy(DosDrives
[x
].label
, "DRIVE-");
188 strcat(DosDrives
[x
].label
, drive
);
189 DosDrives
[x
].disabled
= 0;
191 DosDrives
[25].rootdir
= "/";
192 strcpy(DosDrives
[25].label
, "UNIX-FS");
193 DosDrives
[25].serialnumber
= 0x12345678;
194 DosDrives
[25].disabled
= 0;
196 /* Get the startup directory and try to map it to a DOS drive
197 * and directory. (i.e., if we start in /dos/windows/word and
198 * drive C is defined as /dos, the starting wd for C will be
199 * /windows/word) Also set the default drive to whatever drive
200 * corresponds to the directory we started in.
203 for (x
=0; x
!=MAX_DOS_DRIVES
; x
++)
204 if (DosDrives
[x
].rootdir
!= NULL
)
205 strcpy( DosDrives
[x
].cwd
, "/" );
208 strcat(temp
, "/"); /* For DOS_GetDosFileName */
209 strcpy(DosDrives
[25].cwd
, temp
);
210 strcpy(temp
, DOS_GetDosFileName(temp
));
214 strcpy(DosDrives
[temp
[0] - 'A'].cwd
, &temp
[2]);
215 DOS_SetDefaultDrive(temp
[0] - 'A');
219 DOS_SetDefaultDrive(2);
222 for (x
=0; x
!=MAX_DOS_DRIVES
; x
++) {
223 if (DosDrives
[x
].rootdir
!= NULL
) {
224 dprintf_dosfs(stddeb
, "DOSFS: %c: => %-40s %s %s %X %d\n",
226 DosDrives
[x
].rootdir
,
229 DosDrives
[x
].serialnumber
,
230 DosDrives
[x
].disabled
);
234 for (x
=0; x
!=max_open_dirs
; x
++)
235 DosDirs
[x
].inuse
= 0;
237 dprintf_dosfs(stddeb
,"wine.ini = %s\n",WINE_INI
);
238 dprintf_dosfs(stddeb
,"win.ini = %s\n",WIN_INI
);
239 dprintf_dosfs(stddeb
,"windir = %s\n",WindowsDirectory
);
240 dprintf_dosfs(stddeb
,"sysdir = %s\n",SystemDirectory
);
241 dprintf_dosfs(stddeb
,"tempdir = %s\n",TempDirectory
);
242 dprintf_dosfs(stddeb
,"path = %s\n",WindowsPath
);
245 WORD
DOS_GetEquipment(void)
249 int parallelports
= 0;
253 /* borrowed from Ralph Brown's interrupt lists
255 bits 15-14: number of parallel devices
256 bit 13: [Conv] Internal modem
258 bits 11- 9: number of serial devices
260 bits 7- 6: number of diskette drives minus one
261 bits 5- 4: Initial video mode:
267 bit 2: [PS] =1 if pointing device
269 bit 1: =1 if math co-processor
270 bit 0: =1 if diskette available for boot
272 /* Currently the only of these bits correctly set are:
273 bits 15-14 } Added by William Owen Smith,
274 bits 11-9 } wos@dcs.warwick.ac.uk
279 if (DosDrives
[0].rootdir
!= NULL
)
281 if (DosDrives
[1].rootdir
!= NULL
)
286 for (x
=0; x
!=MAX_PORTS
; x
++) {
287 if (COM
[x
].devicename
)
289 if (LPT
[x
].devicename
)
292 if (serialports
> 7) /* 3 bits -- maximum value = 7 */
294 if (parallelports
> 3) /* 2 bits -- maximum value = 3 */
297 equipment
= (diskdrives
<< 6) | (serialports
<< 9) |
298 (parallelports
<< 14) | 0x02;
300 dprintf_dosfs(stddeb
, "DOS_GetEquipment : diskdrives = %d serialports = %d "
301 "parallelports = %d\n"
302 "DOS_GetEquipment : equipment = %d\n",
303 diskdrives
, serialports
, parallelports
, equipment
);
308 int DOS_ValidDrive(int drive
)
310 dprintf_dosfs(stddeb
,"ValidDrive %c (%d)\n",'A'+drive
,drive
);
312 if (drive
< 0 || drive
>= MAX_DOS_DRIVES
) return 0;
313 if (DosDrives
[drive
].rootdir
== NULL
) return 0;
314 if (DosDrives
[drive
].disabled
) return 0;
316 dprintf_dosfs(stddeb
, " -- valid\n");
320 static void DOS_GetCurrDir_Unix(char *buffer
, int drive
)
322 TDB
*pTask
= (TDB
*)GlobalLock(GetCurrentTask());
324 if (pTask
!= NULL
&& (pTask
->curdrive
& ~0x80) == drive
) {
325 strcpy(buffer
, pTask
->curdir
);
328 strcpy(buffer
, DosDrives
[drive
].cwd
);
332 char *DOS_GetCurrentDir(int drive
)
334 static char temp
[256];
336 if (!DOS_ValidDrive(drive
)) return 0;
338 DOS_GetCurrDir_Unix(temp
, drive
);
339 DOS_SimplifyPath( temp
);
343 dprintf_dosfs(stddeb
,"DOS_GetCWD: %c:%s\n", 'A'+drive
, temp
);
347 char *DOS_GetUnixFileName(const char *dosfilename
)
349 /* a:\windows\system.ini => /dos/windows/system.ini */
351 /* FIXME: should handle devices here (like LPT: or NUL:) */
353 static char dostemp
[256], temp
[256];
354 int drive
= DOS_GetDefaultDrive();
356 if (dosfilename
[0] && dosfilename
[1] == ':')
358 drive
= toupper(*dosfilename
) - 'A';
361 if (!DOS_ValidDrive(drive
)) return NULL
;
363 strncpy( dostemp
, dosfilename
, 255 );
366 strcpy(temp
, DosDrives
[drive
].rootdir
);
367 if (dostemp
[0] != '/') {
368 DOS_GetCurrDir_Unix(temp
+strlen(temp
), drive
);
370 strcat(temp
, dostemp
);
371 DOS_SimplifyPath(temp
);
373 dprintf_dosfs(stddeb
,"GetUnixFileName: %s => %s\n", dosfilename
, temp
);
377 /* Note: This function works on directories as well as long as
378 * the directory ends in a slash.
380 char *DOS_GetDosFileName(char *unixfilename
)
383 static char temp
[256], temp2
[256];
384 /* /dos/windows/system.ini => c:\windows\system.ini */
386 dprintf_dosfs(stddeb
,"DOS_GetDosFileName: %s\n", unixfilename
);
387 if (unixfilename
[0] == '/') {
388 strncpy(temp
, unixfilename
, 255);
391 /* Expand it if it's a relative name. */
393 if(strncmp(unixfilename
, "./", 2) != 0) {
394 strcat(temp
, unixfilename
+ 1);
397 strcat(temp
, unixfilename
);
400 for (i
= 0 ; i
< MAX_DOS_DRIVES
; i
++) {
401 if (DosDrives
[i
].rootdir
!= NULL
) {
402 int len
= strlen(DosDrives
[i
].rootdir
);
403 dprintf_dosfs(stddeb
, " check %c:%s\n", i
+'A', DosDrives
[i
].rootdir
);
404 if (strncmp(DosDrives
[i
].rootdir
, temp
, len
) == 0 && temp
[len
] == '/')
406 sprintf(temp2
, "%c:%s", 'A' + i
, temp
+len
);
412 sprintf(temp
, "Z:%s", unixfilename
);
417 int DOS_ValidDirectory(int drive
, char *name
)
422 strcpy(temp
, DosDrives
[drive
].rootdir
);
424 if (stat(temp
, &s
)) return 0;
425 if (!S_ISDIR(s
.st_mode
)) return 0;
426 dprintf_dosfs(stddeb
, "==> OK\n");
430 int DOS_GetDefaultDrive(void)
432 TDB
*pTask
= (TDB
*)GlobalLock(GetCurrentTask());
433 int drive
= pTask
== NULL
? CurrentDrive
: pTask
->curdrive
& ~0x80;
435 dprintf_dosfs(stddeb
,"GetDefaultDrive (%c)\n",'A'+drive
);
439 void DOS_SetDefaultDrive(int drive
)
441 TDB
*pTask
= (TDB
*)GlobalLock(GetCurrentTask());
443 dprintf_dosfs(stddeb
,"SetDefaultDrive to %c:\n",'A'+drive
);
444 if (DOS_ValidDrive(drive
) && drive
!= DOS_GetDefaultDrive()) {
445 if (pTask
== NULL
) CurrentDrive
= drive
;
448 pTask
->curdrive
= drive
| 0x80;
449 strcpy(temp
, DosDrives
[drive
].rootdir
);
450 strcat(temp
, DosDrives
[drive
].cwd
);
451 strcpy(temp
, DOS_GetDosFileName(temp
));
452 dprintf_dosfs(stddeb
, " curdir = %s\n", temp
);
453 if (strlen(temp
)-2 < sizeof(pTask
->curdir
)) strcpy(pTask
->curdir
, temp
+2);
454 else fprintf(stderr
, "dosfs: curdir too long\n");
459 int DOS_DisableDrive(int drive
)
461 if (drive
>= MAX_DOS_DRIVES
) return 0;
462 if (DosDrives
[drive
].rootdir
== NULL
) return 0;
464 DosDrives
[drive
].disabled
= 1;
468 int DOS_EnableDrive(int drive
)
470 if (drive
>= MAX_DOS_DRIVES
) return 0;
471 if (DosDrives
[drive
].rootdir
== NULL
) return 0;
473 DosDrives
[drive
].disabled
= 0;
477 int DOS_ChangeDir(int drive
, char *dirname
)
479 TDB
*pTask
= (TDB
*)GlobalLock(GetCurrentTask());
482 if (!DOS_ValidDrive(drive
)) return 0;
484 if (dirname
[0] == '\\') {
485 strcpy(temp
, dirname
);
487 DOS_GetCurrDir_Unix(temp
, drive
);
488 strcat(temp
, dirname
);
492 DOS_SimplifyPath(temp
);
493 dprintf_dosfs(stddeb
,"DOS_SetCWD: %c: %s ==> %s\n", 'A'+drive
, dirname
, temp
);
495 if (!DOS_ValidDirectory(drive
, temp
)) return 0;
496 strcpy(DosDrives
[drive
].cwd
, temp
);
497 if (pTask
!= NULL
&& DOS_GetDefaultDrive() == drive
) {
498 strcpy(temp
, DosDrives
[drive
].rootdir
);
499 strcat(temp
, DosDrives
[drive
].cwd
);
500 strcpy(temp
, DOS_GetDosFileName(temp
));
501 dprintf_dosfs(stddeb
, " curdir = %s\n", temp
);
502 if (strlen(temp
)-2 < sizeof(pTask
->curdir
)) strcpy(pTask
->curdir
, temp
+2);
503 else fprintf(stderr
, "dosfs: curdir too long\n");
508 int DOS_MakeDir(int drive
, char *dirname
)
510 char temp
[256], currdir
[256];
512 if (!DOS_ValidDrive(drive
)) return 0;
514 strcpy(temp
, DosDrives
[drive
].rootdir
);
515 DOS_GetCurrDir_Unix(currdir
, drive
);
516 strcat(temp
, currdir
);
517 strcat(temp
, dirname
);
519 DOS_SimplifyPath(temp
);
522 dprintf_dosfs(stddeb
, "DOS_MakeDir: %c:\%s => %s",'A'+drive
, dirname
, temp
);
526 int DOS_GetSerialNumber(int drive
, unsigned long *serialnumber
)
528 if (!DOS_ValidDrive(drive
))
531 *serialnumber
= DosDrives
[drive
].serialnumber
;
535 int DOS_SetSerialNumber(int drive
, unsigned long serialnumber
)
537 if (!DOS_ValidDrive(drive
))
540 DosDrives
[drive
].serialnumber
= serialnumber
;
544 char *DOS_GetVolumeLabel(int drive
)
546 if (!DOS_ValidDrive(drive
))
549 return DosDrives
[drive
].label
;
552 int DOS_SetVolumeLabel(int drive
, char *label
)
554 if (!DOS_ValidDrive(drive
))
557 strncpy(DosDrives
[drive
].label
, label
, 8);
561 int DOS_GetFreeSpace(int drive
, long *size
, long *available
)
565 if (!DOS_ValidDrive(drive
))
568 if (statfs(DosDrives
[drive
].rootdir
, &info
) < 0) {
569 fprintf(stderr
,"dosfs: cannot do statfs(%s)\n",
570 DosDrives
[drive
].rootdir
);
574 *size
= info
.f_bsize
* info
.f_blocks
;
575 *available
= info
.f_bavail
* info
.f_bsize
;
580 char *DOS_FindFile(char *buffer
, int buflen
, char *filename
, char **extensions
,
583 char *workingpath
, *dirname
, *rootname
, **e
;
587 struct stat filestat
;
589 if (strchr(filename
, '\\') != NULL
)
591 strncpy(buffer
, DOS_GetUnixFileName(filename
), buflen
);
592 stat( buffer
, &filestat
);
593 if (S_ISREG(filestat
.st_mode
))
599 if (strchr(filename
, '/') != NULL
)
601 strncpy(buffer
, filename
, buflen
);
605 dprintf_dosfs(stddeb
,"DOS_FindFile: looking for %s\n", filename
);
606 rootnamelen
= strlen(filename
);
607 rootname
= strdup(filename
);
609 workingpath
= strdup(path
);
611 for(dirname
= strtok(workingpath
, ";");
613 dirname
= strtok(NULL
, ";"))
615 if (strchr(dirname
, '\\') != NULL
)
616 d
= opendir( DOS_GetUnixFileName(dirname
) );
618 d
= opendir( dirname
);
620 dprintf_dosfs(stddeb
,"in %s\n",dirname
);
623 while ((f
= readdir(d
)) != NULL
)
625 if (strcasecmp(rootname
, f
->d_name
) != 0) {
626 if (strncasecmp(rootname
, f
->d_name
, rootnamelen
) != 0
627 || extensions
== NULL
628 || f
->d_name
[rootnamelen
] != '.')
631 for (e
= extensions
; *e
!= NULL
; e
++) {
632 if (strcasecmp(*e
, f
->d_name
+ rootnamelen
+ 1) == 0)
635 if (*e
== NULL
) continue;
638 if (strchr(dirname
, '\\') != NULL
) {
639 strncpy(buffer
, DOS_GetUnixFileName(dirname
), buflen
);
641 strncpy(buffer
, dirname
, buflen
);
644 strncat(buffer
, "/", buflen
- strlen(buffer
));
645 strncat(buffer
, f
->d_name
, buflen
- strlen(buffer
));
647 stat(buffer
, &filestat
);
648 if (S_ISREG(filestat
.st_mode
)) {
651 DOS_SimplifyPath(buffer
);
661 /**********************************************************************
664 char *WineIniFileName(void)
667 static char *filename
= NULL
;
668 static char name
[256];
673 strcpy(name
, WINE_INI_USER
);
674 ExpandTildeString(name
);
675 if ((fd
= open(name
, O_RDONLY
)) != -1) {
680 if ((fd
= open(WINE_INI_GLOBAL
, O_RDONLY
)) != -1) {
682 filename
= WINE_INI_GLOBAL
;
685 fprintf(stderr
,"wine: can't open configuration file %s or %s !\n",
686 WINE_INI_GLOBAL
, WINE_INI_USER
);
690 char *WinIniFileName(void)
692 static char *name
= NULL
;
699 strcpy(name
, DOS_GetUnixFileName(WindowsDirectory
));
701 strcat(name
, "win.ini");
703 name
= realloc(name
, strlen(name
) + 1);
708 static int match(char *filename
, char *filemask
)
710 char name
[12], mask
[12];
713 dprintf_dosfs(stddeb
, "match: %s, %s\n", filename
, filemask
);
715 for( i
=0; i
<11; i
++ ) {
723 if( !(*filename
) || *filename
== '.' )
726 name
[i
] = toupper( *filename
++ );
727 while( *filename
&& *filename
!= '.' )
731 for( i
=8; i
<11; i
++ )
735 name
[i
] = toupper( *filename
++ );
738 if( !(*filemask
) || *filemask
== '.' )
740 else if( *filemask
== '*' ) {
747 mask
[i
] = toupper( *filemask
++ );
748 while( *filemask
&& *filemask
!= '.' )
752 for( i
=8; i
<11; i
++ )
755 else if (*filemask
== '*' ) {
757 for( j
=i
; j
<11; j
++ )
762 mask
[i
] = toupper( *filemask
++ );
764 dprintf_dosfs(stddeb
, "changed to: %s, %s\n", name
, mask
);
766 for( i
=0; i
<11; i
++ )
767 if( ( name
[i
] != mask
[i
] ) && ( mask
[i
] != '?' ) )
773 struct dosdirent
*DOS_opendir(char *dosdirname
)
780 if ((unixdirname
= DOS_GetUnixFileName(dosdirname
)) == NULL
) return NULL
;
782 len
= strrchr(unixdirname
, '/') - unixdirname
+ 1;
783 strncpy(dirname
, unixdirname
, len
);
785 unixdirname
= strrchr(unixdirname
, '/') + 1;
787 for (x
=0; x
<= max_open_dirs
; x
++) {
788 if (x
== max_open_dirs
) {
790 DosDirs
=(struct dosdirent
*)realloc(DosDirs
,(++max_open_dirs
)*sizeof(DosDirs
[0]));
792 DosDirs
=(struct dosdirent
*)malloc(sizeof(DosDirs
[0]));
795 break; /* this one is definitely not in use */
797 if (!DosDirs
[x
].inuse
) break;
798 if (strcmp(DosDirs
[x
].unixpath
, dirname
) == 0) break;
801 strncpy(DosDirs
[x
].filemask
, unixdirname
, 12);
802 DosDirs
[x
].filemask
[12] = 0;
803 dprintf_dosfs(stddeb
,"DOS_opendir: %s / %s\n", unixdirname
, dirname
);
805 DosDirs
[x
].inuse
= 1;
806 strcpy(DosDirs
[x
].unixpath
, dirname
);
807 DosDirs
[x
].entnum
= 0;
809 if ((ds
= opendir(dirname
)) == NULL
) return NULL
;
810 if (-1==(DosDirs
[x
].telldirnum
=telldir(ds
))) {
814 if (-1==closedir(ds
)) return NULL
;
820 struct dosdirent
*DOS_readdir(struct dosdirent
*de
)
829 if (!(ds
=opendir(de
->unixpath
))) return NULL
;
830 seekdir(ds
,de
->telldirnum
); /* returns no error value. strange */
832 if (de
->search_attribute
& FA_LABEL
) {
834 de
->search_attribute
&= ~FA_LABEL
; /* don't find it again */
835 for(drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++) {
836 if (DosDrives
[drive
].rootdir
!= NULL
&&
837 strcmp(DosDrives
[drive
].rootdir
, de
->unixpath
) == 0)
839 strcpy(de
->filename
, DOS_GetVolumeLabel(drive
));
840 de
->attribute
= FA_LABEL
;
847 if ((d
= readdir(ds
)) == NULL
) {
848 de
->telldirnum
=telldir(ds
);
853 de
->entnum
++; /* Increment the directory entry number */
854 strcpy(de
->filename
, d
->d_name
);
855 if (d
->d_reclen
> 12)
856 de
->filename
[12] = '\0';
859 } while ( !match(de
->filename
, de
->filemask
) );
861 strcpy(temp
,de
->unixpath
);
863 strcat(temp
,de
->filename
);
864 ToUnix(temp
+ strlen(de
->unixpath
));
868 if S_ISDIR(st
.st_mode
)
869 de
->attribute
|= FA_DIREC
;
871 de
->filesize
= st
.st_size
;
872 de
->filetime
= st
.st_mtime
;
874 de
->telldirnum
= telldir(ds
);
879 void DOS_closedir(struct dosdirent
*de
)
885 char *DOS_GetRedirectedDir(int drive
)
887 if(DOS_ValidDrive(drive
))
888 return (DosDrives
[drive
].rootdir
);