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>
37 #define WINE_INI_USER "~/.winerc"
38 #define MAX_OPEN_DIRS 16
39 #define MAX_DOS_DRIVES 26
41 extern char WindowsDirectory
[256], SystemDirectory
[256],TempDirectory
[256];
43 char WindowsPath
[256];
45 static int CurrentDrive
= 2;
47 struct DosDriveStruct
{ /* eg: */
48 char *rootdir
; /* /usr/windows */
49 char cwd
[256]; /* / */
50 char label
[13]; /* DRIVE-A */
51 unsigned int serialnumber
; /* ABCD5678 */
55 static struct DosDriveStruct DosDrives
[MAX_DOS_DRIVES
];
56 static struct dosdirent DosDirs
[MAX_OPEN_DIRS
];
58 static void ExpandTildeString(char *s
)
61 char temp
[1024], *ptr
= temp
;
75 if ( (entry
= getpwuid(getuid())) == NULL
)
80 strcpy(s
, entry
->pw_dir
);
81 s
+= strlen(entry
->pw_dir
);
86 void ChopOffSlash(char *path
)
88 if (path
[strlen(path
)-1] == '/' || path
[strlen(path
)-1] == '\\')
89 path
[strlen(path
)-1] = '\0';
94 /* \WINDOWS\\SYSTEM => /windows/system */
104 if (*(p
+1) == '/' || *(p
+1) == '\\')
113 /* /windows//system => \WINDOWS\SYSTEM */
122 if (*(p
+1) == '/' || *(p
+1) == '\\')
129 void DOS_InitFS(void)
132 char drive
[2], temp
[256];
134 GetPrivateProfileString("wine", "windows", "c:\\windows",
135 WindowsDirectory
, sizeof(WindowsDirectory
), WINE_INI
);
137 GetPrivateProfileString("wine", "system", "c:\\windows\\system",
138 SystemDirectory
, sizeof(SystemDirectory
), WINE_INI
);
140 GetPrivateProfileString("wine", "temp", "c:\\windows",
141 TempDirectory
, sizeof(TempDirectory
), WINE_INI
);
143 GetPrivateProfileString("wine", "path", "c:\\windows;c:\\windows\\system",
144 WindowsPath
, sizeof(WindowsPath
), WINE_INI
);
146 ChopOffSlash(WindowsDirectory
);
147 ToDos(WindowsDirectory
);
149 ChopOffSlash(SystemDirectory
);
150 ToDos(SystemDirectory
);
152 ChopOffSlash(TempDirectory
);
153 ToDos(TempDirectory
);
156 ExpandTildeString(WindowsPath
);
158 for (x
=0; x
!=MAX_DOS_DRIVES
; x
++) {
159 DosDrives
[x
].serialnumber
= (0xEB0500L
| x
);
163 GetPrivateProfileString("drives", drive
, "*", temp
, sizeof(temp
), WINE_INI
);
164 if (!strcmp(temp
, "*") || *temp
== '\0') {
165 DosDrives
[x
].rootdir
= NULL
;
166 DosDrives
[x
].cwd
[0] = '\0';
167 DosDrives
[x
].label
[0] = '\0';
168 DosDrives
[x
].disabled
= 1;
171 ExpandTildeString(temp
);
173 DosDrives
[x
].rootdir
= strdup(temp
);
174 strcpy(DosDrives
[x
].rootdir
, temp
);
175 strcpy(DosDrives
[x
].cwd
, "/windows/");
176 strcpy(DosDrives
[x
].label
, "DRIVE-");
177 strcat(DosDrives
[x
].label
, drive
);
178 DosDrives
[x
].disabled
= 0;
180 DosDrives
[25].rootdir
= "/";
181 strcpy(DosDrives
[25].cwd
, "/");
182 strcpy(DosDrives
[25].label
, "UNIX-FS");
183 DosDrives
[25].serialnumber
= 0x12345678;
184 DosDrives
[25].disabled
= 0;
186 /* Get the startup directory and try to map it to a DOS drive
187 * and directory. (i.e., if we start in /dos/windows/word and
188 * drive C is defined as /dos, the starting wd for C will be
189 * /windows/word) Also set the default drive to whatever drive
190 * corresponds to the directory we started in.
193 for (x
=0; x
!=MAX_DOS_DRIVES
; x
++)
194 if (DosDrives
[x
].rootdir
!= NULL
)
195 strcpy( DosDrives
[x
].cwd
, "\\" );
198 strcat(temp
, "/"); /* For DOS_GetDosFileName */
199 strcpy(temp
, DOS_GetDosFileName(temp
));
203 strcpy(DosDrives
[temp
[0] - 'A'].cwd
, &temp
[2]);
204 DOS_SetDefaultDrive(temp
[0] - 'A');
208 DOS_SetDefaultDrive(2);
211 for (x
=0; x
!=MAX_DOS_DRIVES
; x
++) {
212 if (DosDrives
[x
].rootdir
!= NULL
) {
213 dprintf_dosfs(stddeb
, "DOSFS: %c: => %-40s %s %s %X %d\n",
215 DosDrives
[x
].rootdir
,
218 DosDrives
[x
].serialnumber
,
219 DosDrives
[x
].disabled
224 for (x
=0; x
!=MAX_OPEN_DIRS
; x
++)
225 DosDirs
[x
].inuse
= 0;
227 dprintf_dosfs(stddeb
,"wine.ini = %s\n",WINE_INI
);
228 dprintf_dosfs(stddeb
,"win.ini = %s\n",WIN_INI
);
229 dprintf_dosfs(stddeb
,"windir = %s\n",WindowsDirectory
);
230 dprintf_dosfs(stddeb
,"sysdir = %s\n",SystemDirectory
);
231 dprintf_dosfs(stddeb
,"tempdir = %s\n",TempDirectory
);
232 dprintf_dosfs(stddeb
,"path = %s\n",WindowsPath
);
235 WORD
DOS_GetEquipment(void)
239 int parallelports
= 0;
243 /* borrowed from Ralph Brown's interrupt lists
245 bits 15-14: number of parallel devices
246 bit 13: [Conv] Internal modem
248 bits 11- 9: number of serial devices
250 bits 7- 6: number of diskette drives minus one
251 bits 5- 4: Initial video mode:
257 bit 2: [PS] =1 if pointing device
259 bit 1: =1 if math co-processor
260 bit 0: =1 if diskette available for boot
262 /* Currently the only of these bits correctly set are:
263 bits 15-14 } Added by William Owen Smith,
264 bits 11-9 } wos@dcs.warwick.ac.uk
269 if (DosDrives
[0].rootdir
!= NULL
)
271 if (DosDrives
[1].rootdir
!= NULL
)
276 for (x
=0; x
!=MAX_PORTS
; x
++) {
277 if (COM
[x
].devicename
)
279 if (LPT
[x
].devicename
)
282 if (serialports
> 7) /* 3 bits -- maximum value = 7 */
284 if (parallelports
> 3) /* 2 bits -- maximum value = 3 */
287 equipment
= (diskdrives
<< 6) | (serialports
<< 9) |
288 (parallelports
<< 14) | 0x02;
290 dprintf_dosfs(stddeb
, "DOS_GetEquipment : diskdrives = %d serialports = %d "
291 "parallelports = %d\n"
292 "DOS_GetEquipment : equipment = %d\n",
293 diskdrives
, serialports
, parallelports
, equipment
);
298 int DOS_ValidDrive(int drive
)
302 dprintf_dosfs(stddeb
,"ValidDrive %c (%d) -- ",'A'+drive
,drive
);
304 if (drive
< 0 || drive
>= MAX_DOS_DRIVES
)
306 if (DosDrives
[drive
].rootdir
== NULL
)
308 if (DosDrives
[drive
].disabled
)
311 dprintf_dosfs(stddeb
, "%s\n", valid
? "Valid" : "Invalid");
316 int DOS_ValidDirectory(char *name
)
320 dprintf_dosfs(stddeb
, "DOS_ValidDirectory: '%s'\n", name
);
321 if ((dirname
= DOS_GetUnixFileName(name
)) == NULL
)
323 if (stat(dirname
,&s
))
325 if (!S_ISDIR(s
.st_mode
))
327 dprintf_dosfs(stddeb
, "==> OK\n");
333 /* Simplify the path in "name" by removing "//"'s and
334 ".."'s in names like "/usr/bin/../lib/test" */
335 void DOS_SimplifyPath(char *name
)
340 dprintf_dosfs(stddeb
,"SimplifyPath: Before %s\n",name
);
343 while ((l
= strstr(name
,"//"))) {
344 strcpy(l
,l
+1); changed
= TRUE
;
346 while ((l
= strstr(name
,"/../"))) {
348 p
= strrchr(name
,'/');
349 if (p
== NULL
) p
= name
;
354 dprintf_dosfs(stddeb
,"SimplifyPath: After %s\n",name
);
358 int DOS_GetDefaultDrive(void)
360 dprintf_dosfs(stddeb
,"GetDefaultDrive (%c)\n",'A'+CurrentDrive
);
361 return( CurrentDrive
);
364 void DOS_SetDefaultDrive(int drive
)
366 dprintf_dosfs(stddeb
,"SetDefaultDrive to %c:\n",'A'+drive
);
367 if (DOS_ValidDrive(drive
))
368 CurrentDrive
= drive
;
371 int DOS_DisableDrive(int drive
)
373 if (drive
>= MAX_DOS_DRIVES
)
375 if (DosDrives
[drive
].rootdir
== NULL
)
378 DosDrives
[drive
].disabled
= 1;
382 int DOS_EnableDrive(int drive
)
384 if (drive
>= MAX_DOS_DRIVES
)
386 if (DosDrives
[drive
].rootdir
== NULL
)
389 DosDrives
[drive
].disabled
= 0;
393 static void GetUnixDirName(char *rootdir
, char *name
)
396 char *nameptr
, *cwdptr
;
398 cwdptr
= rootdir
+ strlen(rootdir
);
401 dprintf_dosfs(stddeb
,"GetUnixDirName: %s <=> %s => ",rootdir
, name
);
404 if (*nameptr
== '.' & !filename
) {
406 if (*nameptr
== '\0') {
410 if (*nameptr
== '.') {
412 while (cwdptr
!= rootdir
) {
414 if (*cwdptr
== '/') {
421 if (*nameptr
== '\\' || *nameptr
== '/') {
427 if (*nameptr
== '\\' || *nameptr
== '/') {
436 *cwdptr
++ = *nameptr
++;
442 dprintf_dosfs(stddeb
,"%s\n", rootdir
);
446 char *DOS_GetUnixFileName(char *dosfilename
)
448 /* a:\windows\system.ini => /dos/windows/system.ini */
450 /* FIXME: should handle devices here (like LPT: or NUL:) */
452 static char temp
[256];
453 static char dostemp
[256];
456 if (dosfilename
[0] && (dosfilename
[1] == ':'))
458 drive
= (islower(*dosfilename
) ? toupper(*dosfilename
) : *dosfilename
) - 'A';
460 if (!DOS_ValidDrive(drive
))
465 drive
= CurrentDrive
;
467 /* Consider dosfilename const */
468 strncpy( dostemp
, dosfilename
, 255 );
471 /* Expand the filename to it's full path if it doesn't
472 * start from the root.
474 DOS_ExpandToFullPath(dostemp
, drive
);
476 strcpy(temp
, DosDrives
[drive
].rootdir
);
477 strcat(temp
, DosDrives
[drive
].cwd
);
478 GetUnixDirName(temp
+ strlen(DosDrives
[drive
].rootdir
), dostemp
);
480 dprintf_dosfs(stddeb
,"GetUnixFileName: %s => %s\n", dosfilename
, temp
);
484 /* Note: This function works on directories as well as long as
485 * the directory ends in a slash.
487 char *DOS_GetDosFileName(char *unixfilename
)
490 static char temp
[256], rootdir
[256];
491 /* /dos/windows/system.ini => c:\windows\system.ini */
493 /* Expand it if it's a relative name.
495 DOS_ExpandToFullUnixPath(unixfilename
);
497 for (i
= 0 ; i
!= MAX_DOS_DRIVES
; i
++) {
498 if (DosDrives
[i
].rootdir
!= NULL
) {
499 strcpy(rootdir
, DosDrives
[i
].rootdir
);
500 strcat(rootdir
, "/");
501 if (strncmp(rootdir
, unixfilename
, strlen(rootdir
)) == 0) {
502 sprintf(temp
, "%c:\\%s", 'A' + i
, unixfilename
+ strlen(rootdir
));
508 sprintf(temp
, "Z:%s", unixfilename
);
513 char *DOS_GetCurrentDir(int drive
)
515 static char temp
[256];
517 if (!DOS_ValidDrive(drive
))
520 strcpy(temp
, DosDrives
[drive
].cwd
);
521 DOS_SimplifyPath( temp
);
525 dprintf_dosfs(stddeb
,"DOS_GetCWD: %c:%s\n", 'A'+drive
, temp
);
529 int DOS_ChangeDir(int drive
, char *dirname
)
531 char temp
[256],old
[256];
533 if (!DOS_ValidDrive(drive
))
536 strcpy(temp
, dirname
);
538 strcpy(old
, DosDrives
[drive
].cwd
);
540 GetUnixDirName(DosDrives
[drive
].cwd
, temp
);
541 strcat(DosDrives
[drive
].cwd
,"/");
543 dprintf_dosfs(stddeb
,"DOS_SetCWD: %c: %s\n",'A'+drive
,
544 DosDrives
[drive
].cwd
);
546 if (!DOS_ValidDirectory(DosDrives
[drive
].cwd
))
548 strcpy(DosDrives
[drive
].cwd
, old
);
551 DOS_SimplifyPath(DosDrives
[drive
].cwd
);
555 int DOS_MakeDir(int drive
, char *dirname
)
559 if (!DOS_ValidDrive(drive
))
562 strcpy(temp
, DosDrives
[drive
].cwd
);
563 GetUnixDirName(temp
, dirname
);
564 strcat(DosDrives
[drive
].cwd
,"/");
566 ToUnix(temp
+ strlen(DosDrives
[drive
].cwd
));
569 dprintf_dosfs(stddeb
,
570 "DOS_MakeDir: %c:\%s => %s",'A'+drive
, dirname
, temp
);
574 /* DOS_ExpandToFullPath takes a dos-style filename and converts it
575 * into a full path based on the current working directory.
576 * (e.g., "foo.bar" => "d:\\moo\\foo.bar")
578 void DOS_ExpandToFullPath(char *filename
, int drive
)
582 dprintf_dosfs(stddeb
, "DOS_ExpandToFullPath: Original = %s\n", filename
);
584 /* If the filename starts with '/' or '\',
585 * don't bother -- we're already at the root.
587 if(filename
[0] == '/' || filename
[0] == '\\')
590 strcpy(temp
, DosDrives
[drive
].cwd
);
591 strcat(temp
, filename
);
592 strcpy(filename
, temp
);
594 dprintf_dosfs(stddeb
, " Expanded = %s\n", temp
);
597 /* DOS_ExpandToFullUnixPath takes a unix filename and converts it
598 * into a full path based on the current working directory. Thus,
599 * it's probably not a good idea to get a relative name, change the
600 * working directory, and then convert it...
602 void DOS_ExpandToFullUnixPath(char *filename
)
606 if(filename
[0] == '/')
610 if(!strncmp(filename
, "./", 2))
611 strcat(temp
, filename
+ 1);
615 strcat(temp
, filename
);
617 dprintf_dosfs(stddeb
, "DOS_ExpandToFullUnixPath: %s => %s\n", filename
, temp
);
618 strcpy(filename
, temp
);
621 int DOS_GetSerialNumber(int drive
, unsigned long *serialnumber
)
623 if (!DOS_ValidDrive(drive
))
626 *serialnumber
= DosDrives
[drive
].serialnumber
;
630 int DOS_SetSerialNumber(int drive
, unsigned long serialnumber
)
632 if (!DOS_ValidDrive(drive
))
635 DosDrives
[drive
].serialnumber
= serialnumber
;
639 char *DOS_GetVolumeLabel(int drive
)
641 if (!DOS_ValidDrive(drive
))
644 return (DosDrives
[drive
].label
);
647 int DOS_SetVolumeLabel(int drive
, char *label
)
649 if (!DOS_ValidDrive(drive
))
652 strncpy(DosDrives
[drive
].label
, label
, 8);
656 int DOS_GetFreeSpace(int drive
, long *size
, long *available
)
660 if (!DOS_ValidDrive(drive
))
663 if (statfs(DosDrives
[drive
].rootdir
, &info
) < 0) {
664 fprintf(stderr
,"dosfs: cannot do statfs(%s)\n",
665 DosDrives
[drive
].rootdir
);
669 *size
= info
.f_bsize
* info
.f_blocks
;
670 *available
= info
.f_bavail
* info
.f_bsize
;
675 char *DOS_FindFile(char *buffer
, int buflen
, char *filename
, char **extensions
,
678 char *workingpath
, *dirname
, *rootname
, **e
;
682 struct stat filestat
;
684 if (strchr(filename
, '\\') != NULL
)
686 strncpy(buffer
, DOS_GetUnixFileName(filename
), buflen
);
687 stat( buffer
, &filestat
);
688 if (S_ISREG(filestat
.st_mode
))
694 if (strchr(filename
, '/') != NULL
)
696 strncpy(buffer
, filename
, buflen
);
700 dprintf_dosfs(stddeb
,"DOS_FindFile: looking for %s\n", filename
);
701 rootnamelen
= strlen(filename
);
702 rootname
= strdup(filename
);
704 workingpath
= strdup(path
);
706 for(dirname
= strtok(workingpath
, ";");
708 dirname
= strtok(NULL
, ";"))
710 if (strchr(dirname
, '\\') != NULL
)
711 d
= opendir( DOS_GetUnixFileName(dirname
) );
713 d
= opendir( dirname
);
715 dprintf_dosfs(stddeb
,"in %s\n",dirname
);
718 while ((f
= readdir(d
)) != NULL
)
720 if (strcasecmp(rootname
, f
->d_name
) != 0) {
721 if (strncasecmp(rootname
, f
->d_name
, rootnamelen
) != 0
722 || extensions
== NULL
723 || f
->d_name
[rootnamelen
] != '.')
726 for (e
= extensions
; *e
!= NULL
; e
++) {
727 if (strcasecmp(*e
, f
->d_name
+ rootnamelen
+ 1) == 0)
730 if (*e
== NULL
) continue;
733 if (strchr(dirname
, '\\') != NULL
) {
734 strncpy(buffer
, DOS_GetUnixFileName(dirname
), buflen
);
736 strncpy(buffer
, dirname
, buflen
);
739 strncat(buffer
, "/", buflen
- strlen(buffer
));
740 strncat(buffer
, f
->d_name
, buflen
- strlen(buffer
));
742 stat(buffer
, &filestat
);
743 if (S_ISREG(filestat
.st_mode
)) {
755 /**********************************************************************
758 char *WineIniFileName(void)
761 static char *filename
= NULL
;
762 static char name
[256];
767 strcpy(name
, WINE_INI_USER
);
768 ExpandTildeString(name
);
769 if ((fd
= open(name
, O_RDONLY
)) != -1) {
774 if ((fd
= open(WINE_INI_GLOBAL
, O_RDONLY
)) != -1) {
776 filename
= WINE_INI_GLOBAL
;
779 fprintf(stderr
,"wine: can't open configuration file %s or %s !\n",
780 WINE_INI_GLOBAL
, WINE_INI_USER
);
784 char *WinIniFileName(void)
786 static char *name
= NULL
;
793 strcpy(name
, DOS_GetUnixFileName(WindowsDirectory
));
795 strcat(name
, "win.ini");
797 name
= realloc(name
, strlen(name
) + 1);
802 static int match(char *filename
, char *filemask
)
804 char name
[12], mask
[12];
807 dprintf_dosfs(stddeb
, "match: %s, %s\n", filename
, filemask
);
809 for( i
=0; i
<11; i
++ ) {
817 if( !(*filename
) || *filename
== '.' )
820 name
[i
] = toupper( *filename
++ );
821 while( *filename
&& *filename
!= '.' )
825 for( i
=8; i
<11; i
++ )
829 name
[i
] = toupper( *filename
++ );
832 if( !(*filemask
) || *filemask
== '.' )
834 else if( *filemask
== '*' ) {
841 mask
[i
] = toupper( *filemask
++ );
842 while( *filemask
&& *filemask
!= '.' )
846 for( i
=8; i
<11; i
++ )
849 else if (*filemask
== '*' ) {
851 for( j
=i
; j
<11; j
++ )
856 mask
[i
] = toupper( *filemask
++ );
858 dprintf_dosfs(stddeb
, "changed to: %s, %s\n", name
, mask
);
860 for( i
=0; i
<11; i
++ )
861 if( ( name
[i
] != mask
[i
] ) && ( mask
[i
] != '?' ) )
867 struct dosdirent
*DOS_opendir(char *dosdirname
)
873 if ((unixdirname
= DOS_GetUnixFileName(dosdirname
)) == NULL
)
876 strcpy(temp
, unixdirname
);
888 for (x
=0; x
<= MAX_OPEN_DIRS
; x
++) {
889 if (x
== MAX_OPEN_DIRS
) {
890 fprintf( stderr
, "DOS_opendir(): Too many open directories\n");
893 if (!DosDirs
[x
].inuse
) break;
894 if (strcmp(DosDirs
[x
].unixpath
,temp
) == 0) break;
897 strncpy(DosDirs
[x
].filemask
, unixdirname
, 12);
898 DosDirs
[x
].filemask
[12] = 0;
899 ToDos(DosDirs
[x
].filemask
);
900 dprintf_dosfs(stddeb
,"DOS_opendir: %s / %s\n", unixdirname
, temp
);
902 DosDirs
[x
].inuse
= 1;
903 strcpy(DosDirs
[x
].unixpath
, temp
);
904 DosDirs
[x
].entnum
= 0;
906 if ((DosDirs
[x
].ds
= opendir(temp
)) == NULL
)
913 struct dosdirent
*DOS_readdir(struct dosdirent
*de
)
923 if ((d
= readdir(de
->ds
)) == NULL
)
926 de
->entnum
++; /* Increment the directory entry number */
927 strcpy(de
->filename
, d
->d_name
);
928 if (d
->d_reclen
> 12)
929 de
->filename
[12] = '\0';
932 } while ( !match(de
->filename
, de
->filemask
) );
934 strcpy(temp
,de
->unixpath
);
936 strcat(temp
,de
->filename
);
937 ToUnix(temp
+ strlen(de
->unixpath
));
941 if S_ISDIR(st
.st_mode
)
942 de
->attribute
|= FA_DIREC
;
944 de
->filesize
= st
.st_size
;
945 de
->filetime
= st
.st_mtime
;
950 void DOS_closedir(struct dosdirent
*de
)
959 char *DOS_GetRedirectedDir(int drive
)
961 if(DOS_ValidDrive(drive
))
962 return (DosDrives
[drive
].rootdir
);