|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * Unix file system handler for AmigaDOS
5: *
6: * Copyright 1996 Ed Hanway, Bernd Schmidt
7: *
8: * Version 0.2: 960730
9: *
10: * Based on example code (c) 1988 The Software Distillery
11: * and published in Transactor for the Amiga, Volume 2, Issues 2-5.
12: * (May - August 1989)
13: *
14: * Known limitations:
15: * Does not support ACTION_INHIBIT (big deal).
16: * Does not support any 2.0+ packet types (except ACTION_SAME_LOCK)
17: * Does not actually enforce exclusive locks.
18: * Does not support removable volumes.
19: * May not return the correct error code in some cases.
20: * Does not check for sane values passed by AmigaDOS. May crash the emulation
21: * if passed garbage values.
22: *
23: * TODO someday:
24: * Implement real locking using flock. Needs test cases.
25: */
26:
27: #include "sysconfig.h"
28: #include "sysdeps.h"
29:
30: #include "config.h"
31: #include "options.h"
32: #include "memory.h"
33: #include "custom.h"
34: #include "events.h"
35: #include "newcpu.h"
36: #include "xwin.h"
37: #include "autoconf.h"
38: #include "compiler.h"
39:
40: #ifdef __bebox__
41: #undef access
42: // This is just a temporary hack.
43: // (Will be obsolete in future versions of the BeOS) [ So I hope -- Bernd ]
44:
45: int access(const char *name, int mode)
46: {
47: struct stat statbuf;
48: // printf("%s\n",name);
49:
50: if(-1 == stat(name, &statbuf)) return(-1);
51: else{
52: // printf("OK\n");
53: // printf("%i\n",S_ISDIR(statbuf.st_mode)?1:0);
54: if(mode&R_OK) if(statbuf.st_mode&S_IRUSR) return(0);
55: if(mode&W_OK) if(statbuf.st_mode&S_IWUSR) return(0);
56: return(-1);
57: }
58: }
59: #endif
60:
61: #define MAKE_CASE_INSENSITIVE
62:
63: typedef struct {
64: char *devname; /* device name, e.g. UAE0: */
65: CPTR devname_amiga;
66: CPTR startup;
67: char *volname; /* volume name, e.g. CDROM, WORK, etc. */
68: char *rootdir; /* root unix directory */
69: int readonly; /* disallow write access? */
70: int devno;
71: } UnitInfo;
72:
73: #define MAX_UNITS 20
74: static int num_units = 0, num_filesys_units = 0;
75: static UnitInfo ui[MAX_UNITS];
76:
77: static ULONG fsdevname, filesysseglist, hardfileseglist, filesys_configdev;
78: static CPTR filesys_parampacket;
79:
80: void add_filesys_unit(char *volname, char *rootdir, int readonly)
81: {
82: if (num_units >= MAX_UNITS) {
83: fprintf(stderr, "Maximum number of file systems mounted.\n");
84: return;
85: }
86:
87: if (volname != NULL) {
88: num_filesys_units++;
89: ui[num_units].volname = my_strdup(volname);
90: } else
91: ui[num_units].volname = NULL;
92: ui[num_units].rootdir = my_strdup(rootdir);
93: ui[num_units].readonly = readonly;
94:
95: num_units++;
96: }
97:
98: void write_filesys_config(FILE *f)
99: {
100: int i;
101: for (i = 0; i < num_units; i++) {
102: if (ui[i].volname != NULL) {
103: fprintf(f, "-%c %s:%s\n", ui[i].readonly ? 'M' : 'm',
104: ui[i].volname, ui[i].rootdir);
105: }
106: }
107: }
108:
109: #ifdef TRACING_ENABLED
110: #define TRACE(x) printf x;
111: #define DUMPLOCK(x) dumplock(x)
112: #else
113: #define TRACE(x)
114: #define DUMPLOCK(x)
115: #endif
116:
117: /* minimal AmigaDOS definitions */
118:
119: /* field offsets in DosPacket */
120: #define dp_Type (8)
121: #define dp_Res1 (12)
122: #define dp_Res2 (16)
123: #define dp_Arg1 (20)
124: #define dp_Arg2 (24)
125: #define dp_Arg3 (28)
126: #define dp_Arg4 (32)
127:
128: /* result codes */
129: #define DOS_TRUE (-1L)
130: #define DOS_FALSE (0L)
131:
132: /* packet types */
133: #define ACTION_CURRENT_VOLUME 7
134: #define ACTION_LOCATE_OBJECT 8
135: #define ACTION_RENAME_DISK 9
136: #define ACTION_FREE_LOCK 15
137: #define ACTION_DELETE_OBJECT 16
138: #define ACTION_RENAME_OBJECT 17
139: #define ACTION_COPY_DIR 19
140: #define ACTION_SET_PROTECT 21
141: #define ACTION_CREATE_DIR 22
142: #define ACTION_EXAMINE_OBJECT 23
143: #define ACTION_EXAMINE_NEXT 24
144: #define ACTION_DISK_INFO 25
145: #define ACTION_INFO 26
146: #define ACTION_FLUSH 27
147: #define ACTION_SET_COMMENT 28
148: #define ACTION_PARENT 29
149: #define ACTION_SET_DATE 34
150: #define ACTION_SAME_LOCK 40
151: #define ACTION_FIND_WRITE 1004
152: #define ACTION_FIND_INPUT 1005
153: #define ACTION_FIND_OUTPUT 1006
154: #define ACTION_END 1007
155: #define ACTION_SEEK 1008
156: #define ACTION_IS_FILESYSTEM 1027
157: #define ACTION_READ 'R'
158: #define ACTION_WRITE 'W'
159:
160: #define DISK_TYPE (0x444f5301) /* DOS\1 */
161:
162: /* errors */
163: #define ERROR_NO_FREE_STORE 103
164: #define ERROR_OBJECT_IN_USE 202
165: #define ERROR_OBJECT_EXISTS 203
166: #define ERROR_DIR_NOT_FOUND 204
167: #define ERROR_OBJECT_NOT_FOUND 205
168: #define ERROR_ACTION_NOT_KNOWN 209
169: #define ERROR_OBJECT_WRONG_TYPE 212
170: #define ERROR_DISK_WRITE_PROTECTED 214
171: #define ERROR_DIRECTORY_NOT_EMPTY 216
172: #define ERROR_DEVICE_NOT_MOUNTED 218
173: #define ERROR_SEEK_ERROR 219
174: #define ERROR_DISK_FULL 221
175: #define ERROR_WRITE_PROTECTED 223
176: #define ERROR_NO_MORE_ENTRIES 232
177: #define ERROR_NOT_IMPLEMENTED 236
178:
179: static long dos_errno(void)
180: {
181: int e = errno;
182:
183: switch(e) {
184: case ENOMEM: return ERROR_NO_FREE_STORE;
185: case EEXIST: return ERROR_OBJECT_EXISTS;
186: case EACCES: return ERROR_WRITE_PROTECTED;
187: case ENOENT: return ERROR_OBJECT_NOT_FOUND;
188: case ENOTDIR: return ERROR_OBJECT_WRONG_TYPE;
189: case ENOSPC: return ERROR_DISK_FULL;
190: case EBUSY: return ERROR_OBJECT_IN_USE;
191: case EISDIR: return ERROR_OBJECT_WRONG_TYPE;
192: #if defined(ETXTBSY)
193: case ETXTBSY: return ERROR_OBJECT_IN_USE;
194: #endif
195: #if defined(EROFS)
196: case EROFS: return ERROR_DISK_WRITE_PROTECTED;
197: #endif
198: #if defined(ENOTEMPTY)
199: #if ENOTEMPTY != EEXIST
200: case ENOTEMPTY: return ERROR_DIRECTORY_NOT_EMPTY;
201: #endif
202: #endif
203:
204: default:
205: TRACE(("Unimplemented error %s\n", strerror(e)));
206: return ERROR_NOT_IMPLEMENTED;
207: }
208: }
209:
210: /* handler state info */
211:
212: typedef struct _unit {
213: struct _unit *next;
214:
215: /* Amiga stuff */
216: CPTR dosbase;
217: CPTR volume;
218: CPTR port; /* Our port */
219:
220: /* Native stuff */
221: long unit; /* unit number */
222: UnitInfo ui; /* unit startup info */
223: } Unit;
224:
225: typedef struct {
226: CPTR addr; /* addr of real packet */
227: long type;
228: long res1;
229: long res2;
230: long arg1;
231: long arg2;
232: long arg3;
233: long arg4;
234: } DosPacket;
235:
236: static char *
237: bstr(CPTR addr)
238: {
239: static char buf[256];
240: int n = get_byte(addr++);
241: int i;
242: for(i = 0; i < n; i++)
243: buf[i] = get_byte(addr++);
244: buf[i] = 0;
245: return buf;
246: }
247:
248: static Unit *units = NULL;
249: static int unit_num = 0;
250:
251: static Unit*
252: find_unit(CPTR port)
253: {
254: Unit* u;
255: for(u = units; u; u = u->next)
256: if(u->port == port)
257: break;
258:
259: return u;
260: }
261:
262: static CPTR DosAllocMem(ULONG len)
263: {
264: ULONG i;
265: CPTR addr;
266:
267: regs.d[0] = len + 4;
268: regs.d[1] = 1; /* MEMF_PUBLIC */
269: addr = CallLib(regs.a[6], -198); /* AllocMem */
270:
271: if(addr) {
272: put_long(addr, len);
273: addr += 4;
274:
275: /* faster to clear memory here rather than use MEMF_CLEAR */
276: for(i = 0; i < len; i += 4)
277: put_long(addr + i, 0);
278: }
279:
280: return addr;
281: }
282:
283: static void DosFreeMem(CPTR addr)
284: {
285: addr -= 4;
286: regs.d[0] = get_long(addr) + 4;
287: regs.a[1] = addr;
288: CallLib(regs.a[6], -210); /* FreeMem */
289: }
290:
291: static void
292: startup(DosPacket* packet)
293: {
294: int i, namelen;
295: char* devname = bstr(packet->arg1 << 2);
296: char* s;
297: Unit* unit;
298:
299: /* find UnitInfo with correct device name */
300: s = strchr(devname, ':');
301: if(s) *s = '\0';
302:
303: for(i = 0; i < num_units; i++) {
304: /* Hardfile volume name? */
305: if (ui[i].volname == NULL)
306: continue;
307:
308: if (ui[i].startup == packet->arg2)
309: break;
310: }
311:
312: if(i == num_units || 0 != access(ui[i].rootdir, R_OK)) {
313: fprintf(stderr, "Failed attempt to mount device\n", devname);
314: packet->res1 = DOS_FALSE;
315: packet->res2 = ERROR_DEVICE_NOT_MOUNTED;
316: return;
317: }
318:
319: unit = (Unit *) malloc(sizeof(Unit));
320: unit->next = units;
321: units = unit;
322:
323: unit->volume = 0;
324: unit->port = regs.a[5];
325: unit->unit = unit_num++;
326:
327: unit->ui.devname = ui[i].devname;
328: unit->ui.volname = my_strdup(ui[i].volname); /* might free later for rename */
329: unit->ui.rootdir = ui[i].rootdir;
330: unit->ui.readonly = ui[i].readonly;
331:
332: TRACE(("**** STARTUP volume %s\n", unit->ui.volname));
333:
334: /* fill in our process in the device node */
335: put_long((packet->arg3 << 2) + 8, unit->port);
336:
337: /* open dos.library */
338: regs.d[0] = 0;
339: regs.a[1] = EXPANSION_doslibname;
340: unit->dosbase = CallLib(regs.a[6], -552); /* OpenLibrary */
341:
342: {
343: CPTR rootnode = get_long(unit->dosbase + 34);
344: CPTR dos_info = get_long(rootnode + 24) << 2;
345: /* make new volume */
346: unit->volume = DosAllocMem(80 + 1 + 44);
347: put_long(unit->volume + 4, 2); /* Type = dt_volume */
348: put_long(unit->volume + 12, 0); /* Lock */
349: put_long(unit->volume + 16, 3800); /* Creation Date */
350: put_long(unit->volume + 20, 0);
351: put_long(unit->volume + 24, 0);
352: put_long(unit->volume + 28, 0); /* lock list */
353: put_long(unit->volume + 40, (unit->volume + 44) >> 2); /* Name */
354: namelen = strlen(unit->ui.volname);
355: put_byte(unit->volume + 44, namelen);
356: for(i = 0; i < namelen; i++)
357: put_byte(unit->volume + 45 + i, unit->ui.volname[i]);
358:
359: /* link into DOS list */
360: put_long(unit->volume, get_long(dos_info + 4));
361: put_long(dos_info + 4, unit->volume >> 2);
362: }
363:
364: put_long(unit->volume + 8, unit->port);
365: put_long(unit->volume + 32, DISK_TYPE);
366:
367: packet->res1 = DOS_TRUE;
368: }
369:
370: #ifdef HAVE_STATFS
371: static void
372: do_info(Unit* unit, DosPacket* packet, CPTR info)
373: {
374: struct statfs statbuf;
375: #if STATFS_NO_ARGS == 2
376: if(-1 == statfs(unit->ui.rootdir, &statbuf))
377: #else
378: if(-1 == statfs(unit->ui.rootdir, &statbuf, sizeof(struct statfs), 0))
379: #endif
380: {
381: packet->res1 = DOS_FALSE;
382: packet->res2 = dos_errno();
383: }
384:
385: put_long(info, 0); /* errors */
386: put_long(info + 4, unit->unit); /* unit number */
387: put_long(info + 8, unit->ui.readonly ? 80 : 82); /* state */
388: put_long(info + 12, statbuf.f_blocks); /* numblocks */
389: put_long(info + 16, statbuf.f_blocks - statbuf.STATBUF_BAVAIL); /* inuse */
390: put_long(info + 20, statbuf.f_bsize); /* bytesperblock */
391: put_long(info + 24, DISK_TYPE); /* disk type */
392: put_long(info + 28, unit->volume >> 2); /* volume node */
393: put_long(info + 32, 0); /* inuse */
394: packet->res1 = DOS_TRUE;
395: }
396: #else
397: static void
398: do_info(Unit* unit, DosPacket* packet, CPTR info)
399: {
400: put_long(info, 0); /* errors */
401: put_long(info + 4, unit->unit); /* unit number */
402: put_long(info + 8, unit->ui.readonly ? 80 : 82); /* state */
403: put_long(info + 12, 256); /* numblocks */
404: put_long(info + 16, 128); /* inuse */
405: put_long(info + 20, 512); /* bytesperblock */
406: put_long(info + 24, DISK_TYPE); /* disk type */
407: put_long(info + 28, unit->volume >> 2); /* volume node */
408: put_long(info + 32, 0); /* inuse */
409: packet->res1 = DOS_TRUE;
410: }
411: #endif
412:
413: static void
414: action_disk_info(Unit* unit, DosPacket* packet)
415: {
416: TRACE(("ACTION_DISK_INFO\n"));
417: do_info(unit, packet, packet->arg1 << 2);
418: }
419:
420: static void
421: action_info(Unit* unit, DosPacket* packet)
422: {
423: TRACE(("ACTION_INFO\n"));
424: do_info(unit, packet, packet->arg2 << 2);
425: }
426:
427: typedef struct key {
428: struct key *next;
429: ULONG uniq;
430: char *path;
431: int fd;
432: off_t file_pos;
433: } Key;
434:
435: static struct key* keys = NULL;
436:
437: static void
438: free_key(Key*k)
439: {
440: Key *k1;
441: Key *prev = NULL;
442: for(k1 = keys; k1; k1 = k1->next) {
443: if(k == k1) {
444: if(prev)
445: prev->next = k->next;
446: else
447: keys = k->next;
448: break;
449: }
450: prev = k1;
451: }
452:
453: if (k->fd >= 0)
454: close(k->fd);
455: free(k->path);
456: free(k);
457: }
458:
459: static Key*
460: lookup_key(ULONG uniq)
461: {
462: Key *k;
463: for(k = keys; k; k = k->next) {
464: if(uniq == k->uniq)
465: return k;
466: }
467: fprintf(stderr, "Error: couldn't find key %ld\n", uniq);
468: exit(1);
469: /* NOTREACHED */
470: return NULL;
471: }
472:
473: static Key*
474: new_key(void)
475: {
476: static ULONG uniq = 0;
477: Key *k = (Key*) malloc(sizeof(Key));
478: k->uniq = ++uniq;
479: k->fd = -1;
480: k->file_pos = 0;
481: k->next = keys;
482: keys = k;
483:
484: return k;
485: }
486:
487: static void
488: dumplock(CPTR lock)
489: {
490: if(!lock) {
491: fprintf(stderr, "LOCK: 0x0\n");
492: return;
493: }
494: fprintf(stderr,
495: "LOCK: 0x%lx { next=0x%lx, key=%s, mode=%ld, handler=0x%lx, volume=0x%lx }\n",
496: lock,
497: get_long(lock)<<2, lookup_key(get_long(lock+4))->path, get_long(lock+8),
498: get_long(lock+12), get_long(lock+16));
499: }
500:
501: static char*
502: get_path(Unit* unit, const char *base, const char *rel)
503: {
504: static char buf[1024];
505: char *s = buf;
506: char *p;
507: char *r;
508:
509: int i;
510:
511: TRACE(("get_path(%s,%s)\n", base, rel));
512:
513: /* root-relative path? */
514: for(i = 0; rel[i] && rel[i] != '/' && rel[i] != ':'; i++);
515: if(':' == rel[i]) {
516: /*base = unit->ui.rootdir;*/ rel += i+1;
517: }
518:
519: while(*base) {
520: *s++ = *base++;
521: }
522: *s = 0;
523: p = s; /* start of relative path */
524: r = buf + strlen(unit->ui.rootdir); /* end of fixed path */
525:
526: while(*rel) {
527: /* start with a slash? go up a level. */
528: if('/' == *rel) {
529: while(s > r && '/' != *s)
530: s--;
531: *s = 0;
532: rel++;
533: } else {
534: *s++ = '/';
535: while(*rel && '/' != *rel) {
536: *s++ = *rel++;
537: }
538: *s = 0;
539: if('/' == *rel)
540: rel++;
541: }
542: }
543: *s = 0;
544:
545: #ifdef MAKE_CASE_INSENSITIVE
546: TRACE(("path=\"%s\"\n", buf));
547: /* go through each section of the path and if it does not exist,
548: * scan its directory for any case insensitive matches
549: */
550: while(*p) {
551: char *p2 = strchr(p+1, '/');
552: char oldp2;
553: if(!p2) {
554: p2 = p+1;
555: while(*p2) p2++;
556: }
557: oldp2 = *p2;
558: *p2 = '\0';
559: if(0 != access(buf, F_OK|R_OK)) {
560: DIR* dir;
561: struct dirent* de;
562: /* does not exist -- check dir for case insensitive match */
563: *p++ = '\0'; /* was '/' */
564: dir = opendir(buf);
565: if (dir) {
566: while((de = readdir(dir))) {
567: #if 0
568: if(0 == stricmp(de->d_name, p)) /* OLSEN */
569: #endif
570: if(0 == strcasecmp(de->d_name, p))
571: break;
572: }
573: if(de) {
574: strcpy(p, de->d_name);
575: }
576: closedir(dir);
577: }
578: *--p = '/';
579: }
580: *p2 = oldp2;
581: p = p2;
582: }
583: #endif
584: TRACE(("path=\"%s\"\n", buf));
585:
586: return my_strdup(buf);
587: }
588:
589: static Key*
590: make_key(Unit* unit, CPTR lock, const char *name)
591: {
592: Key *k = new_key();
593:
594: if(!lock) {
595: k->path = get_path(unit, unit->ui.rootdir, name);
596: } else {
597: Key*oldk = lookup_key(get_long(lock + 4));
598: #if 0
599: const char *nm = strchr (name, ':');
600: if (nm == NULL) {
601: nm = name;
602: } else
603: nm++;
604: #else
605: const char *nm = name;
606: #endif
607: TRACE(("key: 0x%08lx", oldk->uniq));
608: TRACE((" \"%s\"\n", oldk->path));
609: k->path = get_path(unit, oldk->path, nm);
610: }
611:
612: TRACE(("key=\"%s\"\n", k->path));
613: return k;
614: }
615:
616: static Key*
617: dup_key(Key*k)
618: {
619: Key *newk = new_key();
620: newk->path = my_strdup(k->path);
621: return newk;
622: }
623:
624: static CPTR
625: make_lock(Unit* unit, Key *key, long mode)
626: {
627: /* allocate lock */
628: CPTR lock = DosAllocMem(20);
629:
630: put_long(lock + 4, key->uniq);
631: put_long(lock + 8, mode);
632: put_long(lock + 12, unit->port);
633: put_long(lock + 16, unit->volume >> 2);
634:
635: /* prepend to lock chain */
636: put_long(lock, get_long(unit->volume + 28));
637: put_long(unit->volume + 28, lock >> 2);
638:
639: DUMPLOCK(lock);
640: return lock;
641: }
642:
643: static void
644: free_lock(Unit* unit, CPTR lock)
645: {
646: if(!lock)
647: return;
648:
649: if(lock == get_long(unit->volume + 28) << 2) {
650: put_long(unit->volume + 28, get_long(lock));
651: } else {
652: CPTR current = get_long(unit->volume + 28);
653: CPTR next = 0;
654: while(current) {
655: next = get_long(current << 2);
656: if(lock == next << 2)
657: break;
658: current = next;
659: }
660: put_long(current << 2, get_long(lock));
661: }
662: free_key(lookup_key(get_long(lock + 4)));
663: DosFreeMem(lock);
664: }
665:
666: static void
667: action_lock(Unit* unit, DosPacket* packet)
668: {
669: CPTR lock = packet->arg1 << 2;
670: CPTR name = packet->arg2 << 2;
671: long mode = packet->arg3;
672: int access_mode = (mode == -2) ? R_OK : R_OK|W_OK;
673: Key *k;
674:
675: TRACE(("ACTION_LOCK(0x%lx, \"%s\", %d)\n",lock, bstr(name), mode));
676: DUMPLOCK(lock);
677:
678: k = make_key(unit, lock, bstr(name));
679:
680: if(k && 0 == access(k->path, access_mode)) {
681: packet->res1 = make_lock(unit, k, mode) >> 2;
682: } else {
683: if(k)
684: free_key(k);
685: packet->res1 = 0;
686: packet->res2 = ERROR_OBJECT_NOT_FOUND;
687: }
688: }
689:
690: static void
691: action_free_lock(Unit* unit, DosPacket* packet)
692: {
693: CPTR lock = packet->arg1 << 2;
694: TRACE(("ACTION_FREE_LOCK(0x%lx)\n", lock));
695: DUMPLOCK(lock);
696:
697: free_lock(unit, lock);
698:
699: packet->res1 = DOS_TRUE;
700: }
701:
702: static void
703: action_dup_lock(Unit* unit, DosPacket* packet)
704: {
705: CPTR lock = packet->arg1 << 2;
706:
707: TRACE(("ACTION_DUP_LOCK(0x%lx)\n", lock));
708: DUMPLOCK(lock);
709:
710: if(!lock) {
711: packet->res1 = 0;
712: return;
713: }
714:
715: {
716: CPTR oldkey = get_long(lock + 4);
717: CPTR oldmode = get_long(lock + 8);
718: packet->res1 = make_lock(unit, dup_key(lookup_key(oldkey)), oldmode) >> 2;
719: }
720: }
721:
722: /* convert time_t to/from AmigaDOS time */
723: const int secs_per_day = 24 * 60 * 60;
724: const int diff = (8 * 365 + 2) * (24 * 60 * 60);
725:
726: static void
727: get_time(time_t t, long* days, long* mins, long* ticks)
728: {
729: /* time_t is secs since 1-1-1970 */
730: /* days since 1-1-1978 */
731: /* mins since midnight */
732: /* ticks past minute @ 50Hz */
733:
734: t -= diff;
735: *days = t / secs_per_day;
736: t -= *days * secs_per_day;
737: *mins = t / 60;
738: t -= *mins * 60;
739: *ticks = t * 50;
740: }
741:
742: static time_t
743: put_time(long days, long mins, long ticks)
744: {
745: time_t t;
746: t = ticks / 50;
747: t += mins * 60;
748: t += days * secs_per_day;
749: t += diff;
750:
751: return t;
752: }
753:
754:
755: typedef struct {
756: ULONG uniq;
757: char *path;
758: DIR* dir;
759: } ExamineKey;
760:
761: /* Since ACTION_EXAMINE_NEXT is so braindamaged, we have to keep
762: * some of these around
763: */
764:
765: #define EXKEYS 100
766: static ExamineKey examine_keys[EXKEYS];
767: static int next_exkey = 0;
768:
769: static void
770: free_exkey(ExamineKey* ek)
771: {
772: free(ek->path);
773: ek->path = 0;
774: if(ek->dir)
775: closedir(ek->dir);
776: }
777:
778: static ExamineKey*
779: new_exkey(char *path)
780: {
781: ULONG uniq = next_exkey;
782: ExamineKey* ek= &examine_keys[next_exkey++];
783: if(next_exkey==EXKEYS)
784: next_exkey = 0;
785: if(ek->path) {
786: free_exkey(ek);
787: }
788: ek->path = my_strdup(path);
789: ek->dir = 0;
790: ek->uniq = uniq;
791: return ek;
792: }
793:
794: static void
795: get_fileinfo(Unit *unit, DosPacket* packet, CPTR info, char *buf)
796: {
797: struct stat statbuf;
798: long days, mins, ticks;
799:
800: if(-1 == stat(buf, &statbuf)) {
801: packet->res1 = DOS_FALSE;
802: packet->res2 = dos_errno();
803: } else {
804: put_long(info + 4, S_ISDIR(statbuf.st_mode) ? 2 : -3);
805: {
806: /* file name */
807: int i = 8;
808: int n;
809: char *x;
810: if (strcmp (buf, unit->ui.rootdir) == 0) {
811: x = unit->ui.volname;
812: } else {
813: x = strrchr(buf,'/');
814: if(x)
815: x++;
816: else
817: x = buf;
818: }
819: TRACE(("name=\"%s\"\n", x));
820: n = strlen(x);
821: if(n > 106) n = 106;
822: put_byte(info + i++, n);
823: while(n--)
824: put_byte(info + i++, *x++);
825: while(i < 108)
826: put_byte(info + i++, 0);
827: }
828: put_long(info + 116,
829: (S_IRUSR & statbuf.st_mode ? 0 : (1<<3)) |
830: (S_IWUSR & statbuf.st_mode ? 0 : (1<<2)) |
831: #ifndef __DOS__
832: (S_IXUSR & statbuf.st_mode ? 0 : (1<<1)) |
833: #endif
834: (S_IWUSR & statbuf.st_mode ? 0 : (1<<0)));
835: put_long(info + 120, S_ISDIR(statbuf.st_mode) ? 2 : -3);
836: put_long(info + 124, statbuf.st_size);
837: #ifdef HAVE_ST_BLOCKS
838: put_long(info + 128, statbuf.st_blocks);
839: #else
840: put_long(info + 128, statbuf.st_size / 512 + 1);
841: #endif
842: get_time(statbuf.st_mtime, &days, &mins, &ticks);
843: put_long(info + 132, days);
844: put_long(info + 136, mins);
845: put_long(info + 140, ticks);
846: put_long(info + 144, 0); /* no comment */
847: packet->res1 = DOS_TRUE;
848: }
849: }
850:
851: static void
852: do_examine(Unit *unit, DosPacket* packet, ExamineKey* ek, CPTR info)
853: {
854: static char buf[1024];
855: struct dirent* de;
856:
857: if(!ek->dir) {
858: ek->dir = opendir(ek->path);
859: }
860: if(!ek->dir) {
861: free_exkey(ek);
862: packet->res1 = DOS_FALSE;
863: packet->res2 = ERROR_NO_MORE_ENTRIES;
864: return;
865: }
866:
867: de = readdir(ek->dir);
868:
869: while(de && (0 == strcmp(".", de->d_name)
870: || 0 == strcmp("..", de->d_name)))
871: {
872: de = readdir(ek->dir);
873: }
874:
875: if(!de) {
876: TRACE(("no more entries\n"));
877: free_exkey(ek);
878: packet->res1 = DOS_FALSE;
879: packet->res2 = ERROR_NO_MORE_ENTRIES;
880: return;
881: }
882:
883: TRACE(("entry=\"%s\"\n", de->d_name));
884:
885: sprintf(buf, "%s/%s", ek->path, de->d_name);
886:
887: get_fileinfo(unit, packet, info, buf);
888: }
889:
890: static void
891: action_examine_object(Unit* unit, DosPacket* packet)
892: {
893: CPTR lock = packet->arg1 << 2;
894: CPTR info = packet->arg2 << 2;
895: char *path;
896: ExamineKey* ek;
897:
898: TRACE(("ACTION_EXAMINE_OBJECT(0x%lx,0x%lx)\n", lock, info));
899: DUMPLOCK(lock);
900:
901: if(!lock) {
902: path = unit->ui.rootdir;
903: } else {
904: Key*k = lookup_key(get_long(lock + 4));
905: path = k->path;
906: }
907:
908: get_fileinfo(unit, packet, info, path);
909: ek = new_exkey(path);
910: put_long(info, ek->uniq);
911: }
912:
913: static void
914: action_examine_next(Unit* unit, DosPacket* packet)
915: {
916: CPTR lock = packet->arg1 << 2;
917: CPTR info = packet->arg2 << 2;
918:
919: TRACE(("ACTION_EXAMINE_NEXT(0x%lx,0x%lx)\n", lock, info));
920: DUMPLOCK(lock);
921:
922: do_examine(unit, packet, &examine_keys[get_long(info)], info);
923: }
924:
925: static void
926: do_find(Unit* unit, DosPacket* packet, mode_t mode)
927: {
928: CPTR fh = packet->arg1 << 2;
929: CPTR lock = packet->arg2 << 2;
930: CPTR name = packet->arg3 << 2;
931: Key *k;
932: struct stat st;
933:
934: TRACE(("ACTION_FIND_*(0x%lx,0x%lx,\"%s\",%d)\n",fh,lock,bstr(name),mode));
935: DUMPLOCK(lock);
936:
937: k = make_key(unit, lock, bstr(name));
938: if(!k) {
939: packet->res1 = DOS_FALSE;
940: packet->res2 = ERROR_NO_FREE_STORE;
941: return;
942: }
943:
944: /* Fixme: may not quite be right */
945: if (0 == stat (k->path, &st)) {
946: if (S_ISDIR (st.st_mode)) {
947: packet->res1 = DOS_FALSE;
948: packet->res2 = ERROR_OBJECT_WRONG_TYPE;
949: return;
950: }
951: }
952:
953: k->fd = open(k->path, mode | O_BINARY, 0777);
954:
955: if(k->fd < 0) {
956: packet->res1 = DOS_FALSE;
957: packet->res2 = dos_errno();
958: free_key(k);
959: return;
960: }
961: success:
962: put_long(fh+36, k->uniq);
963:
964: packet->res1 = DOS_TRUE;
965: }
966:
967: static void
968: action_find_input(Unit* unit, DosPacket* packet)
969: {
970: do_find(unit, packet, O_RDWR);
971: }
972:
973: static void
974: action_find_output(Unit* unit, DosPacket* packet)
975: {
976: if(unit->ui.readonly) {
977: packet->res1 = DOS_FALSE;
978: packet->res2 = ERROR_DISK_WRITE_PROTECTED;
979: return;
980: }
981: do_find(unit, packet, O_RDWR|O_CREAT|O_TRUNC);
982: }
983:
984: static void
985: action_find_write(Unit* unit, DosPacket* packet)
986: {
987: if(unit->ui.readonly) {
988: packet->res1 = DOS_FALSE;
989: packet->res2 = ERROR_DISK_WRITE_PROTECTED;
990: return;
991: }
992: do_find(unit, packet, O_RDWR);
993: }
994:
995: static void
996: action_end(Unit* unit, DosPacket* packet)
997: {
998: Key *k;
999: TRACE(("ACTION_END(0x%lx)\n", packet->arg1));
1000:
1001: k = lookup_key(packet->arg1);
1002: free_key(k);
1003: packet->res1 = DOS_TRUE;
1004: }
1005:
1006: static void
1007: action_read(Unit* unit, DosPacket* packet)
1008: {
1009: Key *k = lookup_key(packet->arg1);
1010: CPTR addr = packet->arg2;
1011: long size = (LONG)packet->arg3;
1012: int actual;
1013:
1014: TRACE(("ACTION_READ(%s,0x%lx,%ld)\n",k->path,addr,size));
1015: #ifdef RELY_ON_LOADSEG_DETECTION
1016: /* HACK HACK HACK HACK
1017: * Try to detect a LoadSeg() */
1018: if (k->file_pos == 0 && size >= 4) {
1019: unsigned char buf[4];
1020: off_t currpos = lseek(k->fd, 0, SEEK_CUR);
1021: read(k->fd, buf, 4);
1022: lseek(k->fd, currpos, SEEK_SET);
1023: if (buf[0] == 0 && buf[1] == 0 && buf[2] == 3 && buf[3] == 0xF3)
1024: possible_loadseg();
1025: }
1026: #endif
1027: if (valid_address (addr, size)) {
1028: UBYTE *realpt;
1029: realpt = get_real_address (addr);
1030: actual = read(k->fd, realpt, size);
1031:
1032: if (actual <= 0) {
1033: packet->res1 = 0;
1034: packet->res2 = dos_errno();
1035: } else {
1036: packet->res1 = actual;
1037: k->file_pos += actual;
1038: }
1039: } else {
1040: char *buf;
1041: fprintf (stderr, "unixfs warning: Bad pointer passed for read\n");
1042: /* ugh this is inefficient but easy */
1043: buf = (char *)malloc(size);
1044: if(!buf) {
1045: packet->res1 = -1;
1046: packet->res2 = ERROR_NO_FREE_STORE;
1047: return;
1048: }
1049: actual = read(k->fd, buf, size);
1050:
1051: if (actual <= 0) {
1052: packet->res1 = 0;
1053: packet->res2 = dos_errno();
1054: } else {
1055: int i;
1056: packet->res1 = actual;
1057: for(i = 0; i < actual; i++)
1058: put_byte(addr + i, buf[i]);
1059: k->file_pos += actual;
1060: }
1061: free(buf);
1062: }
1063: }
1064:
1065: static void
1066: action_write(Unit* unit, DosPacket* packet)
1067: {
1068: Key*k = lookup_key(packet->arg1);
1069: CPTR addr = packet->arg2;
1070: long size = packet->arg3;
1071: char *buf;
1072: int i;
1073:
1074: TRACE(("ACTION_WRITE(%s,0x%lx,%ld)\n",k->path,addr,size));
1075:
1076: if(unit->ui.readonly) {
1077: packet->res1 = DOS_FALSE;
1078: packet->res2 = ERROR_DISK_WRITE_PROTECTED;
1079: return;
1080: }
1081:
1082: /* ugh this is inefficient but easy */
1083: buf = (char *)malloc(size);
1084: if(!buf) {
1085: packet->res1 = -1;
1086: packet->res2 = ERROR_NO_FREE_STORE;
1087: return;
1088: }
1089:
1090: for(i = 0; i < size; i++)
1091: buf[i] = get_byte(addr + i);
1092:
1093: packet->res1 = write(k->fd, buf, size);
1094: if(packet->res1 != size)
1095: packet->res2 = dos_errno();
1096: if (packet->res1 >= 0)
1097: k->file_pos += packet->res1;
1098:
1099: free(buf);
1100: }
1101:
1102: static void
1103: action_seek(Unit* unit, DosPacket* packet)
1104: {
1105: Key* k = lookup_key(packet->arg1);
1106: long pos = (LONG)packet->arg2;
1107: long mode = (LONG)packet->arg3;
1108: off_t res;
1109: long old;
1110: int whence = SEEK_CUR;
1111: if(mode > 0) whence = SEEK_END;
1112: if(mode < 0) whence = SEEK_SET;
1113:
1114: TRACE(("ACTION_SEEK(%s,%d,%d)\n",k->path,pos,mode));
1115:
1116: old = lseek(k->fd, 0, SEEK_CUR);
1117: res = lseek(k->fd, pos, whence);
1118:
1119: if(-1 == res)
1120: packet->res1 = res;
1121: else
1122: packet->res1 = old;
1123: k->file_pos = res;
1124: }
1125:
1126: static void
1127: action_set_protect(Unit* unit, DosPacket* packet)
1128: {
1129: CPTR lock = packet->arg2 << 2;
1130: CPTR name = packet->arg3 << 2;
1131: ULONG mask = packet->arg4;
1132: struct stat statbuf;
1133: mode_t mode;
1134: Key *k;
1135:
1136: TRACE(("ACTION_SET_PROTECT(0x%lx,\"%s\",0x%lx)\n",lock,bstr(name),mask));
1137:
1138: if(unit->ui.readonly) {
1139: packet->res1 = DOS_FALSE;
1140: packet->res2 = ERROR_DISK_WRITE_PROTECTED;
1141: return;
1142: }
1143:
1144: k = make_key(unit, lock, bstr(name));
1145: if(!k) {
1146: packet->res1 = DOS_FALSE;
1147: packet->res2 = ERROR_NO_FREE_STORE;
1148: return;
1149: }
1150:
1151: if(-1 == stat(k->path, &statbuf)) {
1152: free_key(k);
1153: packet->res1 = DOS_FALSE;
1154: packet->res2 = ERROR_OBJECT_NOT_FOUND;
1155: return;
1156: }
1157:
1158: mode = statbuf.st_mode;
1159:
1160: if(mask & (1 << 3))
1161: mode &= ~S_IRUSR;
1162: else
1163: mode |= S_IRUSR;
1164:
1165: if(mask & (1 << 2) || mask & (1 << 0))
1166: mode &= ~S_IWUSR;
1167: else
1168: mode |= S_IWUSR;
1169:
1170: if(mask & (1 << 1))
1171: mode &= ~S_IXUSR;
1172: else
1173: mode |= S_IXUSR;
1174:
1175: if(-1 == chmod(k->path, mode)) {
1176: packet->res1 = DOS_FALSE;
1177: packet->res2 = dos_errno();
1178: } else {
1179: packet->res1 = DOS_TRUE;
1180: }
1181: free_key(k);
1182: }
1183:
1184: static void
1185: action_same_lock(Unit* unit, DosPacket* packet)
1186: {
1187: CPTR lock1 = packet->arg1 << 2;
1188: CPTR lock2 = packet->arg2 << 2;
1189:
1190: TRACE(("ACTION_SAME_LOCK(0x%lx,0x%lx)\n",lock1,lock2));
1191: DUMPLOCK(lock1); DUMPLOCK(lock2);
1192:
1193: if(!lock1 || !lock2) {
1194: packet->res1 = (lock1 == lock2) ? DOS_TRUE : DOS_FALSE;
1195: } else {
1196: Key* key1 = lookup_key(get_long(lock1 + 4));
1197: Key* key2 = lookup_key(get_long(lock2 + 4));
1198: packet->res1 = (0 == strcmp(key1->path, key2->path)) ? DOS_TRUE : DOS_FALSE;
1199: }
1200: }
1201:
1202: static void
1203: action_parent(Unit* unit, DosPacket* packet)
1204: {
1205: CPTR lock = packet->arg1 << 2;
1206: Key*k;
1207:
1208: TRACE(("ACTION_PARENT(0x%lx)\n",lock));
1209:
1210: if(!lock) {
1211: packet->res1 = 0;
1212: packet->res2 = 0;
1213: return;
1214: }
1215:
1216: k = dup_key(lookup_key(get_long(lock + 4)));
1217: if(0 == strcmp(k->path, unit->ui.rootdir)) {
1218: free_key(k);
1219: packet->res1 = 0;
1220: packet->res2 = 0;
1221: return;
1222: }
1223: {
1224: char *x = strrchr(k->path,'/');
1225: if(!x) { /* ??? This really shouldn't happen! */
1226: free_key(k);
1227: packet->res1 = 0;
1228: packet->res2 = 0;
1229: return;
1230: } else {
1231: *x = '\0';
1232: }
1233: }
1234: packet->res1 = make_lock(unit, k, -2) >> 2;
1235: }
1236:
1237: static void
1238: action_create_dir(Unit* unit, DosPacket* packet)
1239: {
1240: CPTR lock = packet->arg1 << 2;
1241: CPTR name = packet->arg2 << 2;
1242: Key* k;
1243:
1244: TRACE(("ACTION_CREATE_DIR(0x%lx,\"%s\")\n",lock,bstr(name)));
1245:
1246: if(unit->ui.readonly) {
1247: packet->res1 = DOS_FALSE;
1248: packet->res2 = ERROR_DISK_WRITE_PROTECTED;
1249: return;
1250: }
1251:
1252: k = make_key(unit, lock, bstr(name));
1253:
1254: if(!k) {
1255: packet->res1 = DOS_FALSE;
1256: packet->res2 = ERROR_NO_FREE_STORE;
1257: return;
1258: }
1259: #ifndef AMIGA
1260: if(-1 == mkdir(k->path, 0777))
1261: #else
1262: if(-1 == mkdir(k->path))
1263: #endif
1264: {
1265: packet->res1 = DOS_FALSE;
1266: packet->res2 = dos_errno();
1267: free_key(k);
1268: return;
1269: }
1270: packet->res1 = make_lock(unit, k, -2) >> 2;
1271: }
1272:
1273: static void
1274: action_delete_object(Unit* unit, DosPacket* packet)
1275: {
1276: CPTR lock = packet->arg1 << 2;
1277: CPTR name = packet->arg2 << 2;
1278: Key* k;
1279: struct stat statbuf;
1280:
1281: TRACE(("ACTION_DELETE_OBJECT(0x%lx,\"%s\")\n",lock,bstr(name)));
1282:
1283: if(unit->ui.readonly) {
1284: packet->res1 = DOS_FALSE;
1285: packet->res2 = ERROR_DISK_WRITE_PROTECTED;
1286: return;
1287: }
1288:
1289: k = make_key(unit, lock, bstr(name));
1290:
1291: if(!k) {
1292: packet->res1 = DOS_FALSE;
1293: packet->res2 = ERROR_NO_FREE_STORE;
1294: return;
1295: }
1296: if(-1 == stat(k->path, &statbuf)) {
1297: packet->res1 = DOS_FALSE;
1298: packet->res2 = dos_errno();
1299: free_key(k);
1300: return;
1301: }
1302: if(S_ISDIR(statbuf.st_mode)) {
1303: if(-1 == rmdir(k->path)) {
1304: packet->res1 = DOS_FALSE;
1305: packet->res2 = dos_errno();
1306: free_key(k);
1307: return;
1308: }
1309: } else {
1310: if(-1 == unlink(k->path)) {
1311: packet->res1 = DOS_FALSE;
1312: packet->res2 = dos_errno();
1313: free_key(k);
1314: return;
1315: }
1316: }
1317: free_key(k);
1318: packet->res1 = DOS_TRUE;
1319: }
1320:
1321: static void
1322: action_set_date(Unit* unit, DosPacket* packet)
1323: {
1324: CPTR lock = packet->arg2 << 2;
1325: CPTR name = packet->arg3 << 2;
1326: CPTR date = packet->arg4;
1327: Key* k;
1328: #if !defined(AMIGA)
1329: struct utimbuf ut;
1330: #endif
1331:
1332: TRACE(("ACTION_SET_DATE(0x%lx,\"%s\")\n",lock,bstr(name)));
1333:
1334: if(unit->ui.readonly) {
1335: packet->res1 = DOS_FALSE;
1336: packet->res2 = ERROR_DISK_WRITE_PROTECTED;
1337: return;
1338: }
1339:
1340: #if !defined(AMIGA)
1341: ut.actime = ut.modtime = put_time(get_long(date),get_long(date+4),get_long(date+8));
1342: #endif
1343: k = make_key(unit, lock, bstr(name));
1344:
1345: if(!k) {
1346: packet->res1 = DOS_FALSE;
1347: packet->res2 = ERROR_NO_FREE_STORE;
1348: return;
1349: }
1350: #if !defined(AMIGA)
1351: if(-1 == utime(k->path, &ut)) {
1352: packet->res1 = DOS_FALSE;
1353: packet->res2 = dos_errno();
1354: free_key(k);
1355: return;
1356: }
1357: #endif
1358: free_key(k);
1359: packet->res1 = DOS_TRUE;
1360: }
1361:
1362: static void
1363: action_rename_object(Unit* unit, DosPacket* packet)
1364: {
1365: CPTR lock1 = packet->arg1 << 2;
1366: CPTR name1 = packet->arg2 << 2;
1367: Key* k1;
1368: CPTR lock2 = packet->arg3 << 2;
1369: CPTR name2 = packet->arg4 << 2;
1370: Key* k2;
1371:
1372: TRACE(("ACTION_RENAME_OBJECT(0x%lx,\"%s\",",lock1,bstr(name1)));
1373: TRACE(("0x%lx,\"%s\")\n",lock2,bstr(name2)));
1374:
1375: if(unit->ui.readonly) {
1376: packet->res1 = DOS_FALSE;
1377: packet->res2 = ERROR_DISK_WRITE_PROTECTED;
1378: return;
1379: }
1380:
1381: k1 = make_key(unit, lock1, bstr(name1));
1382: if(!k1) {
1383: packet->res1 = DOS_FALSE;
1384: packet->res2 = ERROR_NO_FREE_STORE;
1385: return;
1386: }
1387: k2 = make_key(unit, lock2, bstr(name2));
1388: if(!k2) {
1389: free_key(k1);
1390: packet->res1 = DOS_FALSE;
1391: packet->res2 = ERROR_NO_FREE_STORE;
1392: return;
1393: }
1394:
1395: if(-1 == rename(k1->path, k2->path)) {
1396: packet->res1 = DOS_FALSE;
1397: packet->res2 = dos_errno();
1398: free_key(k1);
1399: free_key(k2);
1400: return;
1401: }
1402: free_key(k1);
1403: free_key(k2);
1404: packet->res1 = DOS_TRUE;
1405: }
1406:
1407: static void
1408: action_current_volume(Unit* unit, DosPacket* packet)
1409: {
1410: packet->res1 = unit->volume >> 2;
1411: }
1412:
1413: static void
1414: action_rename_disk(Unit* unit, DosPacket* packet)
1415: {
1416: CPTR name = packet->arg1 << 2;
1417: int i;
1418: int namelen;
1419:
1420: TRACE(("ACTION_RENAME_DISK(\"%s\")\n", bstr(name)));
1421:
1422: if(unit->ui.readonly) {
1423: packet->res1 = DOS_FALSE;
1424: packet->res2 = ERROR_DISK_WRITE_PROTECTED;
1425: return;
1426: }
1427:
1428: /* get volume name */
1429: namelen = get_byte(name++);
1430: free(unit->ui.volname);
1431: unit->ui.volname = (char *) malloc(namelen + 1);
1432: for(i = 0; i < namelen; i++)
1433: unit->ui.volname[i] = get_byte(name++);
1434: unit->ui.volname[i] = 0;
1435:
1436: put_byte(unit->volume + 44, namelen);
1437: for(i = 0; i < namelen; i++)
1438: put_byte(unit->volume + 45 + i, unit->ui.volname[i]);
1439:
1440: packet->res1 = DOS_TRUE;
1441: }
1442:
1443: static void
1444: action_is_filesystem(Unit* unit, DosPacket* packet)
1445: {
1446: packet->res1 = DOS_TRUE;
1447: }
1448:
1449: static void
1450: action_flush(Unit* unit, DosPacket* packet)
1451: {
1452: /* sync(); */ /* pretty drastic, eh */
1453: packet->res1 = DOS_TRUE;
1454: }
1455:
1456: static ULONG
1457: filesys_handler(void)
1458: {
1459: DosPacket packet;
1460: Unit *unit = find_unit(regs.a[5]);
1461:
1462: /* got DosPacket in A4 */
1463: packet.addr = regs.a[4];
1464: packet.type = get_long(packet.addr + dp_Type);
1465: packet.res1 = get_long(packet.addr + dp_Res1);
1466: packet.res2 = get_long(packet.addr + dp_Res2);
1467: packet.arg1 = get_long(packet.addr + dp_Arg1);
1468: packet.arg2 = get_long(packet.addr + dp_Arg2);
1469: packet.arg3 = get_long(packet.addr + dp_Arg3);
1470: packet.arg4 = get_long(packet.addr + dp_Arg4);
1471:
1472: if(!unit) {
1473: startup(&packet);
1474: put_long(packet.addr + dp_Res1, packet.res1);
1475: put_long(packet.addr + dp_Res2, packet.res2);
1476: return 0;
1477: }
1478:
1479: if(!unit->volume) {
1480: printf("no volume\n");
1481: return 0;
1482: }
1483:
1484: switch(packet.type) {
1485: case ACTION_LOCATE_OBJECT:
1486: action_lock(unit, &packet);
1487: break;
1488:
1489: case ACTION_FREE_LOCK:
1490: action_free_lock(unit, &packet);
1491: break;
1492:
1493: case ACTION_COPY_DIR:
1494: action_dup_lock(unit, &packet);
1495: break;
1496:
1497: case ACTION_DISK_INFO:
1498: action_disk_info(unit, &packet);
1499: break;
1500:
1501: case ACTION_INFO:
1502: action_info(unit, &packet);
1503: break;
1504:
1505: case ACTION_EXAMINE_OBJECT:
1506: action_examine_object(unit, &packet);
1507: break;
1508:
1509: case ACTION_EXAMINE_NEXT:
1510: action_examine_next(unit, &packet);
1511: break;
1512:
1513: case ACTION_FIND_INPUT:
1514: action_find_input(unit, &packet);
1515: break;
1516:
1517: case ACTION_FIND_WRITE:
1518: action_find_write(unit, &packet);
1519: break;
1520:
1521: case ACTION_FIND_OUTPUT:
1522: action_find_output(unit, &packet);
1523: break;
1524:
1525: case ACTION_END:
1526: action_end(unit, &packet);
1527: break;
1528:
1529: case ACTION_READ:
1530: action_read(unit, &packet);
1531: break;
1532:
1533: case ACTION_WRITE:
1534: action_write(unit, &packet);
1535: break;
1536:
1537: case ACTION_SEEK:
1538: action_seek(unit, &packet);
1539: break;
1540:
1541: case ACTION_SET_PROTECT:
1542: action_set_protect(unit, &packet);
1543: break;
1544:
1545: case ACTION_SAME_LOCK:
1546: action_same_lock(unit, &packet);
1547: break;
1548:
1549: case ACTION_PARENT:
1550: action_parent(unit, &packet);
1551: break;
1552:
1553: case ACTION_CREATE_DIR:
1554: action_create_dir(unit, &packet);
1555: break;
1556:
1557: case ACTION_DELETE_OBJECT:
1558: action_delete_object(unit, &packet);
1559: break;
1560:
1561: case ACTION_RENAME_OBJECT:
1562: action_rename_object(unit, &packet);
1563: break;
1564:
1565: case ACTION_SET_DATE:
1566: action_set_date(unit, &packet);
1567: break;
1568:
1569: case ACTION_CURRENT_VOLUME:
1570: action_current_volume(unit, &packet);
1571: break;
1572:
1573: case ACTION_RENAME_DISK:
1574: action_rename_disk(unit, &packet);
1575: break;
1576:
1577: case ACTION_IS_FILESYSTEM:
1578: action_is_filesystem(unit, &packet);
1579: break;
1580:
1581: case ACTION_FLUSH:
1582: action_flush(unit, &packet);
1583: break;
1584:
1585: default:
1586: TRACE(("*** UNSUPPORTED PACKET %ld\n", packet.type));
1587: packet.res1 = DOS_FALSE;
1588: packet.res2 = ERROR_ACTION_NOT_KNOWN;
1589: break;
1590: }
1591:
1592: put_long(packet.addr + dp_Res1, packet.res1);
1593: put_long(packet.addr + dp_Res2, packet.res2);
1594: TRACE(("reply: %8lx, %ld\n", packet.res1, packet.res2));
1595:
1596: return 0;
1597: }
1598:
1599: static ULONG filesys_diagentry(void)
1600: {
1601: CPTR resaddr = regs.a[2] + 0x10;
1602:
1603: filesys_configdev = regs.a[3];
1604:
1605: if (ROM_hardfile_resid != 0) {
1606: /* Build a struct Resident. This will set up and initialize
1607: * the uae.device */
1608: put_word(resaddr + 0x0, 0x4AFC);
1609: put_long(resaddr + 0x2, resaddr);
1610: put_long(resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
1611: put_word(resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */
1612: put_word(resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
1613: put_long(resaddr + 0xE, ROM_hardfile_resname);
1614: put_long(resaddr + 0x12, ROM_hardfile_resid);
1615: put_long(resaddr + 0x16, ROM_hardfile_init);
1616: }
1617: resaddr += 0x1A;
1618:
1619: return 1;
1620: }
1621:
1622: static CPTR build_parmpacket(void)
1623: {
1624: CPTR tmp1;
1625:
1626: regs.d[0] = 88; regs.d[1] = 1; /* MEMF_PUBLIC */
1627: tmp1 = CallLib (get_long(4), -198); /* AllocMem() */
1628: if (tmp1 == 0) {
1629: fprintf(stderr, "Not enough memory for filesystem!\n");
1630: return 0;
1631: }
1632:
1633: put_long (tmp1+12, 0); /* Device flags */
1634: put_long (tmp1+16, 16); /* Env. size */
1635: put_long (tmp1+20, 128); /* 512 bytes/block */
1636: put_long (tmp1+24, 0); /* unused */
1637: put_long (tmp1+28, 1); /* heads */
1638: put_long (tmp1+32, 1); /* unused */
1639: put_long (tmp1+36, 32); /* secs per track */
1640: put_long (tmp1+40, 1); /* reserved blocks */
1641: put_long (tmp1+44, 0); /* unused */
1642: put_long (tmp1+48, 0); /* interleave */
1643: put_long (tmp1+52, 0); /* lowCyl */
1644: #ifndef __DOS__
1645: put_long (tmp1+56, 511); /* upperCyl */
1646: #else
1647: {
1648: extern int numtracks;
1649: put_long (tmp1+56, numtracks-1); /* upperCyl */
1650: }
1651: #endif
1652: put_long (tmp1+60, 0); /* Number of buffers */
1653: put_long (tmp1+64, 0); /* Buffer mem type */
1654: put_long (tmp1+68, 0x7FFFFFFF); /* largest transfer */
1655: put_long (tmp1+72, ~1); /* addMask (?) */
1656: put_long (tmp1+76, (ULONG)-1); /* bootPri */
1657: #if 0
1658: if (have36)
1659: put_long (tmp1+80, 0x444f5301); /* DOS\1 */
1660: else
1661: #endif
1662: put_long (tmp1+80, 0x444f5300); /* DOS\0 */
1663:
1664: put_long (tmp1+84, 0); /* pad */
1665: return tmp1;
1666: }
1667:
1668: static void make_dev(CPTR param_packet, int unit_no, int is_hardfile, int boot)
1669: {
1670: CPTR devicenode, bootnode;
1671:
1672: put_long (param_packet, ui[unit_no].devname_amiga);
1673: put_long (param_packet + 4, is_hardfile ? ROM_hardfile_resname : fsdevname);
1674: put_long (param_packet + 8, ui[unit_no].devno);
1675:
1676: regs.a[0] = param_packet;
1677: devicenode = CallLib (EXPANSION_explibbase, -144); /* MakeDosNode() */
1678: ui[unit_no].startup = get_long(devicenode + 28);
1679: if (!is_hardfile) {
1680: put_long(devicenode+8, 0x0); /* dn_Task */
1681: put_long(devicenode+16, 0x0); /* dn_Handler */
1682: put_long(devicenode+20, 4000); /* dn_StackSize */
1683: put_long(devicenode+32, filesysseglist >> 2); /* dn_SegList */
1684: put_long(devicenode+36, (ULONG)-1); /* dn_GlobalVec */
1685: } else {
1686: /* ??? */
1687: put_long(devicenode+8, 0x0); /* dn_Task */
1688: put_long(devicenode+16, 0x0); /* dn_Handler */
1689: put_long(devicenode+32, 0); /* dn_SegList */
1690: }
1691:
1692: if (boot) {
1693: if (EXPANSION_haveV36) {
1694: regs.d[0] = -1; regs.d[1] = 0;
1695: regs.a[0] = devicenode;
1696: regs.a[1] = filesys_configdev;
1697: CallLib(EXPANSION_explibbase, -36);
1698: } else {
1699: /* Construct a BootNode and Enqueue() it into eb_MountList */
1700: regs.d[0] = 20;
1701: regs.d[1] = 0;
1702: bootnode = CallLib (get_long(4), -198); /* AllocMem() */
1703:
1704: put_word (bootnode + 14, 0); /* Flags (??) */
1705: put_long (bootnode + 16, devicenode);
1706: put_word (bootnode + 8, 0x10FF-unit_no); /* Type/Pri */
1707: put_long (bootnode + 10, filesys_configdev); /* Name */
1708: put_long (bootnode + 0, 0);
1709: put_long (bootnode + 4, 0);
1710: regs.a[0] = EXPANSION_explibbase + 74; /* MountList */
1711: regs.a[1] = bootnode;
1712: CallLib (get_long(4), -270); /* Enqueue() */
1713: }
1714: } else {
1715: /* Call AddDosNode() for the constructed node */
1716: regs.a[0] = devicenode;
1717: regs.d[0] = (ULONG)-1;
1718: regs.a[1] = 0;
1719: regs.d[1] = 0; /* Flags */
1720: CallLib (EXPANSION_explibbase, -150); /* AddDosNode() */
1721: }
1722: }
1723:
1724: void filesys_init(void)
1725: {
1726: int i;
1727: int firstdev = 1;
1728:
1729: /* Open expansion.lib */
1730:
1731: EXPANSION_haveV36 = 0;
1732: regs.d[0] = 36;
1733: regs.a[1] = EXPANSION_explibname;
1734: EXPANSION_explibbase = CallLib (get_long(4), -552); /* OpenLibrary() */
1735: if (EXPANSION_explibbase)
1736: EXPANSION_haveV36 = 1;
1737: else {
1738: regs.d[0] = 0;
1739: regs.a[1] = EXPANSION_explibname;
1740: EXPANSION_explibbase = CallLib (get_long(4), -552); /* OpenLibrary() */
1741: }
1742:
1743: filesys_parampacket = build_parmpacket();
1744:
1745: /* re-use the same parameter packet to make each
1746: * dos node, which will then get tweaked
1747: */
1748:
1749: for(i = 0; i < num_units; i++) {
1750: int is_hardfile = ui[i].volname == NULL;
1751: if (is_hardfile && !EXPANSION_haveV36) {
1752: fprintf(stderr, "Kickstart is older than 2.0, please mount hardfile manually.\n");
1753: continue;
1754: }
1755: make_dev(filesys_parampacket, i, is_hardfile, 1);
1756: }
1757:
1758: regs.a[1] = EXPANSION_explibbase;
1759: CallLib (get_long(4), -414); /* CloseLibrary() */
1760: EXPANSION_explibbase = 0;
1761: }
1762:
1763: void filesys_install(void)
1764: {
1765: int i;
1766: CPTR loop;
1767:
1768: ROM_filesys_resname = ds("UAEunixfs.resource");
1769: ROM_filesys_resid = ds("UAE unixfs 0.2");
1770:
1771: fsdevname = ds("uae.device"); /* does not really exist */
1772:
1773: for(i = 0; i < num_units; i++) {
1774: ui[i].devno = get_new_device(&ui[i].devname, &ui[i].devname_amiga);
1775: }
1776:
1777: ROM_filesys_diagentry = here();
1778: calltrap2(deftrap(filesys_diagentry)); dw(RTS);
1779:
1780: /* align */
1781: align(4);
1782: /* Fake seglist */
1783: dl(16);
1784: filesysseglist = here();
1785: dl(0); /* NextSeg */
1786:
1787: /* start of code */
1788:
1789: /* I don't trust calling functions that Wait() directly,
1790: * so here's a little bit of 68000 code to receive and send our
1791: * DosPackets
1792: */
1793: dw(0x2c79); dl(4); /* move.l $4,a6 */
1794: dw(0x2279); dl(0); /* move.l 0,a1 */
1795: dw(0x4eae); dw(0xfeda); /* jsr FindTask(a6) */
1796: dw(0x2040); /* move.l d0,a0 */
1797: dw(0x4be8); dw(0x005c); /* lea.l pr_MsgPort(a0),a5 */
1798: /* loop: */
1799: loop = here();
1800: dw(0x204d); /* move.l a5,a0 */
1801: dw(0x4eae); dw(0xfe80); /* jsr WaitPort(a6) */
1802: dw(0x204d); /* move.l a5,a0 */
1803: dw(0x4eae); dw(0xfe8c); /* jsr GetMsg(a6) */
1804: dw(0x2840); /* move.l d0,a4 */
1805: dw(0x286c); dw(10); /* move.l LN_NAME(a4),a4 */
1806: calltrap2(deftrap(filesys_handler));
1807: dw(0x226c); dw(0); /* move.l dp_Link(a4),a1 */
1808: dw(0x206c); dw(4); /* move.l dp_Port(a4),a0 */
1809: dw(0x294d); dw(4); /* move.l a5,dp_Port(a4) */
1810: dw(0x4eae); dw(0xfe92); /* jsr PutMsg(a6) */
1811: dw(0x4ef9); dl(loop); /* jmp loop */
1812:
1813: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.