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