|
|
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).
1.1.1.6 root 17: * Does not support several 2.0+ packet types.
1.1 root 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:
1.1.1.13 root 30: #include "threaddep/thread.h"
1.1 root 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.13 root 35: #include "events.h"
1.1 root 36: #include "newcpu.h"
1.1.1.3 root 37: #include "filesys.h"
1.1.1.22 root 38: #include "traps.h"
1.1 root 39: #include "autoconf.h"
1.1.1.4 root 40: #include "fsusage.h"
1.1.1.7 root 41: #include "native2amiga.h"
42: #include "scsidev.h"
43: #include "fsdb.h"
1.1 root 44:
1.1.1.22 root 45: /* Count the number of FS packets waiting to be serviced, for the benefit
46: * of the idle on STOP code. */
47: int active_fs_packets;
48: uae_sem_t packet_counter_sem;
49:
1.1.1.17 root 50: #define TRACING_ENABLED 0
51: #if TRACING_ENABLED
1.1.1.4 root 52: #define TRACE(x) do { write_log x; } while(0)
1.1.1.3 root 53: #define DUMPLOCK(u,x) dumplock(u,x)
54: #else
55: #define TRACE(x)
56: #define DUMPLOCK(u,x)
57: #endif
58:
59: static long dos_errno(void)
1.1 root 60: {
1.1.1.3 root 61: int e = errno;
1.1 root 62:
1.1.1.4 root 63: switch (e) {
1.1.1.3 root 64: case ENOMEM: return ERROR_NO_FREE_STORE;
65: case EEXIST: return ERROR_OBJECT_EXISTS;
66: case EACCES: return ERROR_WRITE_PROTECTED;
1.1.1.11 root 67: case ENOENT: return ERROR_OBJECT_NOT_AROUND;
1.1.1.3 root 68: case ENOTDIR: return ERROR_OBJECT_WRONG_TYPE;
1.1.1.6 root 69: case ENOSPC: return ERROR_DISK_IS_FULL;
1.1.1.3 root 70: case EBUSY: return ERROR_OBJECT_IN_USE;
71: case EISDIR: return ERROR_OBJECT_WRONG_TYPE;
72: #if defined(ETXTBSY)
73: case ETXTBSY: return ERROR_OBJECT_IN_USE;
74: #endif
75: #if defined(EROFS)
76: case EROFS: return ERROR_DISK_WRITE_PROTECTED;
77: #endif
78: #if defined(ENOTEMPTY)
79: #if ENOTEMPTY != EEXIST
80: case ENOTEMPTY: return ERROR_DIRECTORY_NOT_EMPTY;
81: #endif
82: #endif
83:
84: default:
1.1.1.4 root 85: TRACE(("Unimplemented error %s\n", strerror(e)));
1.1.1.3 root 86: return ERROR_NOT_IMPLEMENTED;
87: }
1.1 root 88: }
89:
1.1.1.3 root 90: /*
91: * This _should_ be no issue for us, but let's rather use a guaranteed
92: * thread safe function if we have one.
1.1.1.4 root 93: * This used to be broken in glibc versions <= 2.0.1 (I think). I hope
94: * no one is using this these days.
95: * Michael Krause says it's also broken in libc5. ARRRGHHHHHH!!!!
1.1.1.3 root 96: */
97: #if 0 && defined HAVE_READDIR_R
98:
99: static struct dirent *my_readdir (DIR *dirstream, struct dirent *space)
100: {
101: struct dirent *loc;
102: if (readdir_r (dirstream, space, &loc) == 0) {
103: /* Success */
104: return loc;
105: }
106: return 0;
107: }
108:
109: #else
110: #define my_readdir(dirstream, space) readdir(dirstream)
111: #endif
112:
1.1.1.4 root 113: uaecptr filesys_initcode;
114: static uae_u32 fsdevname, filesys_configdev;
115:
1.1.1.3 root 116: #define FS_STARTUP 0
117: #define FS_GO_DOWN 1
118:
1.1.1.23! root 119: #define DEVNAMES_PER_HDF 32
! 120:
1.1 root 121: typedef struct {
122: char *devname; /* device name, e.g. UAE0: */
1.1.1.3 root 123: uaecptr devname_amiga;
124: uaecptr startup;
1.1 root 125: char *volname; /* volume name, e.g. CDROM, WORK, etc. */
126: char *rootdir; /* root unix directory */
127: int readonly; /* disallow write access? */
1.1.1.22 root 128: int bootpri;
1.1 root 129: int devno;
1.1.1.20 root 130:
1.1.1.3 root 131: struct hardfiledata hf;
132:
133: /* Threading stuff */
134: smp_comm_pipe *unit_pipe, *back_pipe;
1.1.1.13 root 135: uae_thread_id tid;
1.1.1.3 root 136: struct _unit *volatile self;
1.1.1.4 root 137: /* Reset handling */
138: uae_sem_t reset_sync_sem;
139: int reset_state;
1.1.1.23! root 140:
! 141: /* RDB stuff */
! 142: uaecptr rdb_devname_amiga[DEVNAMES_PER_HDF];
! 143: int rdb_lowcyl;
! 144: int rdb_highcyl;
! 145: int rdb_cylblocks;
! 146: uae_u8 *rdb_filesysstore;
! 147: int rdb_filesyssize;
! 148: char *filesysdir;
1.1 root 149: } UnitInfo;
150:
151: #define MAX_UNITS 20
152:
1.1.1.4 root 153: struct uaedev_mount_info {
154: int num_units;
155: UnitInfo ui[MAX_UNITS];
156: };
157:
158: static struct uaedev_mount_info *current_mountinfo;
159:
160: int nr_units (struct uaedev_mount_info *mountinfo)
161: {
162: return mountinfo->num_units;
163: }
164:
1.1.1.23! root 165: int hardfile_fs_type (struct uaedev_mount_info *mountinfo, int unit_no)
1.1.1.4 root 166: {
1.1.1.23! root 167: if (mountinfo->ui[unit_no].volname)
! 168: return FILESYS_VIRTUAL;
! 169:
! 170: if (mountinfo->ui[unit_no].hf.secspertrack == 0) {
! 171: #if 0
! 172: if (mountinfo->ui[unit_no].hf.flags & 1)
! 173: return FILESYS_HARDDRIVE;
! 174: #endif
! 175: return FILESYS_HARDFILE_RDB;
! 176: }
! 177:
! 178: return FILESYS_HARDFILE;
1.1.1.4 root 179: }
180:
1.1.1.6 root 181: static void close_filesys_unit (UnitInfo *uip)
1.1.1.4 root 182: {
183: if (uip->hf.fd != 0)
184: fclose (uip->hf.fd);
185: if (uip->volname != 0)
186: free (uip->volname);
187: if (uip->devname != 0)
188: free (uip->devname);
189: if (uip->rootdir != 0)
190: free (uip->rootdir);
191: if (uip->unit_pipe)
192: free (uip->unit_pipe);
193: if (uip->back_pipe)
194: free (uip->back_pipe);
195:
196: uip->unit_pipe = 0;
197: uip->back_pipe = 0;
198:
199: uip->hf.fd = 0;
200: uip->volname = 0;
201: uip->devname = 0;
202: uip->rootdir = 0;
203: }
204:
205: char *get_filesys_unit (struct uaedev_mount_info *mountinfo, int nr,
1.1.1.22 root 206: char **devname, char **volname, char **rootdir,
207: int *readonly, int *secspertrack, int *surfaces, int *reserved,
208: int *cylinders, int *size, int *blocksize, int *bootpri)
1.1.1.4 root 209: {
210: UnitInfo *uip = mountinfo->ui + nr;
211:
212: if (nr >= mountinfo->num_units)
213: return "No slot allocated for this unit";
1.1.1.20 root 214:
1.1.1.4 root 215: *volname = uip->volname ? my_strdup (uip->volname) : 0;
1.1.1.22 root 216: *devname = uip->devname ? my_strdup (uip->devname) : 0;
1.1.1.4 root 217: *rootdir = uip->rootdir ? my_strdup (uip->rootdir) : 0;
218: *readonly = uip->readonly;
219: *secspertrack = uip->hf.secspertrack;
220: *surfaces = uip->hf.surfaces;
221: *reserved = uip->hf.reservedblocks;
222: *size = uip->hf.size;
223: *cylinders = uip->hf.nrcyls;
1.1.1.6 root 224: *blocksize = uip->hf.blocksize;
1.1.1.22 root 225: *bootpri = uip->bootpri;
1.1.1.4 root 226: return 0;
227: }
228:
1.1.1.6 root 229: static char *set_filesys_unit_1 (struct uaedev_mount_info *mountinfo, int nr,
1.1.1.22 root 230: const char *devname, const char *volname, const char *rootdir,
231: int readonly, int secspertrack, int surfaces, int reserved,
232: int blocksize, int bootpri)
1.1 root 233: {
1.1.1.6 root 234: UnitInfo *ui = mountinfo->ui + nr;
1.1.1.4 root 235:
236: if (nr >= mountinfo->num_units)
237: return "No slot allocated for this unit";
1.1 root 238:
1.1.1.6 root 239: ui->hf.fd = 0;
240: ui->devname = 0;
241: ui->volname = 0;
242: ui->rootdir = 0;
243: ui->unit_pipe = 0;
244: ui->back_pipe = 0;
1.1.1.5 root 245:
1.1.1.3 root 246: if (volname != 0) {
1.1.1.6 root 247: ui->volname = my_strdup (volname);
248: ui->hf.fd = 0;
1.1.1.3 root 249: } else {
1.1.1.6 root 250: ui->volname = 0;
251: ui->hf.fd = fopen (rootdir, "r+b");
252: if (ui->hf.fd == 0) {
1.1.1.3 root 253: readonly = 1;
1.1.1.6 root 254: ui->hf.fd = fopen (rootdir, "rb");
1.1.1.3 root 255: }
1.1.1.6 root 256: if (ui->hf.fd == 0)
1.1.1.3 root 257: return "Hardfile not found";
1.1.1.4 root 258:
1.1.1.23! root 259: if ((secspertrack || surfaces || reserved)
! 260: && (secspertrack < 1 || secspertrack > 32767
! 261: || surfaces < 1 || surfaces > 1023
! 262: || reserved < 0 || reserved > 1023
! 263: || (blocksize & (blocksize - 1)) != 0))
1.1.1.4 root 264: {
1.1.1.3 root 265: return "Bad hardfile geometry";
266: }
1.1.1.6 root 267: fseek (ui->hf.fd, 0, SEEK_END);
268: ui->hf.size = ftell (ui->hf.fd);
269: ui->hf.secspertrack = secspertrack;
270: ui->hf.surfaces = surfaces;
271: ui->hf.reservedblocks = reserved;
1.1.1.23! root 272: ui->hf.nrcyls = (secspertrack * surfaces
! 273: ? (ui->hf.size / blocksize) / (secspertrack * surfaces)
! 274: : 0);
1.1.1.6 root 275: ui->hf.blocksize = blocksize;
276: }
277: ui->self = 0;
278: ui->reset_state = FS_STARTUP;
279: ui->rootdir = my_strdup (rootdir);
1.1.1.22 root 280: if (devname != 0 && strlen (devname) != 0)
281: ui->devname = my_strdup (devname);
1.1.1.6 root 282: ui->readonly = readonly;
1.1.1.22 root 283: if (bootpri < -128)
284: bootpri = -128;
285: if (bootpri > 127)
286: bootpri = 127;
287: ui->bootpri = bootpri;
1.1 root 288:
1.1.1.3 root 289: return 0;
1.1 root 290: }
1.1.1.6 root 291:
292: char *set_filesys_unit (struct uaedev_mount_info *mountinfo, int nr,
1.1.1.22 root 293: const char *devname, const char *volname, const char *rootdir,
294: int readonly, int secspertrack, int surfaces, int reserved,
295: int blocksize, int bootpri)
1.1.1.6 root 296: {
297: UnitInfo ui = mountinfo->ui[nr];
1.1.1.22 root 298: char *result = set_filesys_unit_1 (mountinfo, nr, devname, volname, rootdir,
299: readonly, secspertrack, surfaces, reserved,
300: blocksize, bootpri);
1.1.1.6 root 301: if (result)
302: mountinfo->ui[nr] = ui;
303: else
304: close_filesys_unit (&ui);
305:
306: return result;
307: }
308:
1.1.1.4 root 309: char *add_filesys_unit (struct uaedev_mount_info *mountinfo,
1.1.1.22 root 310: const char *devname, const char *volname, const char *rootdir,
311: int readonly, int secspertrack, int surfaces, int reserved,
312: int blocksize, int bootpri)
1.1.1.4 root 313: {
314: char *retval;
315: int nr = mountinfo->num_units;
316: UnitInfo *uip = mountinfo->ui + nr;
1.1 root 317:
1.1.1.4 root 318: if (nr >= MAX_UNITS)
319: return "Maximum number of file systems mounted";
320:
321: mountinfo->num_units++;
1.1.1.22 root 322: retval = set_filesys_unit_1 (mountinfo, nr, devname, volname, rootdir, readonly,
323: secspertrack, surfaces, reserved, blocksize,
324: bootpri);
1.1.1.4 root 325: if (retval)
326: mountinfo->num_units--;
327: return retval;
328: }
329:
330: int kill_filesys_unit (struct uaedev_mount_info *mountinfo, int nr)
1.1.1.2 root 331: {
1.1.1.4 root 332: UnitInfo *uip = mountinfo->ui;
333: if (nr >= mountinfo->num_units || nr < 0)
1.1.1.2 root 334: return -1;
335:
1.1.1.6 root 336: close_filesys_unit (mountinfo->ui + nr);
1.1.1.4 root 337:
338: mountinfo->num_units--;
339: for (; nr < mountinfo->num_units; nr++) {
340: uip[nr] = uip[nr+1];
1.1.1.2 root 341: }
342: return 0;
343: }
344:
1.1.1.4 root 345: int move_filesys_unit (struct uaedev_mount_info *mountinfo, int nr, int to)
1.1.1.3 root 346: {
1.1.1.4 root 347: UnitInfo tmpui;
348: UnitInfo *uip = mountinfo->ui;
349:
350: if (nr >= mountinfo->num_units || nr < 0
351: || to >= mountinfo->num_units || to < 0
352: || to == nr)
353: return -1;
354: tmpui = uip[nr];
355: if (to > nr) {
356: int i;
357: for (i = nr; i < to; i++)
358: uip[i] = uip[i + 1];
359: } else {
360: int i;
361: for (i = nr; i > to; i--)
362: uip[i] = uip[i - 1];
363: }
364: uip[to] = tmpui;
365: return 0;
1.1.1.3 root 366: }
367:
1.1.1.4 root 368: int sprintf_filesys_unit (struct uaedev_mount_info *mountinfo, char *buffer, int num)
1.1.1.2 root 369: {
1.1.1.4 root 370: UnitInfo *uip = mountinfo->ui;
371: if (num >= mountinfo->num_units)
1.1.1.2 root 372: return -1;
1.1.1.4 root 373:
374: if (uip[num].volname != 0)
1.1.1.6 root 375: sprintf (buffer, "(DH%d:) Filesystem, %s: %s %s", num, uip[num].volname,
1.1.1.4 root 376: uip[num].rootdir, uip[num].readonly ? "ro" : "");
1.1.1.2 root 377: else
1.1.1.6 root 378: sprintf (buffer, "(DH%d:) Hardfile, \"%s\", size %d bytes", num,
1.1.1.4 root 379: uip[num].rootdir, uip[num].hf.size);
1.1.1.2 root 380: return 0;
381: }
382:
1.1.1.6 root 383: void write_filesys_config (struct uaedev_mount_info *mountinfo,
384: const char *unexpanded, const char *default_path, FILE *f)
1.1 root 385: {
1.1.1.4 root 386: UnitInfo *uip = mountinfo->ui;
1.1 root 387: int i;
1.1.1.4 root 388:
389: for (i = 0; i < mountinfo->num_units; i++) {
1.1.1.6 root 390: char *str;
391: str = cfgfile_subst_path (default_path, unexpanded, uip[i].rootdir);
1.1.1.23! root 392: if (hardfile_fs_type (mountinfo, i) == FILESYS_VIRTUAL) {
! 393: fprintf (f, "filesystem2=%s,%s:%s:%s,%d\n", uip[i].readonly ? "ro" : "rw",
! 394: "", uip[i].volname, str, uip[i].bootpri);
1.1.1.7 root 395: fprintf (f, "filesystem=%s,%s:%s\n", uip[i].readonly ? "ro" : "rw",
1.1.1.6 root 396: uip[i].volname, str);
1.1.1.3 root 397: } else {
1.1.1.23! root 398: fprintf (f, "hardfile2=%s,%s:%s,%d,%d,%d,%d,%d,%s,%s\n",
! 399: uip[i].readonly ? "ro" : "rw",
! 400: "", str,
! 401: uip[i].hf.secspertrack,
! 402: uip[i].hf.surfaces, uip[i].hf.reservedblocks,
! 403: uip[i].hf.blocksize, uip[i].bootpri, "", "uae");
1.1.1.12 root 404: fprintf (f, "hardfile=%s,%d,%d,%d,%d,%s\n",
405: uip[i].readonly ? "ro" : "rw", uip[i].hf.secspertrack,
1.1.1.17 root 406: uip[i].hf.surfaces, uip[i].hf.reservedblocks,
407: uip[i].hf.blocksize, str);
1.1 root 408: }
1.1.1.6 root 409: free (str);
1.1 root 410: }
411: }
412:
1.1.1.4 root 413: struct uaedev_mount_info *alloc_mountinfo (void)
414: {
415: struct uaedev_mount_info *info;
416: info = (struct uaedev_mount_info *)malloc (sizeof *info);
1.1.1.6 root 417: /* memset (info, 0xaa, sizeof *info);*/
1.1.1.4 root 418: info->num_units = 0;
419: return info;
420: }
421:
422: struct uaedev_mount_info *dup_mountinfo (struct uaedev_mount_info *mip)
423: {
424: int i;
425: struct uaedev_mount_info *i2 = alloc_mountinfo ();
426:
427: memcpy (i2, mip, sizeof *i2);
428:
429: for (i = 0; i < i2->num_units; i++) {
430: UnitInfo *uip = i2->ui + i;
431: if (uip->volname)
432: uip->volname = my_strdup (uip->volname);
433: if (uip->rootdir)
434: uip->rootdir = my_strdup (uip->rootdir);
435: if (uip->hf.fd)
1.1.1.7 root 436: uip->hf.fd = fdopen ( dup (fileno (uip->hf.fd)), uip->readonly ? "rb" : "r+b");
1.1.1.4 root 437: }
438: return i2;
439: }
440:
441: void free_mountinfo (struct uaedev_mount_info *mip)
442: {
443: int i;
444: for (i = 0; i < mip->num_units; i++)
1.1.1.6 root 445: close_filesys_unit (mip->ui + i);
1.1.1.4 root 446: free (mip);
447: }
448:
449: struct hardfiledata *get_hardfile_data (int nr)
450: {
451: UnitInfo *uip = current_mountinfo->ui;
452: if (nr < 0 || nr >= current_mountinfo->num_units || uip[nr].volname != 0)
453: return 0;
454: return &uip[nr].hf;
455: }
456:
1.1 root 457: /* minimal AmigaDOS definitions */
458:
459: /* field offsets in DosPacket */
1.1.1.3 root 460: #define dp_Type 8
461: #define dp_Res1 12
462: #define dp_Res2 16
463: #define dp_Arg1 20
464: #define dp_Arg2 24
465: #define dp_Arg3 28
466: #define dp_Arg4 32
1.1 root 467:
468: /* result codes */
1.1.1.23! root 469: #define DOS_TRUE (0xffffffffUL)
1.1 root 470: #define DOS_FALSE (0L)
471:
1.1.1.13 root 472: /* Passed as type to Lock() */
473: #define SHARED_LOCK -2 /* File is readable by others */
474: #define ACCESS_READ -2 /* Synonym */
475: #define EXCLUSIVE_LOCK -1 /* No other access allowed */
476: #define ACCESS_WRITE -1 /* Synonym */
477:
1.1 root 478: /* packet types */
479: #define ACTION_CURRENT_VOLUME 7
480: #define ACTION_LOCATE_OBJECT 8
481: #define ACTION_RENAME_DISK 9
482: #define ACTION_FREE_LOCK 15
483: #define ACTION_DELETE_OBJECT 16
484: #define ACTION_RENAME_OBJECT 17
485: #define ACTION_COPY_DIR 19
486: #define ACTION_SET_PROTECT 21
487: #define ACTION_CREATE_DIR 22
488: #define ACTION_EXAMINE_OBJECT 23
489: #define ACTION_EXAMINE_NEXT 24
490: #define ACTION_DISK_INFO 25
491: #define ACTION_INFO 26
492: #define ACTION_FLUSH 27
493: #define ACTION_SET_COMMENT 28
494: #define ACTION_PARENT 29
495: #define ACTION_SET_DATE 34
496: #define ACTION_FIND_WRITE 1004
497: #define ACTION_FIND_INPUT 1005
498: #define ACTION_FIND_OUTPUT 1006
499: #define ACTION_END 1007
500: #define ACTION_SEEK 1008
501: #define ACTION_IS_FILESYSTEM 1027
502: #define ACTION_READ 'R'
503: #define ACTION_WRITE 'W'
504:
1.1.1.3 root 505: /* 2.0+ packet types */
506: #define ACTION_INHIBIT 31
507: #define ACTION_SET_FILE_SIZE 1022
508: #define ACTION_LOCK_RECORD 2008
509: #define ACTION_FREE_RECORD 2009
510: #define ACTION_SAME_LOCK 40
511: #define ACTION_CHANGE_MODE 1028
512: #define ACTION_FH_FROM_LOCK 1026
513: #define ACTION_COPY_DIR_FH 1030
514: #define ACTION_PARENT_FH 1031
515: #define ACTION_EXAMINE_FH 1034
516: #define ACTION_EXAMINE_ALL 1033
517: #define ACTION_MAKE_LINK 1021
518: #define ACTION_READ_LINK 1024
519: #define ACTION_FORMAT 1020
520: #define ACTION_IS_FILESYSTEM 1027
521: #define ACTION_ADD_NOTIFY 4097
522: #define ACTION_REMOVE_NOTIFY 4098
1.1 root 523:
1.1.1.3 root 524: #define DISK_TYPE 0x444f5301 /* DOS\1 */
1.1 root 525:
1.1.1.3 root 526: typedef struct {
527: uae_u32 uniq;
1.1.1.14 root 528: /* The directory we're going through. */
1.1.1.7 root 529: a_inode *aino;
1.1.1.14 root 530: /* The file we're going to look up next. */
531: a_inode *curr_file;
1.1.1.3 root 532: } ExamineKey;
1.1 root 533:
1.1.1.3 root 534: typedef struct key {
535: struct key *next;
1.1.1.7 root 536: a_inode *aino;
1.1.1.3 root 537: uae_u32 uniq;
538: int fd;
539: off_t file_pos;
540: } Key;
1.1 root 541:
1.1.1.3 root 542: /* Since ACTION_EXAMINE_NEXT is so braindamaged, we have to keep
543: * some of these around
544: */
545:
546: #define EXKEYS 100
547: #define MAX_AINO_HASH 128
1.1 root 548:
549: /* handler state info */
550:
551: typedef struct _unit {
552: struct _unit *next;
553:
554: /* Amiga stuff */
1.1.1.4 root 555: uaecptr dosbase;
556: uaecptr volume;
557: uaecptr port; /* Our port */
558: uaecptr locklist;
1.1 root 559:
560: /* Native stuff */
1.1.1.4 root 561: uae_s32 unit; /* unit number */
562: UnitInfo ui; /* unit startup info */
563: char tmpbuf3[256];
1.1.1.3 root 564:
565: /* Dummy message processing */
1.1.1.4 root 566: uaecptr dummy_message;
1.1.1.3 root 567: volatile unsigned int cmds_sent;
568: volatile unsigned int cmds_complete;
569: volatile unsigned int cmds_acked;
570:
571: /* ExKeys */
1.1.1.14 root 572: ExamineKey examine_keys[EXKEYS];
1.1.1.4 root 573: int next_exkey;
1.1.1.14 root 574: unsigned long total_locked_ainos;
1.1.1.3 root 575:
576: /* Keys */
1.1.1.4 root 577: struct key *keys;
578: uae_u32 key_uniq;
579: uae_u32 a_uniq;
1.1.1.3 root 580:
1.1.1.7 root 581: a_inode rootnode;
1.1.1.3 root 582: unsigned long aino_cache_size;
1.1.1.7 root 583: a_inode *aino_hash[MAX_AINO_HASH];
1.1.1.3 root 584: unsigned long nr_cache_hits;
585: unsigned long nr_cache_lookups;
1.1 root 586: } Unit;
587:
1.1.1.3 root 588: typedef uae_u8 *dpacket;
589: #define PUT_PCK_RES1(p,v) do { do_put_mem_long ((uae_u32 *)((p) + dp_Res1), (v)); } while (0)
590: #define PUT_PCK_RES2(p,v) do { do_put_mem_long ((uae_u32 *)((p) + dp_Res2), (v)); } while (0)
591: #define GET_PCK_TYPE(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Type))))
592: #define GET_PCK_RES1(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Res1))))
593: #define GET_PCK_RES2(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Res2))))
594: #define GET_PCK_ARG1(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg1))))
595: #define GET_PCK_ARG2(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg2))))
596: #define GET_PCK_ARG3(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg3))))
597: #define GET_PCK_ARG4(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg4))))
1.1 root 598:
1.1.1.3 root 599: static char *bstr1 (uaecptr addr)
1.1 root 600: {
601: static char buf[256];
602: int i;
1.1.1.22 root 603: int n = get_byte (addr);
1.1.1.3 root 604: addr++;
605:
1.1.1.4 root 606: for (i = 0; i < n; i++, addr++)
1.1.1.22 root 607: buf[i] = get_byte (addr);
1.1 root 608: buf[i] = 0;
609: return buf;
610: }
611:
1.1.1.3 root 612: static char *bstr (Unit *unit, uaecptr addr)
613: {
614: int i;
1.1.1.22 root 615: int n = get_byte (addr);
1.1.1.3 root 616:
617: addr++;
1.1.1.4 root 618: for (i = 0; i < n; i++, addr++)
1.1.1.22 root 619: unit->tmpbuf3[i] = get_byte (addr);
1.1.1.3 root 620: unit->tmpbuf3[i] = 0;
621: return unit->tmpbuf3;
622: }
623:
624: static char *bstr_cut (Unit *unit, uaecptr addr)
625: {
626: char *p = unit->tmpbuf3;
627: int i, colon_seen = 0;
628: int n = get_byte (addr);
629:
630: addr++;
1.1.1.4 root 631: for (i = 0; i < n; i++, addr++) {
1.1.1.22 root 632: uae_u8 c = get_byte (addr);
1.1.1.3 root 633: unit->tmpbuf3[i] = c;
634: if (c == '/' || (c == ':' && colon_seen++ == 0))
635: p = unit->tmpbuf3 + i + 1;
636: }
637: unit->tmpbuf3[i] = 0;
638: return p;
639: }
640:
641: static Unit *units = 0;
1.1 root 642: static int unit_num = 0;
643:
644: static Unit*
1.1.1.4 root 645: find_unit (uaecptr port)
1.1 root 646: {
647: Unit* u;
1.1.1.4 root 648: for (u = units; u; u = u->next)
649: if (u->port == port)
1.1 root 650: break;
651:
652: return u;
653: }
1.1.1.20 root 654:
1.1.1.3 root 655: static void prepare_for_open (char *name)
656: {
657: #if 0
658: struct stat statbuf;
659: int mode;
660:
661: if (-1 == stat (name, &statbuf))
662: return;
663:
664: mode = statbuf.st_mode;
665: mode |= S_IRUSR;
666: mode |= S_IWUSR;
667: mode |= S_IXUSR;
668: chmod (name, mode);
669: #endif
670: }
671:
1.1.1.7 root 672: static void de_recycle_aino (Unit *unit, a_inode *aino)
1.1 root 673: {
1.1.1.3 root 674: if (aino->next == 0 || aino == &unit->rootnode)
675: return;
676: aino->next->prev = aino->prev;
677: aino->prev->next = aino->next;
678: aino->next = aino->prev = 0;
679: unit->aino_cache_size--;
680: }
681:
1.1.1.7 root 682: static void dispose_aino (Unit *unit, a_inode **aip, a_inode *aino)
683: {
684: int hash = aino->uniq % MAX_AINO_HASH;
685: if (unit->aino_hash[hash] == aino)
686: unit->aino_hash[hash] = 0;
687:
688: if (aino->dirty && aino->parent)
689: fsdb_dir_writeback (aino->parent);
690:
691: *aip = aino->sibling;
692: if (aino->comment)
693: free (aino->comment);
694: free (aino->nname);
695: free (aino->aname);
696: free (aino);
697: }
698:
1.1.1.9 root 699: static void recycle_aino (Unit *unit, a_inode *new_aino)
1.1.1.3 root 700: {
1.1.1.9 root 701: if (new_aino->dir || new_aino->shlock > 0
702: || new_aino->elock || new_aino == &unit->rootnode)
1.1.1.3 root 703: /* Still in use */
704: return;
705:
1.1.1.14 root 706: TRACE (("Recycling; cache size %d, total_locked %d\n",
707: unit->aino_cache_size, unit->total_locked_ainos));
708: if (unit->aino_cache_size > 500 + unit->total_locked_ainos) {
1.1.1.3 root 709: /* Reap a few. */
710: int i = 0;
711: while (i < 50) {
1.1.1.16 root 712: a_inode *parent = unit->rootnode.prev->parent;
1.1.1.22 root 713: a_inode **aip, *old_prev;
1.1.1.16 root 714: aip = &parent->child;
715:
1.1.1.19 root 716: if (! parent->locked_children) {
1.1.1.16 root 717: for (;;) {
718: a_inode *aino = *aip;
719: if (aino == 0)
720: break;
721:
722: /* Not recyclable if next == 0 (i.e., not chained into
723: recyclable list), or if parent directory is being
724: ExNext()ed. */
1.1.1.19 root 725: if (aino->next == 0) {
1.1.1.16 root 726: aip = &aino->sibling;
1.1.1.19 root 727: } else {
1.1.1.16 root 728: if (aino->shlock > 0 || aino->elock)
729: write_log ("panic: freeing locked a_inode!\n");
730:
731: de_recycle_aino (unit, aino);
732: dispose_aino (unit, aip, aino);
733: i++;
734: }
1.1.1.3 root 735: }
1.1.1.19 root 736: }
1.1.1.16 root 737: /* In the previous loop, we went through all children of one
738: parent. Re-arrange the recycled list so that we'll find a
739: different parent the next time around. */
1.1.1.22 root 740: old_prev = unit->rootnode.prev;
1.1.1.16 root 741: do {
742: unit->rootnode.next->prev = unit->rootnode.prev;
743: unit->rootnode.prev->next = unit->rootnode.next;
744: unit->rootnode.next = unit->rootnode.prev;
745: unit->rootnode.prev = unit->rootnode.prev->prev;
746: unit->rootnode.prev->next = unit->rootnode.next->prev = &unit->rootnode;
1.1.1.22 root 747: } while (unit->rootnode.prev != old_prev
748: && unit->rootnode.prev->parent == parent);
1.1.1.3 root 749: }
750: #if 0
751: {
752: char buffer[40];
753: sprintf (buffer, "%d ainos reaped.\n", i);
1.1.1.14 root 754: TRACE ((buffer));
1.1.1.3 root 755: }
756: #endif
757: }
1.1.1.9 root 758:
759: /* Chain it into circular list. */
760: new_aino->next = unit->rootnode.next;
761: new_aino->prev = &unit->rootnode;
762: new_aino->prev->next = new_aino;
763: new_aino->next->prev = new_aino;
764: unit->aino_cache_size++;
1.1.1.3 root 765: }
1.1 root 766:
1.1.1.7 root 767: static void update_child_names (Unit *unit, a_inode *a, a_inode *parent)
1.1.1.3 root 768: {
769: int l0 = strlen (parent->nname) + 2;
1.1 root 770:
1.1.1.3 root 771: while (a != 0) {
772: char *name_start;
773: char *new_name;
1.1.1.13 root 774: char dirsep[2] = { FSDB_DIR_SEPARATOR, '\0' };
1.1.1.20 root 775:
1.1.1.3 root 776: a->parent = parent;
1.1.1.13 root 777: name_start = strrchr (a->nname, FSDB_DIR_SEPARATOR);
1.1.1.3 root 778: if (name_start == 0) {
779: write_log ("malformed file name");
780: }
781: name_start++;
782: new_name = (char *)xmalloc (strlen (name_start) + l0);
783: strcpy (new_name, parent->nname);
1.1.1.13 root 784: strcat (new_name, dirsep);
1.1.1.3 root 785: strcat (new_name, name_start);
786: free (a->nname);
787: a->nname = new_name;
788: if (a->child)
789: update_child_names (unit, a->child, a);
790: a = a->sibling;
1.1 root 791: }
1.1.1.3 root 792: }
1.1 root 793:
1.1.1.7 root 794: static void move_aino_children (Unit *unit, a_inode *from, a_inode *to)
1.1.1.3 root 795: {
796: to->child = from->child;
797: from->child = 0;
798: update_child_names (unit, to->child, to);
1.1 root 799: }
800:
1.1.1.7 root 801: static void delete_aino (Unit *unit, a_inode *aino)
1.1 root 802: {
1.1.1.7 root 803: a_inode **aip;
1.1.1.3 root 804:
1.1.1.4 root 805: TRACE(("deleting aino %x\n", aino->uniq));
1.1.1.3 root 806:
1.1.1.7 root 807: aino->dirty = 1;
808: aino->deleted = 1;
1.1.1.3 root 809: de_recycle_aino (unit, aino);
1.1.1.14 root 810:
811: /* If any ExKeys are currently pointing at us, advance them. */
812: if (aino->parent->exnext_count > 0) {
813: int i;
1.1.1.17 root 814: TRACE(("entering exkey validation\n"));
1.1.1.14 root 815: for (i = 0; i < EXKEYS; i++) {
816: ExamineKey *k = unit->examine_keys + i;
817: if (k->uniq == 0)
818: continue;
819: if (k->aino == aino->parent) {
1.1.1.17 root 820: TRACE(("Same parent found for %d\n", i));
821: if (k->curr_file == aino) {
1.1.1.14 root 822: k->curr_file = aino->sibling;
1.1.1.17 root 823: TRACE(("Advancing curr_file\n"));
824: }
1.1.1.14 root 825: }
826: }
827: }
828:
1.1.1.3 root 829: aip = &aino->parent->child;
830: while (*aip != aino && *aip != 0)
831: aip = &(*aip)->sibling;
832: if (*aip != aino) {
833: write_log ("Couldn't delete aino.\n");
834: return;
835: }
1.1.1.7 root 836: dispose_aino (unit, aip, aino);
1.1 root 837: }
838:
1.1.1.7 root 839: static a_inode *lookup_sub (a_inode *dir, uae_u32 uniq)
1.1.1.3 root 840: {
1.1.1.7 root 841: a_inode **cp = &dir->child;
842: a_inode *c, *retval;
1.1.1.3 root 843:
844: for (;;) {
845: c = *cp;
846: if (c == 0)
847: return 0;
848:
849: if (c->uniq == uniq) {
850: retval = c;
851: break;
852: }
853: if (c->dir) {
1.1.1.7 root 854: a_inode *a = lookup_sub (c, uniq);
1.1.1.3 root 855: if (a != 0) {
856: retval = a;
857: break;
858: }
859: }
860: cp = &c->sibling;
861: }
1.1.1.17 root 862: if (! dir->locked_children) {
863: /* Move to the front to speed up repeated lookups. Don't do this if
864: an ExNext is going on in this directory, or we'll terminally
865: confuse it. */
866: *cp = c->sibling;
867: c->sibling = dir->child;
868: dir->child = c;
869: }
1.1.1.3 root 870: return retval;
871: }
872:
1.1.1.7 root 873: static a_inode *lookup_aino (Unit *unit, uae_u32 uniq)
1.1 root 874: {
1.1.1.7 root 875: a_inode *a;
1.1.1.3 root 876: int hash = uniq % MAX_AINO_HASH;
877:
878: if (uniq == 0)
879: return &unit->rootnode;
880: a = unit->aino_hash[hash];
881: if (a == 0 || a->uniq != uniq)
882: a = lookup_sub (&unit->rootnode, uniq);
883: else
884: unit->nr_cache_hits++;
885: unit->nr_cache_lookups++;
886: unit->aino_hash[hash] = a;
887: return a;
888: }
889:
1.1.1.7 root 890: char *build_nname (const char *d, const char *n)
891: {
892: char dsep[2] = { FSDB_DIR_SEPARATOR, '\0' };
893: char *p = (char *) xmalloc (strlen (d) + strlen (n) + 2);
894: strcpy (p, d);
895: strcat (p, dsep);
896: strcat (p, n);
897: return p;
898: }
899:
900: char *build_aname (const char *d, const char *n)
901: {
902: char *p = (char *) xmalloc (strlen (d) + strlen (n) + 2);
903: strcpy (p, d);
904: strcat (p, "/");
905: strcat (p, n);
906: return p;
907: }
908:
1.1.1.3 root 909: /* This gets called to translate an Amiga name that some program used to
1.1.1.7 root 910: * a name that we can use on the native filesystem. */
911: static char *get_nname (Unit *unit, a_inode *base, char *rel,
912: char **modified_rel)
1.1.1.3 root 913: {
1.1.1.7 root 914: char *found;
1.1.1.3 root 915: char *p = 0;
916:
1.1.1.7 root 917: *modified_rel = 0;
1.1.1.20 root 918:
1.1.1.7 root 919: /* If we have a mapping of some other aname to "rel", we must pretend
920: * it does not exist.
921: * This can happen for example if an Amiga program creates a
922: * file called ".". We can't represent this in our filesystem,
923: * so we create a special file "uae_xxx" and record the mapping
924: * aname "." -> nname "uae_xxx" in the database. Then, the Amiga
925: * program looks up "uae_xxx" (yes, it's contrived). The filesystem
926: * should not make the uae_xxx file visible to the Amiga side. */
927: if (fsdb_used_as_nname (base, rel))
928: return 0;
929: /* A file called "." (or whatever else is invalid on this filesystem)
930: * does not exist, as far as the Amiga side is concerned. */
931: if (fsdb_name_invalid (rel))
1.1.1.4 root 932: return 0;
933:
1.1.1.7 root 934: /* See if we have a file that has the same name as the aname we are
935: * looking for. */
936: found = fsdb_search_dir (base->nname, rel);
937: if (found == 0)
938: return found;
939: if (found == rel)
940: return build_nname (base->nname, rel);
941:
942: *modified_rel = found;
943: return build_nname (base->nname, found);
944: }
945:
946: static char *create_nname (Unit *unit, a_inode *base, char *rel)
947: {
948: char *p;
949:
950: /* We are trying to create a file called REL. */
1.1.1.20 root 951:
1.1.1.7 root 952: /* If the name is used otherwise in the directory (or globally), we
953: * need a new unique nname. */
954: if (fsdb_name_invalid (rel) || fsdb_used_as_nname (base, rel)) {
955: oh_dear:
956: p = fsdb_create_unique_nname (base, rel);
957: return p;
958: }
959: p = build_nname (base->nname, rel);
960:
961: /* Delete this code once we know everything works. */
962: if (access (p, R_OK) >= 0 || errno != ENOENT) {
963: write_log ("Filesystem in trouble... please report.\n");
964: free (p);
965: goto oh_dear;
1.1.1.3 root 966: }
967: return p;
968: }
969:
970: /*
971: * This gets called if an ACTION_EXAMINE_NEXT happens and we hit an object
972: * for which we know the name on the native filesystem, but no corresponding
973: * Amiga filesystem name.
974: * @@@ For DOS filesystems, it might make sense to declare the new name
975: * "weak", so that it can get overriden by a subsequent call to get_nname().
976: * That way, if someone does "dir :" and there is a file "foobar.inf", and
977: * someone else tries to open "foobar.info", get_nname() could maybe made to
978: * figure out that this is supposed to be the file "foobar.inf".
979: * DOS sucks...
980: */
1.1.1.7 root 981: static char *get_aname (Unit *unit, a_inode *base, char *rel)
1.1.1.3 root 982: {
1.1.1.7 root 983: return my_strdup (rel);
1.1.1.3 root 984: }
985:
1.1.1.7 root 986: static void init_child_aino (Unit *unit, a_inode *base, a_inode *aino)
1.1.1.3 root 987: {
988: aino->uniq = ++unit->a_uniq;
989: if (unit->a_uniq == 0xFFFFFFFF) {
990: write_log ("Running out of a_inodes (prepare for big trouble)!\n");
991: }
992: aino->shlock = 0;
993: aino->elock = 0;
994:
1.1.1.7 root 995: aino->dirty = 0;
996: aino->deleted = 0;
997:
1.1.1.14 root 998: /* For directories - this one isn't being ExNext()ed yet. */
999: aino->locked_children = 0;
1000: aino->exnext_count = 0;
1001: /* But the parent might be. */
1002: if (base->exnext_count) {
1003: unit->total_locked_ainos++;
1004: base->locked_children++;
1005: }
1.1.1.3 root 1006: /* Update tree structure */
1007: aino->parent = base;
1008: aino->child = 0;
1009: aino->sibling = base->child;
1010: base->child = aino;
1011: aino->next = aino->prev = 0;
1.1.1.7 root 1012: }
1.1.1.3 root 1013:
1.1.1.7 root 1014: static a_inode *new_child_aino (Unit *unit, a_inode *base, char *rel)
1015: {
1016: char *modified_rel;
1017: char *nn;
1018: a_inode *aino;
1019:
1020: TRACE(("new_child_aino %s, %s\n", base->aname, rel));
1021:
1022: aino = fsdb_lookup_aino_aname (base, rel);
1023: if (aino == 0) {
1024: nn = get_nname (unit, base, rel, &modified_rel);
1025: if (nn == 0)
1026: return 0;
1027:
1.1.1.11 root 1028: aino = (a_inode *) xcalloc (sizeof (a_inode), 1);
1.1.1.7 root 1029: if (aino == 0)
1030: return 0;
1031: aino->aname = modified_rel ? modified_rel : my_strdup (rel);
1032: aino->nname = nn;
1033:
1034: aino->comment = 0;
1035: aino->has_dbentry = 0;
1036:
1037: fsdb_fill_file_attrs (aino);
1038: if (aino->dir)
1039: fsdb_clean_dir (aino);
1.1.1.3 root 1040: }
1.1.1.7 root 1041: init_child_aino (unit, base, aino);
1042:
1043: recycle_aino (unit, aino);
1.1.1.17 root 1044: TRACE(("created aino %x, lookup, amigaos_mode %d\n", aino->uniq, aino->amigaos_mode));
1.1.1.7 root 1045: return aino;
1046: }
1047:
1048: static a_inode *create_child_aino (Unit *unit, a_inode *base, char *rel, int isdir)
1049: {
1.1.1.11 root 1050: a_inode *aino = (a_inode *) xcalloc (sizeof (a_inode), 1);
1.1.1.7 root 1051: if (aino == 0)
1052: return 0;
1053:
1054: aino->aname = my_strdup (rel);
1055: aino->nname = create_nname (unit, base, rel);
1056:
1057: init_child_aino (unit, base, aino);
1058: aino->amigaos_mode = 0;
1059: aino->dir = isdir;
1060:
1061: aino->comment = 0;
1062: aino->has_dbentry = 0;
1063: aino->dirty = 1;
1.1.1.5 root 1064:
1.1.1.3 root 1065: recycle_aino (unit, aino);
1.1.1.7 root 1066: TRACE(("created aino %x, create\n", aino->uniq));
1.1.1.3 root 1067: return aino;
1068: }
1069:
1.1.1.7 root 1070: static a_inode *lookup_child_aino (Unit *unit, a_inode *base, char *rel, uae_u32 *err)
1.1.1.3 root 1071: {
1.1.1.7 root 1072: a_inode *c = base->child;
1.1.1.3 root 1073: int l0 = strlen (rel);
1074:
1075: if (base->dir == 0) {
1076: *err = ERROR_OBJECT_WRONG_TYPE;
1077: return 0;
1078: }
1079:
1080: while (c != 0) {
1081: int l1 = strlen (c->aname);
1.1.1.7 root 1082: if (l0 <= l1 && same_aname (rel, c->aname + l1 - l0)
1.1.1.3 root 1083: && (l0 == l1 || c->aname[l1-l0-1] == '/'))
1084: break;
1085: c = c->sibling;
1086: }
1087: if (c != 0)
1088: return c;
1.1.1.7 root 1089: c = new_child_aino (unit, base, rel);
1.1.1.3 root 1090: if (c == 0)
1.1.1.11 root 1091: *err = ERROR_OBJECT_NOT_AROUND;
1.1.1.3 root 1092: return c;
1093: }
1094:
1.1.1.7 root 1095: /* Different version because for this one, REL is an nname. */
1096: static a_inode *lookup_child_aino_for_exnext (Unit *unit, a_inode *base, char *rel, uae_u32 *err)
1.1.1.3 root 1097: {
1.1.1.7 root 1098: a_inode *c = base->child;
1.1.1.3 root 1099: int l0 = strlen (rel);
1100:
1101: *err = 0;
1102: while (c != 0) {
1103: int l1 = strlen (c->nname);
1.1.1.7 root 1104: /* Note: using strcmp here. */
1105: if (l0 <= l1 && strcmp (rel, c->nname + l1 - l0) == 0
1106: && (l0 == l1 || c->nname[l1-l0-1] == FSDB_DIR_SEPARATOR))
1.1.1.3 root 1107: break;
1108: c = c->sibling;
1109: }
1110: if (c != 0)
1111: return c;
1.1.1.7 root 1112: c = fsdb_lookup_aino_nname (base, rel);
1113: if (c == 0) {
1114: c = (a_inode *)malloc (sizeof (a_inode));
1115: if (c == 0) {
1116: *err = ERROR_NO_FREE_STORE;
1117: return 0;
1118: }
1119:
1120: c->nname = build_nname (base->nname, rel);
1.1.1.3 root 1121: c->aname = get_aname (unit, base, rel);
1.1.1.7 root 1122: c->comment = 0;
1123: c->has_dbentry = 0;
1124: fsdb_fill_file_attrs (c);
1125: if (c->dir)
1126: fsdb_clean_dir (c);
1.1.1.3 root 1127: }
1.1.1.7 root 1128: init_child_aino (unit, base, c);
1129:
1130: recycle_aino (unit, c);
1131: TRACE(("created aino %x, exnext\n", c->uniq));
1132:
1.1.1.3 root 1133: return c;
1134: }
1135:
1.1.1.7 root 1136: static a_inode *get_aino (Unit *unit, a_inode *base, const char *rel, uae_u32 *err)
1.1.1.3 root 1137: {
1138: char *tmp;
1139: char *p;
1.1.1.7 root 1140: a_inode *curr;
1.1.1.3 root 1141: int i;
1142:
1143: *err = 0;
1.1.1.4 root 1144: TRACE(("get_path(%s,%s)\n", base->aname, rel));
1.1.1.3 root 1145:
1146: /* root-relative path? */
1.1.1.4 root 1147: for (i = 0; rel[i] && rel[i] != '/' && rel[i] != ':'; i++)
1.1.1.3 root 1148: ;
1149: if (':' == rel[i])
1150: rel += i+1;
1151:
1152: tmp = my_strdup (rel);
1153: p = tmp;
1154: curr = base;
1155:
1.1.1.7 root 1156: while (*p) {
1.1.1.3 root 1157: /* start with a slash? go up a level. */
1158: if (*p == '/') {
1159: if (curr->parent != 0)
1160: curr = curr->parent;
1161: p++;
1162: } else {
1.1.1.7 root 1163: a_inode *next;
1.1.1.3 root 1164:
1165: char *component_end;
1166: component_end = strchr (p, '/');
1167: if (component_end != 0)
1168: *component_end = '\0';
1169: next = lookup_child_aino (unit, curr, p, err);
1170: if (next == 0) {
1171: /* if only last component not found, return parent dir. */
1.1.1.11 root 1172: if (*err != ERROR_OBJECT_NOT_AROUND || component_end != 0)
1.1.1.3 root 1173: curr = 0;
1174: /* ? what error is appropriate? */
1175: break;
1176: }
1177: curr = next;
1178: if (component_end)
1179: p = component_end+1;
1180: else
1181: break;
1182:
1183: }
1184: }
1185: free (tmp);
1186: return curr;
1187: }
1188:
1.1.1.22 root 1189: static uae_u32 startup_handler (TrapContext *dummy)
1.1.1.3 root 1190: {
1191: /* Just got the startup packet. It's in A4. DosBase is in A2,
1192: * our allocated volume structure is in D6, A5 is a pointer to
1193: * our port. */
1.1.1.7 root 1194: uaecptr rootnode = get_long (m68k_areg (regs, 2) + 34);
1195: uaecptr dos_info = get_long (rootnode + 24) << 2;
1.1.1.3 root 1196: uaecptr pkt = m68k_dreg (regs, 3);
1197: uaecptr arg2 = get_long (pkt + dp_Arg2);
1.1 root 1198: int i, namelen;
1.1.1.3 root 1199: char* devname = bstr1 (get_long (pkt + dp_Arg1) << 2);
1.1 root 1200: char* s;
1.1.1.4 root 1201: Unit *unit;
1.1.1.3 root 1202: UnitInfo *uinfo;
1.1 root 1203:
1204: /* find UnitInfo with correct device name */
1.1.1.4 root 1205: s = strchr (devname, ':');
1206: if (s)
1.1.1.3 root 1207: *s = '\0';
1.1 root 1208:
1.1.1.4 root 1209: for (i = 0; i < current_mountinfo->num_units; i++) {
1.1 root 1210: /* Hardfile volume name? */
1.1.1.4 root 1211: if (current_mountinfo->ui[i].volname == 0)
1.1 root 1212: continue;
1.1.1.3 root 1213:
1.1.1.4 root 1214: if (current_mountinfo->ui[i].startup == arg2)
1.1.1.3 root 1215: break;
1.1 root 1216: }
1.1.1.3 root 1217:
1.1.1.4 root 1218: if (i == current_mountinfo->num_units
1219: || access (current_mountinfo->ui[i].rootdir, R_OK) != 0)
1220: {
1221: write_log ("Failed attempt to mount device\n", devname);
1.1.1.3 root 1222: put_long (pkt + dp_Res1, DOS_FALSE);
1223: put_long (pkt + dp_Res2, ERROR_DEVICE_NOT_MOUNTED);
1224: return 1;
1.1 root 1225: }
1.1.1.4 root 1226: uinfo = current_mountinfo->ui + i;
1.1 root 1227:
1.1.1.11 root 1228: unit = (Unit *) xcalloc (sizeof (Unit), 1);
1.1 root 1229: unit->next = units;
1230: units = unit;
1.1.1.3 root 1231: uinfo->self = unit;
1.1 root 1232:
1233: unit->volume = 0;
1.1.1.7 root 1234: unit->port = m68k_areg (regs, 5);
1.1 root 1235: unit->unit = unit_num++;
1236:
1.1.1.3 root 1237: unit->ui.devname = uinfo->devname;
1238: unit->ui.volname = my_strdup (uinfo->volname); /* might free later for rename */
1239: unit->ui.rootdir = uinfo->rootdir;
1240: unit->ui.readonly = uinfo->readonly;
1.1.1.22 root 1241: unit->ui.bootpri = uinfo->bootpri;
1.1.1.3 root 1242: unit->ui.unit_pipe = uinfo->unit_pipe;
1243: unit->ui.back_pipe = uinfo->back_pipe;
1244: unit->cmds_complete = 0;
1245: unit->cmds_sent = 0;
1246: unit->cmds_acked = 0;
1247: for (i = 0; i < EXKEYS; i++) {
1248: unit->examine_keys[i].aino = 0;
1.1.1.14 root 1249: unit->examine_keys[i].curr_file = 0;
1.1.1.3 root 1250: unit->examine_keys[i].uniq = 0;
1251: }
1.1.1.14 root 1252: unit->total_locked_ainos = 0;
1.1.1.3 root 1253: unit->next_exkey = 1;
1254: unit->keys = 0;
1255: unit->a_uniq = unit->key_uniq = 0;
1256:
1257: unit->rootnode.aname = uinfo->volname;
1258: unit->rootnode.nname = uinfo->rootdir;
1259: unit->rootnode.sibling = 0;
1260: unit->rootnode.next = unit->rootnode.prev = &unit->rootnode;
1261: unit->rootnode.uniq = 0;
1262: unit->rootnode.parent = 0;
1263: unit->rootnode.child = 0;
1264: unit->rootnode.dir = 1;
1265: unit->rootnode.amigaos_mode = 0;
1266: unit->rootnode.shlock = 0;
1267: unit->rootnode.elock = 0;
1.1.1.11 root 1268: unit->rootnode.comment = 0;
1269: unit->rootnode.has_dbentry = 0;
1.1.1.3 root 1270: unit->aino_cache_size = 0;
1271: for (i = 0; i < MAX_AINO_HASH; i++)
1272: unit->aino_hash[i] = 0;
1273:
1274: /* write_comm_pipe_int (unit->ui.unit_pipe, -1, 1);*/
1.1 root 1275:
1.1.1.4 root 1276: TRACE(("**** STARTUP volume %s\n", unit->ui.volname));
1.1 root 1277:
1278: /* fill in our process in the device node */
1.1.1.3 root 1279: put_long ((get_long (pkt + dp_Arg3) << 2) + 8, unit->port);
1.1.1.7 root 1280: unit->dosbase = m68k_areg (regs, 2);
1.1 root 1281:
1.1.1.3 root 1282: /* make new volume */
1283: unit->volume = m68k_areg (regs, 3) + 32;
1284: #ifdef UAE_FILESYS_THREADS
1285: unit->locklist = m68k_areg (regs, 3) + 8;
1286: #else
1287: unit->locklist = m68k_areg (regs, 3);
1288: #endif
1289: unit->dummy_message = m68k_areg (regs, 3) + 12;
1.1 root 1290:
1.1.1.3 root 1291: put_long (unit->dummy_message + 10, 0);
1292:
1293: put_long (unit->volume + 4, 2); /* Type = dt_volume */
1294: put_long (unit->volume + 12, 0); /* Lock */
1295: put_long (unit->volume + 16, 3800); /* Creation Date */
1296: put_long (unit->volume + 20, 0);
1297: put_long (unit->volume + 24, 0);
1298: put_long (unit->volume + 28, 0); /* lock list */
1299: put_long (unit->volume + 40, (unit->volume + 44) >> 2); /* Name */
1300: namelen = strlen (unit->ui.volname);
1301: put_byte (unit->volume + 44, namelen);
1.1.1.4 root 1302: for (i = 0; i < namelen; i++)
1.1.1.3 root 1303: put_byte (unit->volume + 45 + i, unit->ui.volname[i]);
1304:
1305: /* link into DOS list */
1.1.1.7 root 1306: put_long (unit->volume, get_long (dos_info + 4));
1.1.1.3 root 1307: put_long (dos_info + 4, unit->volume >> 2);
1308:
1309: put_long (unit->volume + 8, unit->port);
1310: put_long (unit->volume + 32, DISK_TYPE);
1.1 root 1311:
1.1.1.3 root 1312: put_long (pkt + dp_Res1, DOS_TRUE);
1.1.1.7 root 1313:
1314: fsdb_clean_dir (&unit->rootnode);
1315:
1.1.1.3 root 1316: return 0;
1.1 root 1317: }
1318:
1319: static void
1.1.1.4 root 1320: do_info (Unit *unit, dpacket packet, uaecptr info)
1.1 root 1321: {
1.1.1.4 root 1322: struct fs_usage fsu;
1.1.1.20 root 1323:
1.1.1.4 root 1324: if (get_fs_usage (unit->ui.rootdir, 0, &fsu) != 0) {
1.1.1.3 root 1325: PUT_PCK_RES1 (packet, DOS_FALSE);
1326: PUT_PCK_RES2 (packet, dos_errno ());
1.1.1.4 root 1327: return;
1.1 root 1328: }
1329:
1.1.1.4 root 1330: fsu.fsu_blocks >>= 1;
1331: fsu.fsu_bavail >>= 1;
1.1.1.7 root 1332: put_long (info, 0); /* errors */
1333: put_long (info + 4, unit->unit); /* unit number */
1334: put_long (info + 8, unit->ui.readonly ? 80 : 82); /* state */
1335: put_long (info + 12, fsu.fsu_blocks ); /* numblocks */
1336: put_long (info + 16, fsu.fsu_blocks - fsu.fsu_bavail); /* inuse */
1337: put_long (info + 20, 1024); /* bytesperblock */
1338: put_long (info + 24, DISK_TYPE); /* disk type */
1339: put_long (info + 28, unit->volume >> 2); /* volume node */
1340: put_long (info + 32, 0); /* inuse */
1.1.1.3 root 1341: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 1342: }
1343:
1344: static void
1.1.1.4 root 1345: action_disk_info (Unit *unit, dpacket packet)
1.1 root 1346: {
1.1.1.4 root 1347: TRACE(("ACTION_DISK_INFO\n"));
1.1.1.3 root 1348: do_info(unit, packet, GET_PCK_ARG1 (packet) << 2);
1.1 root 1349: }
1350:
1351: static void
1.1.1.4 root 1352: action_info (Unit *unit, dpacket packet)
1.1 root 1353: {
1.1.1.4 root 1354: TRACE(("ACTION_INFO\n"));
1.1.1.3 root 1355: do_info(unit, packet, GET_PCK_ARG2 (packet) << 2);
1.1 root 1356: }
1357:
1.1.1.4 root 1358: static void free_key (Unit *unit, Key *k)
1.1 root 1359: {
1360: Key *k1;
1.1.1.3 root 1361: Key *prev = 0;
1362: for (k1 = unit->keys; k1; k1 = k1->next) {
1363: if (k == k1) {
1.1.1.4 root 1364: if (prev)
1.1.1.3 root 1365: prev->next = k->next;
1366: else
1367: unit->keys = k->next;
1368: break;
1369: }
1370: prev = k1;
1.1 root 1371: }
1372:
1373: if (k->fd >= 0)
1.1.1.13 root 1374: close (k->fd);
1.1.1.3 root 1375:
1.1 root 1376: free(k);
1377: }
1378:
1.1.1.4 root 1379: static Key *lookup_key (Unit *unit, uae_u32 uniq)
1.1 root 1380: {
1381: Key *k;
1.1.1.3 root 1382: /* It's hardly worthwhile to optimize this - most of the time there are
1383: * only one or zero keys. */
1.1.1.4 root 1384: for (k = unit->keys; k; k = k->next) {
1.1.1.3 root 1385: if (uniq == k->uniq)
1386: return k;
1.1 root 1387: }
1.1.1.3 root 1388: write_log ("Error: couldn't find key!\n");
1389: #if 0
1.1 root 1390: exit(1);
1391: /* NOTREACHED */
1.1.1.3 root 1392: #endif
1393: /* There isn't much hope we will recover. Unix would kill the process,
1394: * AmigaOS gets killed by it. */
1395: write_log ("Better reset that Amiga - the system is messed up.\n");
1396: return 0;
1.1 root 1397: }
1398:
1.1.1.4 root 1399: static Key *new_key (Unit *unit)
1.1 root 1400: {
1.1.1.4 root 1401: Key *k = (Key *) xmalloc(sizeof(Key));
1.1.1.3 root 1402: k->uniq = ++unit->key_uniq;
1.1 root 1403: k->fd = -1;
1404: k->file_pos = 0;
1.1.1.3 root 1405: k->next = unit->keys;
1406: unit->keys = k;
1.1 root 1407:
1408: return k;
1409: }
1410:
1411: static void
1.1.1.4 root 1412: dumplock (Unit *unit, uaecptr lock)
1.1 root 1413: {
1.1.1.7 root 1414: a_inode *a;
1.1.1.4 root 1415: TRACE(("LOCK: 0x%lx", lock));
1416: if (!lock) {
1417: TRACE(("\n"));
1.1 root 1418: return;
1419: }
1.1.1.4 root 1420: TRACE(("{ next=0x%lx, mode=%ld, handler=0x%lx, volume=0x%lx, aino %lx ",
1.1.1.7 root 1421: get_long (lock) << 2, get_long (lock+8),
1422: get_long (lock+12), get_long (lock+16),
1423: get_long (lock + 4)));
1.1.1.3 root 1424: a = lookup_aino (unit, get_long (lock + 4));
1425: if (a == 0) {
1.1.1.4 root 1426: TRACE(("not found!"));
1.1.1.3 root 1427: } else {
1.1.1.4 root 1428: TRACE(("%s", a->nname));
1.1.1.3 root 1429: }
1.1.1.4 root 1430: TRACE((" }\n"));
1.1 root 1431: }
1432:
1.1.1.7 root 1433: static a_inode *find_aino (Unit *unit, uaecptr lock, const char *name, uae_u32 *err)
1.1 root 1434: {
1.1.1.7 root 1435: a_inode *a;
1.1 root 1436:
1.1.1.3 root 1437: if (lock) {
1.1.1.7 root 1438: a_inode *olda = lookup_aino (unit, get_long (lock + 4));
1.1.1.3 root 1439: if (olda == 0) {
1440: /* That's the best we can hope to do. */
1441: a = get_aino (unit, &unit->rootnode, name, err);
1.1 root 1442: } else {
1.1.1.4 root 1443: TRACE(("aino: 0x%08lx", (unsigned long int)olda->uniq));
1444: TRACE((" \"%s\"\n", olda->nname));
1.1.1.3 root 1445: a = get_aino (unit, olda, name, err);
1.1 root 1446: }
1447: } else {
1.1.1.3 root 1448: a = get_aino (unit, &unit->rootnode, name, err);
1.1 root 1449: }
1.1.1.3 root 1450: if (a) {
1.1.1.4 root 1451: TRACE(("aino=\"%s\"\n", a->nname));
1.1.1.3 root 1452: }
1453: return a;
1.1 root 1454: }
1455:
1.1.1.4 root 1456: static uaecptr make_lock (Unit *unit, uae_u32 uniq, long mode)
1.1 root 1457: {
1.1.1.3 root 1458: /* allocate lock from the list kept by the assembly code */
1459: uaecptr lock;
1.1 root 1460:
1.1.1.3 root 1461: lock = get_long (unit->locklist);
1462: put_long (unit->locklist, get_long (lock));
1463: lock += 4;
1.1 root 1464:
1.1.1.7 root 1465: put_long (lock + 4, uniq);
1466: put_long (lock + 8, mode);
1467: put_long (lock + 12, unit->port);
1468: put_long (lock + 16, unit->volume >> 2);
1.1 root 1469:
1470: /* prepend to lock chain */
1.1.1.7 root 1471: put_long (lock, get_long (unit->volume + 28));
1472: put_long (unit->volume + 28, lock >> 2);
1.1 root 1473:
1.1.1.3 root 1474: DUMPLOCK(unit, lock);
1.1 root 1475: return lock;
1476: }
1477:
1.1.1.4 root 1478: static void free_lock (Unit *unit, uaecptr lock)
1.1 root 1479: {
1.1.1.4 root 1480: if (! lock)
1.1 root 1481: return;
1482:
1.1.1.7 root 1483: if (lock == get_long (unit->volume + 28) << 2) {
1484: put_long (unit->volume + 28, get_long (lock));
1.1 root 1485: } else {
1.1.1.7 root 1486: uaecptr current = get_long (unit->volume + 28);
1.1.1.3 root 1487: uaecptr next = 0;
1.1.1.4 root 1488: while (current) {
1.1.1.7 root 1489: next = get_long (current << 2);
1.1.1.4 root 1490: if (lock == next << 2)
1.1 root 1491: break;
1492: current = next;
1493: }
1.1.1.7 root 1494: put_long (current << 2, get_long (lock));
1.1 root 1495: }
1.1.1.3 root 1496: lock -= 4;
1497: put_long (lock, get_long (unit->locklist));
1498: put_long (unit->locklist, lock);
1.1 root 1499: }
1500:
1501: static void
1.1.1.4 root 1502: action_lock (Unit *unit, dpacket packet)
1.1 root 1503: {
1.1.1.3 root 1504: uaecptr lock = GET_PCK_ARG1 (packet) << 2;
1505: uaecptr name = GET_PCK_ARG2 (packet) << 2;
1506: long mode = GET_PCK_ARG3 (packet);
1.1.1.7 root 1507: a_inode *a;
1.1.1.3 root 1508: uae_u32 err;
1.1 root 1509:
1.1.1.13 root 1510: if (mode != SHARED_LOCK && mode != EXCLUSIVE_LOCK) {
1.1.1.4 root 1511: TRACE(("Bad mode.\n"));
1.1.1.13 root 1512: mode = SHARED_LOCK;
1.1.1.3 root 1513: }
1.1 root 1514:
1.1.1.4 root 1515: TRACE(("ACTION_LOCK(0x%lx, \"%s\", %d)\n", lock, bstr (unit, name), mode));
1.1.1.3 root 1516: DUMPLOCK(unit, lock);
1.1 root 1517:
1.1.1.3 root 1518: a = find_aino (unit, lock, bstr (unit, name), &err);
1.1.1.13 root 1519: if (err == 0 && (a->elock || (mode != SHARED_LOCK && a->shlock > 0))) {
1.1.1.3 root 1520: err = ERROR_OBJECT_IN_USE;
1.1 root 1521: }
1.1.1.3 root 1522: /* Lock() doesn't do access checks. */
1523: if (err != 0) {
1524: PUT_PCK_RES1 (packet, DOS_FALSE);
1525: PUT_PCK_RES2 (packet, err);
1526: return;
1527: }
1.1.1.13 root 1528: if (mode == SHARED_LOCK)
1.1.1.3 root 1529: a->shlock++;
1530: else
1531: a->elock = 1;
1532: de_recycle_aino (unit, a);
1533: PUT_PCK_RES1 (packet, make_lock (unit, a->uniq, mode) >> 2);
1.1 root 1534: }
1535:
1.1.1.4 root 1536: static void action_free_lock (Unit *unit, dpacket packet)
1.1 root 1537: {
1.1.1.3 root 1538: uaecptr lock = GET_PCK_ARG1 (packet) << 2;
1.1.1.7 root 1539: a_inode *a;
1.1.1.4 root 1540: TRACE(("ACTION_FREE_LOCK(0x%lx)\n", lock));
1.1.1.3 root 1541: DUMPLOCK(unit, lock);
1.1 root 1542:
1.1.1.3 root 1543: a = lookup_aino (unit, get_long (lock + 4));
1544: if (a == 0) {
1545: PUT_PCK_RES1 (packet, DOS_FALSE);
1.1.1.11 root 1546: PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
1.1.1.3 root 1547: return;
1548: }
1549: if (a->elock)
1550: a->elock = 0;
1551: else
1552: a->shlock--;
1553: recycle_aino (unit, a);
1.1 root 1554: free_lock(unit, lock);
1555:
1.1.1.3 root 1556: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 1557: }
1558:
1559: static void
1.1.1.4 root 1560: action_dup_lock (Unit *unit, dpacket packet)
1.1 root 1561: {
1.1.1.3 root 1562: uaecptr lock = GET_PCK_ARG1 (packet) << 2;
1.1.1.7 root 1563: a_inode *a;
1.1.1.4 root 1564: TRACE(("ACTION_DUP_LOCK(0x%lx)\n", lock));
1.1.1.3 root 1565: DUMPLOCK(unit, lock);
1.1 root 1566:
1.1.1.4 root 1567: if (!lock) {
1.1.1.3 root 1568: PUT_PCK_RES1 (packet, 0);
1.1 root 1569: return;
1570: }
1.1.1.3 root 1571: a = lookup_aino (unit, get_long (lock + 4));
1572: if (a == 0) {
1573: PUT_PCK_RES1 (packet, DOS_FALSE);
1.1.1.11 root 1574: PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
1.1.1.3 root 1575: return;
1.1 root 1576: }
1.1.1.3 root 1577: /* DupLock()ing exclusive locks isn't possible, says the Autodoc, but
1578: * at least the RAM-Handler seems to allow it. Let's see what happens
1579: * if we don't. */
1580: if (a->elock) {
1581: PUT_PCK_RES1 (packet, DOS_FALSE);
1582: PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
1583: return;
1584: }
1585: a->shlock++;
1586: de_recycle_aino (unit, a);
1587: PUT_PCK_RES1 (packet, make_lock (unit, a->uniq, -2) >> 2);
1.1 root 1588: }
1589:
1590: /* convert time_t to/from AmigaDOS time */
1591: const int secs_per_day = 24 * 60 * 60;
1592: const int diff = (8 * 365 + 2) * (24 * 60 * 60);
1593:
1594: static void
1.1.1.4 root 1595: get_time (time_t t, long* days, long* mins, long* ticks)
1.1 root 1596: {
1597: /* time_t is secs since 1-1-1970 */
1598: /* days since 1-1-1978 */
1599: /* mins since midnight */
1600: /* ticks past minute @ 50Hz */
1601:
1602: t -= diff;
1603: *days = t / secs_per_day;
1604: t -= *days * secs_per_day;
1605: *mins = t / 60;
1606: t -= *mins * 60;
1607: *ticks = t * 50;
1608: }
1609:
1610: static time_t
1.1.1.4 root 1611: put_time (long days, long mins, long ticks)
1.1 root 1612: {
1613: time_t t;
1614: t = ticks / 50;
1615: t += mins * 60;
1616: t += days * secs_per_day;
1617: t += diff;
1618:
1619: return t;
1620: }
1621:
1.1.1.14 root 1622: static void free_exkey (Unit *unit, ExamineKey *ek)
1.1 root 1623: {
1.1.1.14 root 1624: if (--ek->aino->exnext_count == 0) {
1625: TRACE (("Freeing ExKey and reducing total_locked from %d by %d\n",
1626: unit->total_locked_ainos, ek->aino->locked_children));
1627: unit->total_locked_ainos -= ek->aino->locked_children;
1628: ek->aino->locked_children = 0;
1629: }
1.1.1.3 root 1630: ek->aino = 0;
1631: ek->uniq = 0;
1.1 root 1632: }
1633:
1.1.1.13 root 1634: static ExamineKey *lookup_exkey (Unit *unit, uae_u32 uniq)
1635: {
1636: ExamineKey *ek;
1637: int i;
1638:
1639: ek = unit->examine_keys;
1640: for (i = 0; i < EXKEYS; i++, ek++) {
1641: /* Did we find a free one? */
1642: if (ek->uniq == uniq)
1643: return ek;
1644: }
1645: write_log ("Houston, we have a BIG problem.\n");
1646: return 0;
1647: }
1648:
1.1.1.3 root 1649: /* This is so sick... who invented ACTION_EXAMINE_NEXT? What did he THINK??? */
1.1.1.7 root 1650: static ExamineKey *new_exkey (Unit *unit, a_inode *aino)
1.1 root 1651: {
1.1.1.3 root 1652: uae_u32 uniq;
1.1.1.14 root 1653: uae_u32 oldest = 0xFFFFFFFE;
1.1.1.3 root 1654: ExamineKey *ek, *oldest_ek = 0;
1655: int i;
1656:
1657: ek = unit->examine_keys;
1658: for (i = 0; i < EXKEYS; i++, ek++) {
1659: /* Did we find a free one? */
1660: if (ek->aino == 0)
1661: continue;
1662: if (ek->uniq < oldest)
1663: oldest = (oldest_ek = ek)->uniq;
1664: }
1665: ek = unit->examine_keys;
1666: for (i = 0; i < EXKEYS; i++, ek++) {
1667: /* Did we find a free one? */
1668: if (ek->aino == 0)
1669: goto found;
1670: }
1671: /* This message should usually be harmless. */
1672: write_log ("Houston, we have a problem.\n");
1.1.1.14 root 1673: free_exkey (unit, oldest_ek);
1.1.1.3 root 1674: ek = oldest_ek;
1675: found:
1676:
1677: uniq = unit->next_exkey;
1.1.1.14 root 1678: if (uniq >= 0xFFFFFFFE) {
1.1.1.3 root 1679: /* Things will probably go wrong, but most likely the Amiga will crash
1680: * before this happens because of something else. */
1681: uniq = 1;
1.1 root 1682: }
1.1.1.3 root 1683: unit->next_exkey = uniq+1;
1684: ek->aino = aino;
1.1.1.14 root 1685: ek->curr_file = 0;
1.1 root 1686: ek->uniq = uniq;
1687: return ek;
1688: }
1689:
1.1.1.14 root 1690: static void move_exkeys (Unit *unit, a_inode *from, a_inode *to)
1691: {
1692: int i;
1693: unsigned long tmp = 0;
1694: for (i = 0; i < EXKEYS; i++) {
1695: ExamineKey *k = unit->examine_keys + i;
1696: if (k->uniq == 0)
1697: continue;
1698: if (k->aino == from) {
1699: k->aino = to;
1700: tmp++;
1701: }
1702: }
1703: if (tmp != from->exnext_count)
1704: write_log ("filesys.c: Bug in ExNext bookkeeping. BAD.\n");
1705: to->exnext_count = from->exnext_count;
1706: to->locked_children = from->locked_children;
1707: from->exnext_count = 0;
1708: from->locked_children = 0;
1709: }
1710:
1.1 root 1711: static void
1.1.1.7 root 1712: get_fileinfo (Unit *unit, dpacket packet, uaecptr info, a_inode *aino)
1.1 root 1713: {
1714: struct stat statbuf;
1715: long days, mins, ticks;
1.1.1.3 root 1716: int i, n;
1717: char *x;
1718:
1719: /* No error checks - this had better work. */
1720: stat (aino->nname, &statbuf);
1721:
1722: if (aino->parent == 0) {
1723: x = unit->ui.volname;
1724: put_long (info + 4, 1);
1725: put_long (info + 120, 1);
1.1 root 1726: } else {
1.1.1.3 root 1727: /* AmigaOS docs say these have to contain the same value. */
1.1.1.7 root 1728: put_long (info + 4, aino->dir ? 2 : -3);
1729: put_long (info + 120, aino->dir ? 2 : -3);
1730: x = aino->aname;
1.1.1.3 root 1731: }
1.1.1.4 root 1732: TRACE(("name=\"%s\"\n", x));
1.1.1.7 root 1733: n = strlen (x);
1.1.1.3 root 1734: if (n > 106)
1735: n = 106;
1736: i = 8;
1.1.1.7 root 1737: put_byte (info + i, n); i++;
1738: while (n--)
1739: put_byte (info + i, *x), i++, x++;
1740: while (i < 108)
1741: put_byte (info + i, 0), i++;
1.1.1.3 root 1742:
1743: put_long (info + 116, aino->amigaos_mode);
1.1.1.7 root 1744: put_long (info + 124, statbuf.st_size);
1.1 root 1745: #ifdef HAVE_ST_BLOCKS
1.1.1.7 root 1746: put_long (info + 128, statbuf.st_blocks);
1.1 root 1747: #else
1.1.1.7 root 1748: put_long (info + 128, statbuf.st_size / 512 + 1);
1.1 root 1749: #endif
1.1.1.7 root 1750: get_time (statbuf.st_mtime, &days, &mins, &ticks);
1751: put_long (info + 132, days);
1752: put_long (info + 136, mins);
1753: put_long (info + 140, ticks);
1754: if (aino->comment == 0)
1755: put_long (info + 144, 0);
1756: else {
1757: TRACE(("comment=\"%s\"\n", aino->comment));
1758: i = 144;
1.1.1.16 root 1759: x = aino->comment;
1760: if (! x)
1761: x = "";
1762: n = strlen (x);
1.1.1.7 root 1763: if (n > 78)
1764: n = 78;
1765: put_byte (info + i, n); i++;
1766: while (n--)
1767: put_byte (info + i, *x), i++, x++;
1768: while (i < 224)
1769: put_byte (info + i, 0), i++;
1770: }
1.1.1.3 root 1771: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 1772: }
1773:
1.1.1.4 root 1774: static void action_examine_object (Unit *unit, dpacket packet)
1.1 root 1775: {
1.1.1.3 root 1776: uaecptr lock = GET_PCK_ARG1 (packet) << 2;
1777: uaecptr info = GET_PCK_ARG2 (packet) << 2;
1.1.1.7 root 1778: a_inode *aino = 0;
1.1 root 1779:
1.1.1.4 root 1780: TRACE(("ACTION_EXAMINE_OBJECT(0x%lx,0x%lx)\n", lock, info));
1.1.1.3 root 1781: DUMPLOCK(unit, lock);
1.1 root 1782:
1.1.1.3 root 1783: if (lock != 0)
1.1.1.7 root 1784: aino = lookup_aino (unit, get_long (lock + 4));
1.1.1.3 root 1785: if (aino == 0)
1786: aino = &unit->rootnode;
1787:
1788: get_fileinfo (unit, packet, info, aino);
1789: if (aino->dir) {
1.1.1.7 root 1790: put_long (info, 0xFFFFFFFF);
1.1.1.3 root 1791: } else
1.1.1.7 root 1792: put_long (info, 0);
1.1 root 1793: }
1794:
1.1.1.14 root 1795: /* Read a directory's contents, create a_inodes for each file, and
1796: mark them as locked in memory so that recycle_aino will not reap
1797: them.
1798: We do this to avoid problems with the host OS: we don't want to
1799: leave the directory open on the host side until all ExNext()s have
1800: finished - they may never finish! */
1801:
1802: static void populate_directory (Unit *unit, a_inode *base)
1803: {
1804: DIR *d = opendir (base->nname);
1805: a_inode *aino;
1806:
1807: for (aino = base->child; aino; aino = aino->sibling) {
1808: base->locked_children++;
1809: unit->total_locked_ainos++;
1810: }
1.1.1.17 root 1811: TRACE(("Populating directory, child %p, locked_children %d\n",
1812: base->child, base->locked_children));
1.1.1.14 root 1813: for (;;) {
1814: struct dirent de_space;
1815: struct dirent *de;
1816: uae_u32 err;
1817:
1818: /* Find next file that belongs to the Amiga fs (skipping things
1819: like "..", "." etc. */
1820: do {
1821: de = my_readdir (d, &de_space);
1822: } while (de && fsdb_name_invalid (de->d_name));
1823: if (! de)
1824: break;
1825: /* This calls init_child_aino, which will notice that the parent is
1826: being ExNext()ed, and it will increment the locked counts. */
1827: aino = lookup_child_aino_for_exnext (unit, base, de->d_name, &err);
1828: }
1829: closedir (d);
1830: }
1831:
1832: static void do_examine (Unit *unit, dpacket packet, ExamineKey *ek, uaecptr info)
1833: {
1834: if (ek->curr_file == 0)
1835: goto no_more_entries;
1836:
1837: get_fileinfo (unit, packet, info, ek->curr_file);
1838: ek->curr_file = ek->curr_file->sibling;
1.1.1.17 root 1839: TRACE (("curr_file set to %p %s\n", ek->curr_file,
1840: ek->curr_file ? ek->curr_file->aname : "NULL"));
1.1.1.14 root 1841: return;
1842:
1843: no_more_entries:
1844: TRACE(("no more entries\n"));
1845: free_exkey (unit, ek);
1846: PUT_PCK_RES1 (packet, DOS_FALSE);
1847: PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
1848: }
1849:
1.1.1.4 root 1850: static void action_examine_next (Unit *unit, dpacket packet)
1.1 root 1851: {
1.1.1.3 root 1852: uaecptr lock = GET_PCK_ARG1 (packet) << 2;
1853: uaecptr info = GET_PCK_ARG2 (packet) << 2;
1.1.1.7 root 1854: a_inode *aino = 0;
1.1.1.3 root 1855: ExamineKey *ek;
1856: uae_u32 uniq;
1.1 root 1857:
1.1.1.4 root 1858: TRACE(("ACTION_EXAMINE_NEXT(0x%lx,0x%lx)\n", lock, info));
1.1.1.3 root 1859: DUMPLOCK(unit, lock);
1.1 root 1860:
1.1.1.3 root 1861: if (lock != 0)
1.1.1.7 root 1862: aino = lookup_aino (unit, get_long (lock + 4));
1.1.1.3 root 1863: if (aino == 0)
1864: aino = &unit->rootnode;
1865:
1866: uniq = get_long (info);
1867: if (uniq == 0) {
1868: write_log ("ExNext called for a file! (Houston?)\n");
1.1.1.14 root 1869: goto no_more_entries;
1870: } else if (uniq == 0xFFFFFFFE)
1871: goto no_more_entries;
1872: else if (uniq == 0xFFFFFFFF) {
1.1.1.17 root 1873: TRACE(("Creating new ExKey\n"));
1.1.1.14 root 1874: ek = new_exkey (unit, aino);
1875: if (ek) {
1876: if (aino->exnext_count++ == 0)
1877: populate_directory (unit, aino);
1878: }
1879: ek->curr_file = aino->child;
1.1.1.17 root 1880: TRACE(("Initial curr_file: %p %s\n", ek->curr_file,
1881: ek->curr_file ? ek->curr_file->aname : "NULL"));
1882: } else {
1883: TRACE(("Looking up ExKey\n"));
1.1.1.7 root 1884: ek = lookup_exkey (unit, get_long (info));
1.1.1.17 root 1885: }
1.1.1.3 root 1886: if (ek == 0) {
1887: write_log ("Couldn't find a matching ExKey. Prepare for trouble.\n");
1.1.1.14 root 1888: goto no_more_entries;
1.1.1.3 root 1889: }
1.1.1.7 root 1890: put_long (info, ek->uniq);
1891: do_examine (unit, packet, ek, info);
1.1.1.14 root 1892: return;
1893:
1894: no_more_entries:
1895: PUT_PCK_RES1 (packet, DOS_FALSE);
1896: PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
1.1 root 1897: }
1898:
1.1.1.4 root 1899: static void do_find (Unit *unit, dpacket packet, int mode, int create, int fallback)
1.1 root 1900: {
1.1.1.3 root 1901: uaecptr fh = GET_PCK_ARG1 (packet) << 2;
1902: uaecptr lock = GET_PCK_ARG2 (packet) << 2;
1903: uaecptr name = GET_PCK_ARG3 (packet) << 2;
1.1.1.7 root 1904: a_inode *aino;
1.1 root 1905: Key *k;
1.1.1.3 root 1906: int fd;
1907: uae_u32 err;
1908: mode_t openmode;
1909: int aino_created = 0;
1910:
1.1.1.4 root 1911: TRACE(("ACTION_FIND_*(0x%lx,0x%lx,\"%s\",%d)\n", fh, lock, bstr (unit, name), mode));
1.1.1.3 root 1912: DUMPLOCK(unit, lock);
1913:
1914: aino = find_aino (unit, lock, bstr (unit, name), &err);
1915:
1.1.1.11 root 1916: if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_AROUND)) {
1.1.1.3 root 1917: /* Whatever it is, we can't handle it. */
1918: PUT_PCK_RES1 (packet, DOS_FALSE);
1919: PUT_PCK_RES2 (packet, err);
1920: return;
1921: }
1922: if (err == 0) {
1923: /* Object exists. */
1924: if (aino->dir) {
1925: PUT_PCK_RES1 (packet, DOS_FALSE);
1926: PUT_PCK_RES2 (packet, ERROR_OBJECT_WRONG_TYPE);
1927: return;
1928: }
1929: if (aino->elock || (create == 2 && aino->shlock > 0)) {
1930: PUT_PCK_RES1 (packet, DOS_FALSE);
1931: PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
1932: return;
1933: }
1934: if (create == 2 && (aino->amigaos_mode & A_FIBF_DELETE) != 0) {
1935: PUT_PCK_RES1 (packet, DOS_FALSE);
1936: PUT_PCK_RES2 (packet, ERROR_DELETE_PROTECTED);
1937: return;
1938: }
1939: if (create != 2) {
1940: if ((((mode & aino->amigaos_mode) & A_FIBF_WRITE) != 0 || unit->ui.readonly)
1941: && fallback)
1942: {
1943: mode &= ~A_FIBF_WRITE;
1944: }
1945: /* Kick 1.3 doesn't check read and write access bits - maybe it would be
1946: * simpler just not to do that either. */
1947: if ((mode & A_FIBF_WRITE) != 0 && unit->ui.readonly) {
1948: PUT_PCK_RES1 (packet, DOS_FALSE);
1949: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1950: return;
1951: }
1952: if (((mode & aino->amigaos_mode) & A_FIBF_WRITE) != 0
1953: || mode == 0)
1954: {
1955: PUT_PCK_RES1 (packet, DOS_FALSE);
1956: PUT_PCK_RES2 (packet, ERROR_WRITE_PROTECTED);
1957: return;
1958: }
1959: if (((mode & aino->amigaos_mode) & A_FIBF_READ) != 0) {
1960: PUT_PCK_RES1 (packet, DOS_FALSE);
1961: PUT_PCK_RES2 (packet, ERROR_READ_PROTECTED);
1962: return;
1963: }
1964: }
1965: } else if (create == 0) {
1966: PUT_PCK_RES1 (packet, DOS_FALSE);
1967: PUT_PCK_RES2 (packet, err);
1.1 root 1968: return;
1.1.1.3 root 1969: } else {
1970: /* Object does not exist. aino points to containing directory. */
1.1.1.7 root 1971: aino = create_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 0);
1.1.1.3 root 1972: if (aino == 0) {
1973: PUT_PCK_RES1 (packet, DOS_FALSE);
1.1.1.6 root 1974: PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */
1.1 root 1975: return;
1976: }
1.1.1.3 root 1977: aino_created = 1;
1.1 root 1978: }
1979:
1.1.1.3 root 1980: prepare_for_open (aino->nname);
1.1 root 1981:
1.1.1.3 root 1982: openmode = (((mode & A_FIBF_READ) == 0 ? O_WRONLY
1983: : (mode & A_FIBF_WRITE) == 0 ? O_RDONLY
1984: : O_RDWR)
1985: | (create ? O_CREAT : 0)
1986: | (create == 2 ? O_TRUNC : 0));
1987:
1988: fd = open (aino->nname, openmode | O_BINARY, 0777);
1989:
1990: if (fd < 0) {
1991: if (aino_created)
1992: delete_aino (unit, aino);
1993: PUT_PCK_RES1 (packet, DOS_FALSE);
1.1.1.7 root 1994: PUT_PCK_RES2 (packet, dos_errno ());
1.1 root 1995: return;
1996: }
1.1.1.3 root 1997: k = new_key (unit);
1998: k->fd = fd;
1999: k->aino = aino;
1.1 root 2000:
1.1.1.3 root 2001: put_long (fh+36, k->uniq);
2002: if (create == 2)
2003: aino->elock = 1;
2004: else
2005: aino->shlock++;
2006: de_recycle_aino (unit, aino);
2007: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 2008: }
2009:
2010: static void
1.1.1.6 root 2011: action_fh_from_lock (Unit *unit, dpacket packet)
2012: {
2013: uaecptr fh = GET_PCK_ARG1 (packet) << 2;
2014: uaecptr lock = GET_PCK_ARG2 (packet) << 2;
1.1.1.7 root 2015: a_inode *aino;
1.1.1.6 root 2016: Key *k;
2017: int fd;
2018: mode_t openmode;
2019: int mode;
2020:
2021: TRACE(("ACTION_FH_FROM_LOCK(0x%lx,0x%lx)\n",fh,lock));
2022: DUMPLOCK(unit,lock);
2023:
2024: if (!lock) {
1.1.1.7 root 2025: PUT_PCK_RES1 (packet, DOS_FALSE);
2026: PUT_PCK_RES2 (packet, 0);
2027: return;
1.1.1.6 root 2028: }
2029:
2030: aino = lookup_aino (unit, get_long (lock + 4));
2031: if (aino == 0)
1.1.1.7 root 2032: aino = &unit->rootnode;
1.1.1.6 root 2033: mode = aino->amigaos_mode; /* Use same mode for opened filehandle as existing Lock() */
2034:
2035: prepare_for_open (aino->nname);
1.1.1.17 root 2036: TRACE ((" mode is %d\n", mode));
2037: openmode = (((mode & A_FIBF_READ) ? O_WRONLY
2038: : (mode & A_FIBF_WRITE) ? O_RDONLY
1.1.1.6 root 2039: : O_RDWR));
2040:
1.1.1.8 root 2041: /* the files on CD really can have the write-bit set. */
2042: if (unit->ui.readonly)
2043: openmode = O_RDONLY;
2044:
1.1.1.6 root 2045: fd = open (aino->nname, openmode | O_BINARY, 0777);
2046:
2047: if (fd < 0) {
2048: PUT_PCK_RES1 (packet, DOS_FALSE);
2049: PUT_PCK_RES2 (packet, dos_errno());
2050: return;
2051: }
2052: k = new_key (unit);
2053: k->fd = fd;
2054: k->aino = aino;
2055:
2056: put_long (fh+36, k->uniq);
2057: /* I don't think I need to play with shlock count here, because I'm
2058: opening from an existing lock ??? */
2059:
2060: /* Is this right? I don't completely understand how this works. Do I
2061: also need to free_lock() my lock, since nobody else is going to? */
2062: de_recycle_aino (unit, aino);
2063: PUT_PCK_RES1 (packet, DOS_TRUE);
2064: /* PUT_PCK_RES2 (packet, k->uniq); - this shouldn't be necessary, try without it */
2065: }
2066:
2067: static void
1.1.1.4 root 2068: action_find_input (Unit *unit, dpacket packet)
1.1 root 2069: {
1.1.1.3 root 2070: do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 0, 1);
1.1 root 2071: }
2072:
2073: static void
1.1.1.4 root 2074: action_find_output (Unit *unit, dpacket packet)
1.1 root 2075: {
1.1.1.3 root 2076: if (unit->ui.readonly) {
2077: PUT_PCK_RES1 (packet, DOS_FALSE);
2078: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1 root 2079: return;
2080: }
1.1.1.3 root 2081: do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 2, 0);
1.1 root 2082: }
2083:
2084: static void
1.1.1.4 root 2085: action_find_write (Unit *unit, dpacket packet)
1.1 root 2086: {
1.1.1.3 root 2087: if (unit->ui.readonly) {
2088: PUT_PCK_RES1 (packet, DOS_FALSE);
2089: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1 root 2090: return;
2091: }
1.1.1.3 root 2092: do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 1, 0);
1.1 root 2093: }
2094:
2095: static void
1.1.1.4 root 2096: action_end (Unit *unit, dpacket packet)
1.1 root 2097: {
2098: Key *k;
1.1.1.4 root 2099: TRACE(("ACTION_END(0x%lx)\n", GET_PCK_ARG1 (packet)));
1.1 root 2100:
1.1.1.3 root 2101: k = lookup_key (unit, GET_PCK_ARG1 (packet));
2102: if (k != 0) {
2103: if (k->aino->elock)
2104: k->aino->elock = 0;
2105: else
2106: k->aino->shlock--;
2107: recycle_aino (unit, k->aino);
2108: free_key (unit, k);
2109: }
2110: PUT_PCK_RES1 (packet, DOS_TRUE);
2111: PUT_PCK_RES2 (packet, 0);
1.1 root 2112: }
2113:
2114: static void
1.1.1.4 root 2115: action_read (Unit *unit, dpacket packet)
1.1 root 2116: {
1.1.1.3 root 2117: Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
2118: uaecptr addr = GET_PCK_ARG2 (packet);
2119: long size = (uae_s32)GET_PCK_ARG3 (packet);
1.1 root 2120: int actual;
2121:
1.1.1.3 root 2122: if (k == 0) {
2123: PUT_PCK_RES1 (packet, DOS_FALSE);
2124: /* PUT_PCK_RES2 (packet, EINVAL); */
2125: return;
2126: }
1.1.1.4 root 2127: TRACE(("ACTION_READ(%s,0x%lx,%ld)\n",k->aino->nname,addr,size));
1.1 root 2128: #ifdef RELY_ON_LOADSEG_DETECTION
1.1.1.3 root 2129: /* HACK HACK HACK HACK
1.1 root 2130: * Try to detect a LoadSeg() */
2131: if (k->file_pos == 0 && size >= 4) {
2132: unsigned char buf[4];
2133: off_t currpos = lseek(k->fd, 0, SEEK_CUR);
2134: read(k->fd, buf, 4);
2135: lseek(k->fd, currpos, SEEK_SET);
2136: if (buf[0] == 0 && buf[1] == 0 && buf[2] == 3 && buf[3] == 0xF3)
2137: possible_loadseg();
2138: }
2139: #endif
2140: if (valid_address (addr, size)) {
1.1.1.3 root 2141: uae_u8 *realpt;
1.1 root 2142: realpt = get_real_address (addr);
2143: actual = read(k->fd, realpt, size);
2144:
1.1.1.2 root 2145: if (actual == 0) {
1.1.1.3 root 2146: PUT_PCK_RES1 (packet, 0);
2147: PUT_PCK_RES2 (packet, 0);
1.1.1.2 root 2148: } else if (actual < 0) {
1.1.1.3 root 2149: PUT_PCK_RES1 (packet, 0);
2150: PUT_PCK_RES2 (packet, dos_errno());
1.1 root 2151: } else {
1.1.1.3 root 2152: PUT_PCK_RES1 (packet, actual);
1.1 root 2153: k->file_pos += actual;
2154: }
2155: } else {
2156: char *buf;
1.1.1.4 root 2157: write_log ("unixfs warning: Bad pointer passed for read: %08x\n", addr);
1.1 root 2158: /* ugh this is inefficient but easy */
2159: buf = (char *)malloc(size);
1.1.1.4 root 2160: if (!buf) {
1.1.1.3 root 2161: PUT_PCK_RES1 (packet, -1);
2162: PUT_PCK_RES2 (packet, ERROR_NO_FREE_STORE);
1.1 root 2163: return;
2164: }
2165: actual = read(k->fd, buf, size);
2166:
1.1.1.2 root 2167: if (actual < 0) {
1.1.1.3 root 2168: PUT_PCK_RES1 (packet, 0);
2169: PUT_PCK_RES2 (packet, dos_errno());
1.1 root 2170: } else {
2171: int i;
1.1.1.3 root 2172: PUT_PCK_RES1 (packet, actual);
1.1.1.4 root 2173: for (i = 0; i < actual; i++)
1.1.1.22 root 2174: put_byte (addr + i, buf[i]);
1.1 root 2175: k->file_pos += actual;
2176: }
1.1.1.4 root 2177: free (buf);
1.1 root 2178: }
2179: }
2180:
2181: static void
1.1.1.4 root 2182: action_write (Unit *unit, dpacket packet)
1.1 root 2183: {
1.1.1.3 root 2184: Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
2185: uaecptr addr = GET_PCK_ARG2 (packet);
2186: long size = GET_PCK_ARG3 (packet);
1.1 root 2187: char *buf;
2188: int i;
2189:
1.1.1.3 root 2190: if (k == 0) {
2191: PUT_PCK_RES1 (packet, DOS_FALSE);
2192: /* PUT_PCK_RES2 (packet, EINVAL); */
2193: return;
2194: }
1.1 root 2195:
1.1.1.4 root 2196: TRACE(("ACTION_WRITE(%s,0x%lx,%ld)\n",k->aino->nname,addr,size));
1.1.1.3 root 2197:
2198: if (unit->ui.readonly) {
2199: PUT_PCK_RES1 (packet, DOS_FALSE);
2200: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1 root 2201: return;
2202: }
2203:
2204: /* ugh this is inefficient but easy */
2205: buf = (char *)malloc(size);
1.1.1.3 root 2206: if (!buf) {
2207: PUT_PCK_RES1 (packet, -1);
2208: PUT_PCK_RES2 (packet, ERROR_NO_FREE_STORE);
1.1 root 2209: return;
2210: }
2211:
1.1.1.3 root 2212: for (i = 0; i < size; i++)
1.1.1.22 root 2213: buf[i] = get_byte (addr + i);
1.1 root 2214:
1.1.1.3 root 2215: PUT_PCK_RES1 (packet, write(k->fd, buf, size));
2216: if (GET_PCK_RES1 (packet) != size)
2217: PUT_PCK_RES2 (packet, dos_errno ());
2218: if (GET_PCK_RES1 (packet) >= 0)
2219: k->file_pos += GET_PCK_RES1 (packet);
1.1 root 2220:
1.1.1.4 root 2221: free (buf);
1.1 root 2222: }
2223:
2224: static void
1.1.1.4 root 2225: action_seek (Unit *unit, dpacket packet)
1.1 root 2226: {
1.1.1.4 root 2227: Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
1.1.1.3 root 2228: long pos = (uae_s32)GET_PCK_ARG2 (packet);
2229: long mode = (uae_s32)GET_PCK_ARG3 (packet);
1.1 root 2230: off_t res;
2231: long old;
2232: int whence = SEEK_CUR;
2233:
1.1.1.3 root 2234: if (k == 0) {
2235: PUT_PCK_RES1 (packet, -1);
2236: PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK);
2237: return;
2238: }
1.1 root 2239:
1.1.1.3 root 2240: if (mode > 0) whence = SEEK_END;
2241: if (mode < 0) whence = SEEK_SET;
1.1 root 2242:
1.1.1.4 root 2243: TRACE(("ACTION_SEEK(%s,%d,%d)\n", k->aino->nname, pos, mode));
1.1.1.3 root 2244:
2245: old = lseek (k->fd, 0, SEEK_CUR);
1.1.1.20 root 2246: {
1.1.1.17 root 2247: uae_s32 temppos;
2248: long filesize = lseek (k->fd, 0, SEEK_END);
2249: lseek (k->fd, old, SEEK_SET);
2250:
2251: if (whence == SEEK_CUR) temppos = old + pos;
2252: if (whence == SEEK_SET) temppos = pos;
2253: if (whence == SEEK_END) temppos = filesize + pos;
2254: if (filesize < temppos) {
2255: res = -1;
2256: PUT_PCK_RES1 (packet,res);
2257: PUT_PCK_RES2 (packet, ERROR_SEEK_ERROR);
2258: return;
2259: }
2260: }
2261:
1.1.1.3 root 2262: res = lseek (k->fd, pos, whence);
2263:
2264: if (-1 == res) {
2265: PUT_PCK_RES1 (packet, res);
2266: PUT_PCK_RES2 (packet, ERROR_SEEK_ERROR);
2267: } else
2268: PUT_PCK_RES1 (packet, old);
1.1 root 2269: k->file_pos = res;
2270: }
2271:
2272: static void
1.1.1.4 root 2273: action_set_protect (Unit *unit, dpacket packet)
1.1 root 2274: {
1.1.1.3 root 2275: uaecptr lock = GET_PCK_ARG2 (packet) << 2;
2276: uaecptr name = GET_PCK_ARG3 (packet) << 2;
2277: uae_u32 mask = GET_PCK_ARG4 (packet);
1.1.1.7 root 2278: a_inode *a;
1.1.1.3 root 2279: uae_u32 err;
1.1 root 2280:
1.1.1.4 root 2281: TRACE(("ACTION_SET_PROTECT(0x%lx,\"%s\",0x%lx)\n", lock, bstr (unit, name), mask));
1.1 root 2282:
1.1.1.3 root 2283: if (unit->ui.readonly) {
2284: PUT_PCK_RES1 (packet, DOS_FALSE);
2285: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1 root 2286: return;
2287: }
2288:
1.1.1.3 root 2289: a = find_aino (unit, lock, bstr (unit, name), &err);
2290: if (err != 0) {
2291: PUT_PCK_RES1 (packet, DOS_FALSE);
2292: PUT_PCK_RES2 (packet, err);
1.1 root 2293: return;
2294: }
2295:
1.1.1.7 root 2296: err = fsdb_set_file_attrs (a, mask);
1.1.1.3 root 2297: if (err != 0) {
2298: PUT_PCK_RES1 (packet, DOS_FALSE);
2299: PUT_PCK_RES2 (packet, err);
2300: } else {
2301: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1.1.2 root 2302: }
1.1.1.3 root 2303: }
1.1 root 2304:
1.1.1.7 root 2305: static void action_set_comment (Unit * unit, dpacket packet)
2306: {
2307: uaecptr lock = GET_PCK_ARG2 (packet) << 2;
2308: uaecptr name = GET_PCK_ARG3 (packet) << 2;
2309: uaecptr comment = GET_PCK_ARG4 (packet) << 2;
2310: char *commented;
2311: a_inode *a;
2312: uae_u32 err;
2313: long res1, res2;
2314:
2315: if (unit->ui.readonly) {
2316: PUT_PCK_RES1 (packet, DOS_FALSE);
2317: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
2318: return;
2319: }
2320:
2321: commented = bstr (unit, comment);
2322: commented = strlen (commented) > 0 ? my_strdup (commented) : 0;
2323: TRACE (("ACTION_SET_COMMENT(0x%lx,\"%s\")\n", lock, commented));
2324:
2325: a = find_aino (unit, lock, bstr (unit, name), &err);
2326: if (err != 0) {
2327: PUT_PCK_RES1 (packet, DOS_FALSE);
2328: PUT_PCK_RES2 (packet, err);
2329:
2330: maybe_free_and_out:
2331: if (commented)
2332: free (commented);
2333: return;
2334: }
2335: PUT_PCK_RES1 (packet, DOS_TRUE);
2336: PUT_PCK_RES2 (packet, 0);
2337: if (a->comment == 0 && commented == 0)
2338: goto maybe_free_and_out;
2339: if (a->comment != 0 && commented != 0 && strcmp (a->comment, commented) == 0)
2340: goto maybe_free_and_out;
2341: if (a->comment)
2342: free (a->comment);
2343: a->comment = commented;
2344: a->dirty = 1;
2345: }
2346:
1.1.1.3 root 2347: static void
1.1.1.4 root 2348: action_same_lock (Unit *unit, dpacket packet)
1.1.1.3 root 2349: {
2350: uaecptr lock1 = GET_PCK_ARG1 (packet) << 2;
2351: uaecptr lock2 = GET_PCK_ARG2 (packet) << 2;
1.1 root 2352:
1.1.1.4 root 2353: TRACE(("ACTION_SAME_LOCK(0x%lx,0x%lx)\n",lock1,lock2));
1.1.1.3 root 2354: DUMPLOCK(unit, lock1); DUMPLOCK(unit, lock2);
1.1 root 2355:
1.1.1.3 root 2356: if (!lock1 || !lock2) {
2357: PUT_PCK_RES1 (packet, lock1 == lock2 ? DOS_TRUE : DOS_FALSE);
1.1 root 2358: } else {
1.1.1.3 root 2359: PUT_PCK_RES1 (packet, get_long (lock1 + 4) == get_long (lock2 + 4) ? DOS_TRUE : DOS_FALSE);
1.1 root 2360: }
2361: }
2362:
2363: static void
1.1.1.6 root 2364: action_change_mode (Unit *unit, dpacket packet)
1.1 root 2365: {
1.1.1.6 root 2366: #define CHANGE_LOCK 0
2367: #define CHANGE_FH 1
2368: /* will be CHANGE_FH or CHANGE_LOCK value */
2369: long type = GET_PCK_ARG1 (packet);
2370: /* either a file-handle or lock */
1.1.1.20 root 2371: uaecptr object = GET_PCK_ARG2 (packet) << 2;
1.1.1.6 root 2372: /* will be EXCLUSIVE_LOCK/SHARED_LOCK if CHANGE_LOCK,
2373: * or MODE_OLDFILE/MODE_NEWFILE/MODE_READWRITE if CHANGE_FH */
2374: long mode = GET_PCK_ARG3 (packet);
1.1.1.8 root 2375: unsigned long uniq;
1.1.1.7 root 2376: a_inode *a = NULL, *olda = NULL;
1.1.1.6 root 2377: uae_u32 err = 0;
2378: TRACE(("ACTION_CHANGE_MODE(0x%lx,%d,%d)\n",object,type,mode));
1.1.1.13 root 2379:
1.1.1.6 root 2380: if (! object
2381: || (type != CHANGE_FH && type != CHANGE_LOCK))
2382: {
1.1.1.7 root 2383: PUT_PCK_RES1 (packet, DOS_FALSE);
2384: PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK);
2385: return;
1.1.1.6 root 2386: }
1.1 root 2387:
1.1.1.6 root 2388: /* @@@ Brian: shouldn't this be good enough to support
2389: CHANGE_FH? */
2390: if (type == CHANGE_FH)
2391: mode = (mode == 1006 ? -1 : -2);
1.1.1.8 root 2392:
2393: if (type == CHANGE_LOCK)
1.1.1.13 root 2394: uniq = get_long (object + 4);
1.1.1.8 root 2395: else {
2396: Key *k = lookup_key (unit, object);
2397: if (!k) {
2398: PUT_PCK_RES1 (packet, DOS_FALSE);
1.1.1.11 root 2399: PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
1.1.1.8 root 2400: return;
2401: }
1.1.1.13 root 2402: uniq = k->aino->uniq;
1.1.1.8 root 2403: }
2404: a = lookup_aino (unit, uniq);
2405:
1.1.1.6 root 2406: if (! a)
2407: err = ERROR_INVALID_LOCK;
2408: else {
2409: if (mode == -1) {
2410: if (a->shlock > 1)
2411: err = ERROR_OBJECT_IN_USE;
2412: else {
2413: a->shlock = 0;
2414: a->elock = 1;
2415: }
2416: } else { /* Must be SHARED_LOCK == -2 */
2417: a->elock = 0;
2418: a->shlock++;
2419: }
1.1.1.13 root 2420: }
1.1.1.6 root 2421:
2422: if (err) {
1.1.1.7 root 2423: PUT_PCK_RES1 (packet, DOS_FALSE);
2424: PUT_PCK_RES2 (packet, err);
2425: return;
1.1.1.6 root 2426: } else {
1.1.1.7 root 2427: de_recycle_aino (unit, a);
2428: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1.1.3 root 2429: }
1.1.1.6 root 2430: }
1.1.1.3 root 2431:
1.1.1.6 root 2432: static void
1.1.1.8 root 2433: action_parent_common (Unit *unit, dpacket packet, unsigned long uniq)
1.1.1.6 root 2434: {
1.1.1.8 root 2435: a_inode *olda = lookup_aino (unit, uniq);
1.1.1.3 root 2436: if (olda == 0) {
2437: PUT_PCK_RES1 (packet, DOS_FALSE);
2438: PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK);
2439: return;
2440: }
2441:
2442: if (olda->parent == 0) {
2443: PUT_PCK_RES1 (packet, 0);
2444: PUT_PCK_RES2 (packet, 0);
2445: return;
1.1 root 2446: }
1.1.1.3 root 2447: if (olda->parent->elock) {
2448: PUT_PCK_RES1 (packet, DOS_FALSE);
2449: PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
2450: return;
2451: }
2452: olda->parent->shlock++;
2453: de_recycle_aino (unit, olda->parent);
2454: PUT_PCK_RES1 (packet, make_lock (unit, olda->parent->uniq, -2) >> 2);
1.1 root 2455: }
2456:
2457: static void
1.1.1.6 root 2458: action_parent_fh (Unit *unit, dpacket packet)
2459: {
1.1.1.8 root 2460: Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
2461: if (!k) {
1.1.1.7 root 2462: PUT_PCK_RES1 (packet, DOS_FALSE);
1.1.1.11 root 2463: PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
1.1.1.7 root 2464: return;
1.1.1.6 root 2465: }
1.1.1.8 root 2466: action_parent_common (unit, packet, k->aino->uniq);
1.1.1.6 root 2467: }
2468:
2469: static void
2470: action_parent (Unit *unit, dpacket packet)
2471: {
2472: uaecptr lock = GET_PCK_ARG1 (packet) << 2;
2473:
2474: TRACE(("ACTION_PARENT(0x%lx)\n",lock));
2475:
2476: if (!lock) {
2477: PUT_PCK_RES1 (packet, 0);
2478: PUT_PCK_RES2 (packet, 0);
2479: return;
2480: }
2481: action_parent_common (unit, packet, get_long (lock + 4));
2482: }
2483:
2484: static void
1.1.1.4 root 2485: action_create_dir (Unit *unit, dpacket packet)
1.1 root 2486: {
1.1.1.3 root 2487: uaecptr lock = GET_PCK_ARG1 (packet) << 2;
2488: uaecptr name = GET_PCK_ARG2 (packet) << 2;
1.1.1.7 root 2489: a_inode *aino;
1.1.1.3 root 2490: uae_u32 err;
1.1 root 2491:
1.1.1.4 root 2492: TRACE(("ACTION_CREATE_DIR(0x%lx,\"%s\")\n", lock, bstr (unit, name)));
1.1 root 2493:
1.1.1.3 root 2494: if (unit->ui.readonly) {
2495: PUT_PCK_RES1 (packet, DOS_FALSE);
2496: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1 root 2497: return;
2498: }
2499:
1.1.1.3 root 2500: aino = find_aino (unit, lock, bstr (unit, name), &err);
1.1.1.11 root 2501: if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_AROUND)) {
1.1.1.3 root 2502: PUT_PCK_RES1 (packet, DOS_FALSE);
2503: PUT_PCK_RES2 (packet, err);
1.1 root 2504: return;
2505: }
1.1.1.3 root 2506: if (err == 0) {
2507: /* Object exists. */
2508: PUT_PCK_RES1 (packet, DOS_FALSE);
2509: PUT_PCK_RES2 (packet, ERROR_OBJECT_EXISTS);
2510: return;
1.1 root 2511: }
1.1.1.3 root 2512: /* Object does not exist. aino points to containing directory. */
1.1.1.7 root 2513: aino = create_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 1);
1.1.1.3 root 2514: if (aino == 0) {
2515: PUT_PCK_RES1 (packet, DOS_FALSE);
1.1.1.6 root 2516: PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */
1.1.1.3 root 2517: return;
2518: }
2519:
2520: if (mkdir (aino->nname, 0777) == -1) {
2521: PUT_PCK_RES1 (packet, DOS_FALSE);
2522: PUT_PCK_RES2 (packet, dos_errno());
2523: return;
2524: }
2525: aino->shlock = 1;
2526: de_recycle_aino (unit, aino);
2527: PUT_PCK_RES1 (packet, make_lock (unit, aino->uniq, -2) >> 2);
1.1 root 2528: }
2529:
2530: static void
1.1.1.4 root 2531: action_examine_fh (Unit *unit, dpacket packet)
1.1 root 2532: {
1.1.1.3 root 2533: Key *k;
1.1.1.7 root 2534: a_inode *aino = 0;
1.1.1.3 root 2535: uaecptr info = GET_PCK_ARG2 (packet) << 2;
1.1 root 2536:
1.1.1.6 root 2537: TRACE(("ACTION_EXAMINE_FH(0x%lx,0x%lx)\n",
2538: GET_PCK_ARG1 (packet), GET_PCK_ARG2 (packet) ));
1.1 root 2539:
1.1.1.3 root 2540: k = lookup_key (unit, GET_PCK_ARG1 (packet));
2541: if (k != 0)
2542: aino = k->aino;
2543: if (aino == 0)
2544: aino = &unit->rootnode;
2545:
2546: get_fileinfo (unit, packet, info, aino);
2547: if (aino->dir)
1.1.1.6 root 2548: put_long (info, 0xFFFFFFFF);
1.1.1.3 root 2549: else
1.1.1.6 root 2550: put_long (info, 0);
1.1.1.3 root 2551: }
2552:
2553: /* For a nice example of just how contradictory documentation can be, see the
2554: * Autodoc for DOS:SetFileSize and the Packets.txt description of this packet...
2555: * This implementation tries to mimic the behaviour of the Kick 3.1 ramdisk
2556: * (which seems to match the Autodoc description). */
2557: static void
1.1.1.4 root 2558: action_set_file_size (Unit *unit, dpacket packet)
1.1.1.3 root 2559: {
2560: Key *k, *k1;
2561: off_t offset = GET_PCK_ARG2 (packet);
2562: long mode = (uae_s32)GET_PCK_ARG3 (packet);
2563: int whence = SEEK_CUR;
1.1.1.13 root 2564:
1.1.1.3 root 2565: if (mode > 0) whence = SEEK_END;
2566: if (mode < 0) whence = SEEK_SET;
1.1 root 2567:
1.1.1.4 root 2568: TRACE(("ACTION_SET_FILE_SIZE(0x%lx, %d, 0x%x)\n", GET_PCK_ARG1 (packet), offset, mode));
1.1 root 2569:
1.1.1.3 root 2570: k = lookup_key (unit, GET_PCK_ARG1 (packet));
2571: if (k == 0) {
2572: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1.1.11 root 2573: PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_AROUND);
1.1 root 2574: return;
2575: }
1.1.1.3 root 2576:
2577: /* If any open files have file pointers beyond this size, truncate only
2578: * so far that these pointers do not become invalid. */
2579: for (k1 = unit->keys; k1; k1 = k1->next) {
2580: if (k != k1 && k->aino == k1->aino) {
2581: if (k1->file_pos > offset)
2582: offset = k1->file_pos;
2583: }
2584: }
2585:
2586: /* Write one then truncate: that should give the right size in all cases. */
2587: offset = lseek (k->fd, offset, whence);
2588: write (k->fd, /* whatever */(char *)&k1, 1);
2589: if (k->file_pos > offset)
2590: k->file_pos = offset;
2591: lseek (k->fd, k->file_pos, SEEK_SET);
2592:
1.1.1.6 root 2593: /* Brian: no bug here; the file _must_ be one byte too large after writing
2594: The write is supposed to guarantee that the file can't be smaller than
2595: the requested size, the truncate guarantees that it can't be larger.
2596: If we were to write one byte earlier we'd clobber file data. */
2597: if (truncate (k->aino->nname, offset) == -1) {
1.1.1.3 root 2598: PUT_PCK_RES1 (packet, DOS_FALSE);
2599: PUT_PCK_RES2 (packet, dos_errno ());
1.1 root 2600: return;
2601: }
1.1.1.3 root 2602:
2603: PUT_PCK_RES1 (packet, offset);
2604: PUT_PCK_RES2 (packet, 0);
1.1 root 2605: }
2606:
2607: static void
1.1.1.4 root 2608: action_delete_object (Unit *unit, dpacket packet)
1.1 root 2609: {
1.1.1.3 root 2610: uaecptr lock = GET_PCK_ARG1 (packet) << 2;
2611: uaecptr name = GET_PCK_ARG2 (packet) << 2;
1.1.1.7 root 2612: a_inode *a;
1.1.1.3 root 2613: uae_u32 err;
1.1 root 2614:
1.1.1.4 root 2615: TRACE(("ACTION_DELETE_OBJECT(0x%lx,\"%s\")\n", lock, bstr (unit, name)));
1.1 root 2616:
1.1.1.3 root 2617: if (unit->ui.readonly) {
2618: PUT_PCK_RES1 (packet, DOS_FALSE);
2619: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1 root 2620: return;
2621: }
2622:
1.1.1.3 root 2623: a = find_aino (unit, lock, bstr (unit, name), &err);
1.1 root 2624:
1.1.1.3 root 2625: if (err != 0) {
2626: PUT_PCK_RES1 (packet, DOS_FALSE);
2627: PUT_PCK_RES2 (packet, err);
1.1 root 2628: return;
2629: }
1.1.1.7 root 2630: if (a->amigaos_mode & A_FIBF_DELETE) {
2631: PUT_PCK_RES1 (packet, DOS_FALSE);
2632: PUT_PCK_RES2 (packet, ERROR_DELETE_PROTECTED);
2633: return;
2634: }
1.1.1.3 root 2635: if (a->shlock > 0 || a->elock) {
2636: PUT_PCK_RES1 (packet, DOS_FALSE);
2637: PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
1.1 root 2638: return;
2639: }
1.1.1.3 root 2640: if (a->dir) {
1.1.1.11 root 2641: /* This should take care of removing the fsdb if no files remain. */
2642: fsdb_dir_writeback (a);
1.1.1.3 root 2643: if (rmdir (a->nname) == -1) {
2644: PUT_PCK_RES1 (packet, DOS_FALSE);
2645: PUT_PCK_RES2 (packet, dos_errno());
1.1 root 2646: return;
2647: }
2648: } else {
1.1.1.3 root 2649: if (unlink (a->nname) == -1) {
2650: PUT_PCK_RES1 (packet, DOS_FALSE);
2651: PUT_PCK_RES2 (packet, dos_errno());
1.1 root 2652: return;
2653: }
2654: }
1.1.1.3 root 2655: if (a->child != 0) {
2656: write_log ("Serious error in action_delete_object.\n");
2657: } else {
2658: delete_aino (unit, a);
2659: }
2660: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 2661: }
2662:
2663: static void
1.1.1.4 root 2664: action_set_date (Unit *unit, dpacket packet)
1.1 root 2665: {
1.1.1.3 root 2666: uaecptr lock = GET_PCK_ARG2 (packet) << 2;
2667: uaecptr name = GET_PCK_ARG3 (packet) << 2;
2668: uaecptr date = GET_PCK_ARG4 (packet);
1.1.1.7 root 2669: a_inode *a;
1.1 root 2670: struct utimbuf ut;
1.1.1.3 root 2671: uae_u32 err;
1.1 root 2672:
1.1.1.4 root 2673: TRACE(("ACTION_SET_DATE(0x%lx,\"%s\")\n", lock, bstr (unit, name)));
1.1 root 2674:
1.1.1.4 root 2675: if (unit->ui.readonly) {
1.1.1.3 root 2676: PUT_PCK_RES1 (packet, DOS_FALSE);
2677: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1 root 2678: return;
2679: }
2680:
1.1.1.6 root 2681: ut.actime = ut.modtime = put_time(get_long (date), get_long (date + 4),
2682: get_long (date + 8));
1.1.1.3 root 2683: a = find_aino (unit, lock, bstr (unit, name), &err);
2684: if (err == 0 && utime (a->nname, &ut) == -1)
2685: err = dos_errno ();
2686: if (err != 0) {
2687: PUT_PCK_RES1 (packet, DOS_FALSE);
2688: PUT_PCK_RES2 (packet, err);
2689: } else
2690: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 2691: }
2692:
2693: static void
1.1.1.4 root 2694: action_rename_object (Unit *unit, dpacket packet)
1.1 root 2695: {
1.1.1.3 root 2696: uaecptr lock1 = GET_PCK_ARG1 (packet) << 2;
2697: uaecptr name1 = GET_PCK_ARG2 (packet) << 2;
2698: uaecptr lock2 = GET_PCK_ARG3 (packet) << 2;
2699: uaecptr name2 = GET_PCK_ARG4 (packet) << 2;
1.1.1.7 root 2700: a_inode *a1, *a2;
1.1.1.3 root 2701: uae_u32 err1, err2;
1.1 root 2702:
1.1.1.4 root 2703: TRACE(("ACTION_RENAME_OBJECT(0x%lx,\"%s\",", lock1, bstr (unit, name1)));
2704: TRACE(("0x%lx,\"%s\")\n", lock2, bstr (unit, name2)));
1.1 root 2705:
1.1.1.4 root 2706: if (unit->ui.readonly) {
1.1.1.3 root 2707: PUT_PCK_RES1 (packet, DOS_FALSE);
2708: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1 root 2709: return;
2710: }
2711:
1.1.1.3 root 2712: a1 = find_aino (unit, lock1, bstr (unit, name1), &err1);
2713: if (err1 != 0) {
2714: PUT_PCK_RES1 (packet, DOS_FALSE);
2715: PUT_PCK_RES2 (packet, err1);
2716: return;
2717: }
1.1.1.7 root 2718: /* See whether the other name already exists in the filesystem. */
1.1.1.3 root 2719: a2 = find_aino (unit, lock2, bstr (unit, name2), &err2);
1.1.1.7 root 2720: if (a2 == a1) {
2721: /* Renaming to the same name, but possibly different case. */
2722: if (strcmp (a1->aname, bstr_cut (unit, name2)) == 0) {
2723: /* Exact match -> do nothing. */
2724: PUT_PCK_RES1 (packet, DOS_TRUE);
2725: return;
2726: }
2727: a2 = a2->parent;
1.1.1.11 root 2728: } else if (a2 == 0 || err2 != ERROR_OBJECT_NOT_AROUND) {
1.1.1.3 root 2729: PUT_PCK_RES1 (packet, DOS_FALSE);
2730: PUT_PCK_RES2 (packet, err2 == 0 ? ERROR_OBJECT_EXISTS : err2);
1.1 root 2731: return;
2732: }
1.1.1.7 root 2733:
2734: a2 = create_child_aino (unit, a2, bstr_cut (unit, name2), a1->dir);
1.1.1.3 root 2735: if (a2 == 0) {
2736: PUT_PCK_RES1 (packet, DOS_FALSE);
1.1.1.6 root 2737: PUT_PCK_RES2 (packet, ERROR_DISK_IS_FULL); /* best we can do */
1.1 root 2738: return;
2739: }
2740:
1.1.1.3 root 2741: /* @@@ what should we do if there are locks on a1? */
1.1.1.5 root 2742: if (-1 == rename (a1->nname, a2->nname)) {
1.1.1.3 root 2743: PUT_PCK_RES1 (packet, DOS_FALSE);
1.1.1.5 root 2744: PUT_PCK_RES2 (packet, dos_errno ());
1.1 root 2745: return;
2746: }
1.1.1.7 root 2747: a2->comment = a1->comment;
2748: a1->comment = 0;
2749: a2->amigaos_mode = a1->amigaos_mode;
1.1.1.14 root 2750: a2->uniq = a1->uniq;
2751: move_exkeys (unit, a1, a2);
1.1.1.3 root 2752: move_aino_children (unit, a1, a2);
2753: delete_aino (unit, a1);
2754: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 2755: }
2756:
2757: static void
1.1.1.4 root 2758: action_current_volume (Unit *unit, dpacket packet)
1.1 root 2759: {
1.1.1.3 root 2760: PUT_PCK_RES1 (packet, unit->volume >> 2);
1.1 root 2761: }
2762:
2763: static void
1.1.1.4 root 2764: action_rename_disk (Unit *unit, dpacket packet)
1.1 root 2765: {
1.1.1.3 root 2766: uaecptr name = GET_PCK_ARG1 (packet) << 2;
1.1 root 2767: int i;
2768: int namelen;
2769:
1.1.1.4 root 2770: TRACE(("ACTION_RENAME_DISK(\"%s\")\n", bstr (unit, name)));
1.1 root 2771:
1.1.1.4 root 2772: if (unit->ui.readonly) {
1.1.1.3 root 2773: PUT_PCK_RES1 (packet, DOS_FALSE);
2774: PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
1.1 root 2775: return;
2776: }
2777:
2778: /* get volume name */
1.1.1.3 root 2779: namelen = get_byte (name); name++;
2780: free (unit->ui.volname);
2781: unit->ui.volname = (char *) xmalloc (namelen + 1);
1.1.1.4 root 2782: for (i = 0; i < namelen; i++, name++)
1.1.1.3 root 2783: unit->ui.volname[i] = get_byte (name);
1.1 root 2784: unit->ui.volname[i] = 0;
2785:
1.1.1.3 root 2786: put_byte (unit->volume + 44, namelen);
1.1.1.4 root 2787: for (i = 0; i < namelen; i++)
1.1.1.3 root 2788: put_byte (unit->volume + 45 + i, unit->ui.volname[i]);
1.1 root 2789:
1.1.1.3 root 2790: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 2791: }
2792:
2793: static void
1.1.1.4 root 2794: action_is_filesystem (Unit *unit, dpacket packet)
1.1 root 2795: {
1.1.1.3 root 2796: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 2797: }
2798:
2799: static void
1.1.1.4 root 2800: action_flush (Unit *unit, dpacket packet)
1.1 root 2801: {
2802: /* sync(); */ /* pretty drastic, eh */
1.1.1.3 root 2803: PUT_PCK_RES1 (packet, DOS_TRUE);
1.1 root 2804: }
2805:
1.1.1.3 root 2806: /* We don't want multiple interrupts to be active at the same time. I don't
2807: * know whether AmigaOS takes care of that, but this does. */
2808: static uae_sem_t singlethread_int_sem;
2809:
1.1.1.22 root 2810: static uae_u32 exter_int_helper (TrapContext *dummy)
1.1.1.3 root 2811: {
1.1.1.4 root 2812: UnitInfo *uip = current_mountinfo->ui;
1.1.1.7 root 2813: uaecptr port;
1.1.1.3 root 2814: static int unit_no;
2815:
2816: switch (m68k_dreg (regs, 0)) {
2817: case 0:
2818: /* Determine whether a given EXTER interrupt is for us. */
2819: if (uae_int_requested) {
2820: if (uae_sem_trywait (&singlethread_int_sem) != 0)
2821: /* Pretend it isn't for us. We might get it again later. */
2822: return 0;
2823: /* Clear the interrupt flag _before_ we do any processing.
2824: * That way, we can get too many interrupts, but never not
2825: * enough. */
2826: uae_int_requested = 0;
2827: unit_no = 0;
2828: return 1;
2829: }
1.1 root 2830: return 0;
1.1.1.3 root 2831: case 1:
2832: /* Release a message_lock. This is called as soon as the message is
2833: * received by the assembly code. We use the opportunity to check
2834: * whether we have some locks that we can give back to the assembler
2835: * code.
2836: * Note that this is called from the main loop, unlike the other cases
2837: * in this switch statement which are called from the interrupt handler.
2838: */
1.1.1.7 root 2839: #ifdef UAE_FILESYS_THREADS
1.1.1.3 root 2840: {
2841: Unit *unit = find_unit (m68k_areg (regs, 5));
2842: unit->cmds_complete = unit->cmds_acked;
2843: while (comm_pipe_has_data (unit->ui.back_pipe)) {
2844: uaecptr locks, lockend;
2845: locks = read_comm_pipe_int_blocking (unit->ui.back_pipe);
2846: lockend = locks;
2847: while (get_long (lockend) != 0)
2848: lockend = get_long (lockend);
2849: put_long (lockend, get_long (m68k_areg (regs, 3)));
2850: put_long (m68k_areg (regs, 3), locks);
2851: }
2852: }
1.1.1.7 root 2853: #else
2854: write_log ("exter_int_helper should not be called with arg 1!\n");
2855: #endif
1.1 root 2856: break;
1.1.1.3 root 2857: case 2:
1.1.1.7 root 2858: /* Find work that needs to be done:
2859: * return d0 = 0: none
2860: * d0 = 1: PutMsg(), port in a0, message in a1
2861: * d0 = 2: Signal(), task in a1, signal set in d1
2862: * d0 = 3: ReplyMsg(), message in a1 */
2863:
2864: #ifdef SUPPORT_THREADS
2865: /* First, check signals/messages */
2866: while (comm_pipe_has_data (&native2amiga_pending)) {
2867: switch (read_comm_pipe_int_blocking (&native2amiga_pending)) {
2868: case 0: /* Signal() */
2869: m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending);
2870: m68k_dreg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending);
2871: return 2;
2872:
2873: case 1: /* PutMsg() */
2874: m68k_areg (regs, 0) = read_comm_pipe_u32_blocking (&native2amiga_pending);
2875: m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending);
2876: return 1;
2877:
2878: case 2: /* ReplyMsg() */
2879: m68k_areg (regs, 1) = read_comm_pipe_u32_blocking (&native2amiga_pending);
2880: return 3;
2881:
2882: default:
2883: write_log ("exter_int_helper: unknown native action\n");
2884: break;
2885: }
2886: }
2887: #endif
2888:
1.1.1.3 root 2889: /* Find some unit that needs a message sent, and return its port,
2890: * or zero if all are done.
2891: * Take care not to dereference self for units that didn't have their
2892: * startup packet sent. */
2893: for (;;) {
1.1.1.4 root 2894: if (unit_no >= current_mountinfo->num_units)
1.1.1.3 root 2895: return 0;
1.1.1.7 root 2896:
1.1.1.4 root 2897: if (uip[unit_no].self != 0
2898: && uip[unit_no].self->cmds_acked == uip[unit_no].self->cmds_complete
2899: && uip[unit_no].self->cmds_acked != uip[unit_no].self->cmds_sent)
1.1.1.3 root 2900: break;
2901: unit_no++;
2902: }
1.1.1.4 root 2903: uip[unit_no].self->cmds_acked = uip[unit_no].self->cmds_sent;
1.1.1.7 root 2904: port = uip[unit_no].self->port;
2905: if (port) {
2906: m68k_areg (regs, 0) = port;
2907: m68k_areg (regs, 1) = find_unit (port)->dummy_message;
2908: unit_no++;
2909: return 1;
1.1.1.3 root 2910: }
1.1 root 2911: break;
1.1.1.3 root 2912: case 4:
2913: /* Exit the interrupt, and release the single-threading lock. */
2914: uae_sem_post (&singlethread_int_sem);
1.1 root 2915: break;
2916:
1.1.1.3 root 2917: default:
2918: write_log ("Shouldn't happen in exter_int_helper.\n");
1.1 root 2919: break;
1.1.1.3 root 2920: }
2921: return 0;
2922: }
1.1 root 2923:
1.1.1.3 root 2924: static int handle_packet (Unit *unit, dpacket pck)
2925: {
2926: uae_s32 type = GET_PCK_TYPE (pck);
2927: PUT_PCK_RES2 (pck, 0);
2928: switch (type) {
1.1.1.4 root 2929: case ACTION_LOCATE_OBJECT: action_lock (unit, pck); break;
2930: case ACTION_FREE_LOCK: action_free_lock (unit, pck); break;
2931: case ACTION_COPY_DIR: action_dup_lock (unit, pck); break;
2932: case ACTION_DISK_INFO: action_disk_info (unit, pck); break;
2933: case ACTION_INFO: action_info (unit, pck); break;
2934: case ACTION_EXAMINE_OBJECT: action_examine_object (unit, pck); break;
2935: case ACTION_EXAMINE_NEXT: action_examine_next (unit, pck); break;
2936: case ACTION_FIND_INPUT: action_find_input (unit, pck); break;
2937: case ACTION_FIND_WRITE: action_find_write (unit, pck); break;
2938: case ACTION_FIND_OUTPUT: action_find_output (unit, pck); break;
2939: case ACTION_END: action_end (unit, pck); break;
2940: case ACTION_READ: action_read (unit, pck); break;
2941: case ACTION_WRITE: action_write (unit, pck); break;
2942: case ACTION_SEEK: action_seek (unit, pck); break;
2943: case ACTION_SET_PROTECT: action_set_protect (unit, pck); break;
1.1.1.7 root 2944: case ACTION_SET_COMMENT: action_set_comment (unit, pck); break;
1.1.1.4 root 2945: case ACTION_SAME_LOCK: action_same_lock (unit, pck); break;
2946: case ACTION_PARENT: action_parent (unit, pck); break;
2947: case ACTION_CREATE_DIR: action_create_dir (unit, pck); break;
2948: case ACTION_DELETE_OBJECT: action_delete_object (unit, pck); break;
2949: case ACTION_RENAME_OBJECT: action_rename_object (unit, pck); break;
2950: case ACTION_SET_DATE: action_set_date (unit, pck); break;
2951: case ACTION_CURRENT_VOLUME: action_current_volume (unit, pck); break;
2952: case ACTION_RENAME_DISK: action_rename_disk (unit, pck); break;
2953: case ACTION_IS_FILESYSTEM: action_is_filesystem (unit, pck); break;
2954: case ACTION_FLUSH: action_flush (unit, pck); break;
1.1.1.3 root 2955:
2956: /* 2.0+ packet types */
1.1.1.4 root 2957: case ACTION_SET_FILE_SIZE: action_set_file_size (unit, pck); break;
2958: case ACTION_EXAMINE_FH: action_examine_fh (unit, pck); break;
1.1.1.6 root 2959: case ACTION_FH_FROM_LOCK: action_fh_from_lock (unit, pck); break;
2960: case ACTION_CHANGE_MODE: action_change_mode (unit, pck); break;
2961: case ACTION_PARENT_FH: action_parent_fh (unit, pck); break;
1.1.1.3 root 2962:
2963: /* unsupported packets */
2964: case ACTION_LOCK_RECORD:
2965: case ACTION_FREE_RECORD:
2966: case ACTION_COPY_DIR_FH:
2967: case ACTION_EXAMINE_ALL:
2968: case ACTION_MAKE_LINK:
2969: case ACTION_READ_LINK:
2970: case ACTION_FORMAT:
2971: case ACTION_ADD_NOTIFY:
2972: case ACTION_REMOVE_NOTIFY:
2973: default:
1.1.1.4 root 2974: TRACE(("*** UNSUPPORTED PACKET %ld\n", type));
1.1.1.3 root 2975: return 0;
2976: }
2977: return 1;
2978: }
1.1 root 2979:
1.1.1.3 root 2980: #ifdef UAE_FILESYS_THREADS
1.1.1.13 root 2981: static void *filesys_thread (void *unit_v)
1.1.1.3 root 2982: {
2983: UnitInfo *ui = (UnitInfo *)unit_v;
2984: for (;;) {
2985: uae_u8 *pck;
2986: uae_u8 *msg;
2987: uae_u32 morelocks;
2988: int i;
2989:
2990: pck = (uae_u8 *)read_comm_pipe_pvoid_blocking (ui->unit_pipe);
2991: msg = (uae_u8 *)read_comm_pipe_pvoid_blocking (ui->unit_pipe);
2992: morelocks = (uae_u32)read_comm_pipe_int_blocking (ui->unit_pipe);
2993:
1.1.1.4 root 2994: if (ui->reset_state == FS_GO_DOWN) {
1.1.1.3 root 2995: if (pck != 0)
2996: continue;
2997: /* Death message received. */
1.1.1.4 root 2998: uae_sem_post (&ui->reset_sync_sem);
2999: /* Die. */
3000: return 0;
1.1.1.3 root 3001: }
1.1 root 3002:
1.1.1.3 root 3003: put_long (get_long (morelocks), get_long (ui->self->locklist));
3004: put_long (ui->self->locklist, morelocks);
3005: if (! handle_packet (ui->self, pck)) {
3006: PUT_PCK_RES1 (pck, DOS_FALSE);
3007: PUT_PCK_RES2 (pck, ERROR_ACTION_NOT_KNOWN);
3008: }
3009: /* Mark the packet as processed for the list scan in the assembly code. */
3010: do_put_mem_long ((uae_u32 *)(msg + 4), -1);
3011: /* Acquire the message lock, so that we know we can safely send the
3012: * message. */
3013: ui->self->cmds_sent++;
3014: /* The message is sent by our interrupt handler, so make sure an interrupt
3015: * happens. */
3016: uae_int_requested = 1;
1.1.1.22 root 3017:
3018: uae_sem_wait (&packet_counter_sem);
3019: active_fs_packets--;
3020: uae_sem_post (&packet_counter_sem);
3021:
1.1.1.3 root 3022: /* Send back the locks. */
3023: if (get_long (ui->self->locklist) != 0)
1.1.1.7 root 3024: write_comm_pipe_int (ui->back_pipe, (int)(get_long (ui->self->locklist)), 0);
1.1.1.3 root 3025: put_long (ui->self->locklist, 0);
3026: }
3027: return 0;
3028: }
3029: #endif
1.1 root 3030:
1.1.1.3 root 3031: /* Talk about spaghetti code... */
1.1.1.22 root 3032: static uae_u32 filesys_handler (TrapContext *dummy)
1.1.1.3 root 3033: {
3034: Unit *unit = find_unit (m68k_areg (regs, 5));
3035: uaecptr packet_addr = m68k_dreg (regs, 3);
3036: uaecptr message_addr = m68k_areg (regs, 4);
3037: uae_u8 *pck;
3038: uae_u8 *msg;
3039: if (! valid_address (packet_addr, 36) || ! valid_address (message_addr, 14)) {
3040: write_log ("Bad address passed for packet.\n");
3041: goto error2;
3042: }
3043: pck = get_real_address (packet_addr);
3044: msg = get_real_address (message_addr);
3045:
1.1.1.4 root 3046: #if 0
1.1.1.3 root 3047: if (unit->reset_state == FS_GO_DOWN)
3048: /* You might as well queue it, if you live long enough */
3049: return 1;
1.1.1.4 root 3050: #endif
1.1.1.3 root 3051:
3052: do_put_mem_long ((uae_u32 *)(msg + 4), -1);
3053: if (!unit || !unit->volume) {
3054: write_log ("Filesystem was not initialized.\n");
3055: goto error;
3056: }
3057: #ifdef UAE_FILESYS_THREADS
3058: {
3059: /* Get two more locks and hand them over to the other thread. */
3060: uae_u32 morelocks;
3061: morelocks = get_long (m68k_areg (regs, 3));
3062: put_long (m68k_areg (regs, 3), get_long (get_long (morelocks)));
3063: put_long (get_long (morelocks), 0);
3064:
1.1.1.22 root 3065: uae_sem_wait (&packet_counter_sem);
3066: active_fs_packets++;
3067: uae_sem_post (&packet_counter_sem);
3068:
1.1.1.3 root 3069: /* The packet wasn't processed yet. */
3070: do_put_mem_long ((uae_u32 *)(msg + 4), 0);
3071: write_comm_pipe_pvoid (unit->ui.unit_pipe, (void *)pck, 0);
3072: write_comm_pipe_pvoid (unit->ui.unit_pipe, (void *)msg, 0);
3073: write_comm_pipe_int (unit->ui.unit_pipe, (int)morelocks, 1);
3074: /* Don't reply yet. */
3075: return 1;
3076: }
3077: #endif
1.1 root 3078:
1.1.1.3 root 3079: if (! handle_packet (unit, pck)) {
3080: error:
3081: PUT_PCK_RES1 (pck, DOS_FALSE);
3082: PUT_PCK_RES2 (pck, ERROR_ACTION_NOT_KNOWN);
3083: }
1.1.1.4 root 3084: TRACE(("reply: %8lx, %ld\n", GET_PCK_RES1 (pck), GET_PCK_RES2 (pck)));
1.1 root 3085:
1.1.1.3 root 3086: error2:
1.1 root 3087:
1.1.1.3 root 3088: return 0;
3089: }
1.1 root 3090:
1.1.1.11 root 3091: static int current_deviceno = 0;
1.1.1.13 root 3092: static int current_cdrom = 0;
1.1.1.11 root 3093:
3094: static void reset_uaedevices (void)
3095: {
3096: current_deviceno = 0;
1.1.1.13 root 3097: current_cdrom = 0;
1.1.1.11 root 3098: }
3099:
1.1.1.19 root 3100: static void init_filesys_diagentry (void)
3101: {
3102: do_put_mem_long ((uae_u32 *)(filesysory + 0x2100), EXPANSION_explibname);
3103: do_put_mem_long ((uae_u32 *)(filesysory + 0x2104), filesys_configdev);
3104: do_put_mem_long ((uae_u32 *)(filesysory + 0x2108), EXPANSION_doslibname);
3105: do_put_mem_long ((uae_u32 *)(filesysory + 0x210c), current_mountinfo->num_units);
3106: }
3107:
1.1.1.4 root 3108: void filesys_start_threads (void)
3109: {
3110: UnitInfo *uip;
3111: int i;
3112:
3113: current_mountinfo = dup_mountinfo (currprefs.mountinfo);
3114:
3115: reset_uaedevices ();
1.1.1.20 root 3116:
1.1.1.4 root 3117: uip = current_mountinfo->ui;
3118: for (i = 0; i < current_mountinfo->num_units; i++) {
1.1.1.23! root 3119: UnitInfo *ui = &uip[i];
! 3120: ui->unit_pipe = 0;
1.1.1.4 root 3121:
3122: #ifdef UAE_FILESYS_THREADS
1.1.1.23! root 3123: if (hardfile_fs_type (current_mountinfo, i) == FILESYS_VIRTUAL) {
1.1.1.4 root 3124: uip[i].unit_pipe = (smp_comm_pipe *)xmalloc (sizeof (smp_comm_pipe));
3125: uip[i].back_pipe = (smp_comm_pipe *)xmalloc (sizeof (smp_comm_pipe));
3126: init_comm_pipe (uip[i].unit_pipe, 50, 3);
3127: init_comm_pipe (uip[i].back_pipe, 50, 1);
1.1.1.13 root 3128: uae_start_thread (filesys_thread, (void *)(uip + i), &uip[i].tid);
1.1.1.4 root 3129: }
3130: #endif
3131: }
3132: }
3133:
1.1.1.3 root 3134: void filesys_reset (void)
3135: {
3136: Unit *u, *u1;
1.1 root 3137:
1.1.1.4 root 3138: /* We get called once from customreset at the beginning of the program
3139: * before filesys_start_threads has been called. Survive that. */
3140: if (current_mountinfo == 0)
3141: return;
1.1 root 3142:
1.1.1.4 root 3143: for (u = units; u; u = u1) {
1.1.1.3 root 3144: u1 = u->next;
3145: free (u);
1.1 root 3146: }
1.1.1.3 root 3147: unit_num = 0;
3148: units = 0;
1.1.1.4 root 3149:
3150: free_mountinfo (current_mountinfo);
3151: current_mountinfo = 0;
1.1.1.3 root 3152: }
1.1 root 3153:
1.1.1.16 root 3154: static void free_all_ainos (Unit *u, a_inode *parent)
3155: {
1.1.1.19 root 3156: a_inode *a;
3157: while (a = parent->child) {
3158: free_all_ainos (u, a);
3159: dispose_aino (u, &parent->child, a);
1.1.1.16 root 3160: }
3161: }
3162:
3163:
1.1.1.3 root 3164: void filesys_prepare_reset (void)
3165: {
1.1.1.4 root 3166: UnitInfo *uip = current_mountinfo->ui;
3167: Unit *u;
1.1.1.3 root 3168: int i;
1.1 root 3169:
1.1.1.3 root 3170: #ifdef UAE_FILESYS_THREADS
1.1.1.4 root 3171: for (i = 0; i < current_mountinfo->num_units; i++) {
3172: if (uip[i].unit_pipe != 0) {
3173: uae_sem_init (&uip[i].reset_sync_sem, 0, 0);
3174: uip[i].reset_state = FS_GO_DOWN;
1.1.1.3 root 3175: /* send death message */
1.1.1.4 root 3176: write_comm_pipe_int (uip[i].unit_pipe, 0, 0);
3177: write_comm_pipe_int (uip[i].unit_pipe, 0, 0);
3178: write_comm_pipe_int (uip[i].unit_pipe, 0, 1);
3179: uae_sem_wait (&uip[i].reset_sync_sem);
1.1.1.3 root 3180: }
3181: }
3182: #endif
3183: u = units;
3184: while (u != 0) {
1.1.1.16 root 3185: free_all_ainos (u, &u->rootnode);
3186: u->rootnode.next = u->rootnode.prev = &u->rootnode;
3187: u->aino_cache_size = 0;
1.1.1.3 root 3188: u = u->next;
3189: }
1.1 root 3190: }
3191:
1.1.1.22 root 3192: static uae_u32 filesys_diagentry (TrapContext *dummy)
1.1 root 3193: {
1.1.1.7 root 3194: uaecptr resaddr = m68k_areg (regs, 2) + 0x10;
3195: uaecptr start = resaddr;
3196: uaecptr residents, tmp;
1.1.1.3 root 3197:
1.1.1.4 root 3198: TRACE (("filesystem: diagentry called\n"));
1.1.1.3 root 3199:
1.1.1.7 root 3200: filesys_configdev = m68k_areg (regs, 3);
1.1.1.19 root 3201: init_filesys_diagentry ();
1.1.1.3 root 3202:
3203: uae_sem_init (&singlethread_int_sem, 0, 1);
1.1 root 3204: if (ROM_hardfile_resid != 0) {
3205: /* Build a struct Resident. This will set up and initialize
3206: * the uae.device */
1.1.1.7 root 3207: put_word (resaddr + 0x0, 0x4AFC);
3208: put_long (resaddr + 0x2, resaddr);
3209: put_long (resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
3210: put_word (resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */
3211: put_word (resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
3212: put_long (resaddr + 0xE, ROM_hardfile_resname);
3213: put_long (resaddr + 0x12, ROM_hardfile_resid);
3214: put_long (resaddr + 0x16, ROM_hardfile_init); /* calls filesys_init */
1.1 root 3215: }
3216: resaddr += 0x1A;
1.1.1.7 root 3217: tmp = resaddr;
1.1.1.20 root 3218:
1.1.1.2 root 3219: /* The good thing about this function is that it always gets called
3220: * when we boot. So we could put all sorts of stuff that wants to be done
1.1.1.7 root 3221: * here.
3222: * We can simply add more Resident structures here. Although the Amiga OS
3223: * only knows about the one at address DiagArea + 0x10, we scan for other
3224: * Resident structures and call InitResident() for them at the end of the
3225: * diag entry. */
3226:
3227: resaddr = scsidev_startup(resaddr);
3228: native2amiga_startup();
3229:
3230: /* scan for Residents and return pointer to array of them */
3231: residents = resaddr;
3232: while (tmp < residents && tmp > start) {
3233: if (get_word (tmp) == 0x4AFC &&
3234: get_long (tmp + 0x2) == tmp) {
3235: put_word (resaddr, 0x227C); /* movea.l #tmp,a1 */
3236: put_long (resaddr + 2, tmp);
3237: put_word (resaddr + 6, 0x7200); /* moveq.l #0,d1 */
3238: put_long (resaddr + 8, 0x4EAEFF9A); /* jsr -$66(a6) ; InitResident */
3239: resaddr += 12;
3240: tmp = get_long (tmp + 0x6);
3241: } else {
3242: tmp++;
3243: }
3244: }
1.1.1.15 root 3245: /* call setup_exter */
3246: put_word (resaddr + 0, 0x2079);
3247: put_long (resaddr + 2, RTAREA_BASE + 28 + 4); /* move.l RTAREA_BASE+32,a0 */
3248: put_word (resaddr + 6, 0xd1fc);
3249: put_long (resaddr + 8, RTAREA_BASE + 8 + 4); /* add.l #RTAREA_BASE+12,a0 */
3250: put_word (resaddr + 12, 0x4e90); /* jsr (a0) */
3251: put_word (resaddr + 14, 0x7001); /* moveq.l #1,d0 */
3252: put_word (resaddr + 16, RTS);
1.1 root 3253:
1.1.1.7 root 3254: m68k_areg (regs, 0) = residents;
1.1.1.3 root 3255: return 1;
1.1 root 3256: }
3257:
1.1.1.23! root 3258: /* don't forget filesys.asm! */
! 3259: #define PP_MAXSIZE 4 * 96
! 3260: #define PP_FSSIZE 400
! 3261: #define PP_FSPTR 404
! 3262: #define PP_FSRES 408
! 3263: #define PP_EXPLIB 412
! 3264: #define PP_FSHDSTART 416
! 3265:
! 3266: static uae_u32 REGPARAM2 filesys_dev_bootfilesys (TrapContext *dummy)
! 3267: {
! 3268: uaecptr devicenode = m68k_areg (regs, 3);
! 3269: uaecptr parmpacket = m68k_areg (regs, 1);
! 3270: uaecptr fsres = get_long (parmpacket + PP_FSRES);
! 3271: uaecptr fsnode;
! 3272: uae_u32 dostype, dostype2;
! 3273: int no = m68k_dreg (regs, 6);
! 3274: int unit_no = no & 65535;
! 3275: int type = hardfile_fs_type (current_mountinfo, unit_no);
! 3276:
! 3277: if (type == FILESYS_VIRTUAL)
! 3278: return 0;
! 3279: dostype = get_long (parmpacket + 80);
! 3280: fsnode = get_long (fsres + 18);
! 3281: while (get_long (fsnode)) {
! 3282: dostype2 = get_long (fsnode + 14);
! 3283: if (dostype2 == dostype) {
! 3284: if (get_long (fsnode + 22) & (1 << 7)) {
! 3285: put_long (devicenode + 32, get_long (fsnode + 54)); /* dn_SegList */
! 3286: put_long (devicenode + 36, -1); /* dn_GlobalVec */
! 3287: }
! 3288: return 1;
! 3289: }
! 3290: fsnode = get_long (fsnode);
! 3291: }
! 3292: return 0;
! 3293: }
! 3294:
1.1.1.3 root 3295: /* Remember a pointer AmigaOS gave us so we can later use it to identify
3296: * which unit a given startup message belongs to. */
1.1.1.22 root 3297: static uae_u32 filesys_dev_remember (TrapContext *dummy)
1.1.1.3 root 3298: {
1.1.1.23! root 3299: int no = m68k_dreg (regs, 6);
! 3300: int unit_no = no & 65535;
! 3301: int sub_no = no >> 16;
1.1.1.22 root 3302: UnitInfo *uip = ¤t_mountinfo->ui[unit_no];
1.1.1.3 root 3303: uaecptr devicenode = m68k_areg (regs, 3);
1.1.1.23! root 3304: uaecptr parmpacket = m68k_areg (regs, 1);
1.1.1.3 root 3305:
1.1.1.23! root 3306: /* copy filesystem loaded from RDB */
! 3307: if (get_long (parmpacket + PP_FSPTR)) {
! 3308: int i;
! 3309: for (i = 0; i < uip->rdb_filesyssize; i++)
! 3310: put_byte (get_long (parmpacket + PP_FSPTR) + i, uip->rdb_filesysstore[i]);
! 3311: free (uip->rdb_filesysstore);
! 3312: uip->rdb_filesysstore = 0;
! 3313: uip->rdb_filesyssize = 0;
! 3314: }
! 3315: if ((uae_s32)m68k_dreg (regs, 3) >= 0)
! 3316: uip->startup = get_long (devicenode + 28);
1.1.1.3 root 3317: return devicenode;
3318: }
3319:
1.1.1.23! root 3320: static int legalrdbblock (UnitInfo *uip, int block)
! 3321: {
! 3322: if (block <= 0)
! 3323: return 0;
! 3324: if (block >= uip->hf.size / uip->hf.blocksize)
! 3325: return 0;
! 3326: return 1;
! 3327: }
! 3328:
! 3329: static int rl (uae_u8 *p)
! 3330: {
! 3331: return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
! 3332: }
! 3333:
! 3334: static int rdb_checksum (char *id, uae_u8 *p, int block)
! 3335: {
! 3336: uae_u32 sum = 0;
! 3337: int i, blocksize;
! 3338:
! 3339: if (memcmp (id, p, 4))
! 3340: return 0;
! 3341: blocksize = rl (p + 4);
! 3342: if (blocksize < 1 || blocksize * 4 > FILESYS_MAX_BLOCKSIZE)
! 3343: return 0;
! 3344: for (i = 0; i < blocksize; i++)
! 3345: sum += rl (p + i * 4);
! 3346: sum = -sum;
! 3347: if (sum) {
! 3348: write_log ("RDB: block %d ('%s') checksum error\n", block, id);
! 3349: return 0;
! 3350: }
! 3351: return 1;
! 3352: }
! 3353:
! 3354: static void dump_partinfo (char *name, int num, uaecptr pp, int partblock)
! 3355: {
! 3356: uae_u32 dostype = get_long (pp + 80);
! 3357: write_log ("RDB: '%s' dostype=%08.8X. PartBlock=%d\n", name, dostype, partblock);
! 3358: write_log ("BlockSize: %d, Surfaces: %d, SectorsPerBlock %d\n",
! 3359: get_long (pp + 20) * 4, get_long (pp + 28), get_long (pp + 32));
! 3360: write_log ("SectorsPerTrack: %d, Reserved: %d, LowCyl %d, HighCyl %d\n",
! 3361: get_long (pp + 36), get_long (pp + 40), get_long (pp + 52), get_long (pp + 56));
! 3362: write_log ("Buffers: %d, BufMemType: %08.8x, MaxTransfer: %08.8x, BootPri: %d\n",
! 3363: get_long (pp + 60), get_long (pp + 64), get_long (pp + 68), get_long (pp + 76));
! 3364: }
! 3365:
! 3366: static char *device_dupfix (uaecptr expbase, char *devname)
! 3367: {
! 3368: uaecptr bnode, dnode, name;
! 3369: int len, i, modified;
! 3370: char dname[256], newname[256];
! 3371:
! 3372: strcpy (newname, devname);
! 3373: modified = 1;
! 3374: while (modified) {
! 3375: modified = 0;
! 3376: bnode = get_long (expbase + 74); /* expansion.library bootnode list */
! 3377: while (get_long (bnode)) {
! 3378: dnode = get_long (bnode + 16); /* device node */
! 3379: name = get_long (dnode + 40) << 2; /* device name BSTR */
! 3380: len = get_byte (name);
! 3381: for (i = 0; i < len; i++)
! 3382: dname[i] = get_byte (name + 1 + i);
! 3383: dname[len] = 0;
! 3384: for (;;) {
! 3385: if (strcasecmp (newname, dname) == 0) {
! 3386: if (strlen (newname) > 2 && newname[strlen (newname) - 2] == '_') {
! 3387: newname[strlen (newname) - 1]++;
! 3388: } else {
! 3389: strcat (newname, "_0");
! 3390: }
! 3391: modified = 1;
! 3392: } else {
! 3393: break;
! 3394: }
! 3395: }
! 3396: bnode = get_long (bnode);
! 3397: }
! 3398: }
! 3399: return my_strdup (newname);
! 3400: }
! 3401:
! 3402: #define rdbmnt write_log ("Mounting uaehf.device %d (%d) (size=%llu):\n", unit_no, partnum, hfd->size);
! 3403:
! 3404: static int rdb_mount (UnitInfo *uip, int unit_no, int partnum, uaecptr parmpacket)
! 3405: {
! 3406: int lastblock = 63, blocksize, readblocksize, badblock, driveinitblock;
! 3407: uae_u8 bufrdb[FILESYS_MAX_BLOCKSIZE], *buf = 0;
! 3408: uae_u8 *fsmem = 0;
! 3409: int rdblock, partblock, fileblock, lsegblock, i;
! 3410: uae_u32 flags;
! 3411: struct hardfiledata *hfd = &uip->hf;
! 3412: uae_u32 dostype;
! 3413: uaecptr fsres, fsnode;
! 3414: int err = 0;
! 3415: int oldversion, oldrevision;
! 3416: int newversion, newrevision;
! 3417:
! 3418: if (hfd->blocksize == 0) {
! 3419: rdbmnt
! 3420: write_log ("failed, blocksize == 0\n");
! 3421: return -1;
! 3422: }
! 3423: if (lastblock * hfd->blocksize > hfd->size) {
! 3424: rdbmnt
! 3425: write_log ("failed, too small (%d*%d > %I64u)\n", lastblock, hfd->blocksize, hfd->size);
! 3426: return -2;
! 3427: }
! 3428: for (rdblock = 0; rdblock < lastblock; rdblock++) {
! 3429: hdf_read (hfd, bufrdb, rdblock * hfd->blocksize, hfd->blocksize);
! 3430: if (rdb_checksum ("RDSK", bufrdb, rdblock))
! 3431: break;
! 3432: hdf_read (hfd, bufrdb, rdblock * hfd->blocksize, hfd->blocksize);
! 3433: if (!memcmp ("RDSK", bufrdb, 4)) {
! 3434: bufrdb[0xdc] = 0;
! 3435: bufrdb[0xdd] = 0;
! 3436: bufrdb[0xde] = 0;
! 3437: bufrdb[0xdf] = 0;
! 3438: #if 0
! 3439: if (rdb_checksum ("RDSK", bufrdb, rdblock)) {
! 3440: write_log ("Windows 95/98/ME trashed RDB detected, fixing..\n");
! 3441: hdf_write (hfd, bufrdb, rdblock * hfd->blocksize, hfd->blocksize);
! 3442: break;
! 3443: }
! 3444: #endif
! 3445: }
! 3446: }
! 3447: if (rdblock == lastblock) {
! 3448: rdbmnt
! 3449: write_log ("failed, no RDB detected\n");
! 3450: return -2;
! 3451: }
! 3452: blocksize = rl (bufrdb + 16);
! 3453: readblocksize = blocksize > hfd->blocksize ? blocksize : hfd->blocksize;
! 3454: badblock = rl (bufrdb + 24);
! 3455: if (badblock != -1) {
! 3456: rdbmnt
! 3457: write_log ("RDB: badblock list is not yet supported. Contact the author.\n");
! 3458: return -2;
! 3459: }
! 3460: driveinitblock = rl (bufrdb + 36);
! 3461: if (driveinitblock != -1) {
! 3462: rdbmnt
! 3463: write_log ("RDB: driveinit is not yet supported. Contact the author.\n");
! 3464: return -2;
! 3465: }
! 3466: hfd->cylinders = rl (bufrdb + 64);
! 3467: hfd->sectors = rl (bufrdb + 68);
! 3468: hfd->heads = rl (bufrdb + 72);
! 3469: fileblock = rl (bufrdb + 32);
! 3470:
! 3471: if (partnum == 0) {
! 3472: write_log ("RDB: RDSK detected at %d, FSHD=%d, C=%d S=%d H=%d\n",
! 3473: rdblock, fileblock, hfd->cylinders, hfd->sectors, hfd->heads);
! 3474: }
! 3475:
! 3476: buf = (uae_u8*)xmalloc (readblocksize);
! 3477: for (i = 0; i <= partnum; i++) {
! 3478: if (i == 0)
! 3479: partblock = rl (bufrdb + 28);
! 3480: else
! 3481: partblock = rl (buf + 4 * 4);
! 3482: if (!legalrdbblock (uip, partblock)) {
! 3483: err = -2;
! 3484: goto error;
! 3485: }
! 3486: memset (buf, 0, readblocksize);
! 3487: hdf_read (hfd, buf, partblock * hfd->blocksize, readblocksize);
! 3488: if (!rdb_checksum ("PART", buf, partblock)) {
! 3489: err = -2;
! 3490: goto error;
! 3491: }
! 3492: }
! 3493:
! 3494: rdbmnt
! 3495: flags = rl (buf + 20);
! 3496: if (flags & 2) { /* do not mount */
! 3497: err = -1;
! 3498: write_log ("RDB: Automount disabled, not mounting\n");
! 3499: goto error;
! 3500: }
! 3501:
! 3502: if (!(flags & 1)) /* not bootable */
! 3503: m68k_dreg (regs, 7) = 0;
! 3504:
! 3505: buf[37 + buf[36]] = 0; /* zero terminate BSTR */
! 3506: uip->rdb_devname_amiga[partnum]
! 3507: = ds (device_dupfix (get_long (parmpacket + PP_EXPLIB), buf + 37));
! 3508: put_long (parmpacket, uip->rdb_devname_amiga[partnum]); /* name */
! 3509: put_long (parmpacket + 4, ROM_hardfile_resname);
! 3510: put_long (parmpacket + 8, uip->devno);
! 3511: put_long (parmpacket + 12, 0); /* Device flags */
! 3512: for (i = 0; i < PP_MAXSIZE; i++)
! 3513: put_byte (parmpacket + 16 + i, buf[128 + i]);
! 3514: dump_partinfo (buf + 37, uip->devno, parmpacket, partblock);
! 3515: dostype = get_long (parmpacket + 80);
! 3516:
! 3517: if (dostype == 0) {
! 3518: write_log ("RDB: mount failed, dostype=0\n");
! 3519: err = -1;
! 3520: goto error;
! 3521: }
! 3522:
! 3523: if (hfd->cylinders * hfd->sectors * hfd->heads * blocksize > hfd->size)
! 3524: write_log ("RDB: WARNING: end of partition > size of disk!\n");
! 3525:
! 3526: err = 2;
! 3527:
! 3528: /* load custom filesystems if needed */
! 3529: if (fileblock == -1 || !legalrdbblock (uip, fileblock))
! 3530: goto error;
! 3531:
! 3532: fsres = get_long (parmpacket + PP_FSRES);
! 3533: if (!fsres) {
! 3534: write_log ("RDB: FileSystem.resource not found, this shouldn't happen!\n");
! 3535: goto error;
! 3536: }
! 3537: fsnode = get_long (fsres + 18);
! 3538: while (get_long (fsnode)) {
! 3539: if (get_long (fsnode + 14) == dostype)
! 3540: break;
! 3541: fsnode = get_long (fsnode);
! 3542: }
! 3543: oldversion = oldrevision = -1;
! 3544: if (get_long (fsnode)) {
! 3545: oldversion = get_word (fsnode + 18);
! 3546: oldrevision = get_word (fsnode + 20);
! 3547: } else {
! 3548: fsnode = 0;
! 3549: }
! 3550:
! 3551: for (;;) {
! 3552: if (fileblock == -1) {
! 3553: if (!fsnode)
! 3554: write_log ("RDB: required FS %08.8X not in FileSystem.resource or in RDB\n", dostype);
! 3555: goto error;
! 3556: }
! 3557: if (!legalrdbblock (uip, fileblock)) {
! 3558: write_log ("RDB: corrupt FSHD pointer %d\n", fileblock);
! 3559: goto error;
! 3560: }
! 3561: memset (buf, 0, readblocksize);
! 3562: hdf_read (hfd, buf, fileblock * hfd->blocksize, readblocksize);
! 3563: if (!rdb_checksum ("FSHD", buf, fileblock)) {
! 3564: write_log ("RDB: checksum error in FSHD block %d\n", fileblock);
! 3565: goto error;
! 3566: }
! 3567: fileblock = rl (buf + 16);
! 3568: if ((dostype >> 8) == (rl (buf + 32) >> 8))
! 3569: break;
! 3570: }
! 3571: newversion = (buf[36] << 8) | buf[37];
! 3572: newrevision = (buf[38] << 8) | buf[39];
! 3573:
! 3574: write_log ("RDB: RDB filesystem %08.8X version %d.%d\n", dostype, newversion, newrevision);
! 3575: if (fsnode) {
! 3576: write_log ("RDB: %08.8X in FileSystem.resouce version %d.%d\n", dostype, oldversion, oldrevision);
! 3577: }
! 3578: if (newversion * 65536 + newrevision <= oldversion * 65536 + oldrevision && oldversion >= 0) {
! 3579: write_log ("RDB: FS in FileSystem.resource is newer or same, ignoring RDB filesystem\n");
! 3580: goto error;
! 3581: }
! 3582:
! 3583: for (i = 0; i < 140; i++)
! 3584: put_byte (parmpacket + PP_FSHDSTART + i, buf[32 + i]);
! 3585: put_long (parmpacket + PP_FSHDSTART, dostype);
! 3586: /* we found required FSHD block */
! 3587: fsmem = (uae_u8*)xmalloc (262144);
! 3588: lsegblock = rl (buf + 72);
! 3589: i = 0;
! 3590: for (;;) {
! 3591: int pb = lsegblock;
! 3592: if (!legalrdbblock (uip, lsegblock))
! 3593: goto error;
! 3594: memset (buf, 0, readblocksize);
! 3595: hdf_read (hfd, buf, lsegblock * hfd->blocksize, readblocksize);
! 3596: if (!rdb_checksum ("LSEG", buf, lsegblock))
! 3597: goto error;
! 3598: lsegblock = rl (buf + 16);
! 3599: if (lsegblock == pb)
! 3600: goto error;
! 3601: memcpy (fsmem + i * (blocksize - 20), buf + 20, blocksize - 20);
! 3602: i++;
! 3603: if (lsegblock == -1)
! 3604: break;
! 3605: }
! 3606: write_log ("RDB: Filesystem loaded, %d bytes\n", i * (blocksize - 20));
! 3607: put_long (parmpacket + PP_FSSIZE, i * (blocksize - 20)); /* RDB filesystem size hack */
! 3608: uip->rdb_filesysstore = fsmem;
! 3609: uip->rdb_filesyssize = i * (blocksize - 20);
! 3610: free (buf);
! 3611: return 2;
! 3612: error:
! 3613: free (buf);
! 3614: free (fsmem);
! 3615: return err;
! 3616: }
! 3617:
! 3618: static void get_new_device (int type, uaecptr parmpacket, char **devname,
! 3619: uaecptr *devname_amiga, int unit_no)
! 3620: {
! 3621: char buffer[80];
! 3622:
! 3623: sprintf (buffer, "DH%d", unit_no);
! 3624:
! 3625: if (*devname == NULL)
! 3626: *devname = device_dupfix (get_long (parmpacket + PP_EXPLIB), buffer);
! 3627: *devname_amiga = ds (*devname);
! 3628: if (type == FILESYS_VIRTUAL)
! 3629: write_log ("FS: mounted virtual unit %s\n", buffer);
! 3630: else
! 3631: write_log ("FS: mounted HDF unit %s\n", buffer);
! 3632: }
! 3633:
1.1.1.3 root 3634: /* Fill in per-unit fields of a parampacket */
1.1.1.22 root 3635: static uae_u32 filesys_dev_storeinfo (TrapContext *dummy)
1.1.1.3 root 3636: {
1.1.1.4 root 3637: UnitInfo *uip = current_mountinfo->ui;
1.1.1.23! root 3638: int no = m68k_dreg (regs, 6);
! 3639: int unit_no = no & 65535;
! 3640: int sub_no = no >> 16;
! 3641: int type = hardfile_fs_type (current_mountinfo, unit_no);
1.1.1.3 root 3642: uaecptr parmpacket = m68k_areg (regs, 0);
3643:
1.1.1.23! root 3644: if (type == FILESYS_HARDFILE_RDB || type == FILESYS_HARDDRIVE) {
! 3645: /* RDB hardfile */
! 3646: uip[unit_no].devno = unit_no;
! 3647: return rdb_mount (&uip[unit_no], unit_no, sub_no, parmpacket);
! 3648: }
! 3649: /* No subunits for normal filesystems and hardfiles. */
! 3650: if (sub_no)
! 3651: return -2;
! 3652: get_new_device (type, parmpacket, &uip[unit_no].devname, &uip[unit_no].devname_amiga, unit_no);
! 3653: uip[unit_no].devno = unit_no;
1.1.1.22 root 3654: put_long (parmpacket, uip[unit_no].devname_amiga);
1.1.1.23! root 3655: put_long (parmpacket + 4, type != FILESYS_VIRTUAL ? ROM_hardfile_resname : fsdevname);
1.1.1.4 root 3656: put_long (parmpacket + 8, uip[unit_no].devno);
1.1.1.3 root 3657: put_long (parmpacket + 12, 0); /* Device flags */
3658: put_long (parmpacket + 16, 16); /* Env. size */
1.1.1.6 root 3659: put_long (parmpacket + 20, uip[unit_no].hf.blocksize >> 2); /* longwords per block */
1.1.1.3 root 3660: put_long (parmpacket + 24, 0); /* unused */
1.1.1.4 root 3661: put_long (parmpacket + 28, uip[unit_no].hf.surfaces); /* heads */
1.1.1.22 root 3662: put_long (parmpacket + 32, 1); /* sectors per block */
1.1.1.4 root 3663: put_long (parmpacket + 36, uip[unit_no].hf.secspertrack); /* sectors per track */
3664: put_long (parmpacket + 40, uip[unit_no].hf.reservedblocks); /* reserved blocks */
1.1.1.3 root 3665: put_long (parmpacket + 44, 0); /* unused */
3666: put_long (parmpacket + 48, 0); /* interleave */
3667: put_long (parmpacket + 52, 0); /* lowCyl */
1.1.1.4 root 3668: put_long (parmpacket + 56, uip[unit_no].hf.nrcyls - 1); /* hiCyl */
1.1.1.6 root 3669: put_long (parmpacket + 60, 50); /* Number of buffers */
1.1.1.3 root 3670: put_long (parmpacket + 64, 0); /* Buffer mem type */
3671: put_long (parmpacket + 68, 0x7FFFFFFF); /* largest transfer */
3672: put_long (parmpacket + 72, ~1); /* addMask (?) */
1.1.1.22 root 3673: put_long (parmpacket + 76, uip[unit_no].bootpri); /* bootPri */
1.1.1.3 root 3674: put_long (parmpacket + 80, 0x444f5300); /* DOS\0 */
3675: put_long (parmpacket + 84, 0); /* pad */
3676:
1.1.1.23! root 3677: return type;
1.1 root 3678: }
3679:
1.1.1.3 root 3680: void filesys_install (void)
1.1 root 3681: {
3682: int i;
1.1.1.3 root 3683: uaecptr loop;
3684:
1.1.1.4 root 3685: TRACE (("Installing filesystem\n"));
1.1 root 3686:
1.1.1.22 root 3687: ROM_filesys_resname = ds ("UAEunixfs.resource");
3688: ROM_filesys_resid = ds ("UAE unixfs 0.4");
1.1 root 3689:
1.1.1.4 root 3690: fsdevname = ds ("uae.device"); /* does not really exist */
1.1 root 3691:
3692: ROM_filesys_diagentry = here();
1.1.1.7 root 3693: calltrap (deftrap(filesys_diagentry));
1.1.1.22 root 3694: dw (0x4ED0); /* JMP (a0) - jump to code that inits Residents */
1.1.1.3 root 3695:
3696: loop = here ();
1.1.1.23! root 3697:
! 3698: org (RTAREA_BASE + 0xFF18);
! 3699: calltrap (deftrap (filesys_dev_bootfilesys));
! 3700: dw (RTS);
! 3701:
1.1.1.3 root 3702: /* Special trap for the assembly make_dev routine */
1.1.1.15 root 3703: org (RTAREA_BASE + 0xFF20);
1.1.1.3 root 3704: calltrap (deftrap (filesys_dev_remember));
1.1.1.4 root 3705: dw (RTS);
1.1.1.3 root 3706:
1.1.1.15 root 3707: org (RTAREA_BASE + 0xFF28);
1.1.1.3 root 3708: calltrap (deftrap (filesys_dev_storeinfo));
1.1.1.4 root 3709: dw (RTS);
1.1.1.3 root 3710:
1.1.1.15 root 3711: org (RTAREA_BASE + 0xFF30);
1.1.1.3 root 3712: calltrap (deftrap (filesys_handler));
1.1.1.4 root 3713: dw (RTS);
1.1.1.3 root 3714:
1.1.1.15 root 3715: org (RTAREA_BASE + 0xFF40);
1.1.1.3 root 3716: calltrap (deftrap (startup_handler));
1.1.1.4 root 3717: dw (RTS);
1.1.1.3 root 3718:
1.1.1.15 root 3719: org (RTAREA_BASE + 0xFF50);
1.1.1.3 root 3720: calltrap (deftrap (exter_int_helper));
1.1.1.4 root 3721: dw (RTS);
1.1.1.3 root 3722:
3723: org (loop);
1.1.1.22 root 3724:
3725: uae_sem_init (&packet_counter_sem, 0, 0);
1.1.1.3 root 3726: }
3727:
3728: void filesys_install_code (void)
3729: {
1.1 root 3730: align(4);
3731:
1.1.1.3 root 3732: /* The last offset comes from the code itself, look for it near the top. */
1.1.1.22 root 3733: EXPANSION_bootcode = here () + 8 + 0x1c + 4;
1.1.1.3 root 3734: /* Ouch. Make sure this is _always_ a multiple of two bytes. */
1.1.1.22 root 3735: filesys_initcode = here() + 8 + 0x30 + 4;
1.1.1.15 root 3736:
1.1.1.22 root 3737: #include "filesys_bootrom.c"
1.1 root 3738: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.