Release 951226
[wine/multimedia.git] / misc / dos_fs.c
blob6235df63f38cd48f29760199014b27e263318597
1 /*
2 * DOS-FS
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
8 */
10 #include <ctype.h>
11 #include <errno.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/stat.h>
16 #include <pwd.h>
17 #include <dirent.h>
18 #include <unistd.h>
19 #include <fcntl.h>
21 #if defined(__linux__) || defined(sun)
22 #include <sys/vfs.h>
23 #endif
24 #if defined(__NetBSD__) || defined(__FreeBSD__)
25 #include <sys/param.h>
26 #include <sys/mount.h>
27 #include <sys/errno.h>
28 #endif
29 #ifdef __svr4__
30 #include <sys/statfs.h>
31 #endif
32 #include "wine.h"
33 #include "windows.h"
34 #include "msdos.h"
35 #include "dos_fs.h"
36 #include "comm.h"
37 #include "task.h"
38 #include "stddebug.h"
39 #include "debug.h"
40 #include "xmalloc.h"
42 #define WINE_INI_USER "~/.winerc"
43 #define MAX_DOS_DRIVES 26
45 extern char WindowsDirectory[256], SystemDirectory[256],TempDirectory[256];
47 char WindowsPath[256];
49 static int CurrentDrive = 2;
51 struct DosDriveStruct { /* eg: */
52 char *rootdir; /* /usr/windows */
53 char cwd[256]; /* / */
54 char label[13]; /* DRIVE-A */
55 unsigned int serialnumber; /* ABCD5678 */
56 int disabled; /* 0 */
59 static struct DosDriveStruct DosDrives[MAX_DOS_DRIVES];
60 static struct dosdirent *DosDirs=NULL;
62 WORD ExtendedError;
63 BYTE ErrorClass, Action, ErrorLocus;
65 int DOS_Error(int e, int class, int el)
67 ErrorClass = class;
68 Action = SA_Ask4Retry;
69 ErrorLocus = el;
70 ExtendedError = e;
72 return e;
75 void errno_to_doserr(void)
77 switch (errno) {
78 case EAGAIN:
79 DOS_Error (ShareViolation, EC_Temporary, EL_Unknown);
80 break;
81 case EBADF:
82 DOS_Error (InvalidHandle, EC_AppError, EL_Unknown);
83 break;
84 case ENOSPC:
85 DOS_Error (DiskFull, EC_MediaError, EL_Disk);
86 break;
87 case EACCES:
88 case EPERM:
89 case EROFS:
90 DOS_Error (WriteProtected, EC_AccessDenied, EL_Unknown);
91 break;
92 case EBUSY:
93 DOS_Error (LockViolation, EC_AccessDenied, EL_Unknown);
94 break;
95 case ENOENT:
96 DOS_Error (FileNotFound, EC_NotFound, EL_Unknown);
97 break;
98 case EISDIR:
99 DOS_Error (CanNotMakeDir, EC_AccessDenied, EL_Unknown);
100 break;
101 case ENFILE:
102 case EMFILE:
103 DOS_Error (NoMoreFiles, EC_MediaError, EL_Unknown);
104 break;
105 case EEXIST:
106 DOS_Error (FileExists, EC_Exists, EL_Disk);
107 break;
108 default:
109 dprintf_int(stddeb, "int21: unknown errno %d!\n", errno);
110 DOS_Error (GeneralFailure, EC_SystemFailure, EL_Unknown);
111 break;
116 static void ExpandTildeString(char *s)
118 struct passwd *entry;
119 char temp[1024], *ptr = temp;
121 strcpy(temp, s);
123 while (*ptr)
125 if (*ptr != '~')
127 *s++ = *ptr++;
128 continue;
131 ptr++;
133 if ( (entry = getpwuid(getuid())) == NULL)
135 continue;
138 strcpy(s, entry->pw_dir);
139 s += strlen(entry->pw_dir);
141 *s = 0;
144 /* Simplify the path in "name" by removing "//"'s, "/./"'s, and
145 ".."'s in names like "/usr/bin/../lib/test" */
146 static void DOS_SimplifyPath(char *name)
148 char *l,*p;
149 BOOL changed;
151 dprintf_dosfs(stddeb,"SimplifyPath: Before %s\n",name);
152 do {
153 changed = FALSE;
154 while ((l = strstr(name,"//"))) {
155 strcpy(l,l+1); changed = TRUE;
157 while ((l = strstr(name,"/../"))) {
158 *l = 0;
159 p = strrchr(name,'/');
160 if (p == NULL) p = name;
161 strcpy(p,l+3);
162 changed = TRUE;
164 while ((l = strstr(name, "/./"))) {
165 strcpy(l, l+2); changed = TRUE;
167 } while (changed);
168 dprintf_dosfs(stddeb,"SimplifyPath: After %s\n",name);
172 /* ChopOffSlash takes care to strip directory slashes from the
173 * end off the path name, but leaves a single slash. Multiple
174 * slashes at the end of a path are all removed.
177 void ChopOffSlash(char *path)
179 char *p = path + strlen(path) - 1;
180 while ((*p == '\\') && (p > path)) *p-- = '\0';
183 void ToUnix(char *s)
185 while(*s){
186 if (*s == '\\') *s = '/';
187 *s=tolower(*s); /* umsdos fs can't read files without :( */
188 s++;
192 void ToDos(char *s)
194 while(*s){
195 if (*s == '/') *s = '\\';
196 s++;
200 void DOS_InitFS(void)
202 int x;
203 char drive[2], temp[256];
204 struct dosdirent *dp;
205 GetPrivateProfileString("wine", "windows", "c:\\windows",
206 WindowsDirectory, sizeof(WindowsDirectory), WINE_INI);
208 GetPrivateProfileString("wine", "system", "c:\\windows\\system",
209 SystemDirectory, sizeof(SystemDirectory), WINE_INI);
211 GetPrivateProfileString("wine", "temp", "c:\\windows",
212 TempDirectory, sizeof(TempDirectory), WINE_INI);
214 GetPrivateProfileString("wine", "path", "c:\\windows;c:\\windows\\system",
215 WindowsPath, sizeof(WindowsPath), WINE_INI);
217 ChopOffSlash(WindowsDirectory);
218 ToDos(WindowsDirectory);
220 ChopOffSlash(SystemDirectory);
221 ToDos(SystemDirectory);
223 ChopOffSlash(TempDirectory);
224 ToDos(TempDirectory);
226 ToDos(WindowsPath);
227 ExpandTildeString(WindowsPath);
229 for (x=0; x!=MAX_DOS_DRIVES; x++) {
230 DosDrives[x].serialnumber = (0xEB0500L | x);
232 drive[0] = 'A' + x;
233 drive[1] = '\0';
234 GetPrivateProfileString("drives", drive, "*", temp, sizeof(temp), WINE_INI);
235 if (!strcmp(temp, "*") || *temp == '\0') {
236 DosDrives[x].rootdir = NULL;
237 DosDrives[x].cwd[0] = '\0';
238 DosDrives[x].label[0] = '\0';
239 DosDrives[x].disabled = 1;
240 continue;
242 ExpandTildeString(temp);
243 ChopOffSlash(temp);
244 DosDrives[x].rootdir = strdup(temp);
245 strcpy(DosDrives[x].rootdir, temp);
246 strcpy(DosDrives[x].cwd, "/windows/");
247 strcpy(DosDrives[x].label, "DRIVE-");
248 strcat(DosDrives[x].label, drive);
249 DosDrives[x].disabled = 0;
251 DosDrives[25].rootdir = "/";
252 strcpy(DosDrives[25].label, "UNIX-FS");
253 DosDrives[25].serialnumber = 0x12345678;
254 DosDrives[25].disabled = 0;
256 /* Get the startup directory and try to map it to a DOS drive
257 * and directory. (i.e., if we start in /dos/windows/word and
258 * drive C is defined as /dos, the starting wd for C will be
259 * /windows/word) Also set the default drive to whatever drive
260 * corresponds to the directory we started in.
263 for (x=0; x!=MAX_DOS_DRIVES; x++)
264 if (DosDrives[x].rootdir != NULL)
265 strcpy( DosDrives[x].cwd, "/" );
267 getcwd(temp, 254);
268 strcat(temp, "/"); /* For DOS_GetDosFileName */
269 strcpy(DosDrives[25].cwd, temp );
270 strcpy(temp, DOS_GetDosFileName(temp));
271 if(temp[0] != 'Z')
273 ToUnix(temp + 2);
274 strcpy(DosDrives[temp[0] - 'A'].cwd, &temp[2]);
275 DOS_SetDefaultDrive(temp[0] - 'A');
277 else
279 DOS_SetDefaultDrive(2);
282 for (x=0; x!=MAX_DOS_DRIVES; x++) {
283 if (DosDrives[x].rootdir != NULL) {
284 dprintf_dosfs(stddeb, "DOSFS: %c: => %-40s %s %s %X %d\n",
285 'A'+x,
286 DosDrives[x].rootdir,
287 DosDrives[x].cwd,
288 DosDrives[x].label,
289 DosDrives[x].serialnumber,
290 DosDrives[x].disabled);
293 dp = DosDirs;
294 while (dp)
296 dp->inuse = 0;
297 dp = dp->next;
300 dprintf_dosfs(stddeb,"wine.ini = %s\n",WINE_INI);
301 dprintf_dosfs(stddeb,"win.ini = %s\n",WIN_INI);
302 dprintf_dosfs(stddeb,"windir = %s\n",WindowsDirectory);
303 dprintf_dosfs(stddeb,"sysdir = %s\n",SystemDirectory);
304 dprintf_dosfs(stddeb,"tempdir = %s\n",TempDirectory);
305 dprintf_dosfs(stddeb,"path = %s\n",WindowsPath);
308 WORD DOS_GetEquipment(void)
310 WORD equipment;
311 int diskdrives = 0;
312 int parallelports = 0;
313 int serialports = 0;
314 int x;
316 /* borrowed from Ralph Brown's interrupt lists
318 bits 15-14: number of parallel devices
319 bit 13: [Conv] Internal modem
320 bit 12: reserved
321 bits 11- 9: number of serial devices
322 bit 8: reserved
323 bits 7- 6: number of diskette drives minus one
324 bits 5- 4: Initial video mode:
325 00b = EGA,VGA,PGA
326 01b = 40 x 25 color
327 10b = 80 x 25 color
328 11b = 80 x 25 mono
329 bit 3: reserved
330 bit 2: [PS] =1 if pointing device
331 [non-PS] reserved
332 bit 1: =1 if math co-processor
333 bit 0: =1 if diskette available for boot
335 /* Currently the only of these bits correctly set are:
336 bits 15-14 } Added by William Owen Smith,
337 bits 11-9 } wos@dcs.warwick.ac.uk
338 bits 7-6
339 bit 2 (always set)
342 if (DosDrives[0].rootdir != NULL)
343 diskdrives++;
344 if (DosDrives[1].rootdir != NULL)
345 diskdrives++;
346 if (diskdrives)
347 diskdrives--;
349 for (x=0; x!=MAX_PORTS; x++) {
350 if (COM[x].devicename)
351 serialports++;
352 if (LPT[x].devicename)
353 parallelports++;
355 if (serialports > 7) /* 3 bits -- maximum value = 7 */
356 serialports=7;
357 if (parallelports > 3) /* 2 bits -- maximum value = 3 */
358 parallelports=3;
360 equipment = (diskdrives << 6) | (serialports << 9) |
361 (parallelports << 14) | 0x02;
363 dprintf_dosfs(stddeb, "DOS_GetEquipment : diskdrives = %d serialports = %d "
364 "parallelports = %d\n"
365 "DOS_GetEquipment : equipment = %d\n",
366 diskdrives, serialports, parallelports, equipment);
368 return equipment;
371 int DOS_ValidDrive(int drive)
373 dprintf_dosfs(stddeb,"ValidDrive %c (%d)\n",'A'+drive,drive);
375 if (drive < 0 || drive >= MAX_DOS_DRIVES) return 0;
376 if (DosDrives[drive].rootdir == NULL) return 0;
377 if (DosDrives[drive].disabled) return 0;
379 dprintf_dosfs(stddeb, " -- valid\n");
380 return 1;
383 static void DOS_GetCurrDir_Unix(char *buffer, int drive)
385 TDB *pTask = (TDB *)GlobalLock(GetCurrentTask());
387 if (pTask != NULL && (pTask->curdrive & ~0x80) == drive) {
388 strcpy(buffer, pTask->curdir);
389 ToUnix(buffer);
390 } else {
391 strcpy(buffer, DosDrives[drive].cwd);
395 char *DOS_GetCurrentDir(int drive)
397 static char temp[256];
399 if (!DOS_ValidDrive(drive)) return 0;
401 DOS_GetCurrDir_Unix(temp, drive);
402 DOS_SimplifyPath( temp );
403 ToDos(temp);
404 ChopOffSlash(temp);
406 dprintf_dosfs(stddeb,"DOS_GetCWD: %c:%s\n", 'A'+drive, temp);
407 return temp + 1;
410 char *DOS_GetUnixFileName(const char *dosfilename)
412 /* a:\windows\system.ini => /dos/windows/system.ini */
414 /* FIXME: should handle devices here (like LPT: or NUL:) */
416 static char dostemp[256], temp[256];
417 int drive = DOS_GetDefaultDrive();
419 if (dosfilename[0] && dosfilename[1] == ':')
421 drive = toupper(*dosfilename) - 'A';
422 dosfilename += 2;
424 if (!DOS_ValidDrive(drive)) return NULL;
426 strncpy( dostemp, dosfilename, 255 );
427 dostemp[255] = 0;
428 ToUnix(dostemp);
429 strcpy(temp, DosDrives[drive].rootdir);
430 if (dostemp[0] != '/') {
431 DOS_GetCurrDir_Unix(temp+strlen(temp), drive);
433 strcat(temp, dostemp);
434 DOS_SimplifyPath(temp);
436 dprintf_dosfs(stddeb,"GetUnixFileName: %s => %s\n", dosfilename, temp);
437 return temp;
440 /* Note: This function works on directories as well as long as
441 * the directory ends in a slash.
443 char *DOS_GetDosFileName(char *unixfilename)
445 int i;
446 static char temp[256], temp2[256];
447 /* /dos/windows/system.ini => c:\windows\system.ini */
449 dprintf_dosfs(stddeb,"DOS_GetDosFileName: %s\n", unixfilename);
450 if (unixfilename[0] == '/') {
451 strncpy(temp, unixfilename, 255);
452 temp[255] = 0;
453 } else {
454 /* Expand it if it's a relative name. */
455 getcwd(temp, 255);
456 if(strncmp(unixfilename, "./", 2) == 0) {
457 strcat(temp, unixfilename + 1);
458 } else {
459 strcat(temp, "/");
460 strcat(temp, unixfilename);
463 for (i = 0 ; i < MAX_DOS_DRIVES; i++) {
464 if (DosDrives[i].rootdir != NULL) {
465 int len = strlen(DosDrives[i].rootdir);
466 dprintf_dosfs(stddeb, " check %c:%s\n", i+'A', DosDrives[i].rootdir);
467 if (strncmp(DosDrives[i].rootdir, temp, len) == 0 && temp[len] == '/')
469 sprintf(temp2, "%c:%s", 'A' + i, temp+len);
470 ToDos(temp2+2);
471 return temp2;
475 sprintf(temp, "Z:%s", unixfilename);
476 ToDos(temp+2);
477 return temp;
480 int DOS_ValidDirectory(int drive, char *name)
482 char temp[256];
483 struct stat s;
485 strcpy(temp, DosDrives[drive].rootdir);
486 strcat(temp, name);
487 if (stat(temp, &s)) return 0;
488 if (!S_ISDIR(s.st_mode)) return 0;
489 dprintf_dosfs(stddeb, "==> OK\n");
490 return 1;
493 int DOS_GetDefaultDrive(void)
495 TDB *pTask = (TDB *)GlobalLock(GetCurrentTask());
496 int drive = pTask == NULL ? CurrentDrive : pTask->curdrive & ~0x80;
498 dprintf_dosfs(stddeb,"GetDefaultDrive (%c)\n",'A'+drive);
499 return drive;
502 void DOS_SetDefaultDrive(int drive)
504 TDB *pTask = (TDB *)GlobalLock(GetCurrentTask());
506 dprintf_dosfs(stddeb,"SetDefaultDrive to %c:\n",'A'+drive);
507 if (DOS_ValidDrive(drive) && drive != DOS_GetDefaultDrive()) {
508 if (pTask == NULL) CurrentDrive = drive;
509 else {
510 char temp[256];
511 pTask->curdrive = drive | 0x80;
512 strcpy(temp, DosDrives[drive].rootdir);
513 strcat(temp, DosDrives[drive].cwd);
514 strcpy(temp, DOS_GetDosFileName(temp));
515 dprintf_dosfs(stddeb, " curdir = %s\n", temp);
516 if (strlen(temp)-2 < sizeof(pTask->curdir)) strcpy(pTask->curdir, temp+2);
517 else fprintf(stderr, "dosfs: curdir too long\n");
522 int DOS_DisableDrive(int drive)
524 if (drive >= MAX_DOS_DRIVES) return 0;
525 if (DosDrives[drive].rootdir == NULL) return 0;
527 DosDrives[drive].disabled = 1;
528 return 1;
531 int DOS_EnableDrive(int drive)
533 if (drive >= MAX_DOS_DRIVES) return 0;
534 if (DosDrives[drive].rootdir == NULL) return 0;
536 DosDrives[drive].disabled = 0;
537 return 1;
540 int DOS_ChangeDir(int drive, char *dirname)
542 TDB *pTask = (TDB *)GlobalLock(GetCurrentTask());
543 char temp[256];
545 if (!DOS_ValidDrive(drive)) return 0;
547 if (dirname[0] == '\\') {
548 strcpy(temp, dirname);
549 } else {
550 DOS_GetCurrDir_Unix(temp, drive);
551 strcat(temp, dirname);
553 ToUnix(temp);
554 strcat(temp, "/");
555 DOS_SimplifyPath(temp);
556 dprintf_dosfs(stddeb,"DOS_SetCWD: %c: %s ==> %s\n", 'A'+drive, dirname, temp);
558 if (!DOS_ValidDirectory(drive, temp)) return 0;
559 strcpy(DosDrives[drive].cwd, temp);
560 if (pTask != NULL && DOS_GetDefaultDrive() == drive) {
561 strcpy(temp, DosDrives[drive].rootdir);
562 strcat(temp, DosDrives[drive].cwd);
563 strcpy(temp, DOS_GetDosFileName(temp));
564 dprintf_dosfs(stddeb, " curdir = %s\n", temp);
565 if (strlen(temp)-2 < sizeof(pTask->curdir)) strcpy(pTask->curdir, temp+2);
566 else fprintf(stderr, "dosfs: curdir too long\n");
568 return 1;
571 int DOS_MakeDir(int drive, char *dirname)
573 char temp[256], currdir[256];
575 if (!DOS_ValidDrive(drive)) return 0;
577 strcpy(temp, DosDrives[drive].rootdir);
578 DOS_GetCurrDir_Unix(currdir, drive);
579 strcat(temp, currdir);
580 strcat(temp, dirname);
581 ToUnix(temp);
582 DOS_SimplifyPath(temp);
583 if (mkdir(temp, S_IRWXU | S_IRWXG | S_IRWXO) == -1)
585 dprintf_dosfs(stddeb, "DOS_MakeDir: %c:\%s => %s failed errno %d",'A'+drive, dirname, temp, errno);
586 return 0;
588 dprintf_dosfs(stddeb, "DOS_MakeDir: %c:\%s => %s",'A'+drive, dirname, temp);
589 return 1;
592 int DOS_GetSerialNumber(int drive, unsigned long *serialnumber)
594 if (!DOS_ValidDrive(drive))
595 return 0;
597 *serialnumber = DosDrives[drive].serialnumber;
598 return 1;
601 int DOS_SetSerialNumber(int drive, unsigned long serialnumber)
603 if (!DOS_ValidDrive(drive))
604 return 0;
606 DosDrives[drive].serialnumber = serialnumber;
607 return 1;
610 char *DOS_GetVolumeLabel(int drive)
612 if (!DOS_ValidDrive(drive))
613 return NULL;
615 return DosDrives[drive].label;
618 int DOS_SetVolumeLabel(int drive, char *label)
620 if (!DOS_ValidDrive(drive))
621 return 0;
623 strncpy(DosDrives[drive].label, label, 8);
624 return 1;
627 int DOS_GetFreeSpace(int drive, long *size, long *available)
629 struct statfs info;
631 if (!DOS_ValidDrive(drive))
632 return 0;
634 #ifdef __svr4__
635 if (statfs(DosDrives[drive].rootdir, &info, 0, 0) < 0) {
636 #else
637 if (statfs(DosDrives[drive].rootdir, &info) < 0) {
638 #endif
639 fprintf(stderr,"dosfs: cannot do statfs(%s)\n",
640 DosDrives[drive].rootdir);
641 return 0;
644 *size = info.f_bsize * info.f_blocks;
645 #ifdef __svr4__
646 *available = info.f_bfree * info.f_bsize;
647 #else
648 *available = info.f_bavail * info.f_bsize;
649 #endif
651 return 1;
654 char *DOS_FindFile(char *buffer, int buflen, const char *filename, char **extensions,
655 char *path)
657 char *workingpath, *dirname, *rootname, **e;
658 DIR *d;
659 struct dirent *f;
660 int rootnamelen;
661 struct stat filestat;
663 if (strchr(filename, '\\') != NULL)
665 strncpy(buffer, DOS_GetUnixFileName(filename), buflen);
666 stat( buffer, &filestat);
667 if (S_ISREG(filestat.st_mode))
668 return buffer;
669 else
670 return NULL;
673 if (strchr(filename, '/') != NULL)
675 strncpy(buffer, filename, buflen);
676 return buffer;
679 dprintf_dosfs(stddeb,"DOS_FindFile: looking for %s\n", filename);
680 rootnamelen = strlen(filename);
681 rootname = strdup(filename);
682 ToUnix(rootname);
683 workingpath = strdup(path);
685 for(dirname = strtok(workingpath, ";");
686 dirname != NULL;
687 dirname = strtok(NULL, ";"))
689 if (strchr(dirname, '\\') != NULL)
690 d = opendir( DOS_GetUnixFileName(dirname) );
691 else
692 d = opendir( dirname );
694 dprintf_dosfs(stddeb,"in %s\n",dirname);
695 if (d != NULL)
697 while ((f = readdir(d)) != NULL)
699 if (strcasecmp(rootname, f->d_name) != 0) {
700 if (strncasecmp(rootname, f->d_name, rootnamelen) != 0
701 || extensions == NULL
702 || f->d_name[rootnamelen] != '.')
703 continue;
705 for (e = extensions; *e != NULL; e++) {
706 if (strcasecmp(*e, f->d_name + rootnamelen + 1) == 0)
707 break;
709 if (*e == NULL) continue;
712 if (strchr(dirname, '\\') != NULL) {
713 strncpy(buffer, DOS_GetUnixFileName(dirname), buflen);
714 } else {
715 strncpy(buffer, dirname, buflen);
718 strncat(buffer, "/", buflen - strlen(buffer));
719 strncat(buffer, f->d_name, buflen - strlen(buffer));
721 stat(buffer, &filestat);
722 if (S_ISREG(filestat.st_mode)) {
723 closedir(d);
724 free(rootname);
725 DOS_SimplifyPath(buffer);
726 return buffer;
729 closedir(d);
732 return NULL;
735 /**********************************************************************
736 * WineIniFileName
738 char *WineIniFileName(void)
740 int fd;
741 static char *filename = NULL;
742 static char name[256];
744 if (filename)
745 return filename;
747 strcpy(name, WINE_INI_USER);
748 ExpandTildeString(name);
749 if ((fd = open(name, O_RDONLY)) != -1) {
750 close(fd);
751 filename = name;
752 return filename;
754 if ((fd = open(WINE_INI_GLOBAL, O_RDONLY)) != -1) {
755 close(fd);
756 filename = WINE_INI_GLOBAL;
757 return filename;
759 fprintf(stderr,"wine: can't open configuration file %s or %s !\n",
760 WINE_INI_GLOBAL, WINE_INI_USER);
761 exit(1);
764 char *WinIniFileName(void)
766 static char *name = NULL;
768 if (name)
769 return name;
771 name = xmalloc(1024);
773 strcpy(name, DOS_GetUnixFileName(WindowsDirectory));
774 strcat(name, "/");
775 strcat(name, "win.ini");
777 name = xrealloc(name, strlen(name) + 1);
779 return name;
782 static int match(char *filename, char *filemask)
784 char name[12], mask[12];
785 int i;
787 dprintf_dosfs(stddeb, "match: %s, %s\n", filename, filemask);
789 for( i=0; i<11; i++ ) {
790 name[i] = ' ';
791 mask[i] = ' ';
793 name[11] = 0;
794 mask[11] = 0;
796 for( i=0; i<8; i++ )
797 if( !(*filename) || *filename == '.' )
798 break;
799 else
800 name[i] = toupper( *filename++ );
801 while( *filename && *filename != '.' )
802 filename++;
803 if( *filename )
804 filename++;
805 for( i=8; i<11; i++ )
806 if( !(*filename) )
807 break;
808 else
809 name[i] = toupper( *filename++ );
811 for( i=0; i<8; i++ )
812 if( !(*filemask) || *filemask == '.' )
813 break;
814 else if( *filemask == '*' ) {
815 int j;
816 for( j=i; j<8; j++ )
817 mask[j] = '?';
818 break;
820 else
821 mask[i] = toupper( *filemask++ );
822 while( *filemask && *filemask != '.' )
823 filemask++;
824 if( *filemask )
825 filemask++;
826 for( i=8; i<11; i++ )
827 if( !(*filemask) )
828 break;
829 else if (*filemask == '*' ) {
830 int j;
831 for( j=i; j<11; j++ )
832 mask[j] = '?';
833 break;
835 else
836 mask[i] = toupper( *filemask++ );
838 dprintf_dosfs(stddeb, "changed to: %s, %s\n", name, mask);
840 for( i=0; i<11; i++ )
841 if( ( name[i] != mask[i] ) && ( mask[i] != '?' ) )
842 return 0;
844 return 1;
847 struct dosdirent *DOS_opendir(char *dosdirname)
849 int len;
850 char *unixdirname;
851 char dirname[256];
852 DIR *ds;
853 struct dosdirent *dp;
855 if ((unixdirname = DOS_GetUnixFileName(dosdirname)) == NULL) return NULL;
857 len = strrchr(unixdirname, '/') - unixdirname + 1;
858 strncpy(dirname, unixdirname, len);
859 dirname[len] = 0;
860 unixdirname = strrchr(unixdirname, '/') + 1;
861 if ((ds = opendir(dirname)) == NULL)
862 return NULL;
864 dp = DosDirs;
865 while (dp)
867 if (dp->inuse)
868 break;
869 if (strcmp(dp->unixpath, dirname) == 0)
870 break;
871 dp = dp->next;
873 if (!dp)
875 dp = xmalloc(sizeof(struct dosdirent));
876 dp->next = DosDirs;
877 DosDirs = dp;
880 strncpy(dp->filemask, unixdirname, 12);
881 dp->filemask[12] = 0;
882 dprintf_dosfs(stddeb,"DOS_opendir: %s / %s\n", unixdirname, dirname);
884 dp->inuse = 1;
885 strcpy(dp->unixpath, dirname);
886 dp->entnum = 0;
888 if (closedir(ds) == -1)
890 dp->inuse = 0;
891 return NULL;
893 return dp;
897 struct dosdirent *DOS_readdir(struct dosdirent *de)
899 char temp[WINE_PATH_LENGTH];
900 struct dirent *d;
901 struct stat st;
902 DIR *ds;
903 int i;
905 if (!de->inuse)
906 return NULL;
907 if (!(ds=opendir(de->unixpath))) return NULL;
908 /* skip all already read directory entries.
909 * the dir has hopefully not been modified in the meantime
911 for (i=de->entnum;i--;)
912 readdir(ds);
914 if (de->search_attribute & FA_LABEL) {
915 int drive;
916 de->search_attribute &= ~FA_LABEL; /* don't find it again */
917 for(drive = 0; drive < MAX_DOS_DRIVES; drive++) {
918 if (DosDrives[drive].rootdir != NULL &&
919 strcmp(DosDrives[drive].rootdir, de->unixpath) == 0)
921 strcpy(de->filename, DOS_GetVolumeLabel(drive));
922 de->attribute = FA_LABEL;
923 return de;
928 do {
929 de->entnum++; /* Increment the directory entry number */
930 if ((d = readdir(ds)) == NULL) {
931 closedir(ds);
932 return NULL;
934 strcpy(de->filename, d->d_name);
935 if (d->d_reclen > 12)
936 de->filename[12] = '\0';
937 ToDos(de->filename);
939 strcpy(temp,de->unixpath);
940 strcat(temp,"/");
941 strcat(temp,d->d_name);
942 stat (temp, &st);
943 de->attribute = 0x0;
944 if S_ISDIR(st.st_mode)
945 de->attribute |= FA_DIREC;
947 } while (!(de->attribute & FA_DIREC) &&
948 !match(de->filename, de->filemask) );
951 de->filesize = st.st_size;
952 de->filetime = st.st_mtime;
954 closedir(ds);
955 return de;
958 void DOS_closedir(struct dosdirent *de)
960 if (de && de->inuse)
961 de->inuse = 0;
964 char *DOS_GetRedirectedDir(int drive)
966 if(DOS_ValidDrive(drive))
967 return (DosDrives[drive].rootdir);
968 else
969 return ("/");