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