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