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