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