Release 950817
[wine.git] / misc / dos_fs.c
blob322ddabaeb55e8803bad5cf135866a60f032d641
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 <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>
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
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"
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 */
53 int disabled; /* 0 */
56 static struct DosDriveStruct DosDrives[MAX_DOS_DRIVES];
57 static struct dosdirent *DosDirs=NULL;
59 static void ExpandTildeString(char *s)
61 struct passwd *entry;
62 char temp[1024], *ptr = temp;
64 strcpy(temp, s);
66 while (*ptr)
68 if (*ptr != '~')
70 *s++ = *ptr++;
71 continue;
74 ptr++;
76 if ( (entry = getpwuid(getuid())) == NULL)
78 continue;
81 strcpy(s, entry->pw_dir);
82 s += strlen(entry->pw_dir);
84 *s = 0;
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)
91 char *l,*p;
92 BOOL changed;
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;
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;
107 } while (changed);
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';
123 void ToUnix(char *s)
125 while(*s){
126 if (*s == '\\') *s = '/';
127 *s=tolower(*s); /* umsdos fs can't read files without :( */
128 s++;
132 void ToDos(char *s)
134 while(*s){
135 if (*s == '/') *s = '\\';
136 s++;
140 void DOS_InitFS(void)
142 int x;
143 char drive[2], temp[256];
145 GetPrivateProfileString("wine", "windows", "c:\\windows",
146 WindowsDirectory, sizeof(WindowsDirectory), WINE_INI);
148 GetPrivateProfileString("wine", "system", "c:\\windows\\system",
149 SystemDirectory, sizeof(SystemDirectory), WINE_INI);
151 GetPrivateProfileString("wine", "temp", "c:\\windows",
152 TempDirectory, sizeof(TempDirectory), WINE_INI);
154 GetPrivateProfileString("wine", "path", "c:\\windows;c:\\windows\\system",
155 WindowsPath, sizeof(WindowsPath), WINE_INI);
157 ChopOffSlash(WindowsDirectory);
158 ToDos(WindowsDirectory);
160 ChopOffSlash(SystemDirectory);
161 ToDos(SystemDirectory);
163 ChopOffSlash(TempDirectory);
164 ToDos(TempDirectory);
166 ToDos(WindowsPath);
167 ExpandTildeString(WindowsPath);
169 for (x=0; x!=MAX_DOS_DRIVES; x++) {
170 DosDrives[x].serialnumber = (0xEB0500L | x);
172 drive[0] = 'A' + x;
173 drive[1] = '\0';
174 GetPrivateProfileString("drives", drive, "*", temp, sizeof(temp), WINE_INI);
175 if (!strcmp(temp, "*") || *temp == '\0') {
176 DosDrives[x].rootdir = NULL;
177 DosDrives[x].cwd[0] = '\0';
178 DosDrives[x].label[0] = '\0';
179 DosDrives[x].disabled = 1;
180 continue;
182 ExpandTildeString(temp);
183 ChopOffSlash(temp);
184 DosDrives[x].rootdir = strdup(temp);
185 strcpy(DosDrives[x].rootdir, temp);
186 strcpy(DosDrives[x].cwd, "/windows/");
187 strcpy(DosDrives[x].label, "DRIVE-");
188 strcat(DosDrives[x].label, drive);
189 DosDrives[x].disabled = 0;
191 DosDrives[25].rootdir = "/";
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, "/" );
207 getcwd(temp, 254);
208 strcat(temp, "/"); /* For DOS_GetDosFileName */
209 strcpy(DosDrives[25].cwd, temp );
210 strcpy(temp, DOS_GetDosFileName(temp));
211 if(temp[0] != 'Z')
213 ToUnix(temp + 2);
214 strcpy(DosDrives[temp[0] - 'A'].cwd, &temp[2]);
215 DOS_SetDefaultDrive(temp[0] - 'A');
217 else
219 DOS_SetDefaultDrive(2);
222 for (x=0; x!=MAX_DOS_DRIVES; x++) {
223 if (DosDrives[x].rootdir != NULL) {
224 dprintf_dosfs(stddeb, "DOSFS: %c: => %-40s %s %s %X %d\n",
225 'A'+x,
226 DosDrives[x].rootdir,
227 DosDrives[x].cwd,
228 DosDrives[x].label,
229 DosDrives[x].serialnumber,
230 DosDrives[x].disabled);
234 for (x=0; x!=max_open_dirs ; x++)
235 DosDirs[x].inuse = 0;
237 dprintf_dosfs(stddeb,"wine.ini = %s\n",WINE_INI);
238 dprintf_dosfs(stddeb,"win.ini = %s\n",WIN_INI);
239 dprintf_dosfs(stddeb,"windir = %s\n",WindowsDirectory);
240 dprintf_dosfs(stddeb,"sysdir = %s\n",SystemDirectory);
241 dprintf_dosfs(stddeb,"tempdir = %s\n",TempDirectory);
242 dprintf_dosfs(stddeb,"path = %s\n",WindowsPath);
245 WORD DOS_GetEquipment(void)
247 WORD equipment;
248 int diskdrives = 0;
249 int parallelports = 0;
250 int serialports = 0;
251 int x;
253 /* borrowed from Ralph Brown's interrupt lists
255 bits 15-14: number of parallel devices
256 bit 13: [Conv] Internal modem
257 bit 12: reserved
258 bits 11- 9: number of serial devices
259 bit 8: reserved
260 bits 7- 6: number of diskette drives minus one
261 bits 5- 4: Initial video mode:
262 00b = EGA,VGA,PGA
263 01b = 40 x 25 color
264 10b = 80 x 25 color
265 11b = 80 x 25 mono
266 bit 3: reserved
267 bit 2: [PS] =1 if pointing device
268 [non-PS] reserved
269 bit 1: =1 if math co-processor
270 bit 0: =1 if diskette available for boot
272 /* Currently the only of these bits correctly set are:
273 bits 15-14 } Added by William Owen Smith,
274 bits 11-9 } wos@dcs.warwick.ac.uk
275 bits 7-6
276 bit 2 (always set)
279 if (DosDrives[0].rootdir != NULL)
280 diskdrives++;
281 if (DosDrives[1].rootdir != NULL)
282 diskdrives++;
283 if (diskdrives)
284 diskdrives--;
286 for (x=0; x!=MAX_PORTS; x++) {
287 if (COM[x].devicename)
288 serialports++;
289 if (LPT[x].devicename)
290 parallelports++;
292 if (serialports > 7) /* 3 bits -- maximum value = 7 */
293 serialports=7;
294 if (parallelports > 3) /* 2 bits -- maximum value = 3 */
295 parallelports=3;
297 equipment = (diskdrives << 6) | (serialports << 9) |
298 (parallelports << 14) | 0x02;
300 dprintf_dosfs(stddeb, "DOS_GetEquipment : diskdrives = %d serialports = %d "
301 "parallelports = %d\n"
302 "DOS_GetEquipment : equipment = %d\n",
303 diskdrives, serialports, parallelports, equipment);
305 return equipment;
308 int DOS_ValidDrive(int drive)
310 dprintf_dosfs(stddeb,"ValidDrive %c (%d)\n",'A'+drive,drive);
312 if (drive < 0 || drive >= MAX_DOS_DRIVES) return 0;
313 if (DosDrives[drive].rootdir == NULL) return 0;
314 if (DosDrives[drive].disabled) return 0;
316 dprintf_dosfs(stddeb, " -- valid\n");
317 return 1;
320 static void DOS_GetCurrDir_Unix(char *buffer, int drive)
322 TDB *pTask = (TDB *)GlobalLock(GetCurrentTask());
324 if (pTask != NULL && (pTask->curdrive & ~0x80) == drive) {
325 strcpy(buffer, pTask->curdir);
326 ToUnix(buffer);
327 } else {
328 strcpy(buffer, DosDrives[drive].cwd);
332 char *DOS_GetCurrentDir(int drive)
334 static char temp[256];
336 if (!DOS_ValidDrive(drive)) return 0;
338 DOS_GetCurrDir_Unix(temp, drive);
339 DOS_SimplifyPath( temp );
340 ToDos(temp);
341 ChopOffSlash(temp);
343 dprintf_dosfs(stddeb,"DOS_GetCWD: %c:%s\n", 'A'+drive, temp);
344 return temp + 1;
347 char *DOS_GetUnixFileName(const char *dosfilename)
349 /* a:\windows\system.ini => /dos/windows/system.ini */
351 /* FIXME: should handle devices here (like LPT: or NUL:) */
353 static char dostemp[256], temp[256];
354 int drive = DOS_GetDefaultDrive();
356 if (dosfilename[0] && dosfilename[1] == ':')
358 drive = toupper(*dosfilename) - 'A';
359 dosfilename += 2;
361 if (!DOS_ValidDrive(drive)) return NULL;
363 strncpy( dostemp, dosfilename, 255 );
364 dostemp[255] = 0;
365 ToUnix(dostemp);
366 strcpy(temp, DosDrives[drive].rootdir);
367 if (dostemp[0] != '/') {
368 DOS_GetCurrDir_Unix(temp+strlen(temp), drive);
370 strcat(temp, dostemp);
371 DOS_SimplifyPath(temp);
373 dprintf_dosfs(stddeb,"GetUnixFileName: %s => %s\n", dosfilename, temp);
374 return temp;
377 /* Note: This function works on directories as well as long as
378 * the directory ends in a slash.
380 char *DOS_GetDosFileName(char *unixfilename)
382 int i;
383 static char temp[256], temp2[256];
384 /* /dos/windows/system.ini => c:\windows\system.ini */
386 dprintf_dosfs(stddeb,"DOS_GetDosFileName: %s\n", unixfilename);
387 if (unixfilename[0] == '/') {
388 strncpy(temp, unixfilename, 255);
389 temp[255] = 0;
390 } else {
391 /* Expand it if it's a relative name. */
392 getcwd(temp, 255);
393 if(strncmp(unixfilename, "./", 2) != 0) {
394 strcat(temp, unixfilename + 1);
395 } else {
396 strcat(temp, "/");
397 strcat(temp, unixfilename);
400 for (i = 0 ; i < MAX_DOS_DRIVES; i++) {
401 if (DosDrives[i].rootdir != NULL) {
402 int len = strlen(DosDrives[i].rootdir);
403 dprintf_dosfs(stddeb, " check %c:%s\n", i+'A', DosDrives[i].rootdir);
404 if (strncmp(DosDrives[i].rootdir, temp, len) == 0 && temp[len] == '/')
406 sprintf(temp2, "%c:%s", 'A' + i, temp+len);
407 ToDos(temp2+2);
408 return temp2;
412 sprintf(temp, "Z:%s", unixfilename);
413 ToDos(temp+2);
414 return temp;
417 int DOS_ValidDirectory(int drive, char *name)
419 char temp[256];
420 struct stat s;
422 strcpy(temp, DosDrives[drive].rootdir);
423 strcat(temp, name);
424 if (stat(temp, &s)) return 0;
425 if (!S_ISDIR(s.st_mode)) return 0;
426 dprintf_dosfs(stddeb, "==> OK\n");
427 return 1;
430 int DOS_GetDefaultDrive(void)
432 TDB *pTask = (TDB *)GlobalLock(GetCurrentTask());
433 int drive = pTask == NULL ? CurrentDrive : pTask->curdrive & ~0x80;
435 dprintf_dosfs(stddeb,"GetDefaultDrive (%c)\n",'A'+drive);
436 return drive;
439 void DOS_SetDefaultDrive(int drive)
441 TDB *pTask = (TDB *)GlobalLock(GetCurrentTask());
443 dprintf_dosfs(stddeb,"SetDefaultDrive to %c:\n",'A'+drive);
444 if (DOS_ValidDrive(drive) && drive != DOS_GetDefaultDrive()) {
445 if (pTask == NULL) CurrentDrive = drive;
446 else {
447 char temp[256];
448 pTask->curdrive = drive | 0x80;
449 strcpy(temp, DosDrives[drive].rootdir);
450 strcat(temp, DosDrives[drive].cwd);
451 strcpy(temp, DOS_GetDosFileName(temp));
452 dprintf_dosfs(stddeb, " curdir = %s\n", temp);
453 if (strlen(temp)-2 < sizeof(pTask->curdir)) strcpy(pTask->curdir, temp+2);
454 else fprintf(stderr, "dosfs: curdir too long\n");
459 int DOS_DisableDrive(int drive)
461 if (drive >= MAX_DOS_DRIVES) return 0;
462 if (DosDrives[drive].rootdir == NULL) return 0;
464 DosDrives[drive].disabled = 1;
465 return 1;
468 int DOS_EnableDrive(int drive)
470 if (drive >= MAX_DOS_DRIVES) return 0;
471 if (DosDrives[drive].rootdir == NULL) return 0;
473 DosDrives[drive].disabled = 0;
474 return 1;
477 int DOS_ChangeDir(int drive, char *dirname)
479 TDB *pTask = (TDB *)GlobalLock(GetCurrentTask());
480 char temp[256];
482 if (!DOS_ValidDrive(drive)) return 0;
484 if (dirname[0] == '\\') {
485 strcpy(temp, dirname);
486 } else {
487 DOS_GetCurrDir_Unix(temp, drive);
488 strcat(temp, dirname);
490 ToUnix(temp);
491 strcat(temp, "/");
492 DOS_SimplifyPath(temp);
493 dprintf_dosfs(stddeb,"DOS_SetCWD: %c: %s ==> %s\n", 'A'+drive, dirname, temp);
495 if (!DOS_ValidDirectory(drive, temp)) return 0;
496 strcpy(DosDrives[drive].cwd, temp);
497 if (pTask != NULL && DOS_GetDefaultDrive() == drive) {
498 strcpy(temp, DosDrives[drive].rootdir);
499 strcat(temp, DosDrives[drive].cwd);
500 strcpy(temp, DOS_GetDosFileName(temp));
501 dprintf_dosfs(stddeb, " curdir = %s\n", temp);
502 if (strlen(temp)-2 < sizeof(pTask->curdir)) strcpy(pTask->curdir, temp+2);
503 else fprintf(stderr, "dosfs: curdir too long\n");
505 return 1;
508 int DOS_MakeDir(int drive, char *dirname)
510 char temp[256], currdir[256];
512 if (!DOS_ValidDrive(drive)) return 0;
514 strcpy(temp, DosDrives[drive].rootdir);
515 DOS_GetCurrDir_Unix(currdir, drive);
516 strcat(temp, currdir);
517 strcat(temp, dirname);
518 ToUnix(temp);
519 DOS_SimplifyPath(temp);
520 mkdir(temp,0);
522 dprintf_dosfs(stddeb, "DOS_MakeDir: %c:\%s => %s",'A'+drive, dirname, temp);
523 return 1;
526 int DOS_GetSerialNumber(int drive, unsigned long *serialnumber)
528 if (!DOS_ValidDrive(drive))
529 return 0;
531 *serialnumber = DosDrives[drive].serialnumber;
532 return 1;
535 int DOS_SetSerialNumber(int drive, unsigned long serialnumber)
537 if (!DOS_ValidDrive(drive))
538 return 0;
540 DosDrives[drive].serialnumber = serialnumber;
541 return 1;
544 char *DOS_GetVolumeLabel(int drive)
546 if (!DOS_ValidDrive(drive))
547 return NULL;
549 return DosDrives[drive].label;
552 int DOS_SetVolumeLabel(int drive, char *label)
554 if (!DOS_ValidDrive(drive))
555 return 0;
557 strncpy(DosDrives[drive].label, label, 8);
558 return 1;
561 int DOS_GetFreeSpace(int drive, long *size, long *available)
563 struct statfs info;
565 if (!DOS_ValidDrive(drive))
566 return 0;
568 if (statfs(DosDrives[drive].rootdir, &info) < 0) {
569 fprintf(stderr,"dosfs: cannot do statfs(%s)\n",
570 DosDrives[drive].rootdir);
571 return 0;
574 *size = info.f_bsize * info.f_blocks;
575 *available = info.f_bavail * info.f_bsize;
577 return 1;
580 char *DOS_FindFile(char *buffer, int buflen, char *filename, char **extensions,
581 char *path)
583 char *workingpath, *dirname, *rootname, **e;
584 DIR *d;
585 struct dirent *f;
586 int rootnamelen;
587 struct stat filestat;
589 if (strchr(filename, '\\') != NULL)
591 strncpy(buffer, DOS_GetUnixFileName(filename), buflen);
592 stat( buffer, &filestat);
593 if (S_ISREG(filestat.st_mode))
594 return buffer;
595 else
596 return NULL;
599 if (strchr(filename, '/') != NULL)
601 strncpy(buffer, filename, buflen);
602 return buffer;
605 dprintf_dosfs(stddeb,"DOS_FindFile: looking for %s\n", filename);
606 rootnamelen = strlen(filename);
607 rootname = strdup(filename);
608 ToUnix(rootname);
609 workingpath = strdup(path);
611 for(dirname = strtok(workingpath, ";");
612 dirname != NULL;
613 dirname = strtok(NULL, ";"))
615 if (strchr(dirname, '\\') != NULL)
616 d = opendir( DOS_GetUnixFileName(dirname) );
617 else
618 d = opendir( dirname );
620 dprintf_dosfs(stddeb,"in %s\n",dirname);
621 if (d != NULL)
623 while ((f = readdir(d)) != NULL)
625 if (strcasecmp(rootname, f->d_name) != 0) {
626 if (strncasecmp(rootname, f->d_name, rootnamelen) != 0
627 || extensions == NULL
628 || f->d_name[rootnamelen] != '.')
629 continue;
631 for (e = extensions; *e != NULL; e++) {
632 if (strcasecmp(*e, f->d_name + rootnamelen + 1) == 0)
633 break;
635 if (*e == NULL) continue;
638 if (strchr(dirname, '\\') != NULL) {
639 strncpy(buffer, DOS_GetUnixFileName(dirname), buflen);
640 } else {
641 strncpy(buffer, dirname, buflen);
644 strncat(buffer, "/", buflen - strlen(buffer));
645 strncat(buffer, f->d_name, buflen - strlen(buffer));
647 stat(buffer, &filestat);
648 if (S_ISREG(filestat.st_mode)) {
649 closedir(d);
650 free(rootname);
651 DOS_SimplifyPath(buffer);
652 return buffer;
655 closedir(d);
658 return NULL;
661 /**********************************************************************
662 * WineIniFileName
664 char *WineIniFileName(void)
666 int fd;
667 static char *filename = NULL;
668 static char name[256];
670 if (filename)
671 return filename;
673 strcpy(name, WINE_INI_USER);
674 ExpandTildeString(name);
675 if ((fd = open(name, O_RDONLY)) != -1) {
676 close(fd);
677 filename = name;
678 return filename;
680 if ((fd = open(WINE_INI_GLOBAL, O_RDONLY)) != -1) {
681 close(fd);
682 filename = WINE_INI_GLOBAL;
683 return filename;
685 fprintf(stderr,"wine: can't open configuration file %s or %s !\n",
686 WINE_INI_GLOBAL, WINE_INI_USER);
687 exit(1);
690 char *WinIniFileName(void)
692 static char *name = NULL;
694 if (name)
695 return name;
697 name = malloc(1024);
699 strcpy(name, DOS_GetUnixFileName(WindowsDirectory));
700 strcat(name, "/");
701 strcat(name, "win.ini");
703 name = realloc(name, strlen(name) + 1);
705 return name;
708 static int match(char *filename, char *filemask)
710 char name[12], mask[12];
711 int i;
713 dprintf_dosfs(stddeb, "match: %s, %s\n", filename, filemask);
715 for( i=0; i<11; i++ ) {
716 name[i] = ' ';
717 mask[i] = ' ';
719 name[11] = 0;
720 mask[11] = 0;
722 for( i=0; i<8; i++ )
723 if( !(*filename) || *filename == '.' )
724 break;
725 else
726 name[i] = toupper( *filename++ );
727 while( *filename && *filename != '.' )
728 filename++;
729 if( *filename )
730 filename++;
731 for( i=8; i<11; i++ )
732 if( !(*filename) )
733 break;
734 else
735 name[i] = toupper( *filename++ );
737 for( i=0; i<8; i++ )
738 if( !(*filemask) || *filemask == '.' )
739 break;
740 else if( *filemask == '*' ) {
741 int j;
742 for( j=i; j<8; j++ )
743 mask[j] = '?';
744 break;
746 else
747 mask[i] = toupper( *filemask++ );
748 while( *filemask && *filemask != '.' )
749 filemask++;
750 if( *filemask )
751 filemask++;
752 for( i=8; i<11; i++ )
753 if( !(*filemask) )
754 break;
755 else if (*filemask == '*' ) {
756 int j;
757 for( j=i; j<11; j++ )
758 mask[j] = '?';
759 break;
761 else
762 mask[i] = toupper( *filemask++ );
764 dprintf_dosfs(stddeb, "changed to: %s, %s\n", name, mask);
766 for( i=0; i<11; i++ )
767 if( ( name[i] != mask[i] ) && ( mask[i] != '?' ) )
768 return 0;
770 return 1;
773 struct dosdirent *DOS_opendir(char *dosdirname)
775 int x, len;
776 char *unixdirname;
777 char dirname[256];
778 DIR *ds;
780 if ((unixdirname = DOS_GetUnixFileName(dosdirname)) == NULL) return NULL;
782 len = strrchr(unixdirname, '/') - unixdirname + 1;
783 strncpy(dirname, unixdirname, len);
784 dirname[len] = 0;
785 unixdirname = strrchr(unixdirname, '/') + 1;
787 for (x=0; x <= max_open_dirs; x++) {
788 if (x == max_open_dirs) {
789 if (DosDirs) {
790 DosDirs=(struct dosdirent*)realloc(DosDirs,(++max_open_dirs)*sizeof(DosDirs[0]));
791 } else {
792 DosDirs=(struct dosdirent*)malloc(sizeof(DosDirs[0]));
793 max_open_dirs=1;
795 break; /* this one is definitely not in use */
797 if (!DosDirs[x].inuse) break;
798 if (strcmp(DosDirs[x].unixpath, dirname) == 0) break;
801 strncpy(DosDirs[x].filemask, unixdirname, 12);
802 DosDirs[x].filemask[12] = 0;
803 dprintf_dosfs(stddeb,"DOS_opendir: %s / %s\n", unixdirname, dirname);
805 DosDirs[x].inuse = 1;
806 strcpy(DosDirs[x].unixpath, dirname);
807 DosDirs[x].entnum = 0;
809 if ((ds = opendir(dirname)) == NULL) return NULL;
810 if (-1==(DosDirs[x].telldirnum=telldir(ds))) {
811 closedir(ds);
812 return NULL;
814 if (-1==closedir(ds)) return NULL;
816 return &DosDirs[x];
820 struct dosdirent *DOS_readdir(struct dosdirent *de)
822 char temp[256];
823 struct dirent *d;
824 struct stat st;
825 DIR *ds;
827 if (!de->inuse)
828 return NULL;
829 if (!(ds=opendir(de->unixpath))) return NULL;
830 seekdir(ds,de->telldirnum); /* returns no error value. strange */
832 if (de->search_attribute & FA_LABEL) {
833 int drive;
834 de->search_attribute &= ~FA_LABEL; /* don't find it again */
835 for(drive = 0; drive < MAX_DOS_DRIVES; drive++) {
836 if (DosDrives[drive].rootdir != NULL &&
837 strcmp(DosDrives[drive].rootdir, de->unixpath) == 0)
839 strcpy(de->filename, DOS_GetVolumeLabel(drive));
840 de->attribute = FA_LABEL;
841 return de;
846 do {
847 if ((d = readdir(ds)) == NULL) {
848 de->telldirnum=telldir(ds);
849 closedir(ds);
850 return NULL;
853 de->entnum++; /* Increment the directory entry number */
854 strcpy(de->filename, d->d_name);
855 if (d->d_reclen > 12)
856 de->filename[12] = '\0';
858 ToDos(de->filename);
859 } while ( !match(de->filename, de->filemask) );
861 strcpy(temp,de->unixpath);
862 strcat(temp,"/");
863 strcat(temp,de->filename);
864 ToUnix(temp + strlen(de->unixpath));
866 stat (temp, &st);
867 de->attribute = 0x0;
868 if S_ISDIR(st.st_mode)
869 de->attribute |= FA_DIREC;
871 de->filesize = st.st_size;
872 de->filetime = st.st_mtime;
874 de->telldirnum = telldir(ds);
875 closedir(ds);
876 return de;
879 void DOS_closedir(struct dosdirent *de)
881 if (de && de->inuse)
882 de->inuse = 0;
885 char *DOS_GetRedirectedDir(int drive)
887 if(DOS_ValidDrive(drive))
888 return (DosDrives[drive].rootdir);
889 else
890 return ("/");