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 = '/';
134 if (*s == '/') *s = '\\';
139 void DOS_InitFS(void)
142 char drive[2], temp[256];
144 GetPrivateProfileString("wine", "windows", "c:\\windows",
145 WindowsDirectory, sizeof(WindowsDirectory), WINE_INI);
147 GetPrivateProfileString("wine", "system", "c:\\windows\\system",
148 SystemDirectory, sizeof(SystemDirectory), WINE_INI);
150 GetPrivateProfileString("wine", "temp", "c:\\windows",
151 TempDirectory, sizeof(TempDirectory), WINE_INI);
153 GetPrivateProfileString("wine", "path", "c:\\windows;c:\\windows\\system",
154 WindowsPath, sizeof(WindowsPath), WINE_INI);
156 ChopOffSlash(WindowsDirectory);
157 ToDos(WindowsDirectory);
159 ChopOffSlash(SystemDirectory);
160 ToDos(SystemDirectory);
162 ChopOffSlash(TempDirectory);
163 ToDos(TempDirectory);
166 ExpandTildeString(WindowsPath);
168 for (x=0; x!=MAX_DOS_DRIVES; x++) {
169 DosDrives[x].serialnumber = (0xEB0500L | x);
173 GetPrivateProfileString("drives", drive, "*", temp, sizeof(temp), WINE_INI);
174 if (!strcmp(temp, "*") || *temp == '\0') {
175 DosDrives[x].rootdir = NULL;
176 DosDrives[x].cwd[0] = '\0';
177 DosDrives[x].label[0] = '\0';
178 DosDrives[x].disabled = 1;
181 ExpandTildeString(temp);
183 DosDrives[x].rootdir = strdup(temp);
184 strcpy(DosDrives[x].rootdir, temp);
185 strcpy(DosDrives[x].cwd, "/windows/");
186 strcpy(DosDrives[x].label, "DRIVE-");
187 strcat(DosDrives[x].label, drive);
188 DosDrives[x].disabled = 0;
190 DosDrives[25].rootdir = "/";
191 strcpy(DosDrives[25].cwd, "/");
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(temp, DOS_GetDosFileName(temp));
213 strcpy(DosDrives[temp[0] - 'A'].cwd, &temp[2]);
214 DOS_SetDefaultDrive(temp[0] - 'A');
218 DOS_SetDefaultDrive(2);
221 for (x=0; x!=MAX_DOS_DRIVES; x++) {
222 if (DosDrives[x].rootdir != NULL) {
223 dprintf_dosfs(stddeb, "DOSFS: %c: => %-40s %s %s %X %d\n",
225 DosDrives[x].rootdir,
228 DosDrives[x].serialnumber,
229 DosDrives[x].disabled);
233 for (x=0; x!=max_open_dirs ; x++)
234 DosDirs[x].inuse = 0;
236 dprintf_dosfs(stddeb,"wine.ini = %s\n",WINE_INI);
237 dprintf_dosfs(stddeb,"win.ini = %s\n",WIN_INI);
238 dprintf_dosfs(stddeb,"windir = %s\n",WindowsDirectory);
239 dprintf_dosfs(stddeb,"sysdir = %s\n",SystemDirectory);
240 dprintf_dosfs(stddeb,"tempdir = %s\n",TempDirectory);
241 dprintf_dosfs(stddeb,"path = %s\n",WindowsPath);
244 WORD DOS_GetEquipment(void)
248 int parallelports = 0;
252 /* borrowed from Ralph Brown's interrupt lists
254 bits 15-14: number of parallel devices
255 bit 13: [Conv] Internal modem
257 bits 11- 9: number of serial devices
259 bits 7- 6: number of diskette drives minus one
260 bits 5- 4: Initial video mode:
266 bit 2: [PS] =1 if pointing device
268 bit 1: =1 if math co-processor
269 bit 0: =1 if diskette available for boot
271 /* Currently the only of these bits correctly set are:
272 bits 15-14 } Added by William Owen Smith,
273 bits 11-9 } wos@dcs.warwick.ac.uk
278 if (DosDrives[0].rootdir != NULL)
280 if (DosDrives[1].rootdir != NULL)
285 for (x=0; x!=MAX_PORTS; x++) {
286 if (COM[x].devicename)
288 if (LPT[x].devicename)
291 if (serialports > 7) /* 3 bits -- maximum value = 7 */
293 if (parallelports > 3) /* 2 bits -- maximum value = 3 */
296 equipment = (diskdrives << 6) | (serialports << 9) |
297 (parallelports << 14) | 0x02;
299 dprintf_dosfs(stddeb, "DOS_GetEquipment : diskdrives = %d serialports = %d "
300 "parallelports = %d\n"
301 "DOS_GetEquipment : equipment = %d\n",
302 diskdrives, serialports, parallelports, equipment);
307 int DOS_ValidDrive(int drive)
309 dprintf_dosfs(stddeb,"ValidDrive %c (%d)\n",'A'+drive,drive);
311 if (drive < 0 || drive >= MAX_DOS_DRIVES) return 0;
312 if (DosDrives[drive].rootdir == NULL) return 0;
313 if (DosDrives[drive].disabled) return 0;
315 dprintf_dosfs(stddeb, " -- valid\n");
319 static void DOS_GetCurrDir_Unix(char *buffer, int drive)
321 TDB *pTask = (TDB *)GlobalLock(GetCurrentTask());
323 if (pTask != NULL && (pTask->curdrive & ~0x80) == drive) {
324 strcpy(buffer, pTask->curdir);
327 strcpy(buffer, DosDrives[drive].cwd);
331 char *DOS_GetCurrentDir(int drive)
333 static char temp[256];
335 if (!DOS_ValidDrive(drive)) return 0;
337 DOS_GetCurrDir_Unix(temp, drive);
338 DOS_SimplifyPath( temp );
342 dprintf_dosfs(stddeb,"DOS_GetCWD: %c:%s\n", 'A'+drive, temp);
346 char *DOS_GetUnixFileName(const char *dosfilename)
348 /* a:\windows\system.ini => /dos/windows/system.ini */
350 /* FIXME: should handle devices here (like LPT: or NUL:) */
352 static char dostemp[256], temp[256];
353 int drive = DOS_GetDefaultDrive();
355 if (dosfilename[0] && dosfilename[1] == ':')
357 drive = toupper(*dosfilename) - 'A';
360 if (!DOS_ValidDrive(drive)) return NULL;
362 strncpy( dostemp, dosfilename, 255 );
365 strcpy(temp, DosDrives[drive].rootdir);
366 if (dostemp[0] != '/') {
367 DOS_GetCurrDir_Unix(temp+strlen(temp), drive);
369 strcat(temp, dostemp);
370 DOS_SimplifyPath(temp);
372 dprintf_dosfs(stddeb,"GetUnixFileName: %s => %s\n", dosfilename, temp);
376 /* Note: This function works on directories as well as long as
377 * the directory ends in a slash.
379 char *DOS_GetDosFileName(char *unixfilename)
382 static char temp[256], temp2[256];
383 /* /dos/windows/system.ini => c:\windows\system.ini */
385 dprintf_dosfs(stddeb,"DOS_GetDosFileName: %s\n", unixfilename);
386 if (unixfilename[0] == '/') {
387 strncpy(temp, unixfilename, 255);
390 /* Expand it if it's a relative name. */
392 if(strncmp(unixfilename, "./", 2) != 0) {
393 strcat(temp, unixfilename + 1);
396 strcat(temp, unixfilename);
399 for (i = 0 ; i < MAX_DOS_DRIVES; i++) {
400 if (DosDrives[i].rootdir != NULL) {
401 int len = strlen(DosDrives[i].rootdir);
402 dprintf_dosfs(stddeb, " check %c:%s\n", i+'A', DosDrives[i].rootdir);
403 if (strncmp(DosDrives[i].rootdir, temp, len) == 0 && temp[len] == '/')
405 sprintf(temp2, "%c:%s", 'A' + i, temp+len);
411 sprintf(temp, "Z:%s", unixfilename);
416 int DOS_ValidDirectory(int drive, char *name)
421 strcpy(temp, DosDrives[drive].rootdir);
423 if (stat(temp, &s)) return 0;
424 if (!S_ISDIR(s.st_mode)) return 0;
425 dprintf_dosfs(stddeb, "==> OK\n");
429 int DOS_GetDefaultDrive(void)
431 TDB *pTask = (TDB *)GlobalLock(GetCurrentTask());
432 int drive = pTask == NULL ? CurrentDrive : pTask->curdrive & ~0x80;
434 dprintf_dosfs(stddeb,"GetDefaultDrive (%c)\n",'A'+drive);
438 void DOS_SetDefaultDrive(int drive)
440 TDB *pTask = (TDB *)GlobalLock(GetCurrentTask());
442 dprintf_dosfs(stddeb,"SetDefaultDrive to %c:\n",'A'+drive);
443 if (DOS_ValidDrive(drive) && drive != DOS_GetDefaultDrive()) {
444 if (pTask == NULL) CurrentDrive = drive;
447 pTask->curdrive = drive | 0x80;
448 strcpy(temp, DosDrives[drive].rootdir);
449 strcat(temp, DosDrives[drive].cwd);
450 strcpy(temp, DOS_GetDosFileName(temp));
451 dprintf_dosfs(stddeb, " curdir = %s\n", temp);
452 if (strlen(temp)-2 < sizeof(pTask->curdir)) strcpy(pTask->curdir, temp+2);
453 else fprintf(stderr, "dosfs: curdir too long\n");
458 int DOS_DisableDrive(int drive)
460 if (drive >= MAX_DOS_DRIVES) return 0;
461 if (DosDrives[drive].rootdir == NULL) return 0;
463 DosDrives[drive].disabled = 1;
467 int DOS_EnableDrive(int drive)
469 if (drive >= MAX_DOS_DRIVES) return 0;
470 if (DosDrives[drive].rootdir == NULL) return 0;
472 DosDrives[drive].disabled = 0;
476 int DOS_ChangeDir(int drive, char *dirname)
478 TDB *pTask = (TDB *)GlobalLock(GetCurrentTask());
481 if (!DOS_ValidDrive(drive)) return 0;
483 if (dirname[0] == '\\') {
484 strcpy(temp, dirname);
486 DOS_GetCurrDir_Unix(temp, drive);
487 strcat(temp, dirname);
491 DOS_SimplifyPath(temp);
492 dprintf_dosfs(stddeb,"DOS_SetCWD: %c: %s ==> %s\n", 'A'+drive, dirname, temp);
494 if (!DOS_ValidDirectory(drive, temp)) return 0;
495 strcpy(DosDrives[drive].cwd, temp);
496 if (pTask != NULL && DOS_GetDefaultDrive() == drive) {
497 strcpy(temp, DosDrives[drive].rootdir);
498 strcat(temp, DosDrives[drive].cwd);
499 strcpy(temp, DOS_GetDosFileName(temp));
500 dprintf_dosfs(stddeb, " curdir = %s\n", temp);
501 if (strlen(temp)-2 < sizeof(pTask->curdir)) strcpy(pTask->curdir, temp+2);
502 else fprintf(stderr, "dosfs: curdir too long\n");
507 int DOS_MakeDir(int drive, char *dirname)
509 char temp[256], currdir[256];
511 if (!DOS_ValidDrive(drive)) return 0;
513 strcpy(temp, DosDrives[drive].rootdir);
514 DOS_GetCurrDir_Unix(currdir, drive);
515 strcat(temp, currdir);
516 strcat(temp, dirname);
518 DOS_SimplifyPath(temp);
521 dprintf_dosfs(stddeb, "DOS_MakeDir: %c:\%s => %s",'A'+drive, dirname, temp);
525 int DOS_GetSerialNumber(int drive, unsigned long *serialnumber)
527 if (!DOS_ValidDrive(drive))
530 *serialnumber = DosDrives[drive].serialnumber;
534 int DOS_SetSerialNumber(int drive, unsigned long serialnumber)
536 if (!DOS_ValidDrive(drive))
539 DosDrives[drive].serialnumber = serialnumber;
543 char *DOS_GetVolumeLabel(int drive)
545 if (!DOS_ValidDrive(drive))
548 return DosDrives[drive].label;
551 int DOS_SetVolumeLabel(int drive, char *label)
553 if (!DOS_ValidDrive(drive))
556 strncpy(DosDrives[drive].label, label, 8);
560 int DOS_GetFreeSpace(int drive, long *size, long *available)
564 if (!DOS_ValidDrive(drive))
567 if (statfs(DosDrives[drive].rootdir, &info) < 0) {
568 fprintf(stderr,"dosfs: cannot do statfs(%s)\n",
569 DosDrives[drive].rootdir);
573 *size = info.f_bsize * info.f_blocks;
574 *available = info.f_bavail * info.f_bsize;
579 char *DOS_FindFile(char *buffer, int buflen, char *filename, char **extensions,
582 char *workingpath, *dirname, *rootname, **e;
586 struct stat filestat;
588 if (strchr(filename, '\\') != NULL)
590 strncpy(buffer, DOS_GetUnixFileName(filename), buflen);
591 stat( buffer, &filestat);
592 if (S_ISREG(filestat.st_mode))
598 if (strchr(filename, '/') != NULL)
600 strncpy(buffer, filename, buflen);
604 dprintf_dosfs(stddeb,"DOS_FindFile: looking for %s\n", filename);
605 rootnamelen = strlen(filename);
606 rootname = strdup(filename);
608 workingpath = strdup(path);
610 for(dirname = strtok(workingpath, ";");
612 dirname = strtok(NULL, ";"))
614 if (strchr(dirname, '\\') != NULL)
615 d = opendir( DOS_GetUnixFileName(dirname) );
617 d = opendir( dirname );
619 dprintf_dosfs(stddeb,"in %s\n",dirname);
622 while ((f = readdir(d)) != NULL)
624 if (strcasecmp(rootname, f->d_name) != 0) {
625 if (strncasecmp(rootname, f->d_name, rootnamelen) != 0
626 || extensions == NULL
627 || f->d_name[rootnamelen] != '.')
630 for (e = extensions; *e != NULL; e++) {
631 if (strcasecmp(*e, f->d_name + rootnamelen + 1) == 0)
634 if (*e == NULL) continue;
637 if (strchr(dirname, '\\') != NULL) {
638 strncpy(buffer, DOS_GetUnixFileName(dirname), buflen);
640 strncpy(buffer, dirname, buflen);
643 strncat(buffer, "/", buflen - strlen(buffer));
644 strncat(buffer, f->d_name, buflen - strlen(buffer));
646 stat(buffer, &filestat);
647 if (S_ISREG(filestat.st_mode)) {
650 DOS_SimplifyPath(buffer);
660 /**********************************************************************
663 char *WineIniFileName(void)
666 static char *filename = NULL;
667 static char name[256];
672 strcpy(name, WINE_INI_USER);
673 ExpandTildeString(name);
674 if ((fd = open(name, O_RDONLY)) != -1) {
679 if ((fd = open(WINE_INI_GLOBAL, O_RDONLY)) != -1) {
681 filename = WINE_INI_GLOBAL;
684 fprintf(stderr,"wine: can't open configuration file %s or %s !\n",
685 WINE_INI_GLOBAL, WINE_INI_USER);
689 char *WinIniFileName(void)
691 static char *name = NULL;
698 strcpy(name, DOS_GetUnixFileName(WindowsDirectory));
700 strcat(name, "win.ini");
702 name = realloc(name, strlen(name) + 1);
707 static int match(char *filename, char *filemask)
709 char name[12], mask[12];
712 dprintf_dosfs(stddeb, "match: %s, %s\n", filename, filemask);
714 for( i=0; i<11; i++ ) {
722 if( !(*filename) || *filename == '.' )
725 name[i] = toupper( *filename++ );
726 while( *filename && *filename != '.' )
730 for( i=8; i<11; i++ )
734 name[i] = toupper( *filename++ );
737 if( !(*filemask) || *filemask == '.' )
739 else if( *filemask == '*' ) {
746 mask[i] = toupper( *filemask++ );
747 while( *filemask && *filemask != '.' )
751 for( i=8; i<11; i++ )
754 else if (*filemask == '*' ) {
756 for( j=i; j<11; j++ )
761 mask[i] = toupper( *filemask++ );
763 dprintf_dosfs(stddeb, "changed to: %s, %s\n", name, mask);
765 for( i=0; i<11; i++ )
766 if( ( name[i] != mask[i] ) && ( mask[i] != '?' ) )
772 struct dosdirent *DOS_opendir(char *dosdirname)
779 if ((unixdirname = DOS_GetUnixFileName(dosdirname)) == NULL) return NULL;
781 len = strrchr(unixdirname, '/') - unixdirname + 1;
782 strncpy(dirname, unixdirname, len);
784 unixdirname = strrchr(unixdirname, '/') + 1;
786 for (x=0; x <= max_open_dirs; x++) {
787 if (x == max_open_dirs) {
789 DosDirs=(struct dosdirent*)realloc(DosDirs,(++max_open_dirs)*sizeof(DosDirs[0]));
791 DosDirs=(struct dosdirent*)malloc(sizeof(DosDirs[0]));
794 break; /* this one is definitely not in use */
796 if (!DosDirs[x].inuse) break;
797 if (strcmp(DosDirs[x].unixpath, dirname) == 0) break;
800 strncpy(DosDirs[x].filemask, unixdirname, 12);
801 DosDirs[x].filemask[12] = 0;
802 dprintf_dosfs(stddeb,"DOS_opendir: %s / %s\n", unixdirname, dirname);
804 DosDirs[x].inuse = 1;
805 strcpy(DosDirs[x].unixpath, dirname);
806 DosDirs[x].entnum = 0;
808 if ((ds = opendir(dirname)) == NULL) return NULL;
809 if (-1==(DosDirs[x].telldirnum=telldir(ds))) {
813 if (-1==closedir(ds)) return NULL;
819 struct dosdirent *DOS_readdir(struct dosdirent *de)
828 if (!(ds=opendir(de->unixpath))) return NULL;
829 seekdir(ds,de->telldirnum); /* returns no error value. strange */
831 if (de->search_attribute & FA_LABEL) {
833 de->search_attribute &= ~FA_LABEL; /* don't find it again */
834 for(drive = 0; drive < MAX_DOS_DRIVES; drive++) {
835 if (DosDrives[drive].rootdir != NULL &&
836 strcmp(DosDrives[drive].rootdir, de->unixpath) == 0)
838 strcpy(de->filename, DOS_GetVolumeLabel(drive));
839 de->attribute = FA_LABEL;
846 if ((d = readdir(ds)) == NULL) {
847 de->telldirnum=telldir(ds);
852 de->entnum++; /* Increment the directory entry number */
853 strcpy(de->filename, d->d_name);
854 if (d->d_reclen > 12)
855 de->filename[12] = '\0';
858 } while ( !match(de->filename, de->filemask) );
860 strcpy(temp,de->unixpath);
862 strcat(temp,de->filename);
863 ToUnix(temp + strlen(de->unixpath));
867 if S_ISDIR(st.st_mode)
868 de->attribute |= FA_DIREC;
870 de->filesize = st.st_size;
871 de->filetime = st.st_mtime;
873 de->telldirnum = telldir(ds);
878 void DOS_closedir(struct dosdirent *de)
884 char *DOS_GetRedirectedDir(int drive)
886 if(DOS_ValidDrive(drive))
887 return (DosDrives[drive].rootdir);