|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * Unix file system handler for AmigaDOS
5: *
1.1.1.3 root 6: * Copyright 1996 Ed Hanway
7: * Copyright 1996, 1997 Bernd Schmidt
1.1 root 8: *
1.1.1.3 root 9: * Version 0.4: 970308
1.1 root 10: *
11: * Based on example code (c) 1988 The Software Distillery
12: * and published in Transactor for the Amiga, Volume 2, Issues 2-5.
13: * (May - August 1989)
14: *
15: * Known limitations:
16: * Does not support ACTION_INHIBIT (big deal).
17: * Does not support any 2.0+ packet types (except ACTION_SAME_LOCK)
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.
1.1.1.3 root 22: * Could do tighter checks on malloc return values.
23: * Will probably fail spectacularly in some cases if the filesystem is
24: * modified at the same time by another process while UAE is running.
1.1 root 25: */
26:
27: #include "sysconfig.h"
28: #include "sysdeps.h"
29:
30: #include "config.h"
31: #include "options.h"
1.1.1.3 root 32: #include "uae.h"
1.1 root 33: #include "memory.h"
34: #include "custom.h"
1.1.1.2 root 35: #include "readcpu.h"
1.1 root 36: #include "newcpu.h"
1.1.1.3 root 37: #include "filesys.h"
1.1 root 38: #include "autoconf.h"
39: #include "compiler.h"
1.1.1.4 ! root 40: #include "fsusage.h"
1.1.1.3 root 41: #include "threaddep/penguin.h"
1.1 root 42:
1.1.1.3 root 43: /* #define TRACING_ENABLED */
44: #ifdef TRACING_ENABLED
1.1.1.4 ! root 45: #define TRACE(x) do { write_log x; } while(0)
1.1.1.3 root 46: #define DUMPLOCK(u,x) dumplock(u,x)
47: #else
48: #define TRACE(x)
49: #define DUMPLOCK(u,x)
50: #endif
51:
52: #define MAKE_CASE_INSENSITIVE
1.1 root 53:
1.1.1.3 root 54: /* errors */
55: #define ERROR_NO_FREE_STORE 103
56: #define ERROR_OBJECT_IN_USE 202
57: #define ERROR_OBJECT_EXISTS 203
58: #define ERROR_DIR_NOT_FOUND 204
59: #define ERROR_OBJECT_NOT_FOUND 205
60: #define ERROR_ACTION_NOT_KNOWN 209
61: #define ERROR_INVALID_LOCK 211
62: #define ERROR_OBJECT_WRONG_TYPE 212
63: #define ERROR_DISK_WRITE_PROTECTED 214
64: #define ERROR_DIRECTORY_NOT_EMPTY 216
65: #define ERROR_DEVICE_NOT_MOUNTED 218
66: #define ERROR_SEEK_ERROR 219
67: #define ERROR_DISK_FULL 221
68: #define ERROR_DELETE_PROTECTED 222
69: #define ERROR_WRITE_PROTECTED 223
70: #define ERROR_READ_PROTECTED 224
71: #define ERROR_NO_MORE_ENTRIES 232
72: #define ERROR_NOT_IMPLEMENTED 236
73:
74: #ifndef DONT_HAVE_POSIX
75: static long dos_errno(void)
1.1 root 76: {
1.1.1.3 root 77: int e = errno;
1.1 root 78:
1.1.1.4 ! root 79: switch (e) {
1.1.1.3 root 80: case ENOMEM: return ERROR_NO_FREE_STORE;
81: case EEXIST: return ERROR_OBJECT_EXISTS;
82: case EACCES: return ERROR_WRITE_PROTECTED;
83: case ENOENT: return ERROR_OBJECT_NOT_FOUND;
84: case ENOTDIR: return ERROR_OBJECT_WRONG_TYPE;
85: case ENOSPC: return ERROR_DISK_FULL;
86: case EBUSY: return ERROR_OBJECT_IN_USE;
87: case EISDIR: return ERROR_OBJECT_WRONG_TYPE;
88: #if defined(ETXTBSY)
89: case ETXTBSY: return ERROR_OBJECT_IN_USE;
90: #endif
91: #if defined(EROFS)
92: case EROFS: return ERROR_DISK_WRITE_PROTECTED;
93: #endif
94: #if defined(ENOTEMPTY)
95: #if ENOTEMPTY != EEXIST
96: case ENOTEMPTY: return ERROR_DIRECTORY_NOT_EMPTY;
97: #endif
98: #endif
99:
100: default:
1.1.1.4 ! root 101: TRACE(("Unimplemented error %s\n", strerror(e)));
1.1.1.3 root 102: return ERROR_NOT_IMPLEMENTED;
103: }
1.1 root 104: }
105: #endif
106:
1.1.1.3 root 107: /*
108: * This _should_ be no issue for us, but let's rather use a guaranteed
109: * thread safe function if we have one.
1.1.1.4 ! root 110: * This used to be broken in glibc versions <= 2.0.1 (I think). I hope
! 111: * no one is using this these days.
! 112: * Michael Krause says it's also broken in libc5. ARRRGHHHHHH!!!!
1.1.1.3 root 113: */
114: #if 0 && defined HAVE_READDIR_R
115:
116: static struct dirent *my_readdir (DIR *dirstream, struct dirent *space)
117: {
118: struct dirent *loc;
119: if (readdir_r (dirstream, space, &loc) == 0) {
120: /* Success */
121: return loc;
122: }
123: return 0;
124: }
125:
126: #else
127: #define my_readdir(dirstream, space) readdir(dirstream)
128: #endif
129:
1.1.1.4 ! root 130: uaecptr filesys_initcode;
! 131: static uae_u32 fsdevname, filesys_configdev;
! 132:
1.1.1.3 root 133: #define FS_STARTUP 0
134: #define FS_GO_DOWN 1
135:
136: /* AmigaOS "keys" */
137: struct a_inode {
138: struct a_inode *next, *prev;
139: struct a_inode *parent;
140: struct a_inode *child, *sibling; /* @@@ implement hash tables or something to make this efficient */
141: char *aname;
142: char *nname;
143: int amigaos_mode;
144: int shlock;
145: uae_u32 uniq;
146: unsigned int dir:1;
147: unsigned int elock:1;
148: };
1.1 root 149:
150: typedef struct {
151: char *devname; /* device name, e.g. UAE0: */
1.1.1.3 root 152: uaecptr devname_amiga;
153: uaecptr startup;
1.1 root 154: char *volname; /* volume name, e.g. CDROM, WORK, etc. */
155: char *rootdir; /* root unix directory */
156: int readonly; /* disallow write access? */
157: int devno;
1.1.1.3 root 158:
159: struct hardfiledata hf;
160:
161: /* Threading stuff */
162: smp_comm_pipe *unit_pipe, *back_pipe;
163: penguin_id tid;
164: struct _unit *volatile self;
1.1.1.4 ! root 165: /* Reset handling */
! 166: uae_sem_t reset_sync_sem;
! 167: int reset_state;
1.1 root 168: } UnitInfo;
169:
170: #define MAX_UNITS 20
171:
1.1.1.4 ! root 172: struct uaedev_mount_info {
! 173: int num_units;
! 174: UnitInfo ui[MAX_UNITS];
! 175: };
! 176:
! 177: static struct uaedev_mount_info *current_mountinfo;
! 178:
! 179: int nr_units (struct uaedev_mount_info *mountinfo)
! 180: {
! 181: return mountinfo->num_units;
! 182: }
! 183:
! 184: int is_hardfile (struct uaedev_mount_info *mountinfo, int unit_no)
! 185: {
! 186: return mountinfo->ui[unit_no].volname == 0;
! 187: }
! 188:
! 189: static void close_filesys_unit (struct uaedev_mount_info *mountinfo, int nr)
! 190: {
! 191: UnitInfo *uip = mountinfo->ui + nr;
! 192:
! 193: if (uip->hf.fd != 0)
! 194: fclose (uip->hf.fd);
! 195: if (uip->volname != 0)
! 196: free (uip->volname);
! 197: if (uip->devname != 0)
! 198: free (uip->devname);
! 199: if (uip->rootdir != 0)
! 200: free (uip->rootdir);
! 201: if (uip->unit_pipe)
! 202: free (uip->unit_pipe);
! 203: if (uip->back_pipe)
! 204: free (uip->back_pipe);
! 205:
! 206: uip->unit_pipe = 0;
! 207: uip->back_pipe = 0;
! 208:
! 209: uip->hf.fd = 0;
! 210: uip->volname = 0;
! 211: uip->devname = 0;
! 212: uip->rootdir = 0;
! 213: }
! 214:
! 215: char *get_filesys_unit (struct uaedev_mount_info *mountinfo, int nr,
! 216: char **volname, char **rootdir, int *readonly,
! 217: int *secspertrack, int *surfaces, int *reserved,
! 218: int *cylinders, int *size)
! 219: {
! 220: UnitInfo *uip = mountinfo->ui + nr;
! 221:
! 222: if (nr >= mountinfo->num_units)
! 223: return "No slot allocated for this unit";
! 224:
! 225: *volname = uip->volname ? my_strdup (uip->volname) : 0;
! 226: *rootdir = uip->rootdir ? my_strdup (uip->rootdir) : 0;
! 227: *readonly = uip->readonly;
! 228: *secspertrack = uip->hf.secspertrack;
! 229: *surfaces = uip->hf.surfaces;
! 230: *reserved = uip->hf.reservedblocks;
! 231: *size = uip->hf.size;
! 232: *cylinders = uip->hf.nrcyls;
! 233: return 0;
! 234: }
! 235:
! 236: char *set_filesys_unit (struct uaedev_mount_info *mountinfo, int nr,
! 237: char *volname, char *rootdir, int readonly,
1.1.1.3 root 238: int secspertrack, int surfaces, int reserved)
1.1 root 239: {
1.1.1.4 ! root 240: UnitInfo tmpui;
! 241:
! 242: if (nr >= mountinfo->num_units)
! 243: return "No slot allocated for this unit";
1.1 root 244:
1.1.1.3 root 245: if (volname != 0) {
1.1.1.4 ! root 246: tmpui.volname = my_strdup (volname);
! 247: tmpui.hf.fd = 0;
1.1.1.3 root 248: } else {
1.1.1.4 ! root 249: tmpui.volname = 0;
! 250: tmpui.hf.fd = fopen (rootdir, "r+b");
! 251: if (tmpui.hf.fd == 0) {
1.1.1.3 root 252: readonly = 1;
1.1.1.4 ! root 253: tmpui.hf.fd = fopen (rootdir, "rb");
1.1.1.3 root 254: }
1.1.1.4 ! root 255: if (tmpui.hf.fd == 0)
1.1.1.3 root 256: return "Hardfile not found";
1.1.1.4 ! root 257:
1.1.1.3 root 258: if (secspertrack < 1 || secspertrack > 32767
259: || surfaces < 1 || surfaces > 1023
1.1.1.4 ! root 260: || reserved < 0 || reserved > 1023)
! 261: {
1.1.1.3 root 262: return "Bad hardfile geometry";
263: }
1.1.1.4 ! root 264: fseek (tmpui.hf.fd, 0, SEEK_END);
! 265: tmpui.hf.size = ftell (tmpui.hf.fd);
! 266: tmpui.hf.secspertrack = secspertrack;
! 267: tmpui.hf.surfaces = surfaces;
! 268: tmpui.hf.reservedblocks = reserved;
! 269: tmpui.hf.nrcyls = (tmpui.hf.size >> 9) / (secspertrack * surfaces);
! 270: }
! 271: tmpui.self = 0;
! 272: tmpui.reset_state = FS_STARTUP;
! 273: tmpui.rootdir = my_strdup (rootdir);
! 274: tmpui.readonly = readonly;
! 275:
! 276: close_filesys_unit (mountinfo, nr);
! 277: mountinfo->ui[nr] = tmpui;
1.1 root 278:
1.1.1.3 root 279: return 0;
1.1 root 280: }
1.1.1.4 ! root 281:
! 282: char *add_filesys_unit (struct uaedev_mount_info *mountinfo,
! 283: char *volname, char *rootdir, int readonly,
! 284: int secspertrack, int surfaces, int reserved)
! 285: {
! 286: char *retval;
! 287: int nr = mountinfo->num_units;
! 288: UnitInfo *uip = mountinfo->ui + nr;
1.1 root 289:
1.1.1.4 ! root 290: if (nr >= MAX_UNITS)
! 291: return "Maximum number of file systems mounted";
! 292:
! 293: uip->hf.fd = 0;
! 294: uip->devname = 0;
! 295: uip->volname = 0;
! 296: uip->rootdir = 0;
! 297: uip->unit_pipe = 0;
! 298: uip->back_pipe = 0;
! 299:
! 300: mountinfo->num_units++;
! 301: retval = set_filesys_unit (mountinfo, nr, volname, rootdir, readonly,
! 302: secspertrack, surfaces, reserved);
! 303: if (retval)
! 304: mountinfo->num_units--;
! 305: return retval;
! 306: }
! 307:
! 308: int kill_filesys_unit (struct uaedev_mount_info *mountinfo, int nr)
1.1.1.2 root 309: {
1.1.1.4 ! root 310: UnitInfo *uip = mountinfo->ui;
! 311: if (nr >= mountinfo->num_units || nr < 0)
1.1.1.2 root 312: return -1;
313:
1.1.1.4 ! root 314: close_filesys_unit (mountinfo, nr);
! 315:
! 316: mountinfo->num_units--;
! 317: for (; nr < mountinfo->num_units; nr++) {
! 318: uip[nr] = uip[nr+1];
1.1.1.2 root 319: }
320: return 0;
321: }
322:
1.1.1.4 ! root 323: int move_filesys_unit (struct uaedev_mount_info *mountinfo, int nr, int to)
1.1.1.3 root 324: {
1.1.1.4 ! root 325: UnitInfo tmpui;
! 326: UnitInfo *uip = mountinfo->ui;
! 327:
! 328: if (nr >= mountinfo->num_units || nr < 0
! 329: || to >= mountinfo->num_units || to < 0
! 330: || to == nr)
! 331: return -1;
! 332: tmpui = uip[nr];
! 333: if (to > nr) {
! 334: int i;
! 335: for (i = nr; i < to; i++)
! 336: uip[i] = uip[i + 1];
! 337: } else {
! 338: int i;
! 339: for (i = nr; i > to; i--)
! 340: uip[i] = uip[i - 1];
! 341: }
! 342: uip[to] = tmpui;
! 343: return 0;
1.1.1.3 root 344: }
345:
1.1.1.4 ! root 346: int sprintf_filesys_unit (struct uaedev_mount_info *mountinfo, char *buffer, int num)
1.1.1.2 root 347: {
1.1.1.4 ! root 348: UnitInfo *uip = mountinfo->ui;
! 349: if (num >= mountinfo->num_units)
1.1.1.2 root 350: return -1;
1.1.1.4 ! root 351:
! 352: if (uip[num].volname != 0)
! 353: sprintf (buffer, "(UAE%d:) Filesystem, %s: %s %s", num, uip[num].volname,
! 354: uip[num].rootdir, uip[num].readonly ? "ro" : "");
1.1.1.2 root 355: else
1.1.1.3 root 356: sprintf (buffer, "(UAE%d:) Hardfile, \"%s\", size %d bytes", num,
1.1.1.4 ! root 357: uip[num].rootdir, uip[num].hf.size);
1.1.1.2 root 358: return 0;
359: }
360:
1.1.1.4 ! root 361: void write_filesys_config (struct uaedev_mount_info *mountinfo, FILE *f)
1.1 root 362: {
1.1.1.4 ! root 363: UnitInfo *uip = mountinfo->ui;
1.1 root 364: int i;
1.1.1.4 ! root 365:
! 366: for (i = 0; i < mountinfo->num_units; i++) {
! 367: if (uip[i].volname != 0) {
! 368: fprintf (f, "-%c %s:%s\n", uip[i].readonly ? 'M' : 'm',
! 369: uip[i].volname, uip[i].rootdir);
1.1.1.3 root 370: } else {
1.1.1.4 ! root 371: fprintf (f, "-W %d:%d:%d:%s\n", uip[i].hf.secspertrack,
! 372: uip[i].hf.surfaces, uip[i].hf.reservedblocks,
! 373: uip[i].rootdir);
1.1 root 374: }
375: }
376: }
377:
1.1.1.4 ! root 378: struct uaedev_mount_info *alloc_mountinfo (void)
! 379: {
! 380: struct uaedev_mount_info *info;
! 381: info = (struct uaedev_mount_info *)malloc (sizeof *info);
! 382: info->num_units = 0;
! 383: return info;
! 384: }
! 385:
! 386: struct uaedev_mount_info *dup_mountinfo (struct uaedev_mount_info *mip)
! 387: {
! 388: int i;
! 389: struct uaedev_mount_info *i2 = alloc_mountinfo ();
! 390:
! 391: memcpy (i2, mip, sizeof *i2);
! 392:
! 393: for (i = 0; i < i2->num_units; i++) {
! 394: UnitInfo *uip = i2->ui + i;
! 395: if (uip->volname)
! 396: uip->volname = my_strdup (uip->volname);
! 397: if (uip->rootdir)
! 398: uip->rootdir = my_strdup (uip->rootdir);
! 399: if (uip->hf.fd)
! 400: uip->hf.fd = fdopen (fileno (uip->hf.fd), uip->readonly ? "rb" : "r+b");
! 401: }
! 402: return i2;
! 403: }
! 404:
! 405: void free_mountinfo (struct uaedev_mount_info *mip)
! 406: {
! 407: int i;
! 408: for (i = 0; i < mip->num_units; i++)
! 409: close_filesys_unit (mip, i);
! 410: free (mip);
! 411: }
! 412:
! 413: struct hardfiledata *get_hardfile_data (int nr)
! 414: {
! 415: UnitInfo *uip = current_mountinfo->ui;
! 416: if (nr < 0 || nr >= current_mountinfo->num_units || uip[nr].volname != 0)
! 417: return 0;
! 418: return &uip[nr].hf;
! 419: }
! 420:
1.1 root 421: /* minimal AmigaDOS definitions */
422:
423: /* field offsets in DosPacket */
1.1.1.3 root 424: #define dp_Type 8
425: #define dp_Res1 12
426: #define dp_Res2 16
427: #define dp_Arg1 20
428: #define dp_Arg2 24
429: #define dp_Arg3 28
430: #define dp_Arg4 32
1.1 root 431:
432: /* result codes */
1.1.1.3 root 433: #define DOS_TRUE ((unsigned long)-1L)
1.1 root 434: #define DOS_FALSE (0L)
435:
436: /* packet types */
437: #define ACTION_CURRENT_VOLUME 7
438: #define ACTION_LOCATE_OBJECT 8
439: #define ACTION_RENAME_DISK 9
440: #define ACTION_FREE_LOCK 15
441: #define ACTION_DELETE_OBJECT 16
442: #define ACTION_RENAME_OBJECT 17
443: #define ACTION_COPY_DIR 19
444: #define ACTION_SET_PROTECT 21
445: #define ACTION_CREATE_DIR 22
446: #define ACTION_EXAMINE_OBJECT 23
447: #define ACTION_EXAMINE_NEXT 24
448: #define ACTION_DISK_INFO 25
449: #define ACTION_INFO 26
450: #define ACTION_FLUSH 27
451: #define ACTION_SET_COMMENT 28
452: #define ACTION_PARENT 29
453: #define ACTION_SET_DATE 34
454: #define ACTION_FIND_WRITE 1004
455: #define ACTION_FIND_INPUT 1005
456: #define ACTION_FIND_OUTPUT 1006
457: #define ACTION_END 1007
458: #define ACTION_SEEK 1008
459: #define ACTION_IS_FILESYSTEM 1027
460: #define ACTION_READ 'R'
461: #define ACTION_WRITE 'W'
462:
1.1.1.3 root 463: /* 2.0+ packet types */
464: #define ACTION_INHIBIT 31
465: #define ACTION_SET_FILE_SIZE 1022
466: #define ACTION_LOCK_RECORD 2008
467: #define ACTION_FREE_RECORD 2009
468: #define ACTION_SAME_LOCK 40
469: #define ACTION_CHANGE_MODE 1028
470: #define ACTION_FH_FROM_LOCK 1026
471: #define ACTION_COPY_DIR_FH 1030
472: #define ACTION_PARENT_FH 1031
473: #define ACTION_EXAMINE_FH 1034
474: #define ACTION_EXAMINE_ALL 1033
475: #define ACTION_MAKE_LINK 1021
476: #define ACTION_READ_LINK 1024
477: #define ACTION_FORMAT 1020
478: #define ACTION_IS_FILESYSTEM 1027
479: #define ACTION_ADD_NOTIFY 4097
480: #define ACTION_REMOVE_NOTIFY 4098
1.1 root 481:
1.1.1.3 root 482: #define DISK_TYPE 0x444f5301 /* DOS\1 */
1.1 root 483:
1.1.1.3 root 484: typedef struct {
485: uae_u32 uniq;
486: struct a_inode *aino;
487: DIR* dir;
488: } ExamineKey;
1.1 root 489:
1.1.1.3 root 490: typedef struct key {
491: struct key *next;
492: struct a_inode *aino;
493: uae_u32 uniq;
494: int fd;
495: off_t file_pos;
496: } Key;
1.1 root 497:
1.1.1.3 root 498: /* Since ACTION_EXAMINE_NEXT is so braindamaged, we have to keep
499: * some of these around
500: */
501:
502: #define EXKEYS 100
503: #define MAX_AINO_HASH 128
1.1 root 504:
505: /* handler state info */
506:
507: typedef struct _unit {
508: struct _unit *next;
509:
510: /* Amiga stuff */
1.1.1.4 ! root 511: uaecptr dosbase;
! 512: uaecptr volume;
! 513: uaecptr port; /* Our port */
! 514: uaecptr locklist;
1.1 root 515:
516: /* Native stuff */
1.1.1.4 ! root 517: uae_s32 unit; /* unit number */
! 518: UnitInfo ui; /* unit startup info */
! 519: char tmpbuf3[256];
1.1.1.3 root 520:
521: /* Dummy message processing */
1.1.1.4 ! root 522: uaecptr dummy_message;
1.1.1.3 root 523: volatile unsigned int cmds_sent;
524: volatile unsigned int cmds_complete;
525: volatile unsigned int cmds_acked;
526:
527: /* ExKeys */
528: ExamineKey examine_keys[EXKEYS];
1.1.1.4 ! root 529: int next_exkey;
1.1.1.3 root 530:
531: /* Keys */
1.1.1.4 ! root 532: struct key *keys;
! 533: uae_u32 key_uniq;
! 534: uae_u32 a_uniq;
1.1.1.3 root 535:
536: struct a_inode rootnode;
537: unsigned long aino_cache_size;
538: struct a_inode *aino_hash[MAX_AINO_HASH];
539: unsigned long nr_cache_hits;
540: unsigned long nr_cache_lookups;
1.1 root 541: } Unit;
542:
1.1.1.3 root 543: typedef uae_u8 *dpacket;
544: #define PUT_PCK_RES1(p,v) do { do_put_mem_long ((uae_u32 *)((p) + dp_Res1), (v)); } while (0)
545: #define PUT_PCK_RES2(p,v) do { do_put_mem_long ((uae_u32 *)((p) + dp_Res2), (v)); } while (0)
546: #define GET_PCK_TYPE(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Type))))
547: #define GET_PCK_RES1(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Res1))))
548: #define GET_PCK_RES2(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Res2))))
549: #define GET_PCK_ARG1(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg1))))
550: #define GET_PCK_ARG2(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg2))))
551: #define GET_PCK_ARG3(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg3))))
552: #define GET_PCK_ARG4(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg4))))
1.1 root 553:
1.1.1.3 root 554: static char *bstr1 (uaecptr addr)
1.1 root 555: {
556: static char buf[256];
557: int i;
1.1.1.3 root 558: int n = get_byte(addr);
559: addr++;
560:
1.1.1.4 ! root 561: for (i = 0; i < n; i++, addr++)
1.1.1.3 root 562: buf[i] = get_byte(addr);
1.1 root 563: buf[i] = 0;
564: return buf;
565: }
566:
1.1.1.3 root 567: static char *bstr (Unit *unit, uaecptr addr)
568: {
569: int i;
570: int n = get_byte(addr);
571:
572: addr++;
1.1.1.4 ! root 573: for (i = 0; i < n; i++, addr++)
1.1.1.3 root 574: unit->tmpbuf3[i] = get_byte(addr);
575: unit->tmpbuf3[i] = 0;
576: return unit->tmpbuf3;
577: }
578:
579: static char *bstr_cut (Unit *unit, uaecptr addr)
580: {
581: char *p = unit->tmpbuf3;
582: int i, colon_seen = 0;
583: int n = get_byte (addr);
584:
585: addr++;
1.1.1.4 ! root 586: for (i = 0; i < n; i++, addr++) {
1.1.1.3 root 587: uae_u8 c = get_byte(addr);
588: unit->tmpbuf3[i] = c;
589: if (c == '/' || (c == ':' && colon_seen++ == 0))
590: p = unit->tmpbuf3 + i + 1;
591: }
592: unit->tmpbuf3[i] = 0;
593: return p;
594: }
595:
596: static Unit *units = 0;
1.1 root 597: static int unit_num = 0;
598:
599: static Unit*
1.1.1.4 ! root 600: find_unit (uaecptr port)
1.1 root 601: {
602: Unit* u;
1.1.1.4 ! root 603: for (u = units; u; u = u->next)
! 604: if (u->port == port)
1.1 root 605: break;
606:
607: return u;
608: }
609:
1.1.1.3 root 610: static int get_file_attrs (struct a_inode *aino)
611: {
612: struct stat statbuf;
613: if (-1 == stat (aino->nname, &statbuf))
614: return dos_errno ();
615: aino->dir = S_ISDIR (statbuf.st_mode) ? 1 : 0;
616: aino->amigaos_mode =
1.1.1.4 ! root 617: #if !defined __DOS__ && !defined _WIN32
1.1.1.3 root 618: (S_IXUSR & statbuf.st_mode ? 0 : A_FIBF_EXECUTE) |
619: #endif
620: (S_IWUSR & statbuf.st_mode ? 0 : A_FIBF_WRITE) |
621: #if 0 /* This makes it impossible to overwrite those. */
622: (S_IWUSR & statbuf.st_mode ? 0 : A_FIBF_DELETE) |
623: #endif
624: (S_IRUSR & statbuf.st_mode ? 0 : A_FIBF_READ);
625: return 0;
626: };
627:
628: static int set_file_attrs (struct a_inode *aino, int mask)
629: {
630: struct stat statbuf;
631: int mode;
632:
633: if (-1 == stat(aino->nname, &statbuf))
634: return ERROR_OBJECT_NOT_FOUND;
635:
636: mode = statbuf.st_mode;
637: #ifdef __unix
638: /* Unix dirs behave differently than AmigaOS ones. Just allow anything. */
639: if (aino->dir) {
640: mask = 0;
641: }
642: #endif
643: if (mask & A_FIBF_READ)
644: mode &= ~S_IRUSR;
645: else
646: mode |= S_IRUSR;
647:
648: if ((mask & A_FIBF_WRITE) != 0 || (mask & A_FIBF_DELETE) != 0)
649: mode &= ~S_IWUSR;
650: else
651: mode |= S_IWUSR;
652:
653: if (mask & A_FIBF_EXECUTE)
654: mode &= ~S_IXUSR;
655: else
656: mode |= S_IXUSR;
657:
658: if (-1 == chmod(aino->nname, mode))
659: return dos_errno();
660:
661: aino->amigaos_mode = mask;
662:
663: return 0;
664: }
665:
666: static void prepare_for_open (char *name)
667: {
668: #if 0
669: struct stat statbuf;
670: int mode;
671:
672: if (-1 == stat (name, &statbuf))
673: return;
674:
675: mode = statbuf.st_mode;
676: mode |= S_IRUSR;
677: mode |= S_IWUSR;
678: mode |= S_IXUSR;
679: chmod (name, mode);
680: #endif
681: }
682:
683: static void de_recycle_aino (Unit *unit, struct a_inode *aino)
1.1 root 684: {
1.1.1.3 root 685: if (aino->next == 0 || aino == &unit->rootnode)
686: return;
687: aino->next->prev = aino->prev;
688: aino->prev->next = aino->next;
689: aino->next = aino->prev = 0;
690: unit->aino_cache_size--;
691: }
692:
693: static void recycle_aino (Unit *unit, struct a_inode *aino)
694: {
695: if (aino->dir || aino->shlock > 0 || aino->elock || aino == &unit->rootnode)
696: /* Still in use */
697: return;
698:
699: /* Chain it into circular list. */
700: aino->next = unit->rootnode.next;
701: aino->prev = &unit->rootnode;
702: aino->prev->next = aino;
703: aino->next->prev = aino;
704: unit->aino_cache_size++;
705: if (unit->aino_cache_size > 500) {
706: /* Reap a few. */
707: int i = 0;
708: while (i < 50) {
709: struct a_inode **aip;
710: aip = &unit->rootnode.prev->parent->child;
711: for (;;) {
712: aino = *aip;
713: if (aino == 0)
714: break;
715:
716: if (aino->next == 0)
717: aip = &aino->sibling;
718: else {
719: int hash = aino->uniq % MAX_AINO_HASH;
720: if (unit->aino_hash[hash] == aino)
721: unit->aino_hash[hash] = 0;
722:
723: aino->next->prev = aino->prev;
724: aino->prev->next = aino->next;
725: *aip = aino->sibling;
726: i++;
727:
728: if (aino->shlock > 0 || aino->elock)
729: write_log ("panic: freeing locked a_inode!\n");
730:
731: free (aino->nname);
732: free (aino->aname);
733: free (aino);
734: }
735: }
736: }
737: #if 0
738: {
739: char buffer[40];
740: sprintf (buffer, "%d ainos reaped.\n", i);
741: write_log (buffer);
742: }
743: #endif
744: unit->aino_cache_size -= i;
745: }
746: }
1.1 root 747:
1.1.1.3 root 748: static void update_child_names (Unit *unit, struct a_inode *a, struct a_inode *parent)
749: {
750: int l0 = strlen (parent->nname) + 2;
1.1 root 751:
1.1.1.3 root 752: while (a != 0) {
753: char *name_start;
754: char *new_name;
1.1 root 755:
1.1.1.3 root 756: a->parent = parent;
757: name_start = strrchr (a->nname, '/');
758: if (name_start == 0) {
759: write_log ("malformed file name");
760: }
761: name_start++;
762: new_name = (char *)xmalloc (strlen (name_start) + l0);
763: strcpy (new_name, parent->nname);
764: strcat (new_name, "/");
765: strcat (new_name, name_start);
766: free (a->nname);
767: a->nname = new_name;
768: if (a->child)
769: update_child_names (unit, a->child, a);
770: a = a->sibling;
1.1 root 771: }
1.1.1.3 root 772: }
1.1 root 773:
1.1.1.3 root 774: static void move_aino_children (Unit *unit, struct a_inode *from, struct a_inode *to)
775: {
776: to->child = from->child;
777: from->child = 0;
778: update_child_names (unit, to->child, to);
1.1 root 779: }
780:
1.1.1.3 root 781: static void delete_aino (Unit *unit, struct a_inode *aino)
1.1 root 782: {
1.1.1.3 root 783: struct a_inode **aip;
784: int hash;
785:
1.1.1.4 ! root 786: TRACE(("deleting aino %x\n", aino->uniq));
1.1.1.3 root 787:
788: de_recycle_aino (unit, aino);
789: aip = &aino->parent->child;
790: while (*aip != aino && *aip != 0)
791: aip = &(*aip)->sibling;
792: if (*aip != aino) {
793: write_log ("Couldn't delete aino.\n");
794: return;
795: }
796: hash = aino->uniq % MAX_AINO_HASH;
797: if (unit->aino_hash[hash] == aino)
798: unit->aino_hash[hash] = 0;
799: *aip = aino->sibling;
800: free (aino->nname);
801: free (aino->aname);
802: free (aino);
1.1 root 803: }
804:
1.1.1.3 root 805: static struct a_inode *lookup_sub (struct a_inode *dir, uae_u32 uniq)
806: {
807: struct a_inode **cp = &dir->child;
808: struct a_inode *c, *retval;
809:
810: for (;;) {
811: c = *cp;
812: if (c == 0)
813: return 0;
814:
815: if (c->uniq == uniq) {
816: retval = c;
817: break;
818: }
819: if (c->dir) {
820: struct a_inode *a = lookup_sub (c, uniq);
821: if (a != 0) {
822: retval = a;
823: break;
824: }
825: }
826: cp = &c->sibling;
827: }
828: *cp = c->sibling;
829: c->sibling = dir->child;
830: dir->child = c;
831: return retval;
832: }
833:
834: static struct a_inode *lookup_aino (Unit *unit, uae_u32 uniq)
1.1 root 835: {
1.1.1.3 root 836: struct a_inode *a;
837: int hash = uniq % MAX_AINO_HASH;
838:
839: if (uniq == 0)
840: return &unit->rootnode;
841: a = unit->aino_hash[hash];
842: if (a == 0 || a->uniq != uniq)
843: a = lookup_sub (&unit->rootnode, uniq);
844: else
845: unit->nr_cache_hits++;
846: unit->nr_cache_lookups++;
847: unit->aino_hash[hash] = a;
848: return a;
849: }
850:
851: /* This gets called to translate an Amiga name that some program used to
852: * a name that we can use on the native filesystem. */
853: static char *get_nname (Unit *unit, struct a_inode *base, char *rel)
854: {
855: DIR* dir;
1.1.1.4 ! root 856: struct dirent *de;
1.1.1.3 root 857: char *p = 0;
858:
1.1.1.4 ! root 859: /* Don't allow Unix "." and "..", which confuse AmigaOS and let us
! 860: * escape out of the mount point. */
! 861: if (rel[0] == '.'
! 862: && (rel[1] == '\0'
! 863: || (rel[1] == '.' && rel[2] == '\0')))
! 864: return 0;
! 865:
! 866: dir = opendir (base->nname);
1.1.1.3 root 867: if (dir) {
868: struct dirent de_space;
1.1.1.4 ! root 869: while ((de = my_readdir (dir, &de_space))) {
! 870: if (strcasecmp (de->d_name, rel) == 0)
1.1.1.3 root 871: break;
872: }
873: if (de) {
874: p = (char *)xmalloc (strlen (de->d_name) + strlen (base->nname) + 2);
875: strcpy (p, base->nname);
876: strcat (p, "/");
877: strcat (p, de->d_name);
878: }
1.1.1.4 ! root 879: closedir (dir);
1.1.1.3 root 880: }
881: return p;
882: }
883:
884: /*
885: * This gets called if an ACTION_EXAMINE_NEXT happens and we hit an object
886: * for which we know the name on the native filesystem, but no corresponding
887: * Amiga filesystem name.
888: * @@@ For DOS filesystems, it might make sense to declare the new name
889: * "weak", so that it can get overriden by a subsequent call to get_nname().
890: * That way, if someone does "dir :" and there is a file "foobar.inf", and
891: * someone else tries to open "foobar.info", get_nname() could maybe made to
892: * figure out that this is supposed to be the file "foobar.inf".
893: * DOS sucks...
894: */
895: static char *get_aname (Unit *unit, struct a_inode *base, char *rel)
896: {
897: char *p = 0;
898:
899: p = (char *)xmalloc (strlen (rel) + strlen (base->aname) + 2);
900: strcpy (p, base->aname);
901: strcat (p, "/");
902: strcat (p, rel);
903:
904: return p;
905: }
906:
907: static struct a_inode *new_child_aino (Unit *unit, struct a_inode *base, char *rel, int force)
908: {
909: char *nn;
910: struct a_inode *aino;
911:
912: nn = get_nname (unit, base, rel);
913: if (nn == 0 && !force)
914: return 0;
915: else if (nn != 0)
916: force = 0;
917:
918: aino = (struct a_inode *)malloc (sizeof (struct a_inode));
919: if (aino == 0)
920: return 0;
921: aino->aname = my_strdup (rel);
922: if (nn == 0) {
923: nn = (char *)xmalloc (strlen (base->nname) + strlen (rel) + 2);
924: strcpy (nn, base->nname);
925: strcat (nn, "/");
926: strcat (nn, rel);
927: free (rel);
928: }
929: aino->nname = nn;
930: aino->uniq = ++unit->a_uniq;
931: if (unit->a_uniq == 0xFFFFFFFF) {
932: write_log ("Running out of a_inodes (prepare for big trouble)!\n");
933: }
934: aino->shlock = 0;
935: aino->elock = 0;
936:
937: /* Update tree structure */
938: aino->parent = base;
939: aino->child = 0;
940: aino->sibling = base->child;
941: base->child = aino;
942: aino->next = aino->prev = 0;
943:
944: if (force == 2) {
945: aino->dir = 1;
946: aino->amigaos_mode = 0;
947: } else if (force == 1) {
948: aino->dir = 0;
949: aino->amigaos_mode = 0;
950: } else {
951: get_file_attrs (aino);
952: }
953: recycle_aino (unit, aino);
1.1.1.4 ! root 954: TRACE(("created aino %x, normal\n", aino->uniq));
1.1.1.3 root 955: return aino;
956: }
957:
958: static struct a_inode *lookup_child_aino (Unit *unit, struct a_inode *base, char *rel, uae_u32 *err)
959: {
960: struct a_inode *c = base->child;
961: int l0 = strlen (rel);
962:
963: if (base->dir == 0) {
964: *err = ERROR_OBJECT_WRONG_TYPE;
965: return 0;
966: }
967:
968: while (c != 0) {
969: int l1 = strlen (c->aname);
970: if (l0 <= l1 && strcasecmp (rel, c->aname + l1 - l0) == 0
971: && (l0 == l1 || c->aname[l1-l0-1] == '/'))
972: break;
973: c = c->sibling;
974: }
975: if (c != 0)
976: return c;
977: c = new_child_aino (unit, base, rel, 0);
978: if (c == 0)
979: *err = ERROR_OBJECT_NOT_FOUND;
980: return c;
981: }
982:
983: /* Different version because this one compares with the nname */
984: static struct a_inode *lookup_child_aino_for_exnext (Unit *unit, struct a_inode *base, char *rel, uae_u32 *err)
985: {
986: struct a_inode *c = base->child;
987: int l0 = strlen (rel);
988:
989: *err = 0;
990: while (c != 0) {
991: int l1 = strlen (c->nname);
992: if (l0 <= l1 && strcasecmp (rel, c->nname + l1 - l0) == 0
993: && (l0 == l1 || c->nname[l1-l0-1] == '/'))
994: break;
995: c = c->sibling;
996: }
997: if (c != 0)
998: return c;
999: c = (struct a_inode *)malloc (sizeof (struct a_inode));
1000: if (c == 0)
1001: *err = ERROR_NO_FREE_STORE;
1002: else {
1003: c->nname = (char *)xmalloc (strlen (base->nname) + l0 + 2);
1004: strcpy (c->nname, base->nname);
1005: strcat (c->nname, "/");
1006: strcat (c->nname, rel);
1007: c->aname = get_aname (unit, base, rel);
1008: c->uniq = ++unit->a_uniq;
1009: if (unit->a_uniq == 0xFFFFFFFF) {
1010: write_log ("Running out of a_inodes (prepare for big trouble)!\n");
1011: }
1012: c->shlock = 0;
1013: c->elock = 0;
1014:
1015: /* Update tree structure */
1016: c->parent = base;
1017: c->child = 0;
1018: c->sibling = base->child;
1019: base->child = c;
1020: c->next = c->prev = 0;
1021:
1022: get_file_attrs (c);
1023: recycle_aino (unit, c);
1.1.1.4 ! root 1024: TRACE(("created aino %x, exnext\n", c->uniq));
1.1.1.3 root 1025: }
1026: return c;
1027: }
1028:
1.1.1.4 ! root 1029: static struct a_inode *get_aino (Unit *unit, struct a_inode *base, const char *rel, uae_u32 *err)
1.1.1.3 root 1030: {
1031: char *tmp;
1032: char *p;
1033: struct a_inode *curr;
1034: int i;
1035:
1036: *err = 0;
1.1.1.4 ! root 1037: TRACE(("get_path(%s,%s)\n", base->aname, rel));
1.1.1.3 root 1038:
1039: /* root-relative path? */
1.1.1.4 ! root 1040: for (i = 0; rel[i] && rel[i] != '/' && rel[i] != ':'; i++)
1.1.1.3 root 1041: ;
1042: if (':' == rel[i])
1043: rel += i+1;
1044:
1045: tmp = my_strdup (rel);
1046: p = tmp;
1047: curr = base;
1048:
1049: while(*p) {
1050: /* start with a slash? go up a level. */
1051: if (*p == '/') {
1052: if (curr->parent != 0)
1053: curr = curr->parent;
1054: p++;
1055: } else {
1056: struct a_inode *next;
1057:
1058: char *component_end;
1059: component_end = strchr (p, '/');
1060: if (component_end != 0)
1061: *component_end = '\0';
1062: next = lookup_child_aino (unit, curr, p, err);
1063: if (next == 0) {
1064: /* if only last component not found, return parent dir. */
1065: if (*err != ERROR_OBJECT_NOT_FOUND || component_end != 0)
1066: curr = 0;
1067: /* ? what error is appropriate? */
1068: break;
1069: }
1070: curr = next;
1071: if (component_end)
1072: p = component_end+1;
1073: else
1074: break;
1075:
1076: }
1077: }
1078: free (tmp);
1079: return curr;
1080: }
1081:
1082: static uae_u32 startup_handler (void)
1083: {
1084: /* Just got the startup packet. It's in A4. DosBase is in A2,
1085: * our allocated volume structure is in D6, A5 is a pointer to
1086: * our port. */
1087: uaecptr rootnode = get_long(m68k_areg (regs, 2) + 34);
1088: uaecptr dos_info = get_long(rootnode + 24) << 2;
1089: uaecptr pkt = m68k_dreg (regs, 3);
1090: uaecptr arg2 = get_long (pkt + dp_Arg2);
1.1 root 1091: int i, namelen;
1.1.1.3 root 1092: char* devname = bstr1 (get_long (pkt + dp_Arg1) << 2);
1.1 root 1093: char* s;
1.1.1.4 ! root 1094: Unit *unit;
1.1.1.3 root 1095: UnitInfo *uinfo;
1.1 root 1096:
1097: /* find UnitInfo with correct device name */
1.1.1.4 ! root 1098: s = strchr (devname, ':');
! 1099: if (s)
1.1.1.3 root 1100: *s = '\0';
1.1 root 1101:
1.1.1.4 ! root 1102: for (i = 0; i < current_mountinfo->num_units; i++) {
1.1 root 1103: /* Hardfile volume name? */
1.1.1.4 ! root 1104: if (current_mountinfo->ui[i].volname == 0)
1.1 root 1105: continue;
1.1.1.3 root 1106:
1.1.1.4 ! root 1107: if (current_mountinfo->ui[i].startup == arg2)
1.1.1.3 root 1108: break;
1.1 root 1109: }
1.1.1.3 root 1110:
1.1.1.4 ! root 1111: if (i == current_mountinfo->num_units
! 1112: || access (current_mountinfo->ui[i].rootdir, R_OK) != 0)
! 1113: {
! 1114: write_log ("Failed attempt to mount device\n", devname);
1.1.1.3 root 1115: put_long (pkt + dp_Res1, DOS_FALSE);
1116: put_long (pkt + dp_Res2, ERROR_DEVICE_NOT_MOUNTED);
1117: return 1;
1.1 root 1118: }
1.1.1.4 ! root 1119: uinfo = current_mountinfo->ui + i;
1.1 root 1120:
1.1.1.3 root 1121: unit = (Unit *) xmalloc (sizeof (Unit));
1.1 root 1122: unit->next = units;
1123: units = unit;
1.1.1.3 root 1124: uinfo->self = unit;
1.1 root 1125:
1126: unit->volume = 0;
1.1.1.2 root 1127: unit->port = m68k_areg(regs, 5);
1.1 root 1128: unit->unit = unit_num++;
1129:
1.1.1.3 root 1130: unit->ui.devname = uinfo->devname;
1131: unit->ui.volname = my_strdup (uinfo->volname); /* might free later for rename */
1132: unit->ui.rootdir = uinfo->rootdir;
1133: unit->ui.readonly = uinfo->readonly;
1134: unit->ui.unit_pipe = uinfo->unit_pipe;
1135: unit->ui.back_pipe = uinfo->back_pipe;
1136: unit->cmds_complete = 0;
1137: unit->cmds_sent = 0;
1138: unit->cmds_acked = 0;
1139: for (i = 0; i < EXKEYS; i++) {
1140: unit->examine_keys[i].aino = 0;
1141: unit->examine_keys[i].dir = 0;
1142: unit->examine_keys[i].uniq = 0;
1143: }
1144: unit->next_exkey = 1;
1145: unit->keys = 0;
1146: unit->a_uniq = unit->key_uniq = 0;
1147:
1148: unit->rootnode.aname = uinfo->volname;
1149: unit->rootnode.nname = uinfo->rootdir;
1150: unit->rootnode.sibling = 0;
1151: unit->rootnode.next = unit->rootnode.prev = &unit->rootnode;
1152: unit->rootnode.uniq = 0;
1153: unit->rootnode.parent = 0;
1154: unit->rootnode.child = 0;
1155: unit->rootnode.dir = 1;
1156: unit->rootnode.amigaos_mode = 0;
1157: unit->rootnode.shlock = 0;
1158: unit->rootnode.elock = 0;
1159: unit->aino_cache_size = 0;
1160: for (i = 0; i < MAX_AINO_HASH; i++)
1161: unit->aino_hash[i] = 0;
1162:
1163: /* write_comm_pipe_int (unit->ui.unit_pipe, -1, 1);*/
1.1 root 1164:
1.1.1.4 ! root 1165: TRACE(("**** STARTUP volume %s\n", unit->ui.volname));
1.1 root 1166:
1167: /* fill in our process in the device node */
1.1.1.3 root 1168: put_long ((get_long (pkt + dp_Arg3) << 2) + 8, unit->port);
1169: unit->dosbase = m68k_areg(regs, 2);
1.1 root 1170:
1.1.1.3 root 1171: /* make new volume */
1172: unit->volume = m68k_areg (regs, 3) + 32;
1173: #ifdef UAE_FILESYS_THREADS
1174: unit->locklist = m68k_areg (regs, 3) + 8;
1175: #else
1176: unit->locklist = m68k_areg (regs, 3);
1177: #endif
1178: unit->dummy_message = m68k_areg (regs, 3) + 12;
1.1 root 1179:
1.1.1.3 root 1180: put_long (unit->dummy_message + 10, 0);
1181:
1182: put_long (unit->volume + 4, 2); /* Type = dt_volume */
1183: put_long (unit->volume + 12, 0); /* Lock */
1184: put_long (unit->volume + 16, 3800); /* Creation Date */
1185: put_long (unit->volume + 20, 0);
1186: put_long (unit->volume + 24, 0);
1187: put_long (unit->volume + 28, 0); /* lock list */
1188: put_long (unit->volume + 40, (unit->volume + 44) >> 2); /* Name */
1189: namelen = strlen (unit->ui.volname);
1190: put_byte (unit->volume + 44, namelen);
1.1.1.4 ! root 1191: for (i = 0; i < namelen; i++)
1.1.1.3 root 1192: put_byte (unit->volume + 45 + i, unit->ui.volname[i]);
1193:
1194: /* link into DOS list */
1195: put_long (unit->volume, get_long(dos_info + 4));
1196: put_long (dos_info + 4, unit->volume >> 2);
1197:
1198: put_long (unit->volume + 8, unit->port);
1199: put_long (unit->volume + 32, DISK_TYPE);
1.1 root 1200:
1.1.1.3 root 1201: put_long (pkt + dp_Res1, DOS_TRUE);
1202: return 0;
1.1 root 1203: }
1204:
1205: static void
1.1.1.4 ! root 1206: do_info (Unit *unit, dpacket packet, uaecptr info)
1.1 root 1207: {
1.1.1.4 ! root 1208: struct fs_usage fsu;
! 1209:
! 1210: if (get_fs_usage (unit->ui.rootdir, 0, &fsu) != 0) {
1.1.1.3 root 1211: PUT_PCK_RES1 (packet, DOS_FALSE);
1212: PUT_PCK_RES2 (packet, dos_errno ());
1.1.1.4 ! root 1213: return;
1.1 root 1214: }
1215:
1.1.1.4 ! root 1216: fsu.fsu_blocks >>= 1;
! 1217: fsu.fsu_bavail >>= 1;
1.1 root 1218: put_long(info, 0); /* errors */
1219: put_long(info + 4, unit->unit); /* unit number */
1220: put_long(info + 8, unit->ui.readonly ? 80 : 82); /* state */
1.1.1.4 ! root 1221: put_long(info + 12, fsu.fsu_blocks ); /* numblocks */
! 1222: put_long(info + 16, fsu.fsu_blocks - fsu.fsu_bavail); /* inuse */
! 1223: put_long(info + 20, 1024); /* bytesperblock */
1.1 root 1224: put_long(info + 24, DISK_TYPE); /* disk type */
1225: put_long(info + 28, unit->volume >> 2); /* volume node */
1226: put_long(info + 32, 0); /* inuse */
1.1.1.3 root 1227: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 1228: }
1229:
1230: static void
1.1.1.4 ! root 1231: action_disk_info (Unit *unit, dpacket packet)
1.1 root 1232: {
1.1.1.4 ! root 1233: TRACE(("ACTION_DISK_INFO\n"));
1.1.1.3 root 1234: do_info(unit, packet, GET_PCK_ARG1 (packet) << 2);
1.1 root 1235: }
1236:
1237: static void
1.1.1.4 ! root 1238: action_info (Unit *unit, dpacket packet)
1.1 root 1239: {
1.1.1.4 ! root 1240: TRACE(("ACTION_INFO\n"));
1.1.1.3 root 1241: do_info(unit, packet, GET_PCK_ARG2 (packet) << 2);
1.1 root 1242: }
1243:
1.1.1.4 ! root 1244: static void free_key (Unit *unit, Key *k)
1.1 root 1245: {
1246: Key *k1;
1.1.1.3 root 1247: Key *prev = 0;
1248: for (k1 = unit->keys; k1; k1 = k1->next) {
1249: if (k == k1) {
1.1.1.4 ! root 1250: if (prev)
1.1.1.3 root 1251: prev->next = k->next;
1252: else
1253: unit->keys = k->next;
1254: break;
1255: }
1256: prev = k1;
1.1 root 1257: }
1258:
1259: if (k->fd >= 0)
1260: close(k->fd);
1.1.1.3 root 1261:
1.1 root 1262: free(k);
1263: }
1264:
1.1.1.4 ! root 1265: static Key *lookup_key (Unit *unit, uae_u32 uniq)
1.1 root 1266: {
1267: Key *k;
1.1.1.3 root 1268: /* It's hardly worthwhile to optimize this - most of the time there are
1269: * only one or zero keys. */
1.1.1.4 ! root 1270: for (k = unit->keys; k; k = k->next) {
1.1.1.3 root 1271: if (uniq == k->uniq)
1272: return k;
1.1 root 1273: }
1.1.1.3 root 1274: write_log ("Error: couldn't find key!\n");
1275: #if 0
1.1 root 1276: exit(1);
1277: /* NOTREACHED */
1.1.1.3 root 1278: #endif
1279: /* There isn't much hope we will recover. Unix would kill the process,
1280: * AmigaOS gets killed by it. */
1281: write_log ("Better reset that Amiga - the system is messed up.\n");
1282: return 0;
1.1 root 1283: }
1284:
1.1.1.4 ! root 1285: static Key *new_key (Unit *unit)
1.1 root 1286: {
1.1.1.4 ! root 1287: Key *k = (Key *) xmalloc(sizeof(Key));
1.1.1.3 root 1288: k->uniq = ++unit->key_uniq;
1.1 root 1289: k->fd = -1;
1290: k->file_pos = 0;
1.1.1.3 root 1291: k->next = unit->keys;
1292: unit->keys = k;
1.1 root 1293:
1294: return k;
1295: }
1296:
1297: static void
1.1.1.4 ! root 1298: dumplock (Unit *unit, uaecptr lock)
1.1 root 1299: {
1.1.1.3 root 1300: struct a_inode *a;
1.1.1.4 ! root 1301: TRACE(("LOCK: 0x%lx", lock));
! 1302: if (!lock) {
! 1303: TRACE(("\n"));
1.1 root 1304: return;
1305: }
1.1.1.4 ! root 1306: TRACE(("{ next=0x%lx, mode=%ld, handler=0x%lx, volume=0x%lx, aino %lx ",
1.1.1.3 root 1307: get_long(lock) << 2, get_long(lock+8),
1308: get_long(lock+12), get_long(lock+16),
1309: get_long(lock + 4)));
1310: a = lookup_aino (unit, get_long (lock + 4));
1311: if (a == 0) {
1.1.1.4 ! root 1312: TRACE(("not found!"));
1.1.1.3 root 1313: } else {
1.1.1.4 ! root 1314: TRACE(("%s", a->nname));
1.1.1.3 root 1315: }
1.1.1.4 ! root 1316: TRACE((" }\n"));
1.1 root 1317: }
1318:
1.1.1.4 ! root 1319: static struct a_inode *find_aino (Unit *unit, uaecptr lock, const char *name, uae_u32 *err)
1.1 root 1320: {
1.1.1.3 root 1321: struct a_inode *a;
1.1 root 1322:
1.1.1.3 root 1323: if (lock) {
1324: struct a_inode *olda = lookup_aino (unit, get_long(lock + 4));
1325: if (olda == 0) {
1326: /* That's the best we can hope to do. */
1327: a = get_aino (unit, &unit->rootnode, name, err);
1.1 root 1328: } else {
1.1.1.4 ! root 1329: TRACE(("aino: 0x%08lx", (unsigned long int)olda->uniq));
! 1330: TRACE((" \"%s\"\n", olda->nname));
1.1.1.3 root 1331: a = get_aino (unit, olda, name, err);
1.1 root 1332: }
1333: } else {
1.1.1.3 root 1334: a = get_aino (unit, &unit->rootnode, name, err);
1.1 root 1335: }
1.1.1.3 root 1336: if (a) {
1.1.1.4 ! root 1337: TRACE(("aino=\"%s\"\n", a->nname));
1.1.1.3 root 1338: }
1339: return a;
1.1 root 1340: }
1341:
1.1.1.4 ! root 1342: static uaecptr make_lock (Unit *unit, uae_u32 uniq, long mode)
1.1 root 1343: {
1.1.1.3 root 1344: /* allocate lock from the list kept by the assembly code */
1345: uaecptr lock;
1.1 root 1346:
1.1.1.3 root 1347: lock = get_long (unit->locklist);
1348: put_long (unit->locklist, get_long (lock));
1349: lock += 4;
1.1 root 1350:
1.1.1.3 root 1351: put_long(lock + 4, uniq);
1.1 root 1352: put_long(lock + 8, mode);
1353: put_long(lock + 12, unit->port);
1354: put_long(lock + 16, unit->volume >> 2);
1355:
1356: /* prepend to lock chain */
1357: put_long(lock, get_long(unit->volume + 28));
1358: put_long(unit->volume + 28, lock >> 2);
1359:
1.1.1.3 root 1360: DUMPLOCK(unit, lock);
1.1 root 1361: return lock;
1362: }
1363:
1.1.1.4 ! root 1364: static void free_lock (Unit *unit, uaecptr lock)
1.1 root 1365: {
1.1.1.4 ! root 1366: if (! lock)
1.1 root 1367: return;
1368:
1.1.1.3 root 1369: if (lock == get_long(unit->volume + 28) << 2) {
1.1 root 1370: put_long(unit->volume + 28, get_long(lock));
1371: } else {
1.1.1.3 root 1372: uaecptr current = get_long(unit->volume + 28);
1373: uaecptr next = 0;
1.1.1.4 ! root 1374: while (current) {
1.1 root 1375: next = get_long(current << 2);
1.1.1.4 ! root 1376: if (lock == next << 2)
1.1 root 1377: break;
1378: current = next;
1379: }
1380: put_long(current << 2, get_long(lock));
1381: }
1.1.1.3 root 1382: lock -= 4;
1383: put_long (lock, get_long (unit->locklist));
1384: put_long (unit->locklist, lock);
1.1 root 1385: }
1386:
1387: static void
1.1.1.4 ! root 1388: action_lock (Unit *unit, dpacket packet)
1.1 root 1389: {
1.1.1.3 root 1390: uaecptr lock = GET_PCK_ARG1 (packet) << 2;
1391: uaecptr name = GET_PCK_ARG2 (packet) << 2;
1392: long mode = GET_PCK_ARG3 (packet);
1393: struct a_inode *a;
1394: uae_u32 err;
1.1 root 1395:
1.1.1.3 root 1396: if (mode != -2 && mode != -1) {
1.1.1.4 ! root 1397: TRACE(("Bad mode.\n"));
1.1.1.3 root 1398: mode = -2;
1399: }
1.1 root 1400:
1.1.1.4 ! root 1401: TRACE(("ACTION_LOCK(0x%lx, \"%s\", %d)\n", lock, bstr (unit, name), mode));
1.1.1.3 root 1402: DUMPLOCK(unit, lock);
1.1 root 1403:
1.1.1.3 root 1404: a = find_aino (unit, lock, bstr (unit, name), &err);
1405: if (err == 0 && (a->elock || (mode != -2 && a->shlock > 0))) {
1406: err = ERROR_OBJECT_IN_USE;
1.1 root 1407: }
1.1.1.3 root 1408: /* Lock() doesn't do access checks. */
1409: if (err != 0) {
1410: PUT_PCK_RES1 (packet, DOS_FALSE);
1411: PUT_PCK_RES2 (packet, err);
1412: return;
1413: }
1414: if (mode == -2)
1415: a->shlock++;
1416: else
1417: a->elock = 1;
1418: de_recycle_aino (unit, a);
1419: PUT_PCK_RES1 (packet, make_lock (unit, a->uniq, mode) >> 2);
1.1 root 1420: }
1421:
1.1.1.4 ! root 1422: static void action_free_lock (Unit *unit, dpacket packet)
1.1 root 1423: {
1.1.1.3 root 1424: uaecptr lock = GET_PCK_ARG1 (packet) << 2;
1425: struct a_inode *a;
1.1.1.4 ! root 1426: TRACE(("ACTION_FREE_LOCK(0x%lx)\n", lock));
1.1.1.3 root 1427: DUMPLOCK(unit, lock);
1.1 root 1428:
1.1.1.3 root 1429: a = lookup_aino (unit, get_long (lock + 4));
1430: if (a == 0) {
1431: PUT_PCK_RES1 (packet, DOS_FALSE);
1432: PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_FOUND);
1433: return;
1434: }
1435: if (a->elock)
1436: a->elock = 0;
1437: else
1438: a->shlock--;
1439: recycle_aino (unit, a);
1.1 root 1440: free_lock(unit, lock);
1441:
1.1.1.3 root 1442: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 1443: }
1444:
1445: static void
1.1.1.4 ! root 1446: action_dup_lock (Unit *unit, dpacket packet)
1.1 root 1447: {
1.1.1.3 root 1448: uaecptr lock = GET_PCK_ARG1 (packet) << 2;
1449: struct a_inode *a;
1.1.1.4 ! root 1450: TRACE(("ACTION_DUP_LOCK(0x%lx)\n", lock));
1.1.1.3 root 1451: DUMPLOCK(unit, lock);
1.1 root 1452:
1.1.1.4 ! root 1453: if (!lock) {
1.1.1.3 root 1454: PUT_PCK_RES1 (packet, 0);
1.1 root 1455: return;
1456: }
1.1.1.3 root 1457: a = lookup_aino (unit, get_long (lock + 4));
1458: if (a == 0) {
1459: PUT_PCK_RES1 (packet, DOS_FALSE);
1460: PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_FOUND);
1461: return;
1.1 root 1462: }
1.1.1.3 root 1463: /* DupLock()ing exclusive locks isn't possible, says the Autodoc, but
1464: * at least the RAM-Handler seems to allow it. Let's see what happens
1465: * if we don't. */
1466: if (a->elock) {
1467: PUT_PCK_RES1 (packet, DOS_FALSE);
1468: PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
1469: return;
1470: }
1471: a->shlock++;
1472: de_recycle_aino (unit, a);
1473: PUT_PCK_RES1 (packet, make_lock (unit, a->uniq, -2) >> 2);
1.1 root 1474: }
1475:
1476: /* convert time_t to/from AmigaDOS time */
1477: const int secs_per_day = 24 * 60 * 60;
1478: const int diff = (8 * 365 + 2) * (24 * 60 * 60);
1479:
1480: static void
1.1.1.4 ! root 1481: get_time (time_t t, long* days, long* mins, long* ticks)
1.1 root 1482: {
1483: /* time_t is secs since 1-1-1970 */
1484: /* days since 1-1-1978 */
1485: /* mins since midnight */
1486: /* ticks past minute @ 50Hz */
1487:
1488: t -= diff;
1489: *days = t / secs_per_day;
1490: t -= *days * secs_per_day;
1491: *mins = t / 60;
1492: t -= *mins * 60;
1493: *ticks = t * 50;
1494: }
1495:
1496: static time_t
1.1.1.4 ! root 1497: put_time (long days, long mins, long ticks)
1.1 root 1498: {
1499: time_t t;
1500: t = ticks / 50;
1501: t += mins * 60;
1502: t += days * secs_per_day;
1503: t += diff;
1504:
1505: return t;
1506: }
1507:
1.1.1.4 ! root 1508: static void free_exkey (ExamineKey *ek)
1.1 root 1509: {
1.1.1.3 root 1510: ek->aino = 0;
1511: ek->uniq = 0;
1512: if (ek->dir)
1513: closedir (ek->dir);
1.1 root 1514: }
1515:
1.1.1.3 root 1516: /* This is so sick... who invented ACTION_EXAMINE_NEXT? What did he THINK??? */
1.1.1.4 ! root 1517: static ExamineKey *new_exkey (Unit *unit, struct a_inode *aino)
1.1 root 1518: {
1.1.1.3 root 1519: uae_u32 uniq;
1520: uae_u32 oldest = 0xFFFFFFFF;
1521: ExamineKey *ek, *oldest_ek = 0;
1522: int i;
1523:
1524: ek = unit->examine_keys;
1525: for (i = 0; i < EXKEYS; i++, ek++) {
1526: /* Did we find a free one? */
1527: if (ek->aino == 0)
1528: continue;
1529: if (ek->uniq < oldest)
1530: oldest = (oldest_ek = ek)->uniq;
1531: }
1532: ek = unit->examine_keys;
1533: for (i = 0; i < EXKEYS; i++, ek++) {
1534: /* Did we find a free one? */
1535: if (ek->aino == 0)
1536: goto found;
1537: }
1538: /* This message should usually be harmless. */
1539: write_log ("Houston, we have a problem.\n");
1540: free_exkey (oldest_ek);
1541: ek = oldest_ek;
1542: found:
1543:
1544: uniq = unit->next_exkey;
1545: if (uniq == 0xFFFFFFFF) {
1546: /* Things will probably go wrong, but most likely the Amiga will crash
1547: * before this happens because of something else. */
1548: uniq = 1;
1.1 root 1549: }
1.1.1.3 root 1550: unit->next_exkey = uniq+1;
1551: ek->aino = aino;
1.1 root 1552: ek->dir = 0;
1553: ek->uniq = uniq;
1554: return ek;
1555: }
1556:
1.1.1.4 ! root 1557: static ExamineKey *lookup_exkey (Unit *unit, uae_u32 uniq)
1.1.1.3 root 1558: {
1559: ExamineKey *ek;
1560: int i;
1561:
1562: ek = unit->examine_keys;
1563: for (i = 0; i < EXKEYS; i++, ek++) {
1564: /* Did we find a free one? */
1565: if (ek->uniq == uniq)
1566: return ek;
1567: }
1568: write_log ("Houston, we have a BIG problem.\n");
1569: return 0;
1570: }
1571:
1.1 root 1572: static void
1.1.1.4 ! root 1573: get_fileinfo (Unit *unit, dpacket packet, uaecptr info, struct a_inode *aino)
1.1 root 1574: {
1575: struct stat statbuf;
1576: long days, mins, ticks;
1.1.1.3 root 1577: int i, n;
1578: char *x;
1579:
1580: /* No error checks - this had better work. */
1581: stat (aino->nname, &statbuf);
1582:
1583: if (aino->parent == 0) {
1584: x = unit->ui.volname;
1585: put_long (info + 4, 1);
1586: put_long (info + 120, 1);
1.1 root 1587: } else {
1.1.1.3 root 1588: /* AmigaOS docs say these have to contain the same value. */
1589: put_long(info + 4, aino->dir ? 2 : -3);
1590: put_long(info + 120, aino->dir ? 2 : -3);
1591: x = strrchr (aino->aname, '/');
1592: if (x)
1593: x++;
1594: else
1595: x = aino->aname;
1596: }
1.1.1.4 ! root 1597: TRACE(("name=\"%s\"\n", x));
1.1.1.3 root 1598: n = strlen(x);
1599: if (n > 106)
1600: n = 106;
1601: i = 8;
1602: put_byte(info + i, n); i++;
1603: while(n--)
1604: put_byte(info + i, *x), i++, x++;
1605: while(i < 108)
1606: put_byte(info + i, 0), i++;
1607:
1608: put_long (info + 116, aino->amigaos_mode);
1609: put_long(info + 124, statbuf.st_size);
1.1 root 1610: #ifdef HAVE_ST_BLOCKS
1.1.1.3 root 1611: put_long(info + 128, statbuf.st_blocks);
1.1 root 1612: #else
1.1.1.3 root 1613: put_long(info + 128, statbuf.st_size / 512 + 1);
1.1 root 1614: #endif
1.1.1.3 root 1615: get_time(statbuf.st_mtime, &days, &mins, &ticks);
1616: put_long(info + 132, days);
1617: put_long(info + 136, mins);
1618: put_long(info + 140, ticks);
1619: put_long(info + 144, 0); /* no comment */
1620: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 1621: }
1622:
1.1.1.4 ! root 1623: static void do_examine (Unit *unit, dpacket packet, ExamineKey *ek, uaecptr info)
1.1 root 1624: {
1.1.1.3 root 1625: struct dirent de_space;
1.1 root 1626: struct dirent* de;
1.1.1.3 root 1627: struct a_inode *aino;
1628: uae_u32 err;
1.1 root 1629:
1.1.1.3 root 1630: if (!ek->dir) {
1631: ek->dir = opendir (ek->aino->nname);
1.1 root 1632: }
1.1.1.3 root 1633: if (!ek->dir) {
1634: free_exkey (ek);
1635: PUT_PCK_RES1 (packet, DOS_FALSE);
1636: PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
1.1 root 1637: return;
1638: }
1639:
1.1.1.3 root 1640: de = my_readdir (ek->dir, &de_space);
1.1 root 1641:
1.1.1.3 root 1642: while (de && (0 == strcmp(".", de->d_name)
1.1.1.4 ! root 1643: || 0 == strcmp("..", de->d_name)))
1.1 root 1644: {
1.1.1.3 root 1645: de = my_readdir (ek->dir, &de_space);
1.1 root 1646: }
1647:
1.1.1.3 root 1648: if (!de) {
1.1.1.4 ! root 1649: TRACE(("no more entries\n"));
1.1.1.3 root 1650: free_exkey (ek);
1651: PUT_PCK_RES1 (packet, DOS_FALSE);
1652: PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
1.1 root 1653: return;
1654: }
1655:
1.1.1.4 ! root 1656: TRACE(("entry=\"%s\"\n", de->d_name));
1.1.1.3 root 1657: aino = lookup_child_aino_for_exnext (unit, ek->aino, de->d_name, &err);
1658: if (err != 0) {
1659: write_log ("Severe problem in ExNext.\n");
1660: free_exkey (ek);
1661: PUT_PCK_RES1 (packet, DOS_FALSE);
1662: PUT_PCK_RES2 (packet, err);
1663: return;
1664: }
1665: get_fileinfo (unit, packet, info, aino);
1.1 root 1666: }
1667:
1.1.1.4 ! root 1668: static void action_examine_object (Unit *unit, dpacket packet)
1.1 root 1669: {
1.1.1.3 root 1670: uaecptr lock = GET_PCK_ARG1 (packet) << 2;
1671: uaecptr info = GET_PCK_ARG2 (packet) << 2;
1672: struct a_inode *aino = 0;
1.1 root 1673:
1.1.1.4 ! root 1674: TRACE(("ACTION_EXAMINE_OBJECT(0x%lx,0x%lx)\n", lock, info));
1.1.1.3 root 1675: DUMPLOCK(unit, lock);
1.1 root 1676:
1.1.1.3 root 1677: if (lock != 0)
1678: aino = lookup_aino (unit, get_long(lock + 4));
1679: if (aino == 0)
1680: aino = &unit->rootnode;
1681:
1682: get_fileinfo (unit, packet, info, aino);
1683: if (aino->dir) {
1684: put_long(info, 0xFFFFFFFF);
1685: } else
1686: put_long(info, 0);
1.1 root 1687: }
1688:
1.1.1.4 ! root 1689: static void action_examine_next (Unit *unit, dpacket packet)
1.1 root 1690: {
1.1.1.3 root 1691: uaecptr lock = GET_PCK_ARG1 (packet) << 2;
1692: uaecptr info = GET_PCK_ARG2 (packet) << 2;
1693: struct a_inode *aino = 0;
1694: ExamineKey *ek;
1695: uae_u32 uniq;
1.1 root 1696:
1.1.1.4 ! root 1697: TRACE(("ACTION_EXAMINE_NEXT(0x%lx,0x%lx)\n", lock, info));
1.1.1.3 root 1698: DUMPLOCK(unit, lock);
1.1 root 1699:
1.1.1.3 root 1700: if (lock != 0)
1701: aino = lookup_aino (unit, get_long(lock + 4));
1702: if (aino == 0)
1703: aino = &unit->rootnode;
1704:
1705: uniq = get_long (info);
1706: if (uniq == 0) {
1707: write_log ("ExNext called for a file! (Houston?)\n");
1708: PUT_PCK_RES1 (packet, DOS_FALSE);
1709: PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
1710: return;
1711: } else if (uniq == 0xFFFFFFFF) {
1712: ek = new_exkey(unit, aino);
1713: } else
1714: ek = lookup_exkey (unit, get_long(info));
1715: if (ek == 0) {
1716: write_log ("Couldn't find a matching ExKey. Prepare for trouble.\n");
1717: PUT_PCK_RES1 (packet, DOS_FALSE);
1718: PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
1719: return;
1720: }
1721: put_long(info, ek->uniq);
1722: do_examine(unit, packet, ek, info);
1.1 root 1723: }
1724:
1.1.1.4 ! root 1725: static void do_find (Unit *unit, dpacket packet, int mode, int create, int fallback)
1.1 root 1726: {
1.1.1.3 root 1727: uaecptr fh = GET_PCK_ARG1 (packet) << 2;
1728: uaecptr lock = GET_PCK_ARG2 (packet) << 2;
1729: uaecptr name = GET_PCK_ARG3 (packet) << 2;
1730: struct a_inode *aino;
1.1 root 1731: Key *k;
1.1.1.3 root 1732: int fd;
1733: uae_u32 err;
1734: mode_t openmode;
1735: int aino_created = 0;
1736:
1.1.1.4 ! root 1737: TRACE(("ACTION_FIND_*(0x%lx,0x%lx,\"%s\",%d)\n", fh, lock, bstr (unit, name), mode));
1.1.1.3 root 1738: DUMPLOCK(unit, lock);
1739:
1740: aino = find_aino (unit, lock, bstr (unit, name), &err);
1741:
1742: if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_FOUND)) {
1743: /* Whatever it is, we can't handle it. */
1744: PUT_PCK_RES1 (packet, DOS_FALSE);
1745: PUT_PCK_RES2 (packet, err);
1746: return;
1747: }
1748: if (err == 0) {
1749: /* Object exists. */
1750: if (aino->dir) {
1751: PUT_PCK_RES1 (packet, DOS_FALSE);
1752: PUT_PCK_RES2 (packet, ERROR_OBJECT_WRONG_TYPE);
1753: return;
1754: }
1755: if (aino->elock || (create == 2 && aino->shlock > 0)) {
1756: PUT_PCK_RES1 (packet, DOS_FALSE);
1757: PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
1758: return;
1759: }
1760: if (create == 2 && (aino->amigaos_mode & A_FIBF_DELETE) != 0) {
1761: PUT_PCK_RES1 (packet, DOS_FALSE);
1762: PUT_PCK_RES2 (packet, ERROR_DELETE_PROTECTED);
1763: return;
1764: }
1765: if (create != 2) {
1766: if ((((mode & aino->amigaos_mode) & A_FIBF_WRITE) != 0 || unit->ui.readonly)
1767: && fallback)
1768: {
1769: mode &= ~A_FIBF_WRITE;
1770: }
1771: /* Kick 1.3 doesn't check read and write access bits - maybe it would be
1772: * simpler just not to do that either. */
1773: if ((mode & A_FIBF_WRITE) != 0 && unit->ui.readonly) {
1774: PUT_PCK_RES1 (packet, DOS_FALSE);
1775: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1776: return;
1777: }
1778: if (((mode & aino->amigaos_mode) & A_FIBF_WRITE) != 0
1779: || mode == 0)
1780: {
1781: PUT_PCK_RES1 (packet, DOS_FALSE);
1782: PUT_PCK_RES2 (packet, ERROR_WRITE_PROTECTED);
1783: return;
1784: }
1785: if (((mode & aino->amigaos_mode) & A_FIBF_READ) != 0) {
1786: PUT_PCK_RES1 (packet, DOS_FALSE);
1787: PUT_PCK_RES2 (packet, ERROR_READ_PROTECTED);
1788: return;
1789: }
1790: }
1791: } else if (create == 0) {
1792: PUT_PCK_RES1 (packet, DOS_FALSE);
1793: PUT_PCK_RES2 (packet, err);
1.1 root 1794: return;
1.1.1.3 root 1795: } else {
1796: /* Object does not exist. aino points to containing directory. */
1797: aino = new_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 1);
1798: if (aino == 0) {
1799: PUT_PCK_RES1 (packet, DOS_FALSE);
1800: PUT_PCK_RES2 (packet, ERROR_DISK_FULL); /* best we can do */
1.1 root 1801: return;
1802: }
1.1.1.3 root 1803: aino_created = 1;
1.1 root 1804: }
1805:
1.1.1.3 root 1806: prepare_for_open (aino->nname);
1.1 root 1807:
1.1.1.3 root 1808: openmode = (((mode & A_FIBF_READ) == 0 ? O_WRONLY
1809: : (mode & A_FIBF_WRITE) == 0 ? O_RDONLY
1810: : O_RDWR)
1811: | (create ? O_CREAT : 0)
1812: | (create == 2 ? O_TRUNC : 0));
1813:
1814: fd = open (aino->nname, openmode | O_BINARY, 0777);
1815:
1816: if (fd < 0) {
1817: if (aino_created)
1818: delete_aino (unit, aino);
1819: PUT_PCK_RES1 (packet, DOS_FALSE);
1820: PUT_PCK_RES2 (packet, dos_errno());
1.1 root 1821: return;
1822: }
1.1.1.3 root 1823: k = new_key (unit);
1824: k->fd = fd;
1825: k->aino = aino;
1.1 root 1826:
1.1.1.3 root 1827: put_long (fh+36, k->uniq);
1828: if (create == 2)
1829: aino->elock = 1;
1830: else
1831: aino->shlock++;
1832: de_recycle_aino (unit, aino);
1833: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 1834: }
1835:
1836: static void
1.1.1.4 ! root 1837: action_find_input (Unit *unit, dpacket packet)
1.1 root 1838: {
1.1.1.3 root 1839: do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 0, 1);
1.1 root 1840: }
1841:
1842: static void
1.1.1.4 ! root 1843: action_find_output (Unit *unit, dpacket packet)
1.1 root 1844: {
1.1.1.3 root 1845: if (unit->ui.readonly) {
1846: PUT_PCK_RES1 (packet, DOS_FALSE);
1847: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1 root 1848: return;
1849: }
1.1.1.3 root 1850: do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 2, 0);
1.1 root 1851: }
1852:
1853: static void
1.1.1.4 ! root 1854: action_find_write (Unit *unit, dpacket packet)
1.1 root 1855: {
1.1.1.3 root 1856: if (unit->ui.readonly) {
1857: PUT_PCK_RES1 (packet, DOS_FALSE);
1858: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1 root 1859: return;
1860: }
1.1.1.3 root 1861: do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 1, 0);
1.1 root 1862: }
1863:
1864: static void
1.1.1.4 ! root 1865: action_end (Unit *unit, dpacket packet)
1.1 root 1866: {
1867: Key *k;
1.1.1.4 ! root 1868: TRACE(("ACTION_END(0x%lx)\n", GET_PCK_ARG1 (packet)));
1.1 root 1869:
1.1.1.3 root 1870: k = lookup_key (unit, GET_PCK_ARG1 (packet));
1871: if (k != 0) {
1872: if (k->aino->elock)
1873: k->aino->elock = 0;
1874: else
1875: k->aino->shlock--;
1876: recycle_aino (unit, k->aino);
1877: free_key (unit, k);
1878: }
1879: PUT_PCK_RES1 (packet, DOS_TRUE);
1880: PUT_PCK_RES2 (packet, 0);
1.1 root 1881: }
1882:
1883: static void
1.1.1.4 ! root 1884: action_read (Unit *unit, dpacket packet)
1.1 root 1885: {
1.1.1.3 root 1886: Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
1887: uaecptr addr = GET_PCK_ARG2 (packet);
1888: long size = (uae_s32)GET_PCK_ARG3 (packet);
1.1 root 1889: int actual;
1890:
1.1.1.3 root 1891: if (k == 0) {
1892: PUT_PCK_RES1 (packet, DOS_FALSE);
1893: /* PUT_PCK_RES2 (packet, EINVAL); */
1894: return;
1895: }
1.1.1.4 ! root 1896: TRACE(("ACTION_READ(%s,0x%lx,%ld)\n",k->aino->nname,addr,size));
1.1 root 1897: #ifdef RELY_ON_LOADSEG_DETECTION
1.1.1.3 root 1898: /* HACK HACK HACK HACK
1.1 root 1899: * Try to detect a LoadSeg() */
1900: if (k->file_pos == 0 && size >= 4) {
1901: unsigned char buf[4];
1902: off_t currpos = lseek(k->fd, 0, SEEK_CUR);
1903: read(k->fd, buf, 4);
1904: lseek(k->fd, currpos, SEEK_SET);
1905: if (buf[0] == 0 && buf[1] == 0 && buf[2] == 3 && buf[3] == 0xF3)
1906: possible_loadseg();
1907: }
1908: #endif
1909: if (valid_address (addr, size)) {
1.1.1.3 root 1910: uae_u8 *realpt;
1.1 root 1911: realpt = get_real_address (addr);
1912: actual = read(k->fd, realpt, size);
1913:
1.1.1.2 root 1914: if (actual == 0) {
1.1.1.3 root 1915: PUT_PCK_RES1 (packet, 0);
1916: PUT_PCK_RES2 (packet, 0);
1.1.1.2 root 1917: } else if (actual < 0) {
1.1.1.3 root 1918: PUT_PCK_RES1 (packet, 0);
1919: PUT_PCK_RES2 (packet, dos_errno());
1.1 root 1920: } else {
1.1.1.3 root 1921: PUT_PCK_RES1 (packet, actual);
1.1 root 1922: k->file_pos += actual;
1923: }
1924: } else {
1925: char *buf;
1.1.1.4 ! root 1926: write_log ("unixfs warning: Bad pointer passed for read: %08x\n", addr);
1.1 root 1927: /* ugh this is inefficient but easy */
1928: buf = (char *)malloc(size);
1.1.1.4 ! root 1929: if (!buf) {
1.1.1.3 root 1930: PUT_PCK_RES1 (packet, -1);
1931: PUT_PCK_RES2 (packet, ERROR_NO_FREE_STORE);
1.1 root 1932: return;
1933: }
1934: actual = read(k->fd, buf, size);
1935:
1.1.1.2 root 1936: if (actual < 0) {
1.1.1.3 root 1937: PUT_PCK_RES1 (packet, 0);
1938: PUT_PCK_RES2 (packet, dos_errno());
1.1 root 1939: } else {
1940: int i;
1.1.1.3 root 1941: PUT_PCK_RES1 (packet, actual);
1.1.1.4 ! root 1942: for (i = 0; i < actual; i++)
1.1 root 1943: put_byte(addr + i, buf[i]);
1944: k->file_pos += actual;
1945: }
1.1.1.4 ! root 1946: free (buf);
1.1 root 1947: }
1948: }
1949:
1950: static void
1.1.1.4 ! root 1951: action_write (Unit *unit, dpacket packet)
1.1 root 1952: {
1.1.1.3 root 1953: Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
1954: uaecptr addr = GET_PCK_ARG2 (packet);
1955: long size = GET_PCK_ARG3 (packet);
1.1 root 1956: char *buf;
1957: int i;
1958:
1.1.1.3 root 1959: if (k == 0) {
1960: PUT_PCK_RES1 (packet, DOS_FALSE);
1961: /* PUT_PCK_RES2 (packet, EINVAL); */
1962: return;
1963: }
1.1 root 1964:
1.1.1.4 ! root 1965: TRACE(("ACTION_WRITE(%s,0x%lx,%ld)\n",k->aino->nname,addr,size));
1.1.1.3 root 1966:
1967: if (unit->ui.readonly) {
1968: PUT_PCK_RES1 (packet, DOS_FALSE);
1969: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1 root 1970: return;
1971: }
1972:
1973: /* ugh this is inefficient but easy */
1974: buf = (char *)malloc(size);
1.1.1.3 root 1975: if (!buf) {
1976: PUT_PCK_RES1 (packet, -1);
1977: PUT_PCK_RES2 (packet, ERROR_NO_FREE_STORE);
1.1 root 1978: return;
1979: }
1980:
1.1.1.3 root 1981: for (i = 0; i < size; i++)
1.1 root 1982: buf[i] = get_byte(addr + i);
1983:
1.1.1.3 root 1984: PUT_PCK_RES1 (packet, write(k->fd, buf, size));
1985: if (GET_PCK_RES1 (packet) != size)
1986: PUT_PCK_RES2 (packet, dos_errno ());
1987: if (GET_PCK_RES1 (packet) >= 0)
1988: k->file_pos += GET_PCK_RES1 (packet);
1.1 root 1989:
1.1.1.4 ! root 1990: free (buf);
1.1 root 1991: }
1992:
1993: static void
1.1.1.4 ! root 1994: action_seek (Unit *unit, dpacket packet)
1.1 root 1995: {
1.1.1.4 ! root 1996: Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
1.1.1.3 root 1997: long pos = (uae_s32)GET_PCK_ARG2 (packet);
1998: long mode = (uae_s32)GET_PCK_ARG3 (packet);
1.1 root 1999: off_t res;
2000: long old;
2001: int whence = SEEK_CUR;
2002:
1.1.1.3 root 2003: if (k == 0) {
2004: PUT_PCK_RES1 (packet, -1);
2005: PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK);
2006: return;
2007: }
1.1 root 2008:
1.1.1.3 root 2009: if (mode > 0) whence = SEEK_END;
2010: if (mode < 0) whence = SEEK_SET;
1.1 root 2011:
1.1.1.4 ! root 2012: TRACE(("ACTION_SEEK(%s,%d,%d)\n", k->aino->nname, pos, mode));
1.1.1.3 root 2013:
2014: old = lseek (k->fd, 0, SEEK_CUR);
2015: res = lseek (k->fd, pos, whence);
2016:
2017: if (-1 == res) {
2018: PUT_PCK_RES1 (packet, res);
2019: PUT_PCK_RES2 (packet, ERROR_SEEK_ERROR);
2020: } else
2021: PUT_PCK_RES1 (packet, old);
1.1 root 2022: k->file_pos = res;
2023: }
2024:
2025: static void
1.1.1.4 ! root 2026: action_set_protect (Unit *unit, dpacket packet)
1.1 root 2027: {
1.1.1.3 root 2028: uaecptr lock = GET_PCK_ARG2 (packet) << 2;
2029: uaecptr name = GET_PCK_ARG3 (packet) << 2;
2030: uae_u32 mask = GET_PCK_ARG4 (packet);
2031: struct a_inode *a;
2032: uae_u32 err;
1.1 root 2033:
1.1.1.4 ! root 2034: TRACE(("ACTION_SET_PROTECT(0x%lx,\"%s\",0x%lx)\n", lock, bstr (unit, name), mask));
1.1 root 2035:
1.1.1.3 root 2036: if (unit->ui.readonly) {
2037: PUT_PCK_RES1 (packet, DOS_FALSE);
2038: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1 root 2039: return;
2040: }
2041:
1.1.1.3 root 2042: a = find_aino (unit, lock, bstr (unit, name), &err);
2043: if (err != 0) {
2044: PUT_PCK_RES1 (packet, DOS_FALSE);
2045: PUT_PCK_RES2 (packet, err);
1.1 root 2046: return;
2047: }
2048:
1.1.1.3 root 2049: err = set_file_attrs (a, mask);
2050: if (err != 0) {
2051: PUT_PCK_RES1 (packet, DOS_FALSE);
2052: PUT_PCK_RES2 (packet, err);
2053: } else {
2054: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1.1.2 root 2055: }
1.1.1.3 root 2056: }
1.1 root 2057:
1.1.1.3 root 2058: static void
1.1.1.4 ! root 2059: action_same_lock (Unit *unit, dpacket packet)
1.1.1.3 root 2060: {
2061: uaecptr lock1 = GET_PCK_ARG1 (packet) << 2;
2062: uaecptr lock2 = GET_PCK_ARG2 (packet) << 2;
1.1 root 2063:
1.1.1.4 ! root 2064: TRACE(("ACTION_SAME_LOCK(0x%lx,0x%lx)\n",lock1,lock2));
1.1.1.3 root 2065: DUMPLOCK(unit, lock1); DUMPLOCK(unit, lock2);
1.1 root 2066:
1.1.1.3 root 2067: if (!lock1 || !lock2) {
2068: PUT_PCK_RES1 (packet, lock1 == lock2 ? DOS_TRUE : DOS_FALSE);
1.1 root 2069: } else {
1.1.1.3 root 2070: PUT_PCK_RES1 (packet, get_long (lock1 + 4) == get_long (lock2 + 4) ? DOS_TRUE : DOS_FALSE);
1.1 root 2071: }
2072: }
2073:
2074: static void
1.1.1.4 ! root 2075: action_parent (Unit *unit, dpacket packet)
1.1 root 2076: {
1.1.1.3 root 2077: uaecptr lock = GET_PCK_ARG1 (packet) << 2;
1.1.1.4 ! root 2078: struct a_inode *olda;
1.1 root 2079:
1.1.1.4 ! root 2080: TRACE(("ACTION_PARENT(0x%lx)\n",lock));
1.1 root 2081:
1.1.1.3 root 2082: if (!lock) {
2083: PUT_PCK_RES1 (packet, 0);
2084: PUT_PCK_RES2 (packet, 0);
2085: return;
2086: }
2087:
2088: olda = lookup_aino (unit, get_long(lock + 4));
2089: if (olda == 0) {
2090: PUT_PCK_RES1 (packet, DOS_FALSE);
2091: PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK);
2092: return;
2093: }
2094:
2095: if (olda->parent == 0) {
2096: PUT_PCK_RES1 (packet, 0);
2097: PUT_PCK_RES2 (packet, 0);
2098: return;
1.1 root 2099: }
1.1.1.3 root 2100: if (olda->parent->elock) {
2101: PUT_PCK_RES1 (packet, DOS_FALSE);
2102: PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
2103: return;
2104: }
2105: olda->parent->shlock++;
2106: de_recycle_aino (unit, olda->parent);
2107: PUT_PCK_RES1 (packet, make_lock (unit, olda->parent->uniq, -2) >> 2);
1.1 root 2108: }
2109:
2110: static void
1.1.1.4 ! root 2111: action_create_dir (Unit *unit, dpacket packet)
1.1 root 2112: {
1.1.1.3 root 2113: uaecptr lock = GET_PCK_ARG1 (packet) << 2;
2114: uaecptr name = GET_PCK_ARG2 (packet) << 2;
2115: struct a_inode *aino;
2116: uae_u32 err;
1.1 root 2117:
1.1.1.4 ! root 2118: TRACE(("ACTION_CREATE_DIR(0x%lx,\"%s\")\n", lock, bstr (unit, name)));
1.1 root 2119:
1.1.1.3 root 2120: if (unit->ui.readonly) {
2121: PUT_PCK_RES1 (packet, DOS_FALSE);
2122: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1 root 2123: return;
2124: }
2125:
1.1.1.3 root 2126: aino = find_aino (unit, lock, bstr (unit, name), &err);
2127: if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_FOUND)) {
2128: PUT_PCK_RES1 (packet, DOS_FALSE);
2129: PUT_PCK_RES2 (packet, err);
1.1 root 2130: return;
2131: }
1.1.1.3 root 2132: if (err == 0) {
2133: /* Object exists. */
2134: PUT_PCK_RES1 (packet, DOS_FALSE);
2135: PUT_PCK_RES2 (packet, ERROR_OBJECT_EXISTS);
2136: return;
1.1 root 2137: }
1.1.1.3 root 2138: /* Object does not exist. aino points to containing directory. */
2139: aino = new_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 2);
2140: if (aino == 0) {
2141: PUT_PCK_RES1 (packet, DOS_FALSE);
2142: PUT_PCK_RES2 (packet, ERROR_DISK_FULL); /* best we can do */
2143: return;
2144: }
2145:
2146: if (mkdir (aino->nname, 0777) == -1) {
2147: PUT_PCK_RES1 (packet, DOS_FALSE);
2148: PUT_PCK_RES2 (packet, dos_errno());
2149: return;
2150: }
2151: aino->shlock = 1;
2152: de_recycle_aino (unit, aino);
2153: PUT_PCK_RES1 (packet, make_lock (unit, aino->uniq, -2) >> 2);
1.1 root 2154: }
2155:
2156: static void
1.1.1.4 ! root 2157: action_examine_fh (Unit *unit, dpacket packet)
1.1 root 2158: {
1.1.1.3 root 2159: Key *k;
2160: struct a_inode *aino = 0;
2161: uaecptr info = GET_PCK_ARG2 (packet) << 2;
1.1 root 2162:
1.1.1.4 ! root 2163: TRACE(("ACTION_EXAMINE_FH(0x%lx,0x%lx)\n", GET_PCK_ARG1 (packet), GET_PCK_ARG2 (packet) ));
1.1 root 2164:
1.1.1.3 root 2165: k = lookup_key (unit, GET_PCK_ARG1 (packet));
2166: if (k != 0)
2167: aino = k->aino;
2168: if (aino == 0)
2169: aino = &unit->rootnode;
2170:
2171: get_fileinfo (unit, packet, info, aino);
2172: if (aino->dir)
2173: put_long(info, 0xFFFFFFFF);
2174: else
2175: put_long(info, 0);
2176: }
2177:
2178: /* For a nice example of just how contradictory documentation can be, see the
2179: * Autodoc for DOS:SetFileSize and the Packets.txt description of this packet...
2180: * This implementation tries to mimic the behaviour of the Kick 3.1 ramdisk
2181: * (which seems to match the Autodoc description). */
2182: static void
1.1.1.4 ! root 2183: action_set_file_size (Unit *unit, dpacket packet)
1.1.1.3 root 2184: {
2185: Key *k, *k1;
2186: off_t offset = GET_PCK_ARG2 (packet);
2187: long mode = (uae_s32)GET_PCK_ARG3 (packet);
2188: int whence = SEEK_CUR;
2189:
2190: if (mode > 0) whence = SEEK_END;
2191: if (mode < 0) whence = SEEK_SET;
1.1 root 2192:
1.1.1.4 ! root 2193: TRACE(("ACTION_SET_FILE_SIZE(0x%lx, %d, 0x%x)\n", GET_PCK_ARG1 (packet), offset, mode));
1.1 root 2194:
1.1.1.3 root 2195: k = lookup_key (unit, GET_PCK_ARG1 (packet));
2196: if (k == 0) {
2197: PUT_PCK_RES1 (packet, DOS_TRUE);
2198: PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_FOUND);
1.1 root 2199: return;
2200: }
1.1.1.3 root 2201:
2202: /* If any open files have file pointers beyond this size, truncate only
2203: * so far that these pointers do not become invalid. */
2204: for (k1 = unit->keys; k1; k1 = k1->next) {
2205: if (k != k1 && k->aino == k1->aino) {
2206: if (k1->file_pos > offset)
2207: offset = k1->file_pos;
2208: }
2209: }
2210:
2211: /* Write one then truncate: that should give the right size in all cases. */
2212: offset = lseek (k->fd, offset, whence);
2213: write (k->fd, /* whatever */(char *)&k1, 1);
2214: if (k->file_pos > offset)
2215: k->file_pos = offset;
2216: lseek (k->fd, k->file_pos, SEEK_SET);
2217:
2218: if (truncate (k->aino->nname, k->file_pos) == -1) {
2219: PUT_PCK_RES1 (packet, DOS_FALSE);
2220: PUT_PCK_RES2 (packet, dos_errno ());
1.1 root 2221: return;
2222: }
1.1.1.3 root 2223:
2224: PUT_PCK_RES1 (packet, offset);
2225: PUT_PCK_RES2 (packet, 0);
1.1 root 2226: }
2227:
2228: static void
1.1.1.4 ! root 2229: action_delete_object (Unit *unit, dpacket packet)
1.1 root 2230: {
1.1.1.3 root 2231: uaecptr lock = GET_PCK_ARG1 (packet) << 2;
2232: uaecptr name = GET_PCK_ARG2 (packet) << 2;
2233: struct a_inode *a;
2234: uae_u32 err;
1.1 root 2235:
1.1.1.4 ! root 2236: TRACE(("ACTION_DELETE_OBJECT(0x%lx,\"%s\")\n", lock, bstr (unit, name)));
1.1 root 2237:
1.1.1.3 root 2238: if (unit->ui.readonly) {
2239: PUT_PCK_RES1 (packet, DOS_FALSE);
2240: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1 root 2241: return;
2242: }
2243:
1.1.1.3 root 2244: a = find_aino (unit, lock, bstr (unit, name), &err);
1.1 root 2245:
1.1.1.3 root 2246: if (err != 0) {
2247: PUT_PCK_RES1 (packet, DOS_FALSE);
2248: PUT_PCK_RES2 (packet, err);
1.1 root 2249: return;
2250: }
1.1.1.3 root 2251: if (a->shlock > 0 || a->elock) {
2252: PUT_PCK_RES1 (packet, DOS_FALSE);
2253: PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
1.1 root 2254: return;
2255: }
1.1.1.3 root 2256: if (a->dir) {
2257: if (rmdir (a->nname) == -1) {
2258: PUT_PCK_RES1 (packet, DOS_FALSE);
2259: PUT_PCK_RES2 (packet, dos_errno());
1.1 root 2260: return;
2261: }
2262: } else {
1.1.1.3 root 2263: if (unlink (a->nname) == -1) {
2264: PUT_PCK_RES1 (packet, DOS_FALSE);
2265: PUT_PCK_RES2 (packet, dos_errno());
1.1 root 2266: return;
2267: }
2268: }
1.1.1.3 root 2269: if (a->child != 0) {
2270: write_log ("Serious error in action_delete_object.\n");
2271: } else {
2272: delete_aino (unit, a);
2273: }
2274: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 2275: }
2276:
2277: static void
1.1.1.4 ! root 2278: action_set_date (Unit *unit, dpacket packet)
1.1 root 2279: {
1.1.1.3 root 2280: uaecptr lock = GET_PCK_ARG2 (packet) << 2;
2281: uaecptr name = GET_PCK_ARG3 (packet) << 2;
2282: uaecptr date = GET_PCK_ARG4 (packet);
2283: struct a_inode *a;
1.1 root 2284: struct utimbuf ut;
1.1.1.3 root 2285: uae_u32 err;
1.1 root 2286:
1.1.1.4 ! root 2287: TRACE(("ACTION_SET_DATE(0x%lx,\"%s\")\n", lock, bstr (unit, name)));
1.1 root 2288:
1.1.1.4 ! root 2289: if (unit->ui.readonly) {
1.1.1.3 root 2290: PUT_PCK_RES1 (packet, DOS_FALSE);
2291: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1 root 2292: return;
2293: }
2294:
2295: ut.actime = ut.modtime = put_time(get_long(date),get_long(date+4),get_long(date+8));
1.1.1.3 root 2296: a = find_aino (unit, lock, bstr (unit, name), &err);
2297: if (err == 0 && utime (a->nname, &ut) == -1)
2298: err = dos_errno ();
2299: if (err != 0) {
2300: PUT_PCK_RES1 (packet, DOS_FALSE);
2301: PUT_PCK_RES2 (packet, err);
2302: } else
2303: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 2304: }
2305:
2306: static void
1.1.1.4 ! root 2307: action_rename_object (Unit *unit, dpacket packet)
1.1 root 2308: {
1.1.1.3 root 2309: uaecptr lock1 = GET_PCK_ARG1 (packet) << 2;
2310: uaecptr name1 = GET_PCK_ARG2 (packet) << 2;
2311: uaecptr lock2 = GET_PCK_ARG3 (packet) << 2;
2312: uaecptr name2 = GET_PCK_ARG4 (packet) << 2;
2313: struct a_inode *a1, *a2;
2314: uae_u32 err1, err2;
1.1 root 2315:
1.1.1.4 ! root 2316: TRACE(("ACTION_RENAME_OBJECT(0x%lx,\"%s\",", lock1, bstr (unit, name1)));
! 2317: TRACE(("0x%lx,\"%s\")\n", lock2, bstr (unit, name2)));
1.1 root 2318:
1.1.1.4 ! root 2319: if (unit->ui.readonly) {
1.1.1.3 root 2320: PUT_PCK_RES1 (packet, DOS_FALSE);
2321: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1 root 2322: return;
2323: }
2324:
1.1.1.3 root 2325: a1 = find_aino (unit, lock1, bstr (unit, name1), &err1);
2326: if (err1 != 0) {
2327: PUT_PCK_RES1 (packet, DOS_FALSE);
2328: PUT_PCK_RES2 (packet, err1);
2329: return;
2330: }
2331: a2 = find_aino (unit, lock2, bstr (unit, name2), &err2);
2332: if (a2 == 0 || err2 != ERROR_OBJECT_NOT_FOUND) {
2333: PUT_PCK_RES1 (packet, DOS_FALSE);
2334: PUT_PCK_RES2 (packet, err2 == 0 ? ERROR_OBJECT_EXISTS : err2);
1.1 root 2335: return;
2336: }
1.1.1.3 root 2337: /* Object does not exist. aino points to containing directory. */
2338: a2 = new_child_aino (unit, a2, my_strdup (bstr_cut (unit, name2)), a1->dir ? 2 : 1);
2339: if (a2 == 0) {
2340: PUT_PCK_RES1 (packet, DOS_FALSE);
2341: PUT_PCK_RES2 (packet, ERROR_DISK_FULL); /* best we can do */
1.1 root 2342: return;
2343: }
2344:
1.1.1.3 root 2345: /* @@@ what should we do if there are locks on a1? */
1.1.1.4 ! root 2346: if (-1 == rename(a1->nname, a2->nname)) {
1.1.1.3 root 2347: PUT_PCK_RES1 (packet, DOS_FALSE);
2348: PUT_PCK_RES2 (packet, dos_errno());
1.1 root 2349: return;
2350: }
1.1.1.3 root 2351: move_aino_children (unit, a1, a2);
2352: delete_aino (unit, a1);
2353: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 2354: }
2355:
2356: static void
1.1.1.4 ! root 2357: action_current_volume (Unit *unit, dpacket packet)
1.1 root 2358: {
1.1.1.3 root 2359: PUT_PCK_RES1 (packet, unit->volume >> 2);
1.1 root 2360: }
2361:
2362: static void
1.1.1.4 ! root 2363: action_rename_disk (Unit *unit, dpacket packet)
1.1 root 2364: {
1.1.1.3 root 2365: uaecptr name = GET_PCK_ARG1 (packet) << 2;
1.1 root 2366: int i;
2367: int namelen;
2368:
1.1.1.4 ! root 2369: TRACE(("ACTION_RENAME_DISK(\"%s\")\n", bstr (unit, name)));
1.1 root 2370:
1.1.1.4 ! root 2371: if (unit->ui.readonly) {
1.1.1.3 root 2372: PUT_PCK_RES1 (packet, DOS_FALSE);
2373: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1 root 2374: return;
2375: }
2376:
2377: /* get volume name */
1.1.1.3 root 2378: namelen = get_byte (name); name++;
2379: free (unit->ui.volname);
2380: unit->ui.volname = (char *) xmalloc (namelen + 1);
1.1.1.4 ! root 2381: for (i = 0; i < namelen; i++, name++)
1.1.1.3 root 2382: unit->ui.volname[i] = get_byte (name);
1.1 root 2383: unit->ui.volname[i] = 0;
2384:
1.1.1.3 root 2385: put_byte (unit->volume + 44, namelen);
1.1.1.4 ! root 2386: for (i = 0; i < namelen; i++)
1.1.1.3 root 2387: put_byte (unit->volume + 45 + i, unit->ui.volname[i]);
1.1 root 2388:
1.1.1.3 root 2389: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 2390: }
2391:
2392: static void
1.1.1.4 ! root 2393: action_is_filesystem (Unit *unit, dpacket packet)
1.1 root 2394: {
1.1.1.3 root 2395: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 2396: }
2397:
2398: static void
1.1.1.4 ! root 2399: action_flush (Unit *unit, dpacket packet)
1.1 root 2400: {
2401: /* sync(); */ /* pretty drastic, eh */
1.1.1.3 root 2402: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 2403: }
2404:
1.1.1.3 root 2405: /* We don't want multiple interrupts to be active at the same time. I don't
2406: * know whether AmigaOS takes care of that, but this does. */
2407: static uae_sem_t singlethread_int_sem;
2408:
2409: static uae_u32 exter_int_helper (void)
2410: {
1.1.1.4 ! root 2411: UnitInfo *uip = current_mountinfo->ui;
1.1.1.3 root 2412: static int unit_no;
2413:
2414: switch (m68k_dreg (regs, 0)) {
2415: case 0:
2416: /* Determine whether a given EXTER interrupt is for us. */
2417: if (uae_int_requested) {
2418: if (uae_sem_trywait (&singlethread_int_sem) != 0)
2419: /* Pretend it isn't for us. We might get it again later. */
2420: return 0;
2421: /* Clear the interrupt flag _before_ we do any processing.
2422: * That way, we can get too many interrupts, but never not
2423: * enough. */
2424: uae_int_requested = 0;
2425: unit_no = 0;
2426: return 1;
2427: }
1.1 root 2428: return 0;
1.1.1.3 root 2429: case 1:
2430: /* Release a message_lock. This is called as soon as the message is
2431: * received by the assembly code. We use the opportunity to check
2432: * whether we have some locks that we can give back to the assembler
2433: * code.
2434: * Note that this is called from the main loop, unlike the other cases
2435: * in this switch statement which are called from the interrupt handler.
2436: */
2437: {
2438: Unit *unit = find_unit (m68k_areg (regs, 5));
2439: unit->cmds_complete = unit->cmds_acked;
2440: while (comm_pipe_has_data (unit->ui.back_pipe)) {
2441: uaecptr locks, lockend;
2442: locks = read_comm_pipe_int_blocking (unit->ui.back_pipe);
2443: lockend = locks;
2444: while (get_long (lockend) != 0)
2445: lockend = get_long (lockend);
2446: put_long (lockend, get_long (m68k_areg (regs, 3)));
2447: put_long (m68k_areg (regs, 3), locks);
2448: }
2449: }
1.1 root 2450: break;
1.1.1.3 root 2451: case 2:
2452: /* Find some unit that needs a message sent, and return its port,
2453: * or zero if all are done.
2454: * Take care not to dereference self for units that didn't have their
2455: * startup packet sent. */
2456: for (;;) {
1.1.1.4 ! root 2457: if (unit_no >= current_mountinfo->num_units)
1.1.1.3 root 2458: return 0;
1.1.1.4 ! root 2459: if (uip[unit_no].self != 0
! 2460: && uip[unit_no].self->cmds_acked == uip[unit_no].self->cmds_complete
! 2461: && uip[unit_no].self->cmds_acked != uip[unit_no].self->cmds_sent)
1.1.1.3 root 2462: break;
2463: unit_no++;
2464: }
1.1.1.4 ! root 2465: uip[unit_no].self->cmds_acked = uip[unit_no].self->cmds_sent;
! 2466: return uip[unit_no++].self->port;
1.1 root 2467:
1.1.1.3 root 2468: case 3:
2469: /* Look up a message for a port. */
2470: {
2471: Unit *unit = find_unit (m68k_areg (regs, 2));
2472: return unit->dummy_message;
2473: }
1.1 root 2474: break;
1.1.1.3 root 2475: case 4:
2476: /* Exit the interrupt, and release the single-threading lock. */
2477: uae_sem_post (&singlethread_int_sem);
1.1 root 2478: break;
2479:
1.1.1.3 root 2480: default:
2481: write_log ("Shouldn't happen in exter_int_helper.\n");
1.1 root 2482: break;
1.1.1.3 root 2483: }
2484: return 0;
2485: }
1.1 root 2486:
1.1.1.3 root 2487: static int handle_packet (Unit *unit, dpacket pck)
2488: {
2489: uae_s32 type = GET_PCK_TYPE (pck);
2490: PUT_PCK_RES2 (pck, 0);
2491: switch (type) {
1.1.1.4 ! root 2492: case ACTION_LOCATE_OBJECT: action_lock (unit, pck); break;
! 2493: case ACTION_FREE_LOCK: action_free_lock (unit, pck); break;
! 2494: case ACTION_COPY_DIR: action_dup_lock (unit, pck); break;
! 2495: case ACTION_DISK_INFO: action_disk_info (unit, pck); break;
! 2496: case ACTION_INFO: action_info (unit, pck); break;
! 2497: case ACTION_EXAMINE_OBJECT: action_examine_object (unit, pck); break;
! 2498: case ACTION_EXAMINE_NEXT: action_examine_next (unit, pck); break;
! 2499: case ACTION_FIND_INPUT: action_find_input (unit, pck); break;
! 2500: case ACTION_FIND_WRITE: action_find_write (unit, pck); break;
! 2501: case ACTION_FIND_OUTPUT: action_find_output (unit, pck); break;
! 2502: case ACTION_END: action_end (unit, pck); break;
! 2503: case ACTION_READ: action_read (unit, pck); break;
! 2504: case ACTION_WRITE: action_write (unit, pck); break;
! 2505: case ACTION_SEEK: action_seek (unit, pck); break;
! 2506: case ACTION_SET_PROTECT: action_set_protect (unit, pck); break;
! 2507: case ACTION_SAME_LOCK: action_same_lock (unit, pck); break;
! 2508: case ACTION_PARENT: action_parent (unit, pck); break;
! 2509: case ACTION_CREATE_DIR: action_create_dir (unit, pck); break;
! 2510: case ACTION_DELETE_OBJECT: action_delete_object (unit, pck); break;
! 2511: case ACTION_RENAME_OBJECT: action_rename_object (unit, pck); break;
! 2512: case ACTION_SET_DATE: action_set_date (unit, pck); break;
! 2513: case ACTION_CURRENT_VOLUME: action_current_volume (unit, pck); break;
! 2514: case ACTION_RENAME_DISK: action_rename_disk (unit, pck); break;
! 2515: case ACTION_IS_FILESYSTEM: action_is_filesystem (unit, pck); break;
! 2516: case ACTION_FLUSH: action_flush (unit, pck); break;
1.1.1.3 root 2517:
2518: /* 2.0+ packet types */
1.1.1.4 ! root 2519: case ACTION_SET_FILE_SIZE: action_set_file_size (unit, pck); break;
! 2520: case ACTION_EXAMINE_FH: action_examine_fh (unit, pck); break;
1.1.1.3 root 2521:
2522: /* unsupported packets */
2523: case ACTION_LOCK_RECORD:
2524: case ACTION_FREE_RECORD:
2525: case ACTION_CHANGE_MODE:
2526: case ACTION_FH_FROM_LOCK:
2527: case ACTION_COPY_DIR_FH:
2528: case ACTION_PARENT_FH:
2529: case ACTION_EXAMINE_ALL:
2530: case ACTION_MAKE_LINK:
2531: case ACTION_READ_LINK:
2532: case ACTION_FORMAT:
2533: case ACTION_ADD_NOTIFY:
2534: case ACTION_REMOVE_NOTIFY:
2535: default:
1.1.1.4 ! root 2536: TRACE(("*** UNSUPPORTED PACKET %ld\n", type));
1.1.1.3 root 2537: return 0;
2538: }
2539: return 1;
2540: }
1.1 root 2541:
1.1.1.3 root 2542: #ifdef UAE_FILESYS_THREADS
2543: static void *filesys_penguin (void *unit_v)
2544: {
2545: UnitInfo *ui = (UnitInfo *)unit_v;
2546: for (;;) {
2547: uae_u8 *pck;
2548: uae_u8 *msg;
2549: uae_u32 morelocks;
2550: int i;
2551:
2552: pck = (uae_u8 *)read_comm_pipe_pvoid_blocking (ui->unit_pipe);
2553: msg = (uae_u8 *)read_comm_pipe_pvoid_blocking (ui->unit_pipe);
2554: morelocks = (uae_u32)read_comm_pipe_int_blocking (ui->unit_pipe);
2555:
1.1.1.4 ! root 2556: if (ui->reset_state == FS_GO_DOWN) {
1.1.1.3 root 2557: if (pck != 0)
2558: continue;
2559: /* Death message received. */
1.1.1.4 ! root 2560: uae_sem_post (&ui->reset_sync_sem);
! 2561: /* Die. */
! 2562: return 0;
1.1.1.3 root 2563: }
1.1 root 2564:
1.1.1.3 root 2565: put_long (get_long (morelocks), get_long (ui->self->locklist));
2566: put_long (ui->self->locklist, morelocks);
2567: if (! handle_packet (ui->self, pck)) {
2568: PUT_PCK_RES1 (pck, DOS_FALSE);
2569: PUT_PCK_RES2 (pck, ERROR_ACTION_NOT_KNOWN);
2570: }
2571: /* Mark the packet as processed for the list scan in the assembly code. */
2572: do_put_mem_long ((uae_u32 *)(msg + 4), -1);
2573: /* Acquire the message lock, so that we know we can safely send the
2574: * message. */
2575: ui->self->cmds_sent++;
2576: /* The message is sent by our interrupt handler, so make sure an interrupt
2577: * happens. */
2578: uae_int_requested = 1;
2579: /* Send back the locks. */
2580: if (get_long (ui->self->locklist) != 0)
2581: write_comm_pipe_int (ui->back_pipe, (int)(get_long(ui->self->locklist)), 0);
2582: put_long (ui->self->locklist, 0);
2583: }
2584: return 0;
2585: }
2586: #endif
1.1 root 2587:
1.1.1.3 root 2588: /* Talk about spaghetti code... */
1.1.1.4 ! root 2589: static uae_u32 filesys_handler (void)
1.1.1.3 root 2590: {
2591: Unit *unit = find_unit (m68k_areg (regs, 5));
2592: uaecptr packet_addr = m68k_dreg (regs, 3);
2593: uaecptr message_addr = m68k_areg (regs, 4);
2594: uae_u8 *pck;
2595: uae_u8 *msg;
2596: if (! valid_address (packet_addr, 36) || ! valid_address (message_addr, 14)) {
2597: write_log ("Bad address passed for packet.\n");
2598: goto error2;
2599: }
2600: pck = get_real_address (packet_addr);
2601: msg = get_real_address (message_addr);
2602:
1.1.1.4 ! root 2603: #if 0
1.1.1.3 root 2604: if (unit->reset_state == FS_GO_DOWN)
2605: /* You might as well queue it, if you live long enough */
2606: return 1;
1.1.1.4 ! root 2607: #endif
1.1.1.3 root 2608:
2609: do_put_mem_long ((uae_u32 *)(msg + 4), -1);
2610: if (!unit || !unit->volume) {
2611: write_log ("Filesystem was not initialized.\n");
2612: goto error;
2613: }
2614: #ifdef UAE_FILESYS_THREADS
2615: {
2616: /* Get two more locks and hand them over to the other thread. */
2617: uae_u32 morelocks;
2618: morelocks = get_long (m68k_areg (regs, 3));
2619: put_long (m68k_areg (regs, 3), get_long (get_long (morelocks)));
2620: put_long (get_long (morelocks), 0);
2621:
2622: /* The packet wasn't processed yet. */
2623: do_put_mem_long ((uae_u32 *)(msg + 4), 0);
2624: write_comm_pipe_pvoid (unit->ui.unit_pipe, (void *)pck, 0);
2625: write_comm_pipe_pvoid (unit->ui.unit_pipe, (void *)msg, 0);
2626: write_comm_pipe_int (unit->ui.unit_pipe, (int)morelocks, 1);
2627: /* Don't reply yet. */
2628: return 1;
2629: }
2630: #endif
1.1 root 2631:
1.1.1.3 root 2632: if (! handle_packet (unit, pck)) {
2633: error:
2634: PUT_PCK_RES1 (pck, DOS_FALSE);
2635: PUT_PCK_RES2 (pck, ERROR_ACTION_NOT_KNOWN);
2636: }
1.1.1.4 ! root 2637: TRACE(("reply: %8lx, %ld\n", GET_PCK_RES1 (pck), GET_PCK_RES2 (pck)));
1.1 root 2638:
1.1.1.3 root 2639: error2:
1.1 root 2640:
1.1.1.3 root 2641: return 0;
2642: }
1.1 root 2643:
1.1.1.4 ! root 2644: void filesys_start_threads (void)
! 2645: {
! 2646: UnitInfo *uip;
! 2647: int i;
! 2648:
! 2649: current_mountinfo = dup_mountinfo (currprefs.mountinfo);
! 2650:
! 2651: reset_uaedevices ();
! 2652:
! 2653: uip = current_mountinfo->ui;
! 2654: for (i = 0; i < current_mountinfo->num_units; i++) {
! 2655: uip[i].unit_pipe = 0;
! 2656: uip[i].devno = get_new_device (&uip[i].devname, &uip[i].devname_amiga);
! 2657:
! 2658: #ifdef UAE_FILESYS_THREADS
! 2659: if (! is_hardfile (current_mountinfo, i)) {
! 2660: uip[i].unit_pipe = (smp_comm_pipe *)xmalloc (sizeof (smp_comm_pipe));
! 2661: uip[i].back_pipe = (smp_comm_pipe *)xmalloc (sizeof (smp_comm_pipe));
! 2662: init_comm_pipe (uip[i].unit_pipe, 50, 3);
! 2663: init_comm_pipe (uip[i].back_pipe, 50, 1);
! 2664: start_penguin (filesys_penguin, (void *)(uip + i), &uip[i].tid);
! 2665: }
! 2666: #endif
! 2667: }
! 2668: }
! 2669:
1.1.1.3 root 2670: void filesys_reset (void)
2671: {
2672: Unit *u, *u1;
2673: int i;
1.1 root 2674:
1.1.1.4 ! root 2675: /* We get called once from customreset at the beginning of the program
! 2676: * before filesys_start_threads has been called. Survive that. */
! 2677: if (current_mountinfo == 0)
! 2678: return;
1.1 root 2679:
1.1.1.4 ! root 2680: for (u = units; u; u = u1) {
1.1.1.3 root 2681: u1 = u->next;
2682: free (u);
1.1 root 2683: }
1.1.1.3 root 2684: unit_num = 0;
2685: units = 0;
1.1.1.4 ! root 2686:
! 2687: free_mountinfo (current_mountinfo);
! 2688: current_mountinfo = 0;
1.1.1.3 root 2689: }
1.1 root 2690:
1.1.1.3 root 2691: void filesys_prepare_reset (void)
2692: {
1.1.1.4 ! root 2693: UnitInfo *uip = current_mountinfo->ui;
! 2694: Unit *u;
1.1.1.3 root 2695: int i;
1.1 root 2696:
1.1.1.3 root 2697: #ifdef UAE_FILESYS_THREADS
1.1.1.4 ! root 2698: for (i = 0; i < current_mountinfo->num_units; i++) {
! 2699: if (uip[i].unit_pipe != 0) {
! 2700: uae_sem_init (&uip[i].reset_sync_sem, 0, 0);
! 2701: uip[i].reset_state = FS_GO_DOWN;
1.1.1.3 root 2702: /* send death message */
1.1.1.4 ! root 2703: write_comm_pipe_int (uip[i].unit_pipe, 0, 0);
! 2704: write_comm_pipe_int (uip[i].unit_pipe, 0, 0);
! 2705: write_comm_pipe_int (uip[i].unit_pipe, 0, 1);
! 2706: uae_sem_wait (&uip[i].reset_sync_sem);
1.1.1.3 root 2707: }
2708: }
2709: #endif
2710: u = units;
2711: while (u != 0) {
2712: while (u->rootnode.next != &u->rootnode) {
2713: struct a_inode *a = u->rootnode.next;
2714: u->rootnode.next = a->next;
2715: free (a->nname);
2716: free (a->aname);
2717: free (a);
2718: }
2719: u = u->next;
2720: }
1.1 root 2721: }
2722:
1.1.1.4 ! root 2723: static uae_u32 filesys_diagentry (void)
1.1 root 2724: {
1.1.1.3 root 2725: uaecptr resaddr = m68k_areg(regs, 2) + 0x10;
2726:
1.1.1.4 ! root 2727: TRACE (("filesystem: diagentry called\n"));
1.1.1.3 root 2728:
1.1.1.2 root 2729: filesys_configdev = m68k_areg(regs, 3);
1.1.1.3 root 2730:
2731: do_put_mem_long ((uae_u32 *)(filesysory + 0x2100), EXPANSION_explibname);
2732: do_put_mem_long ((uae_u32 *)(filesysory + 0x2104), filesys_configdev);
2733: do_put_mem_long ((uae_u32 *)(filesysory + 0x2108), EXPANSION_doslibname);
1.1.1.4 ! root 2734: do_put_mem_long ((uae_u32 *)(filesysory + 0x210c), current_mountinfo->num_units);
1.1.1.3 root 2735:
2736: uae_sem_init (&singlethread_int_sem, 0, 1);
1.1 root 2737: if (ROM_hardfile_resid != 0) {
2738: /* Build a struct Resident. This will set up and initialize
2739: * the uae.device */
2740: put_word(resaddr + 0x0, 0x4AFC);
2741: put_long(resaddr + 0x2, resaddr);
2742: put_long(resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
2743: put_word(resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */
2744: put_word(resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
2745: put_long(resaddr + 0xE, ROM_hardfile_resname);
2746: put_long(resaddr + 0x12, ROM_hardfile_resid);
1.1.1.3 root 2747: put_long(resaddr + 0x16, ROM_hardfile_init); /* calls filesys_init */
1.1 root 2748: }
2749: resaddr += 0x1A;
2750:
1.1.1.2 root 2751: /* The good thing about this function is that it always gets called
2752: * when we boot. So we could put all sorts of stuff that wants to be done
2753: * here. */
1.1 root 2754:
1.1.1.3 root 2755: return 1;
1.1 root 2756: }
2757:
1.1.1.3 root 2758: /* Remember a pointer AmigaOS gave us so we can later use it to identify
2759: * which unit a given startup message belongs to. */
1.1.1.4 ! root 2760: static uae_u32 filesys_dev_remember (void)
1.1.1.3 root 2761: {
2762: int unit_no = m68k_dreg (regs, 6);
2763: uaecptr devicenode = m68k_areg (regs, 3);
2764:
1.1.1.4 ! root 2765: current_mountinfo->ui[unit_no].startup = get_long (devicenode + 28);
1.1.1.3 root 2766: return devicenode;
2767: }
2768:
2769: /* Fill in per-unit fields of a parampacket */
1.1.1.4 ! root 2770: static uae_u32 filesys_dev_storeinfo (void)
1.1.1.3 root 2771: {
1.1.1.4 ! root 2772: UnitInfo *uip = current_mountinfo->ui;
1.1.1.3 root 2773: int unit_no = m68k_dreg (regs, 6);
2774: uaecptr parmpacket = m68k_areg (regs, 0);
2775:
1.1.1.4 ! root 2776: put_long (parmpacket, current_mountinfo->ui[unit_no].devname_amiga);
! 2777: put_long (parmpacket + 4, is_hardfile (current_mountinfo, unit_no) ? ROM_hardfile_resname : fsdevname);
! 2778: put_long (parmpacket + 8, uip[unit_no].devno);
1.1.1.3 root 2779: put_long (parmpacket + 12, 0); /* Device flags */
2780: put_long (parmpacket + 16, 16); /* Env. size */
2781: put_long (parmpacket + 20, 128); /* 512 bytes per block */
2782: put_long (parmpacket + 24, 0); /* unused */
1.1.1.4 ! root 2783: put_long (parmpacket + 28, uip[unit_no].hf.surfaces); /* heads */
1.1.1.3 root 2784: put_long (parmpacket + 32, 0); /* unused */
1.1.1.4 ! root 2785: put_long (parmpacket + 36, uip[unit_no].hf.secspertrack); /* sectors per track */
! 2786: put_long (parmpacket + 40, uip[unit_no].hf.reservedblocks); /* reserved blocks */
1.1.1.3 root 2787: put_long (parmpacket + 44, 0); /* unused */
2788: put_long (parmpacket + 48, 0); /* interleave */
2789: put_long (parmpacket + 52, 0); /* lowCyl */
1.1.1.4 ! root 2790: put_long (parmpacket + 56, uip[unit_no].hf.nrcyls - 1); /* hiCyl */
1.1.1.3 root 2791: put_long (parmpacket + 60, 0); /* Number of buffers */
2792: put_long (parmpacket + 64, 0); /* Buffer mem type */
2793: put_long (parmpacket + 68, 0x7FFFFFFF); /* largest transfer */
2794: put_long (parmpacket + 72, ~1); /* addMask (?) */
2795: put_long (parmpacket + 76, (uae_u32)-1); /* bootPri */
2796: put_long (parmpacket + 80, 0x444f5300); /* DOS\0 */
2797: put_long (parmpacket + 84, 0); /* pad */
2798:
1.1.1.4 ! root 2799: return is_hardfile (current_mountinfo, unit_no);
1.1 root 2800: }
2801:
1.1.1.3 root 2802: void filesys_install (void)
1.1 root 2803: {
2804: int i;
1.1.1.3 root 2805: uaecptr loop;
2806:
1.1.1.4 ! root 2807: TRACE (("Installing filesystem\n"));
1.1 root 2808:
2809: ROM_filesys_resname = ds("UAEunixfs.resource");
1.1.1.3 root 2810: ROM_filesys_resid = ds("UAE unixfs 0.4");
1.1 root 2811:
1.1.1.4 ! root 2812: fsdevname = ds ("uae.device"); /* does not really exist */
1.1 root 2813:
2814: ROM_filesys_diagentry = here();
1.1.1.3 root 2815: calltrap (deftrap(filesys_diagentry)); dw(RTS);
2816:
2817: loop = here ();
2818: /* Special trap for the assembly make_dev routine */
1.1.1.4 ! root 2819: org (0xF0FF20);
1.1.1.3 root 2820: calltrap (deftrap (filesys_dev_remember));
1.1.1.4 ! root 2821: dw (RTS);
1.1.1.3 root 2822:
1.1.1.4 ! root 2823: org (0xF0FF28);
1.1.1.3 root 2824: calltrap (deftrap (filesys_dev_storeinfo));
1.1.1.4 ! root 2825: dw (RTS);
1.1.1.3 root 2826:
1.1.1.4 ! root 2827: org (0xF0FF30);
1.1.1.3 root 2828: calltrap (deftrap (filesys_handler));
1.1.1.4 ! root 2829: dw (RTS);
1.1.1.3 root 2830:
1.1.1.4 ! root 2831: org (0xF0FF40);
1.1.1.3 root 2832: calltrap (deftrap (startup_handler));
1.1.1.4 ! root 2833: dw (RTS);
1.1.1.3 root 2834:
1.1.1.4 ! root 2835: org (0xF0FF50);
1.1.1.3 root 2836: calltrap (deftrap (exter_int_helper));
1.1.1.4 ! root 2837: dw (RTS);
1.1.1.3 root 2838:
1.1.1.4 ! root 2839: org (0xF0FF70);
1.1.1.3 root 2840: calltrap (deftrap (mousehack_helper));
1.1.1.4 ! root 2841: dw (RTS);
1.1.1.3 root 2842:
2843: org (loop);
2844: }
2845:
2846: void filesys_install_code (void)
2847: {
1.1 root 2848: align(4);
2849:
1.1.1.3 root 2850: /* The last offset comes from the code itself, look for it near the top. */
2851: filesys_initcode = here() + 8 + 0x6c;
2852: EXPANSION_bootcode = here () + 8 + 0x14;
2853: /* Ouch. Make sure this is _always_ a multiple of two bytes. */
2854: db(0x00); db(0x00); db(0x00); db(0x10); db(0x00); db(0x00); db(0x00); db(0x00);
2855: db(0x60); db(0x00); db(0x01); db(0xc0); db(0x00); db(0x00); db(0x01); db(0x2c);
2856: db(0x00); db(0x00); db(0x00); db(0x6c); db(0x00); db(0x00); db(0x00); db(0x28);
2857: db(0x00); db(0x00); db(0x00); db(0x14); db(0x43); db(0xfa); db(0x02); db(0xf9);
2858: db(0x4e); db(0xae); db(0xff); db(0xa0); db(0x20); db(0x40); db(0x20); db(0x28);
2859: db(0x00); db(0x16); db(0x20); db(0x40); db(0x4e); db(0x90); db(0x4e); db(0x75);
2860: db(0x48); db(0xe7); db(0x00); db(0x20); db(0x70); db(0x00); db(0x4e); db(0xb9);
2861: db(0x00); db(0xf0); db(0xff); db(0x50); db(0x4a); db(0x80); db(0x67); db(0x2e);
2862: db(0x2c); db(0x78); db(0x00); db(0x04); db(0x70); db(0x02); db(0x4e); db(0xb9);
2863: db(0x00); db(0xf0); db(0xff); db(0x50); db(0x4a); db(0x80); db(0x67); db(0x14);
2864: db(0x24); db(0x40); db(0x70); db(0x03); db(0x4e); db(0xb9); db(0x00); db(0xf0);
2865: db(0xff); db(0x50); db(0x20); db(0x4a); db(0x22); db(0x40); db(0x4e); db(0xae);
2866: db(0xfe); db(0x92); db(0x60); db(0xe0); db(0x70); db(0x04); db(0x4e); db(0xb9);
2867: db(0x00); db(0xf0); db(0xff); db(0x50); db(0x70); db(0x01); db(0x4c); db(0xdf);
2868: db(0x04); db(0x00); db(0x4e); db(0x75); db(0x48); db(0xe7); db(0xff); db(0xfe);
2869: db(0x2c); db(0x78); db(0x00); db(0x04); db(0x2a); db(0x79); db(0x00); db(0xf0);
2870: db(0xff); db(0xfc); db(0x43); db(0xfa); db(0x02); db(0x9f); db(0x70); db(0x24);
2871: db(0x7a); db(0x00); db(0x4e); db(0xae); db(0xfd); db(0xd8); db(0x4a); db(0x80);
2872: db(0x66); db(0x0c); db(0x43); db(0xfa); db(0x02); db(0x8f); db(0x70); db(0x00);
2873: db(0x7a); db(0x01); db(0x4e); db(0xae); db(0xfd); db(0xd8); db(0x28); db(0x40);
2874: db(0x70); db(0x58); db(0x72); db(0x01); db(0x4e); db(0xae); db(0xff); db(0x3a);
2875: db(0x26); db(0x40); db(0x7e); db(0x54); db(0x27); db(0xb5); db(0x78); db(0x00);
2876: db(0x78); db(0x00); db(0x59); db(0x87); db(0x64); db(0xf6); db(0x7c); db(0x00);
2877: db(0xbc); db(0xad); db(0x01); db(0x0c); db(0x64); db(0x12); db(0x20); db(0x4b);
2878: db(0x48); db(0xe7); db(0x02); db(0x10); db(0x7e); db(0x01); db(0x61); db(0x6c);
2879: db(0x4c); db(0xdf); db(0x08); db(0x40); db(0x52); db(0x86); db(0x60); db(0xe8);
2880: db(0x2c); db(0x78); db(0x00); db(0x04); db(0x22); db(0x4c); db(0x4e); db(0xae);
2881: db(0xfe); db(0x62); db(0x61); db(0x28); db(0x2c); db(0x78); db(0x00); db(0x04);
2882: db(0x4e); db(0xb9); db(0x00); db(0xf0); db(0xff); db(0x80); db(0x72); db(0x03);
2883: db(0x74); db(0xf6); db(0x20); db(0x7c); db(0x00); db(0x20); db(0x00); db(0x00);
2884: db(0x90); db(0x88); db(0x65); db(0x0a); db(0x67); db(0x08); db(0x78); db(0x00);
2885: db(0x22); db(0x44); db(0x4e); db(0xae); db(0xfd); db(0x96); db(0x4c); db(0xdf);
2886: db(0x7f); db(0xff); db(0x4e); db(0x75); db(0x2c); db(0x78); db(0x00); db(0x04);
2887: db(0x70); db(0x1a); db(0x22); db(0x3c); db(0x00); db(0x01); db(0x00); db(0x01);
2888: db(0x4e); db(0xae); db(0xff); db(0x3a); db(0x22); db(0x40); db(0x41); db(0xfa);
2889: db(0x01); db(0xf0); db(0x23); db(0x48); db(0x00); db(0x0a); db(0x41); db(0xfa);
2890: db(0xff); db(0x10); db(0x23); db(0x48); db(0x00); db(0x0e); db(0x41); db(0xfa);
2891: db(0xff); db(0x08); db(0x23); db(0x48); db(0x00); db(0x12); db(0x70); db(0x0d);
2892: db(0x4e); db(0xee); db(0xff); db(0x58); db(0x2a); db(0x79); db(0x00); db(0xf0);
2893: db(0xff); db(0xfc); db(0x4e); db(0xb9); db(0x00); db(0xf0); db(0xff); db(0x28);
2894: db(0x26); db(0x00); db(0xc0); db(0x85); db(0x66); db(0xbc); db(0x2c); db(0x4c);
2895: db(0x4e); db(0xae); db(0xff); db(0x70); db(0x26); db(0x40); db(0x4e); db(0xb9);
2896: db(0x00); db(0xf0); db(0xff); db(0x20); db(0x70); db(0x00); db(0x27); db(0x40);
2897: db(0x00); db(0x08); db(0x27); db(0x40); db(0x00); db(0x10); db(0x27); db(0x40);
2898: db(0x00); db(0x20); db(0x4a); db(0x83); db(0x66); db(0x1c); db(0x27); db(0x7c);
2899: db(0x00); db(0x00); db(0x0f); db(0xa0); db(0x00); db(0x14); db(0x43); db(0xfa);
2900: db(0xfe); db(0x94); db(0x20); db(0x09); db(0xe4); db(0x88); db(0x27); db(0x40);
2901: db(0x00); db(0x20); db(0x27); db(0x7c); db(0xff); db(0xff); db(0xff); db(0xff);
2902: db(0x00); db(0x24); db(0x4a); db(0x87); db(0x67); db(0x36); db(0x2c); db(0x78);
2903: db(0x00); db(0x04); db(0x70); db(0x14); db(0x72); db(0x00); db(0x4e); db(0xae);
2904: db(0xff); db(0x3a); db(0x22); db(0x40); db(0x70); db(0x00); db(0x22); db(0x80);
2905: db(0x23); db(0x40); db(0x00); db(0x04); db(0x33); db(0x40); db(0x00); db(0x0e);
2906: db(0x30); db(0x3c); db(0x10); db(0xff); db(0x90); db(0x06); db(0x33); db(0x40);
2907: db(0x00); db(0x08); db(0x23); db(0x6d); db(0x01); db(0x04); db(0x00); db(0x0a);
2908: db(0x23); db(0x4b); db(0x00); db(0x10); db(0x41); db(0xec); db(0x00); db(0x4a);
2909: db(0x4e); db(0xee); db(0xfe); db(0xf2); db(0x20); db(0x4b); db(0x72); db(0x00);
2910: db(0x22); db(0x41); db(0x70); db(0xff); db(0x2c); db(0x4c); db(0x4e); db(0xee);
2911: db(0xff); db(0x6a); db(0x2c); db(0x78); db(0x00); db(0x04); db(0x70); db(0x00);
2912: db(0x22); db(0x40); db(0x4e); db(0xae); db(0xfe); db(0xda); db(0x20); db(0x40);
2913: db(0x4b); db(0xe8); db(0x00); db(0x5c); db(0x43); db(0xfa); db(0x01); db(0x39);
2914: db(0x70); db(0x00); db(0x4e); db(0xae); db(0xfd); db(0xd8); db(0x24); db(0x40);
2915: db(0x20); db(0x3c); db(0x00); db(0x00); db(0x00); db(0x9d); db(0x22); db(0x3c);
2916: db(0x00); db(0x01); db(0x00); db(0x01); db(0x4e); db(0xae); db(0xff); db(0x3a);
2917: db(0x26); db(0x40); db(0x7c); db(0x00); db(0x26); db(0x86); db(0x27); db(0x46);
2918: db(0x00); db(0x04); db(0x27); db(0x46); db(0x00); db(0x08); db(0x7a); db(0x00);
2919: db(0x20); db(0x4d); db(0x4e); db(0xae); db(0xfe); db(0x80); db(0x20); db(0x4d);
2920: db(0x4e); db(0xae); db(0xfe); db(0x8c); db(0x28); db(0x40); db(0x26); db(0x2c);
2921: db(0x00); db(0x0a); db(0x70); db(0x00); db(0x4e); db(0xb9); db(0x00); db(0xf0);
2922: db(0xff); db(0x40); db(0x60); db(0x74); db(0x20); db(0x4d); db(0x4e); db(0xae);
2923: db(0xfe); db(0x80); db(0x20); db(0x4d); db(0x4e); db(0xae); db(0xfe); db(0x8c);
2924: db(0x28); db(0x40); db(0x26); db(0x2c); db(0x00); db(0x0a); db(0x66); db(0x38);
2925: db(0x70); db(0x01); db(0x4e); db(0xb9); db(0x00); db(0xf0); db(0xff); db(0x50);
2926: db(0x45); db(0xeb); db(0x00); db(0x04); db(0x20); db(0x52); db(0x20); db(0x08);
2927: db(0x67); db(0xda); db(0x22); db(0x50); db(0x20); db(0x40); db(0x20); db(0x28);
2928: db(0x00); db(0x04); db(0x6a); db(0x16); db(0x48); db(0xe7); db(0x00); db(0xc0);
2929: db(0x28); db(0x68); db(0x00); db(0x0a); db(0x61); db(0x40); db(0x53); db(0x85);
2930: db(0x4c); db(0xdf); db(0x03); db(0x00); db(0x24); db(0x89); db(0x20); db(0x49);
2931: db(0x60); db(0xdc); db(0x24); db(0x48); db(0x20); db(0x49); db(0x60); db(0xd6);
2932: db(0xba); db(0xbc); db(0x00); db(0x00); db(0x00); db(0x14); db(0x65); db(0x08);
2933: db(0x70); db(0x01); db(0x29); db(0x40); db(0x00); db(0x04); db(0x60); db(0x0e);
2934: db(0x61); db(0x2a); db(0x4e); db(0xb9); db(0x00); db(0xf0); db(0xff); db(0x30);
2935: db(0x4a); db(0x80); db(0x67); db(0x0c); db(0x52); db(0x85); db(0x28); db(0xab);
2936: db(0x00); db(0x04); db(0x27); db(0x4c); db(0x00); db(0x04); db(0x60); db(0x8c);
2937: db(0x28); db(0x43); db(0x61); db(0x02); db(0x60); db(0x86); db(0x22); db(0x54);
2938: db(0x20); db(0x6c); db(0x00); db(0x04); db(0x29); db(0x4d); db(0x00); db(0x04);
2939: db(0x4e); db(0xee); db(0xfe); db(0x92); db(0x2f); db(0x05); db(0x7a); db(0xfc);
2940: db(0x24); db(0x53); db(0x2e); db(0x0a); db(0x22); db(0x0a); db(0x67); db(0x0a);
2941: db(0x52); db(0x85); db(0x67); db(0x1e); db(0x22); db(0x4a); db(0x24); db(0x52);
2942: db(0x60); db(0xf2); db(0x52); db(0x85); db(0x67); db(0x3c); db(0x24); db(0x47);
2943: db(0x70); db(0x18); db(0x72); db(0x01); db(0x4e); db(0xae); db(0xff); db(0x3a);
2944: db(0x52); db(0x46); db(0x24); db(0x40); db(0x24); db(0x87); db(0x2e); db(0x0a);
2945: db(0x60); db(0xe8); db(0x20); db(0x12); db(0x67); db(0x24); db(0x20); db(0x40);
2946: db(0x20); db(0x10); db(0x67); db(0x1e); db(0x20); db(0x40); db(0x20); db(0x10);
2947: db(0x67); db(0x18); db(0x70); db(0x00); db(0x22); db(0x80); db(0x22); db(0x4a);
2948: db(0x24); db(0x51); db(0x70); db(0x18); db(0x4e); db(0xae); db(0xff); db(0x2e);
2949: db(0xdc); db(0xbc); db(0x00); db(0x01); db(0x00); db(0x00); db(0x20); db(0x0a);
2950: db(0x66); db(0xec); db(0x26); db(0x87); db(0x2a); db(0x1f); db(0x4e); db(0x75);
2951: db(0x55); db(0x41); db(0x45); db(0x20); db(0x66); db(0x69); db(0x6c); db(0x65);
2952: db(0x73); db(0x79); db(0x73); db(0x74); db(0x65); db(0x6d); db(0x00); db(0x64);
2953: db(0x6f); db(0x73); db(0x2e); db(0x6c); db(0x69); db(0x62); db(0x72); db(0x61);
2954: db(0x72); db(0x79); db(0x00); db(0x65); db(0x78); db(0x70); db(0x61); db(0x6e);
2955: db(0x73); db(0x69); db(0x6f); db(0x6e); db(0x2e); db(0x6c); db(0x69); db(0x62);
2956: db(0x72); db(0x61); db(0x72); db(0x79); db(0x00); db(0x00);
1.1 root 2957: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.