Release 950216
[wine] / misc / dos_fs.c
1 /*
2  * DOS-FS
3  * NOV 1993 Erik Bos <erik@xs4all.nl>
4  *
5  * FindFile by Bob, hacked for dos & unixpaths by Erik.
6  *
7  * Bugfix by dash@ifi.uio.no: ToUnix() was called to often
8  */
9
10 #include <ctype.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/stat.h>
15 #include <pwd.h>
16 #include <dirent.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19
20 #if defined(__linux__) || defined(sun)
21 #include <sys/vfs.h>
22 #endif
23 #if defined(__NetBSD__) || defined(__FreeBSD__)
24 #include <sys/param.h>
25 #include <sys/mount.h>
26 #endif
27
28 #include "wine.h"
29 #include "windows.h"
30 #include "msdos.h"
31 #include "dos_fs.h"
32 #include "autoconf.h"
33 #include "comm.h"
34 #include "stddebug.h"
35 #include "debug.h"
36
37 #define WINE_INI_USER "~/.winerc"
38 #define MAX_OPEN_DIRS 16
39 #define MAX_DOS_DRIVES  26
40
41 extern char WindowsDirectory[256], SystemDirectory[256],TempDirectory[256];
42
43 char WindowsPath[256];
44
45 static int CurrentDrive = 2;
46
47 struct DosDriveStruct {                 /*  eg: */
48         char            *rootdir;       /*  /usr/windows        */
49         char            cwd[256];       /*  /                   */
50         char            label[13];      /*  DRIVE-A             */              
51         unsigned int    serialnumber;   /*  ABCD5678            */
52         int             disabled;       /*  0                   */
53 };
54
55 static struct DosDriveStruct DosDrives[MAX_DOS_DRIVES];
56 static struct dosdirent DosDirs[MAX_OPEN_DIRS];
57
58 static void ExpandTildeString(char *s)
59 {
60     struct passwd *entry;
61     char temp[1024], *ptr = temp;
62         
63     strcpy(temp, s);
64
65     while (*ptr)
66     {
67         if (*ptr != '~') 
68         { 
69             *s++ = *ptr++;
70             continue;
71         }
72
73         ptr++;
74
75         if ( (entry = getpwuid(getuid())) == NULL) 
76         {
77             continue;
78         }
79
80         strcpy(s, entry->pw_dir);
81         s += strlen(entry->pw_dir);
82     }
83     *s = 0;
84 }
85
86 void ChopOffSlash(char *path)
87 {
88         if (path[strlen(path)-1] == '/' || path[strlen(path)-1] == '\\')
89                 path[strlen(path)-1] = '\0';
90 }
91
92 void ToUnix(char *s)
93 {
94         /*  \WINDOWS\\SYSTEM   =>   /windows/system */
95
96         char *p;
97
98         for (p = s; *p; p++) 
99         {
100                 if (*p != '\\')
101                         *s++ = tolower(*p);
102                 else {
103                         *s++ = '/';
104                         if (*(p+1) == '/' || *(p+1) == '\\')
105                                 p++;
106                 }
107         }
108         *s = '\0';
109 }
110
111 void ToDos(char *s)
112 {
113         /* /windows//system   =>   \WINDOWS\SYSTEM */
114
115         char *p;
116         for (p = s; *p; p++) 
117         {
118                 if (*p != '/')
119                         *s++ = toupper(*p);
120                 else {
121                         *s++ = '\\';
122                         if (*(p+1) == '/' || *(p+1) == '\\') 
123                             p++;
124                 }
125         }
126         *s = '\0';
127 }
128
129 void DOS_InitFS(void)
130 {
131         int x;
132         char drive[2], temp[256];
133
134         GetPrivateProfileString("wine", "windows", "c:\\windows", 
135                 WindowsDirectory, sizeof(WindowsDirectory), WINE_INI);
136
137         GetPrivateProfileString("wine", "system", "c:\\windows\\system", 
138                 SystemDirectory, sizeof(SystemDirectory), WINE_INI);
139
140         GetPrivateProfileString("wine", "temp", "c:\\windows", 
141                 TempDirectory, sizeof(TempDirectory), WINE_INI);
142
143         GetPrivateProfileString("wine", "path", "c:\\windows;c:\\windows\\system", 
144                 WindowsPath, sizeof(WindowsPath), WINE_INI);
145
146         ChopOffSlash(WindowsDirectory);
147         ToDos(WindowsDirectory);
148
149         ChopOffSlash(SystemDirectory);
150         ToDos(SystemDirectory);
151
152         ChopOffSlash(TempDirectory);
153         ToDos(TempDirectory);
154
155         ToDos(WindowsPath);
156         ExpandTildeString(WindowsPath);
157
158         for (x=0; x!=MAX_DOS_DRIVES; x++) {
159                 DosDrives[x].serialnumber = (0xEB0500L | x);
160                 
161                 drive[0] = 'A' + x;
162                 drive[1] = '\0';
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;
169                         continue;
170                 }
171                 ExpandTildeString(temp);
172                 ChopOffSlash(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;
179         }
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;
185
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.
191          */
192         getcwd(temp, 254);
193         strcat(temp, "/");      /* For DOS_GetDosFileName */
194         strcpy(temp, DOS_GetDosFileName(temp));
195         if(temp[0] != 'Z')
196         {
197             ToUnix(&temp[2]);
198             strcpy(DosDrives[temp[0] - 'A'].cwd, &temp[2]);
199             DOS_SetDefaultDrive(temp[0] - 'A');
200         }
201         else
202         {
203             DOS_SetDefaultDrive(2);
204         }
205
206         for (x=0; x!=MAX_DOS_DRIVES; x++) {
207                 if (DosDrives[x].rootdir != NULL) {
208             dprintf_dosfs(stddeb, "DOSFS: %c: => %-40s %s %s %X %d\n",
209                         'A'+x,
210                         DosDrives[x].rootdir,
211                         DosDrives[x].cwd,
212                         DosDrives[x].label,
213                         DosDrives[x].serialnumber,
214                         DosDrives[x].disabled
215                         );      
216                 }
217         }
218
219         for (x=0; x!=MAX_OPEN_DIRS ; x++)
220                 DosDirs[x].inuse = 0;
221
222     dprintf_dosfs(stddeb,"wine.ini = %s\n",WINE_INI);
223     dprintf_dosfs(stddeb,"win.ini = %s\n",WIN_INI);
224     dprintf_dosfs(stddeb,"windir = %s\n",WindowsDirectory);
225     dprintf_dosfs(stddeb,"sysdir = %s\n",SystemDirectory);
226     dprintf_dosfs(stddeb,"tempdir = %s\n",TempDirectory);
227     dprintf_dosfs(stddeb,"path = %s\n",WindowsPath);
228 }
229
230 WORD DOS_GetEquipment(void)
231 {
232         WORD equipment;
233         int diskdrives = 0;
234         int parallelports = 0;
235         int serialports = 0;
236         int x;
237
238 /* borrowed from Ralph Brown's interrupt lists 
239
240                     bits 15-14: number of parallel devices
241                     bit     13: [Conv] Internal modem
242                     bit     12: reserved
243                     bits 11- 9: number of serial devices
244                     bit      8: reserved
245                     bits  7- 6: number of diskette drives minus one
246                     bits  5- 4: Initial video mode:
247                                     00b = EGA,VGA,PGA
248                                     01b = 40 x 25 color
249                                     10b = 80 x 25 color
250                                     11b = 80 x 25 mono
251                     bit      3: reserved
252                     bit      2: [PS] =1 if pointing device
253                                 [non-PS] reserved
254                     bit      1: =1 if math co-processor
255                     bit      0: =1 if diskette available for boot
256 */
257 /*  Currently the only of these bits correctly set are:
258                 bits 15-14              } Added by William Owen Smith, 
259                 bits 11-9               } wos@dcs.warwick.ac.uk
260                 bits 7-6
261                 bit  2                  (always set)
262 */
263
264         if (DosDrives[0].rootdir != NULL)
265                 diskdrives++;
266         if (DosDrives[1].rootdir != NULL)
267                 diskdrives++;
268         if (diskdrives)
269                 diskdrives--;
270         
271         for (x=0; x!=MAX_PORTS; x++) {
272                 if (COM[x].devicename)
273                         serialports++;
274                 if (LPT[x].devicename)
275                         parallelports++;
276         }
277         if (serialports > 7)            /* 3 bits -- maximum value = 7 */
278                 serialports=7;
279         if (parallelports > 3)          /* 2 bits -- maximum value = 3 */
280                 parallelports=3;
281
282         equipment = (diskdrives << 6) | (serialports << 9) | 
283                     (parallelports << 14) | 0x02;
284
285     dprintf_dosfs(stddeb, "DOS_GetEquipment : diskdrives = %d serialports = %d "
286                         "parallelports = %d\n"
287                         "DOS_GetEquipment : equipment = %d\n",
288                         diskdrives, serialports, parallelports, equipment);
289
290         return (equipment);
291 }
292
293 int DOS_ValidDrive(int drive)
294 {
295     dprintf_dosfs(stddeb,"ValidDrive %c (%d)\n",'A'+drive,drive);
296         if (drive >= MAX_DOS_DRIVES)
297                 return 0;
298         if (DosDrives[drive].rootdir == NULL)
299                 return 0;
300         if (DosDrives[drive].disabled)
301                 return 0;
302
303         return 1;
304 }
305
306
307 int DOS_ValidDirectory(char *name)
308 {
309         char *dirname;
310         struct stat s;
311         dprintf_dosfs(stddeb, "DOS_ValidDirectory: '%s'\n", name);
312         if ((dirname = DOS_GetUnixFileName(name)) == NULL)
313                 return 0;
314         if (stat(dirname,&s))
315                 return 0;
316         if (!S_ISDIR(s.st_mode))
317                 return 0;
318         dprintf_dosfs(stddeb, "==> OK\n");
319         return 1;
320 }
321
322
323
324 int DOS_GetDefaultDrive(void)
325 {
326     dprintf_dosfs(stddeb,"GetDefaultDrive (%c)\n",'A'+CurrentDrive);
327         return( CurrentDrive);
328 }
329
330 void DOS_SetDefaultDrive(int drive)
331 {
332     dprintf_dosfs(stddeb,"SetDefaultDrive to %c:\n",'A'+drive);
333         if (DOS_ValidDrive(drive))
334                 CurrentDrive = drive;
335 }
336
337 int DOS_DisableDrive(int drive)
338 {
339         if (drive >= MAX_DOS_DRIVES)
340                 return 0;
341         if (DosDrives[drive].rootdir == NULL)
342                 return 0;
343
344         DosDrives[drive].disabled = 1;
345         return 1;
346 }
347
348 int DOS_EnableDrive(int drive)
349 {
350         if (drive >= MAX_DOS_DRIVES)
351                 return 0;
352         if (DosDrives[drive].rootdir == NULL)
353                 return 0;
354
355         DosDrives[drive].disabled = 0;
356         return 1;
357 }
358
359 static void GetUnixDirName(char *rootdir, char *name)
360 {
361         int filename = 1;
362         char *nameptr, *cwdptr;
363         
364         cwdptr = rootdir + strlen(rootdir);
365         nameptr = name;
366
367         dprintf_dosfs(stddeb,"GetUnixDirName: %s <=> %s => ",rootdir, name);
368
369         while (*nameptr) {
370                 if (*nameptr == '.' & !filename) {
371                         nameptr++;
372                         if (*nameptr == '\0') {
373                                 cwdptr--;
374                                 break;
375                         }
376                         if (*nameptr == '.') {
377                                 cwdptr--;
378                                 while (cwdptr != rootdir) {
379                                         cwdptr--;
380                                         if (*cwdptr == '/') {
381                                                 *(cwdptr+1) = '\0';
382                                                 goto next;
383                                         }
384                                 }
385                                 goto next;
386                         }
387                         if (*nameptr == '\\' || *nameptr == '/') {
388                         next:   nameptr++;              
389                                 filename = 0;
390                                 continue;
391                         }
392                 }
393                 if (*nameptr == '\\' || *nameptr == '/') {
394                         filename = 0;
395                         if (nameptr == name)
396                                 cwdptr = rootdir;
397                         *cwdptr++='/';          
398                         nameptr++;
399                         continue;
400                 }
401                 filename = 1;
402                 *cwdptr++ = *nameptr++;
403         }
404         *cwdptr = '\0';
405
406         ToUnix(rootdir);
407
408         dprintf_dosfs(stddeb,"%s\n", rootdir);
409
410 }
411
412 char *DOS_GetUnixFileName(char *dosfilename)
413
414         /*   a:\windows\system.ini  =>  /dos/windows/system.ini */
415         
416         static char temp[256];
417         int drive;
418
419         if (dosfilename[1] == ':') 
420         {
421                 drive = (islower(*dosfilename) ? toupper(*dosfilename) : *dosfilename) - 'A';
422                 
423                 if (!DOS_ValidDrive(drive))             
424                         return NULL;
425                 else
426                         dosfilename+=2;
427         } else
428                 drive = CurrentDrive;
429
430         /* Expand the filename to it's full path if it doesn't
431          * start from the root.
432          */
433         DOS_ExpandToFullPath(dosfilename, drive);
434
435         strcpy(temp, DosDrives[drive].rootdir);
436         strcat(temp, DosDrives[drive].cwd);
437         GetUnixDirName(temp + strlen(DosDrives[drive].rootdir), dosfilename);
438
439         dprintf_dosfs(stddeb,"GetUnixFileName: %s => %s\n", dosfilename, temp);
440         return(temp);
441 }
442
443 /* Note: This function works on directories as well as long as
444  * the directory ends in a slash.
445  */
446 char *DOS_GetDosFileName(char *unixfilename)
447
448         int i;
449         static char temp[256], rootdir[256];
450         /*   /dos/windows/system.ini => c:\windows\system.ini */
451         
452         /* Expand it if it's a relative name.
453          */
454         DOS_ExpandToFullUnixPath(unixfilename);
455
456         for (i = 0 ; i != MAX_DOS_DRIVES; i++) {
457                 if (DosDrives[i].rootdir != NULL) {
458                         strcpy(rootdir, DosDrives[i].rootdir);
459                         strcat(rootdir, "/");
460                         if (strncmp(rootdir, unixfilename, strlen(rootdir)) == 0) {
461                                 sprintf(temp, "%c:\\%s", 'A' + i, unixfilename + strlen(rootdir));
462                                 ToDos(temp);
463                                 return temp;
464                         }       
465                 }
466         }
467         sprintf(temp, "Z:%s", unixfilename);
468         ToDos(temp);
469         return(temp);
470 }
471
472 char *DOS_GetCurrentDir(int drive)
473
474         /* should return 'WINDOWS\SYSTEM' */
475
476         static char temp[256];
477
478         if (!DOS_ValidDrive(drive)) 
479                 return 0;
480         
481         strcpy(temp, DosDrives[drive].cwd);
482         ToDos(temp);
483         ChopOffSlash(temp);
484
485         dprintf_dosfs(stddeb,"DOS_GetCWD: %c: %s\n",'A'+drive, temp + 1);
486         return (temp + 1);
487 }
488
489 int DOS_ChangeDir(int drive, char *dirname)
490 {
491         char temp[256],old[256];
492
493         if (!DOS_ValidDrive(drive)) 
494                 return 0;
495
496         strcpy(temp, dirname);
497         ToUnix(temp);
498         strcpy(old, DosDrives[drive].cwd);
499         
500         GetUnixDirName(DosDrives[drive].cwd, temp);
501         strcat(DosDrives[drive].cwd,"/");
502
503         dprintf_dosfs(stddeb,"DOS_SetCWD: %c: %s\n",'A'+drive,
504                       DosDrives[drive].cwd);
505
506         if (!DOS_ValidDirectory(DosDrives[drive].cwd))
507         {
508                 strcpy(DosDrives[drive].cwd, old);
509                 return 0;
510         }
511         return 1;
512 }
513
514 int DOS_MakeDir(int drive, char *dirname)
515 {
516         char temp[256];
517         
518         if (!DOS_ValidDrive(drive))
519                 return 0;       
520
521         strcpy(temp, DosDrives[drive].cwd);
522         GetUnixDirName(temp, dirname);
523         strcat(DosDrives[drive].cwd,"/");
524
525         ToUnix(temp + strlen(DosDrives[drive].cwd));
526         mkdir(temp,0);  
527
528         dprintf_dosfs(stddeb,
529                 "DOS_MakeDir: %c:\%s => %s",'A'+drive, dirname, temp);
530         return 1;
531 }
532
533 /* DOS_ExpandToFullPath takes a dos-style filename and converts it
534  * into a full path based on the current working directory.
535  * (e.g., "foo.bar" => "d:\\moo\\foo.bar")
536  */
537 void DOS_ExpandToFullPath(char *filename, int drive)
538 {
539         char temp[256];
540
541         dprintf_dosfs(stddeb, "DOS_ExpandToFullPath: Original = %s\n", filename);
542
543         /* If the filename starts with '/' or '\',
544          * don't bother -- we're already at the root.
545          */
546         if(filename[0] == '/' || filename[0] == '\\')
547             return;
548
549         strcpy(temp, DosDrives[drive].cwd);
550         strcat(temp, filename);
551         strcpy(filename, temp);
552
553         dprintf_dosfs(stddeb, "                      Expanded = %s\n", temp); 
554 }
555
556 /* DOS_ExpandToFullUnixPath takes a unix filename and converts it
557  * into a full path based on the current working directory.  Thus,
558  * it's probably not a good idea to get a relative name, change the
559  * working directory, and then convert it...
560  */
561 void DOS_ExpandToFullUnixPath(char *filename)
562 {
563         char temp[256];
564
565         if(filename[0] == '/')
566             return;
567
568         getcwd(temp, 255);
569         if(strncmp(filename, "./", 2))
570                 strcat(temp, filename + 1);
571         else
572         {
573                 strcat(temp, "/");
574                 strcat(temp, filename);
575         }
576         dprintf_dosfs(stddeb, "DOS_ExpandToFullUnixPath: %s => %s\n", filename, temp);
577         strcpy(filename, temp);
578 }
579
580 int DOS_GetSerialNumber(int drive, unsigned long *serialnumber)
581 {
582         if (!DOS_ValidDrive(drive)) 
583                 return 0;
584
585         *serialnumber = DosDrives[drive].serialnumber;
586         return 1;
587 }
588
589 int DOS_SetSerialNumber(int drive, unsigned long serialnumber)
590 {
591         if (!DOS_ValidDrive(drive)) 
592                 return 0;
593
594         DosDrives[drive].serialnumber = serialnumber;
595         return 1;
596 }
597
598 char *DOS_GetVolumeLabel(int drive)
599 {
600         if (!DOS_ValidDrive(drive)) 
601                 return NULL;
602
603         return (DosDrives[drive].label);
604 }
605
606 int DOS_SetVolumeLabel(int drive, char *label)
607 {
608         if (!DOS_ValidDrive(drive)) 
609                 return 0;
610
611         strncpy(DosDrives[drive].label, label, 8);
612         return 1;
613 }
614
615 int DOS_GetFreeSpace(int drive, long *size, long *available)
616 {
617         struct statfs info;
618
619         if (!DOS_ValidDrive(drive))
620                 return 0;
621
622         if (statfs(DosDrives[drive].rootdir, &info) < 0) {
623                 fprintf(stderr,"dosfs: cannot do statfs(%s)\n",
624                         DosDrives[drive].rootdir);
625                 return 0;
626         }
627
628         *size = info.f_bsize * info.f_blocks;
629         *available = info.f_bavail * info.f_bsize;
630
631         return 1;
632 }
633
634 char *DOS_FindFile(char *buffer, int buflen, char *filename, char **extensions, 
635                 char *path)
636 {
637     char *workingpath, *dirname, *rootname, **e;
638     DIR *d;
639     struct dirent *f;
640     int rootnamelen, found = 0;
641     struct stat filestat;
642
643     if (strchr(filename, '\\') != NULL)
644     {
645         strncpy(buffer, DOS_GetUnixFileName(filename), buflen);
646         stat( buffer, &filestat);
647         if (S_ISREG(filestat.st_mode))
648             return buffer;
649         else
650             return NULL;
651     }
652
653     if (strchr(filename, '/') != NULL)
654     {
655         strncpy(buffer, filename, buflen);
656         return buffer;
657     }
658
659     dprintf_dosfs(stddeb,"DOS_FindFile: looking for %s\n", filename);
660     rootnamelen = strlen(filename);
661     rootname = strdup(filename);
662     ToUnix(rootname);
663     workingpath = strdup(path);
664
665     for(dirname = strtok(workingpath, ";"); 
666         dirname != NULL;
667         dirname = strtok(NULL, ";"))
668     {
669         if (strchr(dirname, '\\') != NULL)
670                 d = opendir( DOS_GetUnixFileName(dirname) );
671         else
672                 d = opendir( dirname );
673
674         dprintf_dosfs(stddeb,"in %s\n",dirname);
675         if (d != NULL)
676         {
677             while ((f = readdir(d)) != NULL)
678             {
679                 if (strncasecmp(rootname, f->d_name, rootnamelen) == 0)
680                 {
681                     if (extensions == NULL || 
682                         strcasecmp(rootname, f->d_name) == 0)
683                                 found = 1;
684                     else 
685                     if (f->d_name[rootnamelen] == '.')
686                         for (e = extensions; *e != NULL; e++)
687                             if (strcasecmp(*e, f->d_name + rootnamelen + 1) 
688                                 == 0)
689                             {
690                                 found = 1;
691                                 break;
692                             }
693
694                     if (found)
695                     {
696                         if (strchr(dirname, '\\') != NULL)
697                                 strncpy(buffer, DOS_GetUnixFileName(dirname), buflen);
698                         else
699                                 strncpy(buffer, dirname, buflen);
700
701                         strncat(buffer, "/", buflen - strlen(buffer));
702                         strncat(buffer, f->d_name, buflen - strlen(buffer));
703
704                         stat(buffer, &filestat);
705                         if (S_ISREG(filestat.st_mode)) {
706                                 closedir(d);
707                                 free(rootname);
708                                 return buffer;
709                         } else 
710                                 found = 0; 
711                     }
712                 }
713             }
714             closedir(d);
715         }
716     }
717     return NULL;
718 }
719
720 /**********************************************************************
721  *              WineIniFileName
722  */
723 char *WineIniFileName(void)
724 {
725         int fd;
726         static char *filename = NULL;
727         static char name[256];
728
729         if (filename)
730                 return filename;
731
732         strcpy(name, WINE_INI_USER);
733         ExpandTildeString(name);
734         if ((fd = open(name, O_RDONLY)) != -1) {
735                 close(fd);
736                 filename = name;
737                 return(filename);
738         }
739         if ((fd = open(WINE_INI_GLOBAL, O_RDONLY)) != -1) {
740                 close(fd);
741                 filename = WINE_INI_GLOBAL;
742                 return(filename);
743         }
744         fprintf(stderr,"wine: can't open configuration file %s or %s !\n", 
745                                 WINE_INI_GLOBAL, WINE_INI_USER);
746         exit(1);
747 }
748
749 char *WinIniFileName(void)
750 {
751         static char *name = NULL;
752         
753         if (name)
754                 return name;
755                 
756         name = malloc(1024);
757
758         strcpy(name, DOS_GetUnixFileName(WindowsDirectory));
759         strcat(name, "/");
760         strcat(name, "win.ini");
761
762         name = realloc(name, strlen(name) + 1);
763         
764         return name;
765 }
766
767 static int match(char *filename, char *filemask)
768 {
769         int x, masklength = strlen(filemask);
770
771         dprintf_dosfs(stddeb, "match: %s, %s\n", filename, filemask);
772         for (x = 0; x != masklength ; x++) {
773 /*              printf("(%c%c) ", *filename, filemask[x]); 
774 */
775                 if (!*filename)
776                         /* stop if EOFname */
777                         return 1;
778
779                 if (filemask[x] == '?') {
780                         /* skip the next char */
781                         filename++;
782                         continue;
783                 }
784
785                 if (filemask[x] == '*') {
786                         /* skip each char until '.' or EOFname */
787                         while (*filename && *filename !='.')
788                                 filename++;
789                         continue;
790                 }
791                 if (filemask[x] != *filename)
792                         return 0;
793
794                 filename++;
795         }
796         return 1;
797 }
798
799 struct dosdirent *DOS_opendir(char *dosdirname)
800 {
801         int x,y;
802         char *unixdirname;
803         char temp[256];
804         
805         for (x=0; x != MAX_OPEN_DIRS && DosDirs[x].inuse; x++)
806                 ;
807
808         if (x == MAX_OPEN_DIRS)
809                 return NULL;
810
811         if ((unixdirname = DOS_GetUnixFileName(dosdirname)) == NULL)
812                 return NULL;
813
814         strcpy(temp, unixdirname);
815         y = strlen(temp);
816         while (y--)
817         {
818                 if (temp[y] == '/') 
819                 {
820                         temp[y++] = '\0';
821                         strcpy(DosDirs[x].filemask, temp +y);
822                         ToDos(DosDirs[x].filemask);
823                         break;
824                 }
825         }
826
827         dprintf_dosfs(stddeb,"DOS_opendir: %s -> %s\n", unixdirname, temp);
828
829         DosDirs[x].inuse = 1;
830         strcpy(DosDirs[x].unixpath, temp);
831
832         if ((DosDirs[x].ds = opendir(temp)) == NULL)
833                 return NULL;
834
835         return &DosDirs[x];
836 }
837
838
839 struct dosdirent *DOS_readdir(struct dosdirent *de)
840 {
841         char temp[256];
842         struct dirent *d;
843         struct stat st;
844
845         if (!de->inuse)
846                 return NULL;
847         
848         do {
849                 if ((d = readdir(de->ds)) == NULL) 
850                         return NULL;
851
852                 strcpy(de->filename, d->d_name);
853                 if (d->d_reclen > 12)
854                         de->filename[12] = '\0';
855                 
856                 ToDos(de->filename);
857         } while ( !match(de->filename, de->filemask) );
858
859         strcpy(temp,de->unixpath);
860         strcat(temp,"/");
861         strcat(temp,de->filename);
862         ToUnix(temp + strlen(de->unixpath));
863
864         stat (temp, &st);
865         de->attribute = 0x0;
866         if S_ISDIR(st.st_mode)
867                 de->attribute |= FA_DIREC;
868         
869         de->filesize = st.st_size;
870         de->filetime = st.st_mtime;
871
872         return de;
873 }
874
875 void DOS_closedir(struct dosdirent *de)
876 {
877         if (de && de->inuse)
878         {
879                 closedir(de->ds);
880                 de->inuse = 0;
881         }
882 }