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