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