Release 950727
[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 "task.h"
35 #include "stddebug.h"
36 #include "debug.h"
37
38 #define WINE_INI_USER "~/.winerc"
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 max_open_dirs = 0;
46 static int CurrentDrive = 2;
47
48 struct DosDriveStruct {                 /*  eg: */
49         char            *rootdir;       /*  /usr/windows        */
50         char            cwd[256];       /*  /                   */
51         char            label[13];      /*  DRIVE-A             */
52         unsigned int    serialnumber;   /*  ABCD5678            */
53         int             disabled;       /*  0                   */
54 };
55
56 static struct DosDriveStruct DosDrives[MAX_DOS_DRIVES];
57 static struct dosdirent *DosDirs=NULL;
58
59 static void ExpandTildeString(char *s)
60 {
61     struct passwd *entry;
62     char temp[1024], *ptr = temp;
63         
64     strcpy(temp, s);
65
66     while (*ptr)
67     {
68         if (*ptr != '~') 
69         { 
70             *s++ = *ptr++;
71             continue;
72         }
73
74         ptr++;
75
76         if ( (entry = getpwuid(getuid())) == NULL) 
77         {
78             continue;
79         }
80
81         strcpy(s, entry->pw_dir);
82         s += strlen(entry->pw_dir);
83     }
84     *s = 0;
85 }
86
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)
90 {
91   char *l,*p;
92   BOOL changed;
93
94   dprintf_dosfs(stddeb,"SimplifyPath: Before %s\n",name);
95   do {
96     changed = FALSE;
97     while ((l = strstr(name,"//"))) {
98       strcpy(l,l+1); changed = TRUE;
99     } 
100     while ((l = strstr(name,"/../"))) {
101       *l = 0;
102       p = strrchr(name,'/');
103       if (p == NULL) p = name;
104       strcpy(p,l+3);
105       changed = TRUE;
106     }
107   } while (changed);
108   dprintf_dosfs(stddeb,"SimplifyPath: After %s\n",name);
109 }
110
111
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.
115  */
116
117 void ChopOffSlash(char *path)
118 {
119     char *p = path + strlen(path) - 1;
120     while ((*p == '\\') && (p > path)) *p-- = '\0';
121 }
122
123 void ToUnix(char *s)
124 {
125     while(*s){
126         if (*s == '\\') *s = '/';
127         s++;
128     }
129 }
130
131 void ToDos(char *s)
132 {
133     while(*s){
134         if (*s == '/') *s = '\\';
135         s++;
136     }
137 }
138
139 void DOS_InitFS(void)
140 {
141     int x;
142     char drive[2], temp[256];
143     
144     GetPrivateProfileString("wine", "windows", "c:\\windows", 
145                             WindowsDirectory, sizeof(WindowsDirectory), WINE_INI);
146     
147     GetPrivateProfileString("wine", "system", "c:\\windows\\system", 
148                             SystemDirectory, sizeof(SystemDirectory), WINE_INI);
149     
150     GetPrivateProfileString("wine", "temp", "c:\\windows", 
151                             TempDirectory, sizeof(TempDirectory), WINE_INI);
152
153     GetPrivateProfileString("wine", "path", "c:\\windows;c:\\windows\\system", 
154                             WindowsPath, sizeof(WindowsPath), WINE_INI);
155     
156     ChopOffSlash(WindowsDirectory);
157     ToDos(WindowsDirectory);
158     
159     ChopOffSlash(SystemDirectory);
160     ToDos(SystemDirectory);
161     
162     ChopOffSlash(TempDirectory);
163     ToDos(TempDirectory);
164     
165     ToDos(WindowsPath);
166     ExpandTildeString(WindowsPath);
167     
168     for (x=0; x!=MAX_DOS_DRIVES; x++) {
169         DosDrives[x].serialnumber = (0xEB0500L | x);
170         
171         drive[0] = 'A' + x;
172         drive[1] = '\0';
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;
179             continue;
180         }
181         ExpandTildeString(temp);
182         ChopOffSlash(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;
189     }
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;
195     
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.
201      */
202
203     for (x=0; x!=MAX_DOS_DRIVES; x++) 
204         if (DosDrives[x].rootdir != NULL) 
205             strcpy( DosDrives[x].cwd, "/" );
206
207     getcwd(temp, 254);
208     strcat(temp, "/");      /* For DOS_GetDosFileName */
209     strcpy(temp, DOS_GetDosFileName(temp));
210     if(temp[0] != 'Z')
211     {
212         ToUnix(temp + 2);
213         strcpy(DosDrives[temp[0] - 'A'].cwd, &temp[2]);
214         DOS_SetDefaultDrive(temp[0] - 'A');
215     }
216     else
217     {
218         DOS_SetDefaultDrive(2);
219     }
220     
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",
224                           'A'+x,
225                           DosDrives[x].rootdir,
226                           DosDrives[x].cwd,
227                           DosDrives[x].label,
228                           DosDrives[x].serialnumber,
229                           DosDrives[x].disabled);       
230         }
231     }
232     
233     for (x=0; x!=max_open_dirs ; x++)
234         DosDirs[x].inuse = 0;
235
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);
242 }
243
244 WORD DOS_GetEquipment(void)
245 {
246     WORD equipment;
247     int diskdrives = 0;
248     int parallelports = 0;
249     int serialports = 0;
250     int x;
251
252 /* borrowed from Ralph Brown's interrupt lists 
253
254                     bits 15-14: number of parallel devices
255                     bit     13: [Conv] Internal modem
256                     bit     12: reserved
257                     bits 11- 9: number of serial devices
258                     bit      8: reserved
259                     bits  7- 6: number of diskette drives minus one
260                     bits  5- 4: Initial video mode:
261                                     00b = EGA,VGA,PGA
262                                     01b = 40 x 25 color
263                                     10b = 80 x 25 color
264                                     11b = 80 x 25 mono
265                     bit      3: reserved
266                     bit      2: [PS] =1 if pointing device
267                                 [non-PS] reserved
268                     bit      1: =1 if math co-processor
269                     bit      0: =1 if diskette available for boot
270 */
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
274                 bits 7-6
275                 bit  2                  (always set)
276 */
277
278     if (DosDrives[0].rootdir != NULL)
279         diskdrives++;
280     if (DosDrives[1].rootdir != NULL)
281         diskdrives++;
282     if (diskdrives)
283         diskdrives--;
284         
285     for (x=0; x!=MAX_PORTS; x++) {
286         if (COM[x].devicename)
287             serialports++;
288         if (LPT[x].devicename)
289             parallelports++;
290     }
291     if (serialports > 7)                /* 3 bits -- maximum value = 7 */
292         serialports=7;
293     if (parallelports > 3)              /* 2 bits -- maximum value = 3 */
294         parallelports=3;
295     
296     equipment = (diskdrives << 6) | (serialports << 9) | 
297                 (parallelports << 14) | 0x02;
298
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);
303     
304     return equipment;
305 }
306
307 int DOS_ValidDrive(int drive)
308 {
309     dprintf_dosfs(stddeb,"ValidDrive %c (%d)\n",'A'+drive,drive);
310
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;
314
315     dprintf_dosfs(stddeb, " -- valid\n");
316     return 1;
317 }
318
319 static void DOS_GetCurrDir_Unix(char *buffer, int drive)
320 {
321     TDB *pTask = (TDB *)GlobalLock(GetCurrentTask());
322     
323     if (pTask != NULL && (pTask->curdrive & ~0x80) == drive) {
324         strcpy(buffer, pTask->curdir);
325         ToUnix(buffer);
326     } else {
327         strcpy(buffer, DosDrives[drive].cwd);
328     }
329 }
330
331 char *DOS_GetCurrentDir(int drive)
332
333     static char temp[256];
334
335     if (!DOS_ValidDrive(drive)) return 0;
336
337     DOS_GetCurrDir_Unix(temp, drive);
338     DOS_SimplifyPath( temp );
339     ToDos(temp);
340     ChopOffSlash(temp);
341
342     dprintf_dosfs(stddeb,"DOS_GetCWD: %c:%s\n", 'A'+drive, temp);
343     return temp + 1;
344 }
345
346 char *DOS_GetUnixFileName(const char *dosfilename)
347
348     /*   a:\windows\system.ini  =>  /dos/windows/system.ini */
349     
350     /* FIXME: should handle devices here (like LPT: or NUL:) */
351     
352     static char dostemp[256], temp[256];
353     int drive = DOS_GetDefaultDrive();
354     
355     if (dosfilename[0] && dosfilename[1] == ':')
356     {
357         drive = toupper(*dosfilename) - 'A';
358         dosfilename += 2;
359     }    
360     if (!DOS_ValidDrive(drive)) return NULL;
361
362     strncpy( dostemp, dosfilename, 255 );
363     dostemp[255] = 0;
364     ToUnix(dostemp);
365     strcpy(temp, DosDrives[drive].rootdir);
366     if (dostemp[0] != '/') {
367         DOS_GetCurrDir_Unix(temp+strlen(temp), drive);
368     }
369     strcat(temp, dostemp);
370     DOS_SimplifyPath(temp);
371         
372     dprintf_dosfs(stddeb,"GetUnixFileName: %s => %s\n", dosfilename, temp);
373     return temp;
374 }
375
376 /* Note: This function works on directories as well as long as
377  * the directory ends in a slash.
378  */
379 char *DOS_GetDosFileName(char *unixfilename)
380
381     int i;
382     static char temp[256], temp2[256];
383     /*   /dos/windows/system.ini => c:\windows\system.ini */
384     
385     dprintf_dosfs(stddeb,"DOS_GetDosFileName: %s\n", unixfilename);
386     if (unixfilename[0] == '/') {
387         strncpy(temp, unixfilename, 255);
388         temp[255] = 0;
389     } else {
390         /* Expand it if it's a relative name. */
391         getcwd(temp, 255);
392         if(strncmp(unixfilename, "./", 2) != 0) {
393             strcat(temp, unixfilename + 1);
394         } else {            
395             strcat(temp, "/");
396             strcat(temp, unixfilename);
397         }
398     }
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] == '/')
404             {
405                 sprintf(temp2, "%c:%s", 'A' + i, temp+len);
406                 ToDos(temp2+2);
407                 return temp2;
408             }   
409         }
410     }
411     sprintf(temp, "Z:%s", unixfilename);
412     ToDos(temp+2);
413     return temp;
414 }
415
416 int DOS_ValidDirectory(int drive, char *name)
417 {
418     char temp[256];
419     struct stat s;
420     
421     strcpy(temp, DosDrives[drive].rootdir);
422     strcat(temp, name);
423     if (stat(temp, &s)) return 0;
424     if (!S_ISDIR(s.st_mode)) return 0;
425     dprintf_dosfs(stddeb, "==> OK\n");
426     return 1;
427 }
428
429 int DOS_GetDefaultDrive(void)
430 {
431     TDB *pTask = (TDB *)GlobalLock(GetCurrentTask());
432     int drive = pTask == NULL ? CurrentDrive : pTask->curdrive & ~0x80;
433     
434     dprintf_dosfs(stddeb,"GetDefaultDrive (%c)\n",'A'+drive);
435     return drive;
436 }
437
438 void DOS_SetDefaultDrive(int drive)
439 {
440     TDB *pTask = (TDB *)GlobalLock(GetCurrentTask());
441     
442     dprintf_dosfs(stddeb,"SetDefaultDrive to %c:\n",'A'+drive);
443     if (DOS_ValidDrive(drive) && drive != DOS_GetDefaultDrive()) {
444         if (pTask == NULL) CurrentDrive = drive;
445         else {
446             char temp[256];
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");
454         }
455     }
456 }
457
458 int DOS_DisableDrive(int drive)
459 {
460     if (drive >= MAX_DOS_DRIVES) return 0;
461     if (DosDrives[drive].rootdir == NULL) return 0;
462
463     DosDrives[drive].disabled = 1;
464     return 1;
465 }
466
467 int DOS_EnableDrive(int drive)
468 {
469     if (drive >= MAX_DOS_DRIVES) return 0;
470     if (DosDrives[drive].rootdir == NULL) return 0;
471
472     DosDrives[drive].disabled = 0;
473     return 1;
474 }
475
476 int DOS_ChangeDir(int drive, char *dirname)
477 {
478     TDB *pTask = (TDB *)GlobalLock(GetCurrentTask());
479     char temp[256];
480     
481     if (!DOS_ValidDrive(drive)) return 0;
482
483     if (dirname[0] == '\\') {
484         strcpy(temp, dirname);
485     } else {
486         DOS_GetCurrDir_Unix(temp, drive);
487         strcat(temp, dirname);
488     }
489     ToUnix(temp);
490     strcat(temp, "/");
491     DOS_SimplifyPath(temp);
492     dprintf_dosfs(stddeb,"DOS_SetCWD: %c: %s ==> %s\n", 'A'+drive, dirname, temp);
493
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");
503     }
504     return 1;
505 }
506
507 int DOS_MakeDir(int drive, char *dirname)
508 {
509     char temp[256], currdir[256];
510     
511     if (!DOS_ValidDrive(drive)) return 0;       
512
513     strcpy(temp, DosDrives[drive].rootdir);
514     DOS_GetCurrDir_Unix(currdir, drive);
515     strcat(temp, currdir);
516     strcat(temp, dirname);
517     ToUnix(temp);
518     DOS_SimplifyPath(temp);
519     mkdir(temp,0);      
520     
521     dprintf_dosfs(stddeb, "DOS_MakeDir: %c:\%s => %s",'A'+drive, dirname, temp);
522     return 1;
523 }
524
525 int DOS_GetSerialNumber(int drive, unsigned long *serialnumber)
526 {
527         if (!DOS_ValidDrive(drive)) 
528                 return 0;
529
530         *serialnumber = DosDrives[drive].serialnumber;
531         return 1;
532 }
533
534 int DOS_SetSerialNumber(int drive, unsigned long serialnumber)
535 {
536         if (!DOS_ValidDrive(drive)) 
537                 return 0;
538
539         DosDrives[drive].serialnumber = serialnumber;
540         return 1;
541 }
542
543 char *DOS_GetVolumeLabel(int drive)
544 {
545         if (!DOS_ValidDrive(drive)) 
546                 return NULL;
547
548         return DosDrives[drive].label;
549 }
550
551 int DOS_SetVolumeLabel(int drive, char *label)
552 {
553         if (!DOS_ValidDrive(drive)) 
554                 return 0;
555
556         strncpy(DosDrives[drive].label, label, 8);
557         return 1;
558 }
559
560 int DOS_GetFreeSpace(int drive, long *size, long *available)
561 {
562         struct statfs info;
563
564         if (!DOS_ValidDrive(drive))
565                 return 0;
566
567         if (statfs(DosDrives[drive].rootdir, &info) < 0) {
568                 fprintf(stderr,"dosfs: cannot do statfs(%s)\n",
569                         DosDrives[drive].rootdir);
570                 return 0;
571         }
572
573         *size = info.f_bsize * info.f_blocks;
574         *available = info.f_bavail * info.f_bsize;
575
576         return 1;
577 }
578
579 char *DOS_FindFile(char *buffer, int buflen, char *filename, char **extensions, 
580                 char *path)
581 {
582     char *workingpath, *dirname, *rootname, **e;
583     DIR *d;
584     struct dirent *f;
585     int rootnamelen;
586     struct stat filestat;
587
588     if (strchr(filename, '\\') != NULL)
589     {
590         strncpy(buffer, DOS_GetUnixFileName(filename), buflen);
591         stat( buffer, &filestat);
592         if (S_ISREG(filestat.st_mode))
593             return buffer;
594         else
595             return NULL;
596     }
597
598     if (strchr(filename, '/') != NULL)
599     {
600         strncpy(buffer, filename, buflen);
601         return buffer;
602     }
603
604     dprintf_dosfs(stddeb,"DOS_FindFile: looking for %s\n", filename);
605     rootnamelen = strlen(filename);
606     rootname = strdup(filename);
607     ToUnix(rootname);
608     workingpath = strdup(path);
609
610     for(dirname = strtok(workingpath, ";"); 
611         dirname != NULL;
612         dirname = strtok(NULL, ";"))
613     {
614         if (strchr(dirname, '\\') != NULL)
615                 d = opendir( DOS_GetUnixFileName(dirname) );
616         else
617                 d = opendir( dirname );
618
619         dprintf_dosfs(stddeb,"in %s\n",dirname);
620         if (d != NULL)
621         {
622             while ((f = readdir(d)) != NULL)
623             {           
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] != '.')
628                         continue;
629
630                     for (e = extensions; *e != NULL; e++) {
631                         if (strcasecmp(*e, f->d_name + rootnamelen + 1) == 0)
632                             break;
633                     }
634                     if (*e == NULL) continue;
635                 }
636
637                 if (strchr(dirname, '\\') != NULL) {
638                     strncpy(buffer, DOS_GetUnixFileName(dirname), buflen);
639                 } else {
640                     strncpy(buffer, dirname, buflen);
641                 }
642
643                 strncat(buffer, "/", buflen - strlen(buffer));
644                 strncat(buffer, f->d_name, buflen - strlen(buffer));
645                 
646                 stat(buffer, &filestat);
647                 if (S_ISREG(filestat.st_mode)) {
648                     closedir(d);
649                     free(rootname);
650                     DOS_SimplifyPath(buffer);
651                     return buffer;
652                 } 
653             }
654             closedir(d);
655         }
656     }
657     return NULL;
658 }
659
660 /**********************************************************************
661  *              WineIniFileName
662  */
663 char *WineIniFileName(void)
664 {
665         int fd;
666         static char *filename = NULL;
667         static char name[256];
668
669         if (filename)
670                 return filename;
671
672         strcpy(name, WINE_INI_USER);
673         ExpandTildeString(name);
674         if ((fd = open(name, O_RDONLY)) != -1) {
675                 close(fd);
676                 filename = name;
677                 return filename;
678         }
679         if ((fd = open(WINE_INI_GLOBAL, O_RDONLY)) != -1) {
680                 close(fd);
681                 filename = WINE_INI_GLOBAL;
682                 return filename;
683         }
684         fprintf(stderr,"wine: can't open configuration file %s or %s !\n",
685                 WINE_INI_GLOBAL, WINE_INI_USER);
686         exit(1);
687 }
688
689 char *WinIniFileName(void)
690 {
691         static char *name = NULL;
692         
693         if (name)
694                 return name;
695                 
696         name = malloc(1024);
697
698         strcpy(name, DOS_GetUnixFileName(WindowsDirectory));
699         strcat(name, "/");
700         strcat(name, "win.ini");
701
702         name = realloc(name, strlen(name) + 1);
703         
704         return name;
705 }
706
707 static int match(char *filename, char *filemask)
708 {
709         char name[12], mask[12];
710         int i;
711
712         dprintf_dosfs(stddeb, "match: %s, %s\n", filename, filemask);
713  
714         for( i=0; i<11; i++ ) {
715           name[i] = ' ';
716           mask[i] = ' ';
717         }
718         name[11] = 0;
719         mask[11] = 0; 
720  
721         for( i=0; i<8; i++ )
722           if( !(*filename) || *filename == '.' )
723             break;
724           else
725             name[i] = toupper( *filename++ );
726         while( *filename && *filename != '.' )
727           filename++;
728         if( *filename )
729           filename++;
730         for( i=8; i<11; i++ )
731           if( !(*filename) )
732             break;
733           else
734             name[i] = toupper( *filename++ );
735
736         for( i=0; i<8; i++ )
737           if( !(*filemask) || *filemask == '.' )
738             break;
739           else if( *filemask == '*' ) {
740             int j;
741             for( j=i; j<8; j++ )
742               mask[j] = '?';
743             break;
744           }
745           else
746             mask[i] = toupper( *filemask++ );
747         while( *filemask && *filemask != '.' )
748           filemask++;      
749         if( *filemask )
750           filemask++;
751         for( i=8; i<11; i++ )
752           if( !(*filemask) )
753             break;
754           else if (*filemask == '*' ) {
755             int j;
756             for( j=i; j<11; j++ )
757               mask[j] = '?';
758             break;
759           }
760           else
761             mask[i] = toupper( *filemask++ );
762         
763         dprintf_dosfs(stddeb, "changed to: %s, %s\n", name, mask);
764
765         for( i=0; i<11; i++ )
766           if( ( name[i] != mask[i] ) && ( mask[i] != '?' ) )
767             return 0;
768
769         return 1;
770 }
771
772 struct dosdirent *DOS_opendir(char *dosdirname)
773 {
774     int x, len;
775     char *unixdirname;
776     char dirname[256];
777     DIR  *ds;
778     
779     if ((unixdirname = DOS_GetUnixFileName(dosdirname)) == NULL) return NULL;
780     
781     len = strrchr(unixdirname, '/') - unixdirname + 1;
782     strncpy(dirname, unixdirname, len);
783     dirname[len] = 0;
784     unixdirname = strrchr(unixdirname, '/') + 1;
785
786     for (x=0; x <= max_open_dirs; x++) {
787         if (x == max_open_dirs) {
788             if (DosDirs) {
789                 DosDirs=(struct dosdirent*)realloc(DosDirs,(++max_open_dirs)*sizeof(DosDirs[0]));
790             } else {
791                 DosDirs=(struct dosdirent*)malloc(sizeof(DosDirs[0]));
792                 max_open_dirs=1;
793             }
794             break; /* this one is definitely not in use */
795         }
796         if (!DosDirs[x].inuse) break;
797         if (strcmp(DosDirs[x].unixpath, dirname) == 0) break;
798     }
799     
800     strncpy(DosDirs[x].filemask, unixdirname, 12);
801     DosDirs[x].filemask[12] = 0;
802     dprintf_dosfs(stddeb,"DOS_opendir: %s / %s\n", unixdirname, dirname);
803
804     DosDirs[x].inuse = 1;
805     strcpy(DosDirs[x].unixpath, dirname);
806     DosDirs[x].entnum = 0;
807
808     if ((ds = opendir(dirname)) == NULL) return NULL;
809     if (-1==(DosDirs[x].telldirnum=telldir(ds))) {
810         closedir(ds);
811         return NULL;
812     }
813     if (-1==closedir(ds)) return NULL;
814
815     return &DosDirs[x];
816 }
817
818
819 struct dosdirent *DOS_readdir(struct dosdirent *de)
820 {
821         char temp[256];
822         struct dirent *d;
823         struct stat st;
824         DIR     *ds;
825
826         if (!de->inuse)
827                 return NULL;
828         if (!(ds=opendir(de->unixpath))) return NULL;
829         seekdir(ds,de->telldirnum); /* returns no error value. strange */
830    
831         if (de->search_attribute & FA_LABEL)  { 
832             int drive;
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)
837                 {
838                     strcpy(de->filename, DOS_GetVolumeLabel(drive));
839                     de->attribute = FA_LABEL;
840                     return de;
841                 }
842             }
843         }
844     
845         do {
846             if ((d = readdir(ds)) == NULL)  {
847                 de->telldirnum=telldir(ds);
848                 closedir(ds);
849                 return NULL;
850             }
851
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';
856
857             ToDos(de->filename);
858         } while ( !match(de->filename, de->filemask) );
859
860         strcpy(temp,de->unixpath);
861         strcat(temp,"/");
862         strcat(temp,de->filename);
863         ToUnix(temp + strlen(de->unixpath));
864
865         stat (temp, &st);
866         de->attribute = 0x0;
867         if S_ISDIR(st.st_mode)
868                 de->attribute |= FA_DIREC;
869         
870         de->filesize = st.st_size;
871         de->filetime = st.st_mtime;
872
873         de->telldirnum = telldir(ds);
874         closedir(ds);
875         return de;
876 }
877
878 void DOS_closedir(struct dosdirent *de)
879 {
880         if (de && de->inuse)
881                 de->inuse = 0;
882 }
883
884 char *DOS_GetRedirectedDir(int drive)
885 {
886     if(DOS_ValidDrive(drive))
887         return (DosDrives[drive].rootdir);
888     else
889         return ("/");
890 }