Release 940405
[wine.git] / misc / dos_fs.c
blob9c9e9ef6fbea55a4d6599b00faa5f19cf4139290
1 /*
2 * DOS-FS
3 * NOV 1993 Erik Bos (erik@(trashcan.)hacktic.nl)
5 * FindFile by Bob, hacked for dos & unixpaths by Erik.
6 */
8 #include <ctype.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/stat.h>
13 #include <pwd.h>
14 #include <dirent.h>
15 #include <unistd.h>
16 #include <fcntl.h>
18 #if defined(__linux__) || defined(sun)
19 #include <sys/vfs.h>
20 #endif
21 #if defined(__NetBSD__) || defined(__FreeBSD__)
22 #include <sys/types.h>
23 #include <sys/mount.h>
24 #endif
26 #include "windows.h"
27 #include "msdos.h"
28 #include "prototypes.h"
29 #include "autoconf.h"
31 /* #define DEBUG */
33 #define WINE_INI_USER "~/.winerc"
34 #define MAX_OPEN_DIRS 16
35 #define MAX_DOS_DRIVES 26
37 extern char WindowsDirectory[256], SystemDirectory[256],TempDirectory[256];
39 char WindowsPath[256];
41 static int CurrentDrive = 2;
43 struct DosDriveStruct { /* eg: */
44 char *rootdir; /* /usr/windows */
45 char cwd[256]; /* / */
46 char label[13]; /* DRIVE-A */
47 unsigned int serialnumber; /* ABCD5678 */
48 int disabled; /* 0 */
51 static struct DosDriveStruct DosDrives[MAX_DOS_DRIVES];
52 static struct dosdirent DosDirs[MAX_OPEN_DIRS];
54 static void ExpandTildeString(char *s)
56 struct passwd *entry;
57 char temp[1024], *ptr = temp;
59 strcpy(temp, s);
60 while (*ptr)
62 if (*ptr != '~') {
63 *s++ = *ptr++;
64 continue;
66 ptr++;
67 if ( (entry = getpwuid(getuid())) == NULL) {
68 continue;
70 strcpy(s, entry->pw_dir);
71 s += strlen(entry->pw_dir);
75 void ChopOffSlash(char *path)
77 if (path[strlen(path)-1] == '/' || path[strlen(path)-1] == '\\')
78 path[strlen(path)-1] = '\0';
81 void DOS_InitFS(void)
83 int x;
84 char drive[2], temp[256], *ptr;
86 GetPrivateProfileString("wine", "windows", "c:\\windows",
87 WindowsDirectory, sizeof(WindowsDirectory), WINE_INI);
89 GetPrivateProfileString("wine", "system", "c:\\windows\\system",
90 SystemDirectory, sizeof(SystemDirectory), WINE_INI);
92 GetPrivateProfileString("wine", "temp", "c:\\windows",
93 TempDirectory, sizeof(TempDirectory), WINE_INI);
95 GetPrivateProfileString("wine", "path", "c:\\windows;c:\\windows\\system",
96 WindowsPath, sizeof(WindowsPath), WINE_INI);
98 ChopOffSlash(WindowsDirectory);
99 ToDos(WindowsDirectory);
101 ChopOffSlash(SystemDirectory);
102 ToDos(SystemDirectory);
104 ChopOffSlash(TempDirectory);
105 ToDos(TempDirectory);
107 ToDos(WindowsPath);
108 ExpandTildeString(WindowsPath);
110 for (x=0; x!=MAX_DOS_DRIVES; x++) {
111 DosDrives[x].serialnumber = (0xEB0500L | x);
113 drive[0] = 'A' + x;
114 drive[1] = '\0';
115 GetPrivateProfileString("drives", drive, "*", temp, sizeof(temp), WINE_INI);
116 if (!strcmp(temp, "*") || *temp == '\0') {
117 DosDrives[x].rootdir = NULL;
118 DosDrives[x].cwd[0] = '\0';
119 DosDrives[x].label[0] = '\0';
120 DosDrives[x].disabled = 1;
121 continue;
123 ExpandTildeString(temp);
124 if ((ptr = (char *) malloc(strlen(temp)+1)) == NULL) {
125 fprintf(stderr,"DOSFS: can't malloc for drive info!");
126 continue;
128 ChopOffSlash(temp);
129 DosDrives[x].rootdir = ptr;
130 strcpy(DosDrives[x].rootdir, temp);
131 strcpy(DosDrives[x].cwd, "/windows/");
132 strcpy(DosDrives[x].label, "DRIVE-");
133 strcat(DosDrives[x].label, drive);
134 DosDrives[x].disabled = 0;
136 DOS_SetDefaultDrive(2);
138 for (x=0; x!=MAX_DOS_DRIVES; x++) {
139 if (DosDrives[x].rootdir != NULL) {
140 #ifdef DEBUG
141 fprintf(stderr, "DOSFS: %c: => %-40s %s %s %X %d\n",
142 'A'+x,
143 DosDrives[x].rootdir,
144 DosDrives[x].cwd,
145 DosDrives[x].label,
146 DosDrives[x].serialnumber,
147 DosDrives[x].disabled
149 #endif
153 for (x=0; x!=MAX_OPEN_DIRS ; x++)
154 DosDirs[x].inuse = 0;
156 #ifdef DEBUG
157 fprintf(stderr,"wine.ini = %s\n",WINE_INI);
158 fprintf(stderr,"win.ini = %s\n",WIN_INI);
159 fprintf(stderr,"windir = %s\n",WindowsDirectory);
160 fprintf(stderr,"sysdir = %s\n",SystemDirectory);
161 fprintf(stderr,"tempdir = %s\n",TempDirectory);
162 fprintf(stderr,"path = %s\n",WindowsPath);
163 #endif
166 WORD DOS_GetEquipment(void)
168 WORD equipment;
169 int diskdrives = 0;
171 /* borrowed from Ralph Brown's interrupt lists
173 bits 15-14: number of parallel devices
174 bit 13: [Conv] Internal modem
175 bit 12: reserved
176 bits 11- 9: number of serial devices
177 bit 8: reserved
178 bits 7- 6: number of diskette drives minus one
179 bits 5- 4: Initial video mode:
180 00b = EGA,VGA,PGA
181 01b = 40 x 25 color
182 10b = 80 x 25 color
183 11b = 80 x 25 mono
184 bit 3: reserved
185 bit 2: [PS] =1 if pointing device
186 [non-PS] reserved
187 bit 1: =1 if math co-processor
188 bit 0: =1 if diskette available for boot
191 if (DosDrives[0].rootdir != NULL)
192 diskdrives++;
193 if (DosDrives[1].rootdir != NULL)
194 diskdrives++;
195 if (diskdrives)
196 diskdrives--;
198 equipment = (diskdrives << 6) || 0x02;
200 return (equipment);
203 int DOS_ValidDrive(int drive)
206 #ifdef DEBUG
207 fprintf(stderr,"ValidDrive %c (%d)\n",'A'+drive,drive);
208 #endif
210 if (drive >= MAX_DOS_DRIVES)
211 return 0;
212 if (DosDrives[drive].rootdir == NULL)
213 return 0;
214 if (DosDrives[drive].disabled)
215 return 0;
217 return 1;
220 int DOS_GetDefaultDrive(void)
222 #ifdef DEBUG
223 fprintf(stderr,"GetDefaultDrive (%c)\n",'A'+CurrentDrive);
224 #endif
226 return( CurrentDrive);
229 void DOS_SetDefaultDrive(int drive)
231 #ifdef DEBUG
232 fprintf(stderr,"SetDefaultDrive to %c:\n",'A'+drive);
233 #endif
235 if (DOS_ValidDrive(drive))
236 CurrentDrive = drive;
239 void ToUnix(char *s)
241 /* \WINDOWS\\SYSTEM => /windows/system */
243 char *p;
245 for (p = s; *p; p++)
247 if (*p != '\\')
248 *s++ = tolower(*p);
249 else {
250 *s++ = '/';
251 if (*(p+1) == '/' || *(p+1) == '\\')
252 p++;
255 *s = '\0';
258 void ToDos(char *s)
260 /* /windows//system => \WINDOWS\SYSTEM */
262 char *p;
263 for (p = s; *p; p++)
265 if (*p != '/')
266 *s++ = toupper(*p);
267 else {
268 *s++ = '\\';
269 if (*s == '/' || *s == '\\')
270 p++;
273 *s = '\0';
276 int DOS_DisableDrive(int drive)
278 if (drive >= MAX_DOS_DRIVES)
279 return 0;
280 if (DosDrives[drive].rootdir == NULL)
281 return 0;
283 DosDrives[drive].disabled = 1;
284 return 1;
287 int DOS_EnableDrive(int drive)
289 if (drive >= MAX_DOS_DRIVES)
290 return 0;
291 if (DosDrives[drive].rootdir == NULL)
292 return 0;
294 DosDrives[drive].disabled = 0;
295 return 1;
298 static void GetUnixDirName(char *rootdir, char *name)
300 int filename = 1;
301 char *nameptr, *cwdptr;
303 cwdptr = rootdir + strlen(rootdir);
304 nameptr = name;
306 #ifdef DEBUG
307 fprintf(stderr,"GetUnixDirName: %s <=> %s => ",rootdir, name);
308 #endif
310 while (*nameptr) {
311 if (*nameptr == '.' & !filename) {
312 nameptr++;
313 if (*nameptr == '\0') {
314 cwdptr--;
315 break;
317 if (*nameptr == '.') {
318 cwdptr--;
319 while (cwdptr != rootdir) {
320 cwdptr--;
321 if (*cwdptr == '/') {
322 *(cwdptr+1) = '\0';
323 goto next;
326 goto next;
328 if (*nameptr == '\\' || *nameptr == '/') {
329 next: nameptr++;
330 filename = 0;
331 continue;
334 if (*nameptr == '\\' || *nameptr == '/') {
335 filename = 0;
336 if (nameptr == name)
337 cwdptr = rootdir;
338 *cwdptr++='/';
339 nameptr++;
340 continue;
342 filename = 1;
343 *cwdptr++ = *nameptr++;
345 *cwdptr = '\0';
347 ToUnix(rootdir);
349 #ifdef DEBUG
350 fprintf(stderr,"%s\n", rootdir);
351 #endif
355 char *GetUnixFileName(char *dosfilename)
357 /* a:\windows\system.ini => /dos/windows/system.ini */
359 char temp[256];
360 int drive;
362 if (dosfilename[1] == ':')
364 drive = (islower(*dosfilename) ? toupper(*dosfilename) : *dosfilename) - 'A';
366 if (!DOS_ValidDrive(drive))
367 return NULL;
368 else
369 dosfilename+=2;
370 } else
371 drive = CurrentDrive;
373 strcpy(temp, DosDrives[drive].rootdir);
374 strcat(temp, DosDrives[drive].cwd);
375 GetUnixDirName(temp + strlen(DosDrives[drive].rootdir), dosfilename);
377 ToUnix(temp);
379 #ifdef DEBUG
380 fprintf(stderr,"GetUnixFileName: %s => %s\n", dosfilename, temp);
381 #endif
383 return(temp);
386 char *DOS_GetCurrentDir(int drive)
388 /* should return 'WINDOWS\SYSTEM' */
390 char temp[256];
392 if (!DOS_ValidDrive(drive))
393 return 0;
395 strcpy(temp, DosDrives[drive].cwd);
396 ToDos(temp);
397 fprintf(stderr, "2 %s\n", temp);
398 ChopOffSlash(temp);
400 #ifdef DEBUG
401 fprintf(stderr,"DOS_GetCWD: %c: %s\n",'A'+drive, temp + 1);
402 #endif
403 return (temp + 1);
406 int DOS_ChangeDir(int drive, char *dirname)
408 char temp[256];
410 if (!DOS_ValidDrive(drive))
411 return 0;
413 strcpy(temp, dirname);
414 ToUnix(temp);
416 GetUnixDirName(DosDrives[drive].cwd, temp);
417 strcat(DosDrives[drive].cwd,"/");
418 #ifdef DEBUG
419 fprintf(stderr,"DOS_SetCWD: %c: %s\n",'A'+drive, DosDrives[drive].cwd);
420 #endif
421 return 1;
424 int DOS_MakeDir(int drive, char *dirname)
426 char temp[256];
428 if (!DOS_ValidDrive(drive))
429 return 0;
431 strcpy(temp, DosDrives[drive].cwd);
432 GetUnixDirName(temp, dirname);
433 strcat(DosDrives[drive].cwd,"/");
435 ToUnix(temp);
436 mkdir(temp,0);
438 #ifdef DEBUG
439 fprintf(stderr,"DOS_MakeDir: %c:\%s => %s",'A'+drive, dirname, temp);
440 #endif
441 return 1;
444 int DOS_GetSerialNumber(int drive, unsigned long *serialnumber)
446 if (!DOS_ValidDrive(drive))
447 return 0;
449 *serialnumber = DosDrives[drive].serialnumber;
450 return 1;
453 int DOS_SetSerialNumber(int drive, unsigned long serialnumber)
455 if (!DOS_ValidDrive(drive))
456 return 0;
458 DosDrives[drive].serialnumber = serialnumber;
459 return 1;
462 char *DOS_GetVolumeLabel(int drive)
464 if (!DOS_ValidDrive(drive))
465 return NULL;
467 return (DosDrives[drive].label);
470 int DOS_SetVolumeLabel(int drive, char *label)
472 if (!DOS_ValidDrive(drive))
473 return 0;
475 strncpy(DosDrives[drive].label, label, 8);
476 return 1;
479 int DOS_GetFreeSpace(int drive, long *size, long *available)
481 struct statfs info;
483 if (!DOS_ValidDrive(drive))
484 return 0;
486 if (statfs(DosDrives[drive].rootdir, &info) < 0) {
487 fprintf(stderr,"dosfs: cannot do statfs(%s)\n",DosDrives[drive].rootdir);
488 return 0;
491 *size = info.f_bsize * info.f_blocks / 1024;
492 *available = info.f_bavail * info.f_bsize / 1024;
494 return 1;
497 char *FindFile(char *buffer, int buflen, char *filename, char **extensions,
498 char *path)
500 char *workingpath, *dirname, *rootname, **e;
501 DIR *d;
502 struct dirent *f;
503 int rootnamelen, found = 0;
504 struct stat filestat;
506 if (strchr(filename, '\\') != NULL)
508 strncpy(buffer, GetUnixFileName(filename), buflen);
509 ToUnix(buffer);
510 return buffer;
513 if (strchr(filename, '/') != NULL)
515 strncpy(buffer, filename, buflen);
516 return buffer;
519 #ifdef DEBUG
520 fprintf(stderr,"FindFile: looking for %s\n", filename);
521 #endif
523 rootnamelen = strlen(filename);
524 if ((rootname = malloc(rootnamelen + 1)) == NULL)
525 return NULL;
526 strcpy(rootname, filename);
527 ToUnix(rootname);
529 if ((workingpath = malloc(strlen(path) + 1)) == NULL)
530 return NULL;
531 strcpy(workingpath, path);
533 for(dirname = strtok(workingpath, ";");
534 dirname != NULL;
535 dirname = strtok(NULL, ";"))
537 if (strchr(dirname, '\\') != NULL)
538 d = opendir( GetUnixFileName(dirname) );
539 else
540 d = opendir( dirname );
542 #ifdef DEBUG
543 fprintf(stderr,"in %s\n",dirname);
544 #endif
546 if (d != NULL)
548 while ((f = readdir(d)) != NULL)
550 if (strncasecmp(rootname, f->d_name, rootnamelen) == 0)
552 if (extensions == NULL ||
553 strcasecmp(rootname, f->d_name) == 0)
554 found = 1;
555 else
556 if (f->d_name[rootnamelen] == '.')
557 for (e = extensions; *e != NULL; e++)
558 if (strcasecmp(*e, f->d_name + rootnamelen + 1)
559 == 0)
561 found = 1;
562 break;
565 if (found)
567 if (strchr(dirname, '\\') != NULL)
568 strncpy(buffer, GetUnixFileName(dirname), buflen);
569 else
570 strncpy(buffer, dirname, buflen);
572 strncat(buffer, "/", buflen - strlen(buffer));
573 strncat(buffer, f->d_name, buflen - strlen(buffer));
575 fprintf(stderr,"$$%s$$\n", buffer);
577 stat(buffer, &filestat);
578 if (S_ISREG(filestat.st_mode)) {
579 closedir(d);
580 free(rootname);
581 ToUnix(buffer);
582 return buffer;
583 } else
584 found = 0;
588 closedir(d);
591 return NULL;
594 /**********************************************************************
595 * WineIniFileName
597 char *WineIniFileName(void)
599 int fd;
600 static char *filename = NULL;
601 char name[256];
603 if (filename)
604 return filename;
606 strcpy(name, WINE_INI_USER);
607 ExpandTildeString(name);
608 if ((fd = open(name, O_RDONLY)) != -1) {
609 close(fd);
610 filename = malloc(strlen(name) + 1);
611 strcpy(filename, name);
612 return(filename);
614 if ((fd = open(WINE_INI_GLOBAL, O_RDONLY)) != -1) {
615 close(fd);
616 filename = malloc(strlen(WINE_INI_GLOBAL) + 1);
617 strcpy(filename, WINE_INI_GLOBAL);
618 return(filename);
620 fprintf(stderr,"wine: can't open configuration file %s or %s !\n",
621 WINE_INI_GLOBAL, WINE_INI_USER);
622 exit(1);
625 char *WinIniFileName(void)
627 static char *name = NULL;
629 if (name)
630 return name;
632 name = malloc(1024);
634 strcpy(name, GetUnixFileName(WindowsDirectory));
635 strcat(name, "/");
636 strcat(name, "win.ini");
637 ToUnix(name);
639 name = realloc(name, strlen(name) + 1);
641 return name;
644 static int match(char *filename, char *filemask)
646 int x, masklength = strlen(filemask);
648 #ifdef DEBUG
649 fprintf(stderr, "match: %s, %s\n", filename, filemask);
650 #endif
652 for (x = 0; x != masklength ; x++) {
653 /* printf("(%c%c) ", *filename, filemask[x]);
655 if (!*filename)
656 /* stop if EOFname */
657 return 1;
659 if (filemask[x] == '?') {
660 /* skip the next char */
661 filename++;
662 continue;
665 if (filemask[x] == '*') {
666 /* skip each char until '.' or EOFname */
667 while (*filename && *filename !='.')
668 filename++;
669 continue;
671 if (filemask[x] != *filename)
672 return 0;
674 filename++;
676 return 1;
679 struct dosdirent *DOS_opendir(char *dosdirname)
681 int x,y;
682 char *unixdirname;
683 char temp[256];
685 for (x=0; x != MAX_OPEN_DIRS && DosDirs[x].inuse; x++)
688 if (x == MAX_OPEN_DIRS)
689 return NULL;
691 if ((unixdirname = GetUnixFileName(dosdirname)) == NULL)
692 return NULL;
694 strcpy(temp, unixdirname);
695 y = strlen(temp);
696 while (y--)
698 if (temp[y] == '/')
700 temp[y++] = '\0';
701 strcpy(DosDirs[x].filemask, temp +y);
702 ToDos(DosDirs[x].filemask);
703 break;
707 #ifdef DEBUG
708 fprintf(stderr,"DOS_opendir: %s -> %s\n", unixdirname, temp);
709 #endif
711 DosDirs[x].inuse = 1;
712 strcpy(DosDirs[x].unixpath, temp);
714 if ((DosDirs[x].ds = opendir(temp)) == NULL)
715 return NULL;
717 return &DosDirs[x];
721 struct dosdirent *DOS_readdir(struct dosdirent *de)
723 char temp[256];
724 struct dirent *d;
725 struct stat st;
727 if (!de->inuse)
728 return NULL;
730 do {
731 if ((d = readdir(de->ds)) == NULL)
733 closedir(de->ds);
734 de->inuse = 0;
735 return de;
738 strcpy(de->filename, d->d_name);
739 if (d->d_reclen > 12)
740 de->filename[12] = '\0';
742 ToDos(de->filename);
743 } while ( !match(de->filename, de->filemask) );
745 strcpy(temp,de->unixpath);
746 strcat(temp,"/");
747 strcat(temp,de->filename);
748 ToUnix(temp);
750 stat (temp, &st);
751 de->attribute = 0x0;
752 if S_ISDIR(st.st_mode)
753 de->attribute |= FA_DIREC;
755 de->filesize = st.st_size;
756 de->filetime = st.st_mtime;
758 return de;
761 void DOS_closedir(struct dosdirent *de)
763 if (de->inuse)
765 closedir(de->ds);
766 de->inuse = 0;