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