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