Release 0.7
[wine] / misc / dos_fs.c
1 /*
2  * DOS-FS
3  * NOV 1993 Erik Bos (erik@(trashcan.)hacktic.nl)
4  *
5  * FindFile by Bob, hacked for dos & unixpaths by Erik.
6  */
7
8 #include <ctype.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/stat.h>
13 #ifdef __linux__
14 #include <sys/vfs.h>
15 #endif
16 #ifdef __NetBSD__
17 #include <sys/types.h>
18 #include <sys/mount.h>
19 #endif
20 #include <dirent.h>
21 #include "windows.h"
22 #include "wine.h"
23 #include "int21.h"
24
25 /*
26  #define DEBUG 
27 */
28 #define MAX_OPEN_DIRS 16
29
30 extern char WindowsDirectory[256], SystemDirectory[256],TempDirectory[256];
31
32 char WindowsPath[256];
33
34 void DOS_DeInitFS(void);
35 int DOS_SetDefaultDrive(int);
36 char *GetDirectUnixFileName(char *);
37 void ToDos(char *);
38 void ToUnix(char *);
39
40 int CurrentDrive = 2;
41
42 struct DosDriveStruct {                 /*  eg: */
43         char            *rootdir;       /*  /usr/windows        */
44         char            cwd[256];       /*  /                   */
45         char            label[13];      /*  DRIVE-A             */              
46         unsigned int    serialnumber;   /*  ABCD5678            */
47         int             disabled;       /*  0                   */
48 };
49
50 struct DosDriveStruct DosDrives[MAX_DOS_DRIVES];
51
52 struct dosdirent DosDirs[MAX_OPEN_DIRS];
53
54 void DOS_InitFS(void)
55 {
56         int x;
57         char drive[2], temp[256], *ptr;
58
59         GetPrivateProfileString("wine", "windows", "c:\\windows", 
60                 WindowsDirectory, sizeof(WindowsDirectory), WINE_INI);
61
62         GetPrivateProfileString("wine", "system", "c:\\windows\\system", 
63                 SystemDirectory, sizeof(SystemDirectory), WINE_INI);
64
65         GetPrivateProfileString("wine", "temp", "c:\\windows", 
66                 TempDirectory, sizeof(TempDirectory), WINE_INI);
67
68         GetPrivateProfileString("wine", "path", "c:\\windows;c:\\windows\\system", 
69                 WindowsPath, sizeof(WindowsPath), WINE_INI);
70
71         ToDos(WindowsDirectory);
72         ToDos(SystemDirectory);
73         ToDos(TempDirectory);
74         ToDos(WindowsPath);
75
76 #ifdef DEBUG
77         fprintf(stderr,"wine.ini = %s\n",WINE_INI);
78         fprintf(stderr,"win.ini = %s\n",WIN_INI);
79         fprintf(stderr,"windir = %s\n",WindowsDirectory);
80         fprintf(stderr,"sysdir = %s\n",SystemDirectory);
81         fprintf(stderr,"tempdir = %s\n",TempDirectory);
82         fprintf(stderr,"path = %s\n",WindowsPath);
83 #endif
84
85         for (x=0; x!=MAX_DOS_DRIVES; x++) {
86                 DosDrives[x].serialnumber = (0xEB0500L | x);
87                 
88                 drive[0] = 'A' + x;
89                 drive[1] = '\0';
90                 GetPrivateProfileString("drives", drive, "*", temp, sizeof(temp), WINE_INI);
91                 if (!strcmp(temp, "*") || *temp == '\0') {
92                         DosDrives[x].rootdir = NULL;            
93                         DosDrives[x].cwd[0] = '\0';
94                         DosDrives[x].label[0] = '\0';
95                         DosDrives[x].disabled = 1;
96                         continue;
97                 }
98
99                 if ((ptr = (char *) malloc(strlen(temp)+1)) == NULL) {
100                         fprintf(stderr,"DOSFS: can't malloc for drive info!");
101                         continue;
102                 }
103                         if (temp[strlen(temp)-1] == '/')
104                                 temp[strlen(temp)] = '\0';
105                         DosDrives[x].rootdir = ptr;
106                         strcpy(DosDrives[x].rootdir, temp);
107                         strcpy(DosDrives[x].cwd, "/windows/");
108                         strcpy(DosDrives[x].label, "DRIVE-");
109                         strcat(DosDrives[x].label, drive);
110                         DosDrives[x].disabled = 0;
111         }
112
113         atexit(DOS_DeInitFS);
114
115         DOS_SetDefaultDrive(2);
116
117         for (x=0; x!=MAX_DOS_DRIVES; x++) {
118                 if (DosDrives[x].rootdir != NULL) {
119 #ifdef DEBUG
120                         fprintf(stderr, "DOSFS: %c: => %-40s %s %s %X %d\n",
121                         'A'+x,
122                         DosDrives[x].rootdir,
123                         DosDrives[x].cwd,
124                         DosDrives[x].label,
125                         DosDrives[x].serialnumber,
126                         DosDrives[x].disabled
127                         );      
128 #endif
129                 }
130         }
131
132         for (x=0; x!=MAX_OPEN_DIRS ; x++)
133                 DosDirs[x].inuse = 0;
134
135 }
136
137 void DOS_DeInitFS(void)
138 {
139         int x;
140
141         for (x=0; x!=MAX_DOS_DRIVES ; x++)
142                 if (DosDrives[x].rootdir != NULL) {
143 #ifdef DEBUG
144
145                         fprintf(stderr, "DOSFS: %c: => %s %s %s %X %d\n",
146                         'A'+x,
147                         DosDrives[x].rootdir,
148                         DosDrives[x].cwd,
149                         DosDrives[x].label,
150                         DosDrives[x].serialnumber,
151                         DosDrives[x].disabled
152                         );      
153                         free(DosDrives[x].rootdir);
154 #endif
155                 }
156 }
157
158 WORD DOS_GetEquipment(void)
159 {
160         WORD equipment;
161         int diskdrives = 0;
162
163 /* borrowed from Ralph Brown's interrupt lists 
164
165                     bits 15-14: number of parallel devices
166                     bit     13: [Conv] Internal modem
167                     bit     12: reserved
168                     bits 11- 9: number of serial devices
169                     bit      8: reserved
170                     bits  7- 6: number of diskette drives minus one
171                     bits  5- 4: Initial video mode:
172                                     00b = EGA,VGA,PGA
173                                     01b = 40 x 25 color
174                                     10b = 80 x 25 color
175                                     11b = 80 x 25 mono
176                     bit      3: reserved
177                     bit      2: [PS] =1 if pointing device
178                                 [non-PS] reserved
179                     bit      1: =1 if math co-processor
180                     bit      0: =1 if diskette available for boot
181 */
182
183         if (DosDrives[0].rootdir != NULL)
184                 diskdrives++;
185         if (DosDrives[1].rootdir != NULL)
186                 diskdrives++;
187         if (diskdrives)
188                 diskdrives--;
189
190         equipment = diskdrives << 6;
191
192         return (equipment);
193 }
194
195 int DOS_ValidDrive(int drive)
196 {
197 /*
198 #ifdef DEBUG
199         fprintf(stderr,"ValidDrive %c (%d)\n",'A'+drive,drive);
200 #endif
201 */
202         if (drive >= MAX_DOS_DRIVES)
203                 return 0;
204         if (DosDrives[drive].rootdir == NULL)
205                 return 0;
206         if (DosDrives[drive].disabled)
207                 return 0;
208
209         return 1;
210 }
211
212 int DOS_GetDefaultDrive(void)
213 {
214 #ifdef DEBUG
215         fprintf(stderr,"GetDefaultDrive (%c)\n",'A'+CurrentDrive);
216 #endif
217
218         return( CurrentDrive);
219 }
220
221 int DOS_SetDefaultDrive(int drive)
222 {
223 #ifdef DEBUG
224         fprintf(stderr,"SetDefaultDrive to %c:\n",'A'+drive);
225 #endif
226
227         if (!DOS_ValidDrive(drive))
228                 return 1;
229                 
230         CurrentDrive = drive;
231 }
232
233 void ToUnix(char *s)
234 {
235         while (*s) {
236                 if (*s == '/')
237                     break;
238                 if (*s == '\\')
239                         *s = '/';               
240                 if (isupper(*s))
241                         *s = tolower(*s);
242         s++;
243         }
244 }
245
246 void ToDos(char *s)
247 {
248         while (*s) {
249                 if (*s == '/')
250                         *s = '\\';              
251                 if (islower(*s))
252                         *s = toupper(*s);
253         s++;
254         }
255 }
256
257 int DOS_DisableDrive(int drive)
258 {
259         if (drive >= MAX_DOS_DRIVES)
260                 return 0;
261         if (DosDrives[drive].rootdir == NULL)
262                 return 0;
263
264         DosDrives[drive].disabled = 1;
265         return 1;
266 }
267
268 int DOS_EnableDrive(int drive)
269 {
270         if (drive >= MAX_DOS_DRIVES)
271                 return 0;
272         if (DosDrives[drive].rootdir == NULL)
273                 return 0;
274
275         DosDrives[drive].disabled = 0;
276         return 1;
277 }
278
279 void GetUnixDirName(char *rootdir, char *name)
280 {
281         int filename;
282         char *nameptr, *cwdptr;
283         
284         cwdptr = rootdir + strlen(rootdir);
285         nameptr = name;
286 /*
287 #ifdef DEBUG
288         fprintf(stderr,"GetUnixDirName: %s <=> %s => ",rootdir, name);
289 #endif
290 */      
291         while (*nameptr) {
292                 if (*nameptr == '.' & !filename) {
293                         nameptr++;
294                         if (*nameptr == '\0') {
295                                 cwdptr--;
296                                 break;
297                         }
298                         if (*nameptr == '.') {
299                                 cwdptr--;
300                                 while (cwdptr != rootdir) {
301                                         cwdptr--;
302                                         if (*cwdptr == '/') {
303                                                 *(cwdptr+1) = '\0';
304                                                 goto next;
305                                         }
306                                         
307                                 }
308                                 goto next;
309                         }
310                         if (*nameptr == '\\' || *nameptr == '/') {
311                         next:   nameptr++;              
312                                 filename = 0;
313                                 continue;
314                         }
315                 }
316                 if (*nameptr == '\\' || *nameptr == '/') {
317                         filename = 0;
318                         if (nameptr == name)
319                                 cwdptr = rootdir;
320                         *cwdptr++='/';          
321                         nameptr++;
322                         continue;
323                 }
324                 filename = 1;
325                 *cwdptr++ = *nameptr++;
326         }
327         *cwdptr = '\0';
328
329         ToUnix(rootdir);
330 /*
331 #ifdef DEBUG
332         fprintf(stderr,"%s\n", rootdir);
333 #endif
334 */
335 }
336
337 char *GetDirectUnixFileName(char *dosfilename)
338
339         /*   a:\windows\system.ini  =>  /dos/windows/system.ini   */
340         
341         static char temp[256];
342         int drive;
343         char x;
344
345         if (dosfilename[1] == ':') 
346         {
347                 drive = (islower(*dosfilename) ? toupper(*dosfilename) : *dosfilename) - 'A';
348                 
349                 if (!DOS_ValidDrive(drive))             
350                         return NULL;
351                 else
352                         dosfilename+=2;
353         } else
354                 drive = CurrentDrive;
355
356         strcpy(temp,DosDrives[drive].rootdir);
357         strcat(temp, DosDrives[drive].cwd);
358         GetUnixDirName(temp + strlen(DosDrives[drive].rootdir), dosfilename);
359
360         ToUnix(temp);
361
362 #ifdef DEBUG
363         fprintf(stderr,"GetDirectUnixFileName: %c:%s => %s\n",'A'+ drive, dosfilename, temp);
364 #endif
365
366         return(temp);
367 }
368
369 char *GetUnixFileName(char *dosfilename)
370 {
371         char *dirname, *unixname, workingpath[256], temp[256];
372
373         /* check if program specified a path */
374
375         if (*dosfilename == '.' || *dosfilename == '\\')
376                 return( GetDirectUnixFileName(dosfilename) );   
377
378         /* nope, lets find it */
379
380 #ifdef DEBUG
381         fprintf(stderr,"GetUnixFileName: %s\n",dosfilename);
382 #endif
383
384         strcpy(workingpath, WindowsPath);
385     
386         for(dirname = strtok(workingpath, ";") ;
387                 dirname != NULL;
388                 dirname = strtok(NULL, ";"))
389         {
390                 strcpy(temp,dirname);   
391                 if (temp[strlen(temp)-1] != '\\')
392                         strcat(temp,"\\");
393                 strcat(temp,dosfilename);
394
395 #ifdef DEBUG
396                 fprintf(stderr,"trying %s\n",temp);
397 #endif
398
399                 if ( (unixname = GetDirectUnixFileName(temp)) != NULL)
400                         return unixname;
401         }
402         puts("FAILED!");
403         return NULL;
404 }
405
406 char *DOS_GetCurrentDir(int drive, char *dirname)
407
408         /* should return 'windows\system' */
409
410         char temp[256];
411
412         if (!DOS_ValidDrive(drive)) 
413                 return 0;
414         
415         strcpy(temp, DosDrives[drive].cwd);
416         ToDos(temp);
417
418         if (temp[strlen(temp)-1] == '\\')
419                 temp[strlen(temp)] = '\0';      
420
421 #ifdef DEBUG
422         fprintf(stderr,"DOS_GetCWD: %c:\%s",'A'+drive, temp+1);
423 #endif
424         return (temp+1);
425 }
426
427 int DOS_ChangeDir(int drive, char *dirname)
428 {
429         if (!DOS_ValidDrive(drive)) 
430                 return 0;
431
432         GetUnixDirName(DosDrives[drive].cwd, dirname);
433         strcat(DosDrives[drive].cwd,"/");
434 #ifdef DEBUG
435         fprintf(stderr,"DOS_SetCWD: %c:\%s",'A'+drive, DosDrives[drive].cwd);
436 #endif
437         return 1;
438 }
439
440 int DOS_MakeDir(int drive, char *dirname)
441 {
442         char temp[256];
443         
444         if (!DOS_ValidDrive(drive))
445                 return 0;       
446
447         strcpy(temp, DosDrives[drive].cwd);
448         GetUnixDirName(temp, dirname);
449         strcat(DosDrives[drive].cwd,"/");
450
451         ToUnix(temp);
452         mkdir(temp,0);  
453
454 #ifdef DEBUG
455         fprintf(stderr,"DOS_MakeDir: %c:\%s => %s",'A'+drive, dirname, temp);
456 #endif
457 }
458
459 /*
460 void main(void)
461 {
462         strcpy(DosDrives[0].cwd, "1/2/3/");     
463         
464         puts(DosDrives[0].cwd);
465         ChangeDir(0,"..");
466         puts(DosDrives[0].cwd);
467         
468         ChangeDir(0,"..\\..");
469         puts(DosDrives[0].cwd);
470
471         ChangeDir(0,".");
472         puts(DosDrives[0].cwd);
473
474         ChangeDir(0,"test");
475         puts(DosDrives[0].cwd);
476
477         ChangeDir(0,"\\qwerty\\ab");
478         puts(DosDrives[0].cwd);
479
480         ChangeDir(0,"erik\\.\\bos\\..\\24");
481         puts(DosDrives[0].cwd);
482
483 }
484 */
485
486 int DOS_GetSerialNumber(int drive, unsigned long *serialnumber)
487 {
488         if (!DOS_ValidDrive(drive)) 
489                 return 0;
490
491         *serialnumber = DosDrives[drive].serialnumber;
492         return 1;
493 }
494
495 int DOS_SetSerialNumber(int drive, unsigned long serialnumber)
496 {
497         if (!DOS_ValidDrive(drive)) 
498                 return 0;
499
500         DosDrives[drive].serialnumber = serialnumber;
501         return 1;
502 }
503
504 int DOS_GetFreeSpace(int drive, long *size, long *available)
505 {
506         struct statfs info;
507
508         if (!DOS_ValidDrive(drive))
509                 return 0;
510
511         if (statfs(DosDrives[drive].rootdir, &info) < 0) {
512                 fprintf(stderr,"dosfs: cannot do statfs(%s)\n",DosDrives[drive].rootdir);
513                 return 0;
514         }
515
516         *size = info.f_bsize * info.f_blocks / 1024;
517         *available = info.f_bavail * info.f_bsize / 1024;
518         
519         return 1;
520 }
521
522 char *FindFile(char *buffer, int buflen, char *rootname, char **extensions, 
523                 char *path)
524 {
525     char *workingpath;
526     char *dirname;
527     DIR *d;
528     struct dirent *f;
529     char **e;
530     int rootnamelen;
531     int found = 0;
532
533
534     if (strchr(rootname, '\\') != NULL)
535     {
536         strncpy(buffer, GetDirectUnixFileName(rootname), buflen);
537         ToUnix(buffer);
538         
539 #ifdef DEBUG
540 fprintf(stderr,"FindFile: %s -> %s\n",rootname,buffer);
541 #endif
542
543         return buffer;
544     }
545
546     if (strchr(rootname, '/') != NULL)
547     {
548         strncpy(buffer, rootname, buflen);
549
550 #ifdef DEBUG
551 fprintf(stderr,"FindFile: %s -> %s\n",rootname,buffer);
552 #endif
553
554         return buffer;
555     }
556
557 #ifdef DEBUG
558 fprintf(stderr,"FindFile: looking for %s\n",rootname);
559 #endif
560
561     ToUnix(rootname);
562
563     rootnamelen = strlen(rootname);
564     workingpath = malloc(strlen(path) + 1);
565     if (workingpath == NULL)
566         return NULL;
567     strcpy(workingpath, path);
568
569     for(dirname = strtok(workingpath, ";"); 
570         dirname != NULL;
571         dirname = strtok(NULL, ";"))
572     {
573         if (strchr(dirname, '\\')!=NULL)
574                 d = opendir( GetDirectUnixFileName(dirname) );
575         else
576                 d = opendir( dirname );
577
578 #ifdef DEBUG
579         fprintf(stderr,"in %s\n",dirname);
580 #endif
581         
582         if (d != NULL)
583         {
584             while ((f = readdir(d)) != NULL)
585             {
586                 if (strncasecmp(rootname, f->d_name, rootnamelen) == 0)
587                 {
588                     if (extensions == NULL || 
589                         strcasecmp(rootname, f->d_name) == 0)
590                     {
591                         found = 1;
592                     }
593                     else if (f->d_name[rootnamelen] == '.')
594                     {
595                         for (e = extensions; *e != NULL; e++)
596                         {
597                             if (strcasecmp(*e, f->d_name + rootnamelen + 1) 
598                                 == 0)
599                             {
600                                 found = 1;
601                                 break;
602                             }
603                         }
604                     }
605                     
606                     if (found)
607                     {
608                         if (strchr(dirname, '\\')!=NULL)
609                                 strncpy(buffer, GetDirectUnixFileName(dirname), buflen);
610                          else
611                                 strncpy(buffer, dirname, buflen);
612
613                         if (buffer[strlen(buffer)-1]!='/')                      
614                                 strncat(buffer, "/", buflen - strlen(buffer));
615                         
616                         strncat(buffer, f->d_name, buflen - strlen(buffer));
617                         closedir(d);
618
619                         ToUnix(buffer);
620
621                         return buffer;
622                     }
623                 }
624             }
625             closedir(d);
626         }
627     }
628     return NULL;
629 }
630
631 /**********************************************************************
632  *              WineIniFileName
633  */
634 char *WineIniFileName(void)
635 {
636     static char *IniName = NULL;
637     char inipath[256];
638     
639     if (IniName)
640         return IniName;
641
642     getcwd(inipath, 256);
643     strcat(inipath, ";");
644     strcat(inipath, getenv("HOME"));
645     strcat(inipath, ";");
646     strcat(inipath, getenv("WINEPATH"));
647
648     IniName = malloc(1024);
649     if (FindFile(IniName, 1024, "wine.ini", NULL, inipath) == NULL)
650     {
651         free(IniName);
652         IniName = NULL;
653         return NULL;
654     }
655     
656     IniName = realloc(IniName, strlen(IniName) + 1);
657
658     ToUnix(IniName);
659         
660     return IniName;
661 }
662
663 char *WinIniFileName()
664 {
665         static char name[256];
666         
667         strcpy(name,GetDirectUnixFileName(WindowsDirectory));   
668         strcat(name,"win.ini");
669
670         ToUnix(name);
671         
672         return name;
673 }
674
675 struct dosdirent *DOS_opendir(char *dosdirname)
676 {
677         int x,y;
678         char *unixdirname;
679         char temp[256];
680         
681         for (x=0; x != MAX_OPEN_DIRS && DosDirs[x].inuse; x++)
682                 ;
683
684         if (x == MAX_OPEN_DIRS)
685                 return NULL;
686
687         if ((unixdirname = GetDirectUnixFileName(dosdirname)) == NULL)
688                 return NULL;
689
690         strcpy(temp,unixdirname);
691
692
693         y = strlen(temp);
694
695         while (y--)
696         {
697                 if (temp[y] == '/') 
698                 {
699                         temp[y] = '\0';
700                         break;
701                 }
702         }
703
704         fprintf(stderr,"%s -> %s\n",unixdirname,temp);
705
706         DosDirs[x].inuse = 1;
707         strcpy(DosDirs[x].unixpath, temp);
708
709         if ((DosDirs[x].ds = opendir(temp)) == NULL)
710                 return NULL;
711
712         return &DosDirs[x];
713 }
714
715
716 struct dosdirent *DOS_readdir(struct dosdirent *de)
717 {
718         char temp[256];
719         struct dirent *d;
720         struct stat st;
721
722         if (!de->inuse)
723                 return NULL;
724         
725         if ((d = readdir(de->ds)) == NULL) 
726         {
727                 closedir(de->ds);
728                 de->inuse = 0;
729                 return de;
730         }
731
732         strcpy(de->filename, d->d_name);
733         if (d->d_reclen > 12)
734                 de->filename[12] = '\0';
735         ToDos (de->filename);
736
737         de->attribute = 0x0;
738
739         strcpy(temp,de->unixpath);
740         strcat(temp,"/");
741         strcat(temp,de->filename);
742         ToUnix(temp);
743         stat (temp, &st);
744         if S_ISDIR(st.st_mode)
745                 de->attribute |= 0x08;
746
747         return de;
748 }
749
750 void DOS_closedir(struct dosdirent *de)
751 {
752         if (de->inuse)
753         {
754                 closedir(de->ds);
755                 de->inuse = 0;
756         }
757 }