Release 941122
[wine.git] / misc / dos_fs.c
blobae19ea3961493cb68645e77fd90da7507661fb38
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 "windows.h"
29 #include "msdos.h"
30 #include "prototypes.h"
31 #include "autoconf.h"
32 #include "comm.h"
33 #include "stddebug.h"
34 #include "debug.h"
36 #define WINE_INI_USER "~/.winerc"
37 #define MAX_OPEN_DIRS 16
38 #define MAX_DOS_DRIVES 26
40 extern char WindowsDirectory[256], SystemDirectory[256],TempDirectory[256];
42 char WindowsPath[256];
44 static int CurrentDrive = 2;
46 struct DosDriveStruct { /* eg: */
47 char *rootdir; /* /usr/windows */
48 char cwd[256]; /* / */
49 char label[13]; /* DRIVE-A */
50 unsigned int serialnumber; /* ABCD5678 */
51 int disabled; /* 0 */
54 static struct DosDriveStruct DosDrives[MAX_DOS_DRIVES];
55 static struct dosdirent DosDirs[MAX_OPEN_DIRS];
57 static void ExpandTildeString(char *s)
59 struct passwd *entry;
60 char temp[1024], *ptr = temp;
62 strcpy(temp, s);
64 while (*ptr)
66 if (*ptr != '~')
68 *s++ = *ptr++;
69 continue;
72 ptr++;
74 if ( (entry = getpwuid(getuid())) == NULL)
76 continue;
79 strcpy(s, entry->pw_dir);
80 s += strlen(entry->pw_dir);
82 *s = 0;
85 void ChopOffSlash(char *path)
87 if (path[strlen(path)-1] == '/' || path[strlen(path)-1] == '\\')
88 path[strlen(path)-1] = '\0';
91 void DOS_InitFS(void)
93 int x;
94 char drive[2], temp[256];
96 GetPrivateProfileString("wine", "windows", "c:\\windows",
97 WindowsDirectory, sizeof(WindowsDirectory), WINE_INI);
99 GetPrivateProfileString("wine", "system", "c:\\windows\\system",
100 SystemDirectory, sizeof(SystemDirectory), WINE_INI);
102 GetPrivateProfileString("wine", "temp", "c:\\windows",
103 TempDirectory, sizeof(TempDirectory), WINE_INI);
105 GetPrivateProfileString("wine", "path", "c:\\windows;c:\\windows\\system",
106 WindowsPath, sizeof(WindowsPath), WINE_INI);
108 ChopOffSlash(WindowsDirectory);
109 ToDos(WindowsDirectory);
111 ChopOffSlash(SystemDirectory);
112 ToDos(SystemDirectory);
114 ChopOffSlash(TempDirectory);
115 ToDos(TempDirectory);
117 ToDos(WindowsPath);
118 ExpandTildeString(WindowsPath);
120 for (x=0; x!=MAX_DOS_DRIVES; x++) {
121 DosDrives[x].serialnumber = (0xEB0500L | x);
123 drive[0] = 'A' + x;
124 drive[1] = '\0';
125 GetPrivateProfileString("drives", drive, "*", temp, sizeof(temp), WINE_INI);
126 if (!strcmp(temp, "*") || *temp == '\0') {
127 DosDrives[x].rootdir = NULL;
128 DosDrives[x].cwd[0] = '\0';
129 DosDrives[x].label[0] = '\0';
130 DosDrives[x].disabled = 1;
131 continue;
133 ExpandTildeString(temp);
134 ChopOffSlash(temp);
135 DosDrives[x].rootdir = strdup(temp);
136 strcpy(DosDrives[x].rootdir, temp);
137 strcpy(DosDrives[x].cwd, "/windows/");
138 strcpy(DosDrives[x].label, "DRIVE-");
139 strcat(DosDrives[x].label, drive);
140 DosDrives[x].disabled = 0;
142 DosDrives[25].rootdir = "/";
143 strcpy(DosDrives[25].cwd, "/");
144 strcpy(DosDrives[25].label, "UNIX-FS");
145 DosDrives[25].serialnumber = 0x12345678;
146 DosDrives[25].disabled = 0;
148 DOS_SetDefaultDrive(2);
150 for (x=0; x!=MAX_DOS_DRIVES; x++) {
151 if (DosDrives[x].rootdir != NULL) {
152 dprintf_dosfs(stddeb, "DOSFS: %c: => %-40s %s %s %X %d\n",
153 'A'+x,
154 DosDrives[x].rootdir,
155 DosDrives[x].cwd,
156 DosDrives[x].label,
157 DosDrives[x].serialnumber,
158 DosDrives[x].disabled
163 for (x=0; x!=MAX_OPEN_DIRS ; x++)
164 DosDirs[x].inuse = 0;
166 dprintf_dosfs(stddeb,"wine.ini = %s\n",WINE_INI);
167 dprintf_dosfs(stddeb,"win.ini = %s\n",WIN_INI);
168 dprintf_dosfs(stddeb,"windir = %s\n",WindowsDirectory);
169 dprintf_dosfs(stddeb,"sysdir = %s\n",SystemDirectory);
170 dprintf_dosfs(stddeb,"tempdir = %s\n",TempDirectory);
171 dprintf_dosfs(stddeb,"path = %s\n",WindowsPath);
174 WORD DOS_GetEquipment(void)
176 WORD equipment;
177 int diskdrives = 0;
178 int parallelports = 0;
179 int serialports = 0;
180 int x;
181 extern struct DosDeviceStruct COM[MAX_PORTS];
182 extern struct DosDeviceStruct LPT[MAX_PORTS];
184 /* borrowed from Ralph Brown's interrupt lists
186 bits 15-14: number of parallel devices
187 bit 13: [Conv] Internal modem
188 bit 12: reserved
189 bits 11- 9: number of serial devices
190 bit 8: reserved
191 bits 7- 6: number of diskette drives minus one
192 bits 5- 4: Initial video mode:
193 00b = EGA,VGA,PGA
194 01b = 40 x 25 color
195 10b = 80 x 25 color
196 11b = 80 x 25 mono
197 bit 3: reserved
198 bit 2: [PS] =1 if pointing device
199 [non-PS] reserved
200 bit 1: =1 if math co-processor
201 bit 0: =1 if diskette available for boot
203 /* Currently the only of these bits correctly set are:
204 bits 15-14 } Added by William Owen Smith,
205 bits 11-9 } wos@dcs.warwick.ac.uk
206 bits 7-6
207 bit 2 (always set)
210 if (DosDrives[0].rootdir != NULL)
211 diskdrives++;
212 if (DosDrives[1].rootdir != NULL)
213 diskdrives++;
214 if (diskdrives)
215 diskdrives--;
217 for (x=0; x!=MAX_PORTS; x++) {
218 if (COM[x].devicename)
219 serialports++;
220 if (LPT[x].devicename)
221 parallelports++;
223 if (serialports > 7) /* 3 bits -- maximum value = 7 */
224 serialports=7;
225 if (parallelports > 3) /* 2 bits -- maximum value = 3 */
226 parallelports=3;
228 equipment = (diskdrives << 6) | (serialports << 9) |
229 (parallelports << 14) | 0x02;
231 dprintf_dosfs(stddeb, "DOS_GetEquipment : diskdrives = %d serialports = %d "
232 "parallelports = %d\n"
233 "DOS_GetEquipment : equipment = %d\n",
234 diskdrives, serialports, parallelports, equipment);
236 return (equipment);
239 int DOS_ValidDrive(int drive)
241 dprintf_dosfs(stddeb,"ValidDrive %c (%d)\n",'A'+drive,drive);
242 if (drive >= MAX_DOS_DRIVES)
243 return 0;
244 if (DosDrives[drive].rootdir == NULL)
245 return 0;
246 if (DosDrives[drive].disabled)
247 return 0;
249 return 1;
253 int DOS_ValidDirectory(char *name)
255 char *dirname;
256 struct stat s;
257 dprintf_dosfs(stddeb, "DOS_ValidDirectory: '%s'\n", name);
258 if ((dirname = GetUnixFileName(name)) == NULL)
259 return 0;
260 if (stat(dirname,&s))
261 return 0;
262 if (!S_ISDIR(s.st_mode))
263 return 0;
264 dprintf_dosfs(stddeb, "==> OK\n");
265 return 1;
270 int DOS_GetDefaultDrive(void)
272 dprintf_dosfs(stddeb,"GetDefaultDrive (%c)\n",'A'+CurrentDrive);
273 return( CurrentDrive);
276 void DOS_SetDefaultDrive(int drive)
278 dprintf_dosfs(stddeb,"SetDefaultDrive to %c:\n",'A'+drive);
279 if (DOS_ValidDrive(drive))
280 CurrentDrive = drive;
283 void ToUnix(char *s)
285 /* \WINDOWS\\SYSTEM => /windows/system */
287 char *p;
289 for (p = s; *p; p++)
291 if (*p != '\\')
292 *s++ = tolower(*p);
293 else {
294 *s++ = '/';
295 if (*(p+1) == '/' || *(p+1) == '\\')
296 p++;
299 *s = '\0';
302 void ToDos(char *s)
304 /* /windows//system => \WINDOWS\SYSTEM */
306 char *p;
307 for (p = s; *p; p++)
309 if (*p != '/')
310 *s++ = toupper(*p);
311 else {
312 *s++ = '\\';
313 if (*(p+1) == '/' || *(p+1) == '\\')
314 p++;
317 *s = '\0';
320 int DOS_DisableDrive(int drive)
322 if (drive >= MAX_DOS_DRIVES)
323 return 0;
324 if (DosDrives[drive].rootdir == NULL)
325 return 0;
327 DosDrives[drive].disabled = 1;
328 return 1;
331 int DOS_EnableDrive(int drive)
333 if (drive >= MAX_DOS_DRIVES)
334 return 0;
335 if (DosDrives[drive].rootdir == NULL)
336 return 0;
338 DosDrives[drive].disabled = 0;
339 return 1;
342 static void GetUnixDirName(char *rootdir, char *name)
344 int filename = 1;
345 char *nameptr, *cwdptr;
347 cwdptr = rootdir + strlen(rootdir);
348 nameptr = name;
350 dprintf_dosfs(stddeb,"GetUnixDirName: %s <=> %s => ",rootdir, name);
352 while (*nameptr) {
353 if (*nameptr == '.' & !filename) {
354 nameptr++;
355 if (*nameptr == '\0') {
356 cwdptr--;
357 break;
359 if (*nameptr == '.') {
360 cwdptr--;
361 while (cwdptr != rootdir) {
362 cwdptr--;
363 if (*cwdptr == '/') {
364 *(cwdptr+1) = '\0';
365 goto next;
368 goto next;
370 if (*nameptr == '\\' || *nameptr == '/') {
371 next: nameptr++;
372 filename = 0;
373 continue;
376 if (*nameptr == '\\' || *nameptr == '/') {
377 filename = 0;
378 if (nameptr == name)
379 cwdptr = rootdir;
380 *cwdptr++='/';
381 nameptr++;
382 continue;
384 filename = 1;
385 *cwdptr++ = *nameptr++;
387 *cwdptr = '\0';
389 ToUnix(rootdir);
391 dprintf_dosfs(stddeb,"%s\n", rootdir);
395 char *GetUnixFileName(char *dosfilename)
397 /* a:\windows\system.ini => /dos/windows/system.ini */
399 static char temp[256];
400 int drive;
402 if (dosfilename[1] == ':')
404 drive = (islower(*dosfilename) ? toupper(*dosfilename) : *dosfilename) - 'A';
406 if (!DOS_ValidDrive(drive))
407 return NULL;
408 else
409 dosfilename+=2;
410 } else
411 drive = CurrentDrive;
413 strcpy(temp, DosDrives[drive].rootdir);
414 strcat(temp, DosDrives[drive].cwd);
415 GetUnixDirName(temp + strlen(DosDrives[drive].rootdir), dosfilename);
417 dprintf_dosfs(stddeb,"GetUnixFileName: %s => %s\n", dosfilename, temp);
418 return(temp);
421 char *GetDosFileName(char *unixfilename)
423 int i;
424 static char temp[256], rootdir[256];
425 /* /dos/windows/system.ini => c:\windows\system.ini */
427 for (i = 0 ; i != MAX_DOS_DRIVES; i++) {
428 if (DosDrives[i].rootdir != NULL) {
429 strcpy(rootdir, DosDrives[i].rootdir);
430 strcat(rootdir, "/");
431 if (strncmp(rootdir, unixfilename, strlen(rootdir)) == 0) {
432 sprintf(temp, "%c:\\%s", 'A' + i, unixfilename + strlen(rootdir));
433 ToDos(temp);
434 return temp;
438 sprintf(temp, "Z:%s", unixfilename);
439 ToDos(temp);
440 return(temp);
443 char *DOS_GetCurrentDir(int drive)
445 /* should return 'WINDOWS\SYSTEM' */
447 static char temp[256];
449 if (!DOS_ValidDrive(drive))
450 return 0;
452 strcpy(temp, DosDrives[drive].cwd);
453 ToDos(temp);
454 ChopOffSlash(temp);
456 dprintf_dosfs(stddeb,"DOS_GetCWD: %c: %s\n",'A'+drive, temp + 1);
457 return (temp + 1);
460 int DOS_ChangeDir(int drive, char *dirname)
462 char temp[256],old[256];
464 if (!DOS_ValidDrive(drive))
465 return 0;
467 strcpy(temp, dirname);
468 ToUnix(temp);
469 strcpy(old, DosDrives[drive].cwd);
471 GetUnixDirName(DosDrives[drive].cwd, temp);
472 strcat(DosDrives[drive].cwd,"/");
474 dprintf_dosfs(stddeb,"DOS_SetCWD: %c: %s\n",'A'+drive,
475 DosDrives[drive].cwd);
477 if (!DOS_ValidDirectory(DosDrives[drive].cwd))
479 strcpy(DosDrives[drive].cwd, old);
480 return 0;
482 return 1;
485 int DOS_MakeDir(int drive, char *dirname)
487 char temp[256];
489 if (!DOS_ValidDrive(drive))
490 return 0;
492 strcpy(temp, DosDrives[drive].cwd);
493 GetUnixDirName(temp, dirname);
494 strcat(DosDrives[drive].cwd,"/");
496 ToUnix(temp + strlen(DosDrives[drive].cwd));
497 mkdir(temp,0);
499 dprintf_dosfs(stddeb,
500 "DOS_MakeDir: %c:\%s => %s",'A'+drive, dirname, temp);
501 return 1;
504 int DOS_GetSerialNumber(int drive, unsigned long *serialnumber)
506 if (!DOS_ValidDrive(drive))
507 return 0;
509 *serialnumber = DosDrives[drive].serialnumber;
510 return 1;
513 int DOS_SetSerialNumber(int drive, unsigned long serialnumber)
515 if (!DOS_ValidDrive(drive))
516 return 0;
518 DosDrives[drive].serialnumber = serialnumber;
519 return 1;
522 char *DOS_GetVolumeLabel(int drive)
524 if (!DOS_ValidDrive(drive))
525 return NULL;
527 return (DosDrives[drive].label);
530 int DOS_SetVolumeLabel(int drive, char *label)
532 if (!DOS_ValidDrive(drive))
533 return 0;
535 strncpy(DosDrives[drive].label, label, 8);
536 return 1;
539 int DOS_GetFreeSpace(int drive, long *size, long *available)
541 struct statfs info;
543 if (!DOS_ValidDrive(drive))
544 return 0;
546 if (statfs(DosDrives[drive].rootdir, &info) < 0) {
547 fprintf(stderr,"dosfs: cannot do statfs(%s)\n",
548 DosDrives[drive].rootdir);
549 return 0;
552 *size = info.f_bsize * info.f_blocks;
553 *available = info.f_bavail * info.f_bsize;
555 return 1;
558 char *FindFile(char *buffer, int buflen, char *filename, char **extensions,
559 char *path)
561 char *workingpath, *dirname, *rootname, **e;
562 DIR *d;
563 struct dirent *f;
564 int rootnamelen, found = 0;
565 struct stat filestat;
567 if (strchr(filename, '\\') != NULL)
569 strncpy(buffer, GetUnixFileName(filename), buflen);
570 stat( buffer, &filestat);
571 if (S_ISREG(filestat.st_mode))
572 return buffer;
573 else
574 return NULL;
577 if (strchr(filename, '/') != NULL)
579 strncpy(buffer, filename, buflen);
580 return buffer;
583 dprintf_dosfs(stddeb,"FindFile: looking for %s\n", filename);
584 rootnamelen = strlen(filename);
585 rootname = strdup(filename);
586 ToUnix(rootname);
587 workingpath = strdup(path);
589 for(dirname = strtok(workingpath, ";");
590 dirname != NULL;
591 dirname = strtok(NULL, ";"))
593 if (strchr(dirname, '\\') != NULL)
594 d = opendir( GetUnixFileName(dirname) );
595 else
596 d = opendir( dirname );
598 dprintf_dosfs(stddeb,"in %s\n",dirname);
599 if (d != NULL)
601 while ((f = readdir(d)) != NULL)
603 if (strncasecmp(rootname, f->d_name, rootnamelen) == 0)
605 if (extensions == NULL ||
606 strcasecmp(rootname, f->d_name) == 0)
607 found = 1;
608 else
609 if (f->d_name[rootnamelen] == '.')
610 for (e = extensions; *e != NULL; e++)
611 if (strcasecmp(*e, f->d_name + rootnamelen + 1)
612 == 0)
614 found = 1;
615 break;
618 if (found)
620 if (strchr(dirname, '\\') != NULL)
621 strncpy(buffer, GetUnixFileName(dirname), buflen);
622 else
623 strncpy(buffer, dirname, buflen);
625 strncat(buffer, "/", buflen - strlen(buffer));
626 strncat(buffer, f->d_name, buflen - strlen(buffer));
628 stat(buffer, &filestat);
629 if (S_ISREG(filestat.st_mode)) {
630 closedir(d);
631 free(rootname);
632 return buffer;
633 } else
634 found = 0;
638 closedir(d);
641 return NULL;
644 /**********************************************************************
645 * WineIniFileName
647 char *WineIniFileName(void)
649 int fd;
650 static char *filename = NULL;
651 static char name[256];
653 if (filename)
654 return filename;
656 strcpy(name, WINE_INI_USER);
657 ExpandTildeString(name);
658 if ((fd = open(name, O_RDONLY)) != -1) {
659 close(fd);
660 filename = name;
661 return(filename);
663 if ((fd = open(WINE_INI_GLOBAL, O_RDONLY)) != -1) {
664 close(fd);
665 filename = WINE_INI_GLOBAL;
666 return(filename);
668 fprintf(stderr,"wine: can't open configuration file %s or %s !\n",
669 WINE_INI_GLOBAL, WINE_INI_USER);
670 exit(1);
673 char *WinIniFileName(void)
675 static char *name = NULL;
677 if (name)
678 return name;
680 name = malloc(1024);
682 strcpy(name, GetUnixFileName(WindowsDirectory));
683 strcat(name, "/");
684 strcat(name, "win.ini");
686 name = realloc(name, strlen(name) + 1);
688 return name;
691 static int match(char *filename, char *filemask)
693 int x, masklength = strlen(filemask);
695 dprintf_dosfs(stddeb, "match: %s, %s\n", filename, filemask);
696 for (x = 0; x != masklength ; x++) {
697 /* printf("(%c%c) ", *filename, filemask[x]);
699 if (!*filename)
700 /* stop if EOFname */
701 return 1;
703 if (filemask[x] == '?') {
704 /* skip the next char */
705 filename++;
706 continue;
709 if (filemask[x] == '*') {
710 /* skip each char until '.' or EOFname */
711 while (*filename && *filename !='.')
712 filename++;
713 continue;
715 if (filemask[x] != *filename)
716 return 0;
718 filename++;
720 return 1;
723 struct dosdirent *DOS_opendir(char *dosdirname)
725 int x,y;
726 char *unixdirname;
727 char temp[256];
729 for (x=0; x != MAX_OPEN_DIRS && DosDirs[x].inuse; x++)
732 if (x == MAX_OPEN_DIRS)
733 return NULL;
735 if ((unixdirname = GetUnixFileName(dosdirname)) == NULL)
736 return NULL;
738 strcpy(temp, unixdirname);
739 y = strlen(temp);
740 while (y--)
742 if (temp[y] == '/')
744 temp[y++] = '\0';
745 strcpy(DosDirs[x].filemask, temp +y);
746 ToDos(DosDirs[x].filemask);
747 break;
751 dprintf_dosfs(stddeb,"DOS_opendir: %s -> %s\n", unixdirname, temp);
753 DosDirs[x].inuse = 1;
754 strcpy(DosDirs[x].unixpath, temp);
756 if ((DosDirs[x].ds = opendir(temp)) == NULL)
757 return NULL;
759 return &DosDirs[x];
763 struct dosdirent *DOS_readdir(struct dosdirent *de)
765 char temp[256];
766 struct dirent *d;
767 struct stat st;
769 if (!de->inuse)
770 return NULL;
772 do {
773 if ((d = readdir(de->ds)) == NULL)
774 return NULL;
776 strcpy(de->filename, d->d_name);
777 if (d->d_reclen > 12)
778 de->filename[12] = '\0';
780 ToDos(de->filename);
781 } while ( !match(de->filename, de->filemask) );
783 strcpy(temp,de->unixpath);
784 strcat(temp,"/");
785 strcat(temp,de->filename);
786 ToUnix(temp + strlen(de->unixpath));
788 stat (temp, &st);
789 de->attribute = 0x0;
790 if S_ISDIR(st.st_mode)
791 de->attribute |= FA_DIREC;
793 de->filesize = st.st_size;
794 de->filetime = st.st_mtime;
796 return de;
799 void DOS_closedir(struct dosdirent *de)
801 if (de && de->inuse)
803 closedir(de->ds);
804 de->inuse = 0;