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