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