]> git.sesse.net Git - pistorm/blob - a314/software-amiga/a314fs_pistorm/a314fs.c
Adapt a314fs to work on PiStorm + A314 emulation
[pistorm] / a314 / software-amiga / a314fs_pistorm / a314fs.c
1 /*
2  * Copyright (c) 2018-2021 Niklas Ekström
3  */
4
5 #include <exec/types.h>
6 #include <exec/ports.h>
7 #include <exec/nodes.h>
8 #include <exec/libraries.h>
9
10 #include <devices/timer.h>
11
12 #include <libraries/dos.h>
13 #include <libraries/dosextens.h>
14 #include <libraries/filehandler.h>
15
16 #include <proto/exec.h>
17 #include <proto/dos.h>
18
19 #include <string.h>
20 #include <stdarg.h>
21
22 #include "../../a314device/a314.h"
23 #include "../../a314device/proto_a314.h"
24
25 #include "messages.h"
26
27 #define MKBADDRU(x) (((ULONG)x) >> 2)
28
29 #define ID_314_DISK (('3' << 24) | ('1' << 16) | ('4' << 8))
30
31 #define REQ_RES_BUF_SIZE 256
32 #define BUFFER_SIZE 4096
33
34 // Not defined if using NDK13
35 #ifndef ACTION_EXAMINE_FH
36 #define ACTION_EXAMINE_FH 1034
37 #endif
38
39 #ifndef ACTION_SAME_LOCK
40 #define ACTION_SAME_LOCK 40
41 #endif
42
43 // Grab a reserved action type which seems to be unused
44 #define ACTION_UNSUPPORTED 65535
45
46 struct ExecBase *SysBase;
47 struct DosLibrary *DOSBase;
48 struct MsgPort *mp;
49
50 struct DeviceList *my_volume;
51 char default_volume_name[] = "\006PiDisk";
52
53 char device_name[32]; // "\004PI0:"
54
55 struct MsgPort *timer_mp;
56 struct timerequest *tr;
57
58 struct MsgPort *a314_mp;
59 struct A314_IORequest *a314_ior;
60
61 struct Library *A314Base;
62
63 long socket;
64
65 // These are allocated in A314 memory.
66 char *request_buffer = NULL;
67 char *data_buffer = NULL;
68
69 void MyNewList(struct List *l)
70 {
71     l->lh_Head = (struct Node *)&(l->lh_Tail);
72     l->lh_Tail = NULL;
73     l->lh_TailPred = (struct Node *)&(l->lh_Head);
74 }
75
76 struct MsgPort *MyCreatePort(char *name, long pri)
77 {
78         int sigbit = AllocSignal(-1);
79         if (sigbit == -1)
80                 return NULL;
81
82         struct MsgPort *port = (struct MsgPort *)AllocMem(sizeof(struct MsgPort), MEMF_PUBLIC | MEMF_CLEAR);
83         if (!port)
84         {
85                 FreeSignal(sigbit);
86                 return NULL;
87         }
88
89         port->mp_Node.ln_Name = name;
90         port->mp_Node.ln_Pri = pri;
91         port->mp_Node.ln_Type = NT_MSGPORT;
92         port->mp_Flags = PA_SIGNAL;
93         port->mp_SigBit = sigbit;
94         port->mp_SigTask = FindTask(NULL);
95
96         if (name)
97                 AddPort(port);
98         else
99                 MyNewList(&(port->mp_MsgList));
100
101         return port;
102 }
103
104 struct IORequest *MyCreateExtIO(struct MsgPort *ioReplyPort, ULONG size)
105 {
106         if (!ioReplyPort)
107                 return NULL;
108
109         struct IORequest *ioReq = (struct IORequest *)AllocMem(size, MEMF_PUBLIC | MEMF_CLEAR);
110         if (!ioReq)
111                 return NULL;
112
113         ioReq->io_Message.mn_Node.ln_Type = NT_MESSAGE;
114         ioReq->io_Message.mn_Length = size;
115         ioReq->io_Message.mn_ReplyPort = ioReplyPort;
116
117         return ioReq;
118 }
119
120 #define DEBUG 0
121
122 #if !DEBUG
123 void dbg_init()
124 {
125 }
126
127 void dbg(const char* fmt, ...)
128 {
129 }
130 #else
131 struct FileHandle *dbg_log;
132 struct MsgPort *dbg_replyport;
133 struct StandardPacket *dbg_sp;
134 char dbg_buf[256];
135
136 void dbg_init()
137 {
138         dbg_log = (struct FileHandle *)BADDR(Open("CON:200/0/440/256/a314fs", MODE_NEWFILE));
139         dbg_replyport = MyCreatePort(NULL, 0);
140         dbg_sp = (struct StandardPacket *)AllocMem(sizeof(struct StandardPacket), MEMF_PUBLIC | MEMF_CLEAR);
141 }
142
143 void dbg_out(int l)
144 {
145         dbg_sp->sp_Msg.mn_Node.ln_Name = (char *)&(dbg_sp->sp_Pkt);
146         dbg_sp->sp_Pkt.dp_Link = &(dbg_sp->sp_Msg);
147         dbg_sp->sp_Pkt.dp_Port = dbg_replyport;
148         dbg_sp->sp_Pkt.dp_Type = ACTION_WRITE;
149         dbg_sp->sp_Pkt.dp_Arg1 = (long)dbg_log->fh_Arg1;
150         dbg_sp->sp_Pkt.dp_Arg2 = (long)dbg_buf;
151         dbg_sp->sp_Pkt.dp_Arg3 = (long)l - 1;
152
153         PutMsg((struct MsgPort *)dbg_log->fh_Type, (struct Message *)dbg_sp);
154         WaitPort(dbg_replyport);
155         GetMsg(dbg_replyport);
156 }
157
158 void dbg(const char* fmt, ...)
159 {
160         char numbuf[16];
161
162         const char *p = fmt;
163         char *q = dbg_buf;
164
165         va_list args;
166         va_start(args, fmt);
167         while (*p != 0)
168         {
169                 char c = *p++;
170                 if (c == '$')
171                 {
172                         c = *p++;
173                         if (c == 'b')
174                         {
175                                 UBYTE x = va_arg(args, UBYTE);
176                                 *q++ = '$';
177                                 for (int i = 0; i < 2; i++)
178                                 {
179                                         int ni = (x >> ((1 - i) * 4)) & 0xf;
180                                         *q++ = (ni >= 10) ? ('a' + (ni - 10)) : ('0' + ni);
181                                 }
182                         }
183                         else if (c == 'w')
184                         {
185                                 UWORD x = va_arg(args, UWORD);
186                                 *q++ = '$';
187                                 for (int i = 0; i < 4; i++)
188                                 {
189                                         int ni = (x >> ((3 - i) * 4)) & 0xf;
190                                         *q++ = (ni >= 10) ? ('a' + (ni - 10)) : ('0' + ni);
191                                 }
192                         }
193                         else if (c == 'l')
194                         {
195                                 ULONG x = va_arg(args, ULONG);
196                                 *q++ = '$';
197                                 for (int i = 0; i < 8; i++)
198                                 {
199                                         int ni = (x >> ((7 - i) * 4)) & 0xf;
200                                         *q++ = (ni >= 10) ? ('a' + (ni - 10)) : ('0' + ni);
201                                 }
202                         }
203                         else if (c == 'S')
204                         {
205                                 unsigned char *s = (unsigned char *)va_arg(args, ULONG);
206                                 int l = *s++;
207                                 for (int i = 0; i < l; i++)
208                                         *q++ = *s++;
209                         }
210                         else if (c == 's')
211                         {
212                                 unsigned char *s = (unsigned char *)va_arg(args, ULONG);
213                                 while (*s)
214                                         *q++ = *s++;
215                                 *q++ = 0;
216                         }
217                 }
218                 else
219                 {
220                         *q++ = c;
221                 }
222         }
223         *q++ = 0;
224
225         va_end(args);
226
227         dbg_out(q - dbg_buf);
228 }
229 #endif
230
231 char *DosAllocMem(int len)
232 {
233         long *p = (long *)AllocMem(len + 4, MEMF_PUBLIC | MEMF_CLEAR);
234         *p++ = len;
235         return((char *)p);
236 }
237
238 void DosFreeMem(char *p)
239 {
240         long *lp = (long *)p;
241         long len = *--lp;
242         FreeMem((char *)lp, len);
243 }
244
245 void reply_packet(struct DosPacket *dp)
246 {
247         struct MsgPort *reply_port = dp->dp_Port;
248         dp->dp_Port = mp;
249         PutMsg(reply_port, dp->dp_Link);
250 }
251
252 // Routines for talking to the A314 driver.
253 LONG a314_cmd_wait(UWORD command, char *buffer, int length)
254 {
255         a314_ior->a314_Request.io_Command = command;
256         a314_ior->a314_Request.io_Error = 0;
257         a314_ior->a314_Socket = socket;
258         a314_ior->a314_Buffer = buffer;
259         a314_ior->a314_Length = length;
260         return DoIO((struct IORequest *)a314_ior);
261 }
262
263 LONG a314_connect(char *name)
264 {
265         struct DateStamp ds;
266         DateStamp(&ds);
267         socket = ds.ds_Tick;
268         return a314_cmd_wait(A314_CONNECT, name, strlen(name));
269 }
270
271 LONG a314_read(char *buf, int length)
272 {
273         return a314_cmd_wait(A314_READ, buf, length);
274 }
275
276 LONG a314_write(char *buf, int length)
277 {
278         return a314_cmd_wait(A314_WRITE, buf, length);
279 }
280
281 LONG a314_eos()
282 {
283         return a314_cmd_wait(A314_EOS, NULL, 0);
284 }
285
286 LONG a314_reset()
287 {
288         return a314_cmd_wait(A314_RESET, NULL, 0);
289 }
290
291 void create_and_add_volume()
292 {
293         my_volume = (struct DeviceList *)DosAllocMem(sizeof(struct DeviceList));
294         my_volume->dl_Name = MKBADDRU(default_volume_name);
295         my_volume->dl_Type = DLT_VOLUME;
296         my_volume->dl_Task = mp;
297         my_volume->dl_DiskType = ID_314_DISK;
298         DateStamp(&my_volume->dl_VolumeDate);
299
300         struct RootNode *root = (struct RootNode *)DOSBase->dl_Root;
301         struct DosInfo *info = (struct DosInfo *)BADDR(root->rn_Info);
302
303         Forbid();
304         my_volume->dl_Next = info->di_DevInfo;
305         info->di_DevInfo = MKBADDRU(my_volume);
306         Permit();
307 }
308
309 void startup_fs_handler(struct DosPacket *dp)
310 {
311         unsigned char *name = (unsigned char *)BADDR(dp->dp_Arg1);
312         struct FileSysStartupMsg *fssm = (struct FileSysStartupMsg *)BADDR(dp->dp_Arg2);
313         struct DeviceNode *node = (struct DeviceNode *)BADDR(dp->dp_Arg3);
314
315         memcpy(device_name, name, *name + 1);
316         device_name[*name + 1] = 0;
317
318         node->dn_Task = mp;
319
320         dp->dp_Res1 = DOSTRUE;
321         dp->dp_Res2 = 0;
322         reply_packet(dp);
323
324         dbg_init();
325
326         dbg("ACTION_STARTUP\n");
327         dbg("  device_name = $S\n", (ULONG)device_name);
328         dbg("  fssm = $l\n", (ULONG)fssm);
329         dbg("  node = $l\n", (ULONG)node);
330
331         timer_mp = MyCreatePort(NULL, 0);
332         tr = (struct timerequest *)MyCreateExtIO(timer_mp, sizeof(struct timerequest));
333         if (OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *)tr, 0) != 0)
334         {
335                 // If this happens, there's nothing we can do.
336                 // For now, assume this does not happen.
337                 dbg("Fatal error: unable to open timer.device\n");
338                 return;
339         }
340
341         a314_mp = MyCreatePort(NULL, 0);
342         a314_ior = (struct A314_IORequest *)MyCreateExtIO(a314_mp, sizeof(struct A314_IORequest));
343         if (OpenDevice(A314_NAME, 0, (struct IORequest *)a314_ior, 0) != 0)
344         {
345                 // If this fails, there's nothing we can do.
346                 // For now, assume this does not happen.
347                 dbg("Fatal error: unable to open a314.device\n");
348                 return;
349         }
350
351         A314Base = &(a314_ior->a314_Request.io_Device->dd_Library);
352
353         if (a314_connect("a314fs") != A314_CONNECT_OK)
354         {
355                 dbg("Fatal error: unable to connect to a314fs on rasp\n");
356                 // This COULD happen.
357                 // If it DOES happen, we just wait for a bit and try again.
358
359                 // TODO: Have to use timer.device to set a timer for ~2 seconds and then try connecting again.
360                 return;
361         }
362
363         request_buffer = AllocMem(REQ_RES_BUF_SIZE, MEMF_FAST);
364         data_buffer = AllocMem(BUFFER_SIZE, MEMF_FAST);
365
366         // We can assume that we arrive here, and have a stream to the Pi side, to where we can transfer data.
367         create_and_add_volume();
368
369         dbg("Startup successful\n");
370
371         // If we end up having problems with the connections, treat the disc as ejected, and try inserting it again in two seconds.
372         // TODO: This is not currently handled.
373 }
374
375 void wait_for_response()
376 {
377         for (unsigned long i = 0; 1; i++)
378         {
379                 if (*request_buffer)
380                 {
381                         dbg("--Got response after $l sleeps\n", i);
382                         return;
383                 }
384
385                 tr->tr_node.io_Command = TR_ADDREQUEST;
386                 tr->tr_node.io_Message.mn_ReplyPort = timer_mp;
387                 tr->tr_time.tv_secs = 0;
388                 tr->tr_time.tv_micro = 1000;
389                 DoIO((struct IORequest *)tr);
390         }
391 }
392
393 void write_req_and_wait_for_res(int len)
394 {
395         ULONG buf[2] = {TranslateAddressA314(request_buffer), len};
396         a314_write((char *)&buf[0], 8);
397         //wait_for_response();
398         a314_read((char *)&buf[0], 8);
399 }
400
401 struct FileLock *create_and_add_file_lock(long key, long mode)
402 {
403         struct FileLock *lock = (struct FileLock *)DosAllocMem(sizeof(struct FileLock));
404
405         lock->fl_Key = key;
406         lock->fl_Access = mode;
407         lock->fl_Task = mp;
408         lock->fl_Volume = MKBADDRU(my_volume);
409
410         Forbid();
411         lock->fl_Link = my_volume->dl_Lock;
412         my_volume->dl_Lock = MKBADDRU(lock);
413         Permit();
414
415         return lock;
416 }
417
418 void action_locate_object(struct DosPacket *dp)
419 {
420         struct FileLock *parent = (struct FileLock *)BADDR(dp->dp_Arg1);
421         unsigned char *name = (unsigned char *)BADDR(dp->dp_Arg2);
422         long mode = dp->dp_Arg3;
423
424         dbg("ACTION_LOCATE_OBJECT\n");
425         dbg("  parent lock = $l\n", parent);
426         dbg("  name = $S\n", name);
427         dbg("  mode = $s\n", mode == SHARED_LOCK ? "SHARED_LOCK" : "EXCLUSIVE_LOCK");
428
429         struct LocateObjectRequest *req = (struct LocateObjectRequest *)request_buffer;
430         req->has_response = 0;
431         req->type = dp->dp_Type;
432         req->key = parent == NULL ? 0 : parent->fl_Key;
433         req->mode = mode;
434
435         int nlen = *name;
436         memcpy(req->name, name, nlen + 1);
437
438         write_req_and_wait_for_res(sizeof(struct LocateObjectRequest) + nlen);
439
440         struct LocateObjectResponse *res = (struct LocateObjectResponse *)request_buffer;
441         if (!res->success)
442         {
443                 dbg("  Failed, error code $l\n", (LONG)res->error_code);
444                 dp->dp_Res1 = DOSFALSE;
445                 dp->dp_Res2 = res->error_code;
446         }
447         else
448         {
449                 struct FileLock *lock = create_and_add_file_lock(res->key, mode);
450
451                 dbg("  Returning lock $l\n", lock);
452                 dp->dp_Res1 = MKBADDRU(lock);
453                 dp->dp_Res2 = 0;
454         }
455
456         reply_packet(dp);
457 }
458
459 void action_free_lock(struct DosPacket *dp)
460 {
461         ULONG arg1 = dp->dp_Arg1;
462         struct FileLock *lock = (struct FileLock *)BADDR(dp->dp_Arg1);
463
464         dbg("ACTION_FREE_LOCK\n");
465         dbg("  lock = $l\n", lock);
466
467         if (lock != NULL)
468         {
469                 struct FreeLockRequest *req = (struct FreeLockRequest *)request_buffer;
470                 req->has_response = 0;
471                 req->type = dp->dp_Type;
472                 req->key = lock->fl_Key;
473
474                 write_req_and_wait_for_res(sizeof(struct FreeLockRequest));
475
476                 // Ignore the response. Must succeed.
477                 //struct FreeLockResponse *res = (struct FreeLockResponse *)request_buffer;
478
479                 Forbid();
480                 if (my_volume->dl_Lock == arg1)
481                         my_volume->dl_Lock = lock->fl_Link;
482                 else
483                 {
484                         struct FileLock *prev = (struct FileLock *)BADDR(my_volume->dl_Lock);
485                         while (prev->fl_Link != arg1)
486                                 prev = (struct FileLock *)BADDR(prev->fl_Link);
487                         prev->fl_Link = lock->fl_Link;
488                 }
489                 Permit();
490                 DosFreeMem((char *)lock);
491         }
492
493         dp->dp_Res1 = DOSTRUE;
494         dp->dp_Res2 = 0;
495         reply_packet(dp);
496 }
497
498 void action_copy_dir(struct DosPacket *dp)
499 {
500         struct FileLock *parent = (struct FileLock *)BADDR(dp->dp_Arg1);
501
502         dbg("ACTION_COPY_DIR\n");
503         dbg("  lock to duplicate = $l\n", parent);
504
505         if (parent == NULL)
506         {
507                 dp->dp_Res1 = 0;
508                 dp->dp_Res2 = 0;
509         }
510         else
511         {
512                 struct CopyDirRequest *req = (struct CopyDirRequest *)request_buffer;
513                 req->has_response = 0;
514                 req->type = dp->dp_Type;
515                 req->key = parent->fl_Key;
516
517                 write_req_and_wait_for_res(sizeof(struct CopyDirRequest));
518
519                 struct CopyDirResponse *res = (struct CopyDirResponse *)request_buffer;
520                 if (!res->success)
521                 {
522                         dbg("  Failed, error code $l\n", (LONG)res->error_code);
523                         dp->dp_Res1 = DOSFALSE;
524                         dp->dp_Res2 = res->error_code;
525                 }
526                 else
527                 {
528                         struct FileLock *lock = create_and_add_file_lock(res->key, parent->fl_Access);
529
530                         dbg("  Returning lock $l\n", lock);
531                         dp->dp_Res1 = MKBADDRU(lock);
532                         dp->dp_Res2 = 0;
533                 }
534         }
535
536         reply_packet(dp);
537 }
538
539 void action_parent(struct DosPacket *dp)
540 {
541         struct FileLock *prev_lock = (struct FileLock *)BADDR(dp->dp_Arg1);
542
543         dbg("ACTION_PARENT\n");
544         dbg("  lock = $l\n", prev_lock);
545
546         if (prev_lock == NULL)
547         {
548                 dp->dp_Res1 = DOSFALSE;
549                 dp->dp_Res2 = ERROR_INVALID_LOCK;
550         }
551         else
552         {
553                 struct ParentRequest *req = (struct ParentRequest *)request_buffer;
554                 req->has_response = 0;
555                 req->type = dp->dp_Type;
556                 req->key = prev_lock->fl_Key;
557
558                 write_req_and_wait_for_res(sizeof(struct ParentRequest));
559
560                 struct ParentResponse *res = (struct ParentResponse *)request_buffer;
561                 if (!res->success)
562                 {
563                         dbg("  Failed, error code $l\n", (LONG)res->error_code);
564                         dp->dp_Res1 = DOSFALSE;
565                         dp->dp_Res2 = res->error_code;
566                 }
567                 else if (res->key == 0)
568                 {
569                         dp->dp_Res1 = 0;
570                         dp->dp_Res2 = 0;
571                 }
572                 else
573                 {
574                         struct FileLock *lock = create_and_add_file_lock(res->key, SHARED_LOCK);
575
576                         dbg("  Returning lock $l\n", lock);
577                         dp->dp_Res1 = MKBADDRU(lock);
578                         dp->dp_Res2 = 0;
579                 }
580         }
581
582         reply_packet(dp);
583 }
584
585 void action_examine_object(struct DosPacket *dp)
586 {
587         struct FileLock *lock = (struct FileLock *)BADDR(dp->dp_Arg1);
588         struct FileInfoBlock *fib = (struct FileInfoBlock *)BADDR(dp->dp_Arg2);
589
590         dbg("ACTION_EXAMINE_OBJECT\n");
591         dbg("  lock = $l\n", lock);
592         dbg("  fib = $l\n", fib);
593
594         struct ExamineObjectRequest *req = (struct ExamineObjectRequest *)request_buffer;
595         req->has_response = 0;
596         req->type = dp->dp_Type;
597         req->key = lock == NULL ? 0 : lock->fl_Key;
598
599         write_req_and_wait_for_res(sizeof(struct ExamineObjectRequest));
600
601         struct ExamineObjectResponse *res = (struct ExamineObjectResponse *)request_buffer;
602         if (!res->success)
603         {
604                 dbg("  Failed, error code $l\n", (LONG)res->error_code);
605                 dp->dp_Res1 = DOSFALSE;
606                 dp->dp_Res2 = res->error_code;
607         }
608         else
609         {
610                 int nlen = (unsigned char)(res->data[0]);
611                 memcpy(fib->fib_FileName, res->data, nlen + 1);
612                 fib->fib_FileName[nlen + 1] = 0;
613
614                 int clen = (unsigned char)(res->data[nlen + 1]);
615                 memcpy(fib->fib_Comment, &(res->data[nlen + 1]), clen + 1);
616                 fib->fib_Comment[clen + 1] = 0;
617
618                 fib->fib_DiskKey = res->disk_key;
619                 fib->fib_DirEntryType = res->entry_type;
620                 fib->fib_EntryType = res->entry_type;
621                 fib->fib_Protection = res->protection;
622                 fib->fib_Size = res->size;
623                 fib->fib_NumBlocks = (res->size + 511) >> 9;
624                 fib->fib_Date.ds_Days = res->date[0];
625                 fib->fib_Date.ds_Minute = res->date[1];
626                 fib->fib_Date.ds_Tick = res->date[2];
627
628                 dp->dp_Res1 = DOSTRUE;
629                 dp->dp_Res2 = 0;
630         }
631
632         reply_packet(dp);
633 }
634
635 void action_examine_next(struct DosPacket *dp)
636 {
637         struct FileLock *lock = (struct FileLock *)BADDR(dp->dp_Arg1);
638         struct FileInfoBlock *fib = (struct FileInfoBlock *)BADDR(dp->dp_Arg2);
639
640         dbg("ACTION_EXAMINE_NEXT\n");
641         dbg("  lock = $l\n", lock);
642         dbg("  fib = $l\n", fib);
643
644         struct ExamineNextRequest *req = (struct ExamineNextRequest *)request_buffer;
645         req->has_response = 0;
646         req->type = dp->dp_Type;
647         req->key = lock == NULL ? 0 : lock->fl_Key;
648         req->disk_key = fib->fib_DiskKey;
649
650         write_req_and_wait_for_res(sizeof(struct ExamineNextRequest));
651
652         struct ExamineNextResponse *res = (struct ExamineNextResponse *)request_buffer;
653         if (!res->success)
654         {
655                 dbg("  Failed, error code $l\n", (LONG)res->error_code);
656                 dp->dp_Res1 = DOSFALSE;
657                 dp->dp_Res2 = res->error_code;
658         }
659         else
660         {
661                 int nlen = (unsigned char)(res->data[0]);
662                 memcpy(fib->fib_FileName, res->data, nlen + 1);
663                 fib->fib_FileName[nlen + 1] = 0;
664
665                 int clen = (unsigned char)(res->data[nlen + 1]);
666                 memcpy(fib->fib_Comment, &(res->data[nlen + 1]), clen + 1);
667                 fib->fib_Comment[clen + 1] = 0;
668
669                 fib->fib_DiskKey = res->disk_key;
670                 fib->fib_DirEntryType = res->entry_type;
671                 fib->fib_EntryType = res->entry_type;
672                 fib->fib_Protection = res->protection;
673                 fib->fib_Size = res->size;
674                 fib->fib_NumBlocks = (res->size + 511) >> 9;
675                 fib->fib_Date.ds_Days = res->date[0];
676                 fib->fib_Date.ds_Minute = res->date[1];
677                 fib->fib_Date.ds_Tick = res->date[2];
678
679                 dp->dp_Res1 = DOSTRUE;
680                 dp->dp_Res2 = 0;
681         }
682
683         reply_packet(dp);
684 }
685
686 void action_examine_fh(struct DosPacket *dp)
687 {
688         ULONG arg1 = dp->dp_Arg1;
689         struct FileInfoBlock *fib = (struct FileInfoBlock *)BADDR(dp->dp_Arg2);
690
691         dbg("ACTION_EXAMINE_FH\n");
692         dbg("  arg1 = $l\n", arg1);
693         dbg("  fib = $l\n", fib);
694
695         struct ExamineFhRequest *req = (struct ExamineFhRequest *)request_buffer;
696         req->has_response = 0;
697         req->type = dp->dp_Type;
698         req->arg1 = arg1;
699
700         write_req_and_wait_for_res(sizeof(struct ExamineFhRequest));
701
702         struct ExamineFhResponse *res = (struct ExamineFhResponse *)request_buffer;
703         if (!res->success)
704         {
705                 dbg("  Failed, error code $l\n", (LONG)res->error_code);
706                 dp->dp_Res1 = DOSFALSE;
707                 dp->dp_Res2 = res->error_code;
708         }
709         else
710         {
711                 int nlen = (unsigned char)(res->data[0]);
712                 memcpy(fib->fib_FileName, res->data, nlen + 1);
713                 fib->fib_FileName[nlen + 1] = 0;
714
715                 int clen = (unsigned char)(res->data[nlen + 1]);
716                 memcpy(fib->fib_Comment, &(res->data[nlen + 1]), clen + 1);
717                 fib->fib_Comment[clen + 1] = 0;
718
719                 fib->fib_DiskKey = res->disk_key;
720                 fib->fib_DirEntryType = res->entry_type;
721                 fib->fib_EntryType = res->entry_type;
722                 fib->fib_Protection = res->protection;
723                 fib->fib_Size = res->size;
724                 fib->fib_NumBlocks = (res->size + 511) >> 9;
725                 fib->fib_Date.ds_Days = res->date[0];
726                 fib->fib_Date.ds_Minute = res->date[1];
727                 fib->fib_Date.ds_Tick = res->date[2];
728
729                 dp->dp_Res1 = DOSTRUE;
730                 dp->dp_Res2 = 0;
731         }
732
733         reply_packet(dp);
734 }
735
736 void action_findxxx(struct DosPacket *dp)
737 {
738         struct FileHandle *fh = (struct FileHandle *)BADDR(dp->dp_Arg1);
739         struct FileLock *lock = (struct FileLock *)BADDR(dp->dp_Arg2);
740         unsigned char *name = (unsigned char *)BADDR(dp->dp_Arg3);
741
742         if (dp->dp_Type == ACTION_FINDUPDATE)
743                 dbg("ACTION_FINDUPDATE\n");
744         else if (dp->dp_Type == ACTION_FINDINPUT)
745                 dbg("ACTION_FINDINPUT\n");
746         else if (dp->dp_Type == ACTION_FINDOUTPUT)
747                 dbg("ACTION_FINDOUTPUT\n");
748
749         dbg("  file handle = $l\n", fh);
750         dbg("  lock = $l\n", lock);
751         dbg("  name = $S\n", name);
752
753         struct FindXxxRequest *req = (struct FindXxxRequest *)request_buffer;
754         req->has_response = 0;
755         req->type = dp->dp_Type;
756         req->key = lock == NULL ? 0 : lock->fl_Key;
757
758         int nlen = *name;
759         memcpy(req->name, name, nlen + 1);
760
761         write_req_and_wait_for_res(sizeof(struct FindXxxRequest) + nlen);
762
763         struct FindXxxResponse *res = (struct FindXxxResponse *)request_buffer;
764         if (!res->success)
765         {
766                 dbg("  Failed, error code $l\n", (LONG)res->error_code);
767                 dp->dp_Res1 = DOSFALSE;
768                 dp->dp_Res2 = res->error_code;
769         }
770         else
771         {
772                 fh->fh_Arg1 = res->arg1;
773                 fh->fh_Type = mp;
774                 fh->fh_Port = DOSFALSE;  // Not an interactive file.
775
776                 dp->dp_Res1 = DOSTRUE;
777                 dp->dp_Res2 = 0;
778         }
779
780         reply_packet(dp);
781 }
782
783 void action_read(struct DosPacket *dp)
784 {
785         ULONG arg1 = dp->dp_Arg1;
786         UBYTE *dst = (UBYTE *)dp->dp_Arg2;
787         int length = dp->dp_Arg3;
788
789         dbg("ACTION_READ\n");
790         dbg("  arg1 = $l\n", arg1);
791         dbg("  length = $l\n", length);
792
793         if (length == 0)
794         {
795                 dp->dp_Res1 = -1;
796                 dp->dp_Res2 = ERROR_INVALID_LOCK; // This is not the correct error.
797                 reply_packet(dp);
798                 return;
799         }
800
801         int total_read = 0;
802         while (length)
803         {
804                 int to_read = length;
805                 if (to_read > BUFFER_SIZE)
806                         to_read = BUFFER_SIZE;
807
808                 struct ReadRequest *req = (struct ReadRequest *)request_buffer;
809                 req->has_response = 0;
810                 req->type = dp->dp_Type;
811                 req->arg1 = arg1;
812                 req->address = TranslateAddressA314(data_buffer);
813                 req->length = to_read;
814
815                 write_req_and_wait_for_res(sizeof(struct ReadRequest));
816
817                 struct ReadResponse *res = (struct ReadResponse *)request_buffer;
818                 if (!res->success)
819                 {
820                         dbg("  Failed, error code $l\n", (LONG)res->error_code);
821                         dp->dp_Res1 = -1;
822                         dp->dp_Res2 = res->error_code;
823                         reply_packet(dp);
824                         return;
825                 }
826
827                 if (res->actual)
828                 {
829                         memcpy(dst, data_buffer, res->actual);
830                         dst += res->actual;
831                         total_read += res->actual;
832                         length -= res->actual;
833                 }
834
835                 if (res->actual < to_read)
836                         break;
837         }
838
839         dp->dp_Res1 = total_read;
840         dp->dp_Res2 = 0;
841         reply_packet(dp);
842 }
843
844 void action_write(struct DosPacket *dp)
845 {
846         ULONG arg1 = dp->dp_Arg1;
847         UBYTE *src = (UBYTE *)dp->dp_Arg2;
848         int length = dp->dp_Arg3;
849
850         dbg("ACTION_WRITE\n");
851         dbg("  arg1 = $l\n", arg1);
852         dbg("  length = $l\n", length);
853
854         int total_written = 0;
855         while (length)
856         {
857                 int to_write = length;
858                 if (to_write > BUFFER_SIZE)
859                         to_write = BUFFER_SIZE;
860
861                 memcpy(data_buffer, src, to_write);
862
863                 struct WriteRequest *req = (struct WriteRequest *)request_buffer;
864                 req->has_response = 0;
865                 req->type = dp->dp_Type;
866                 req->arg1 = arg1;
867                 req->address = TranslateAddressA314(data_buffer);
868                 req->length = to_write;
869
870                 write_req_and_wait_for_res(sizeof(struct WriteRequest));
871
872                 struct WriteResponse *res = (struct WriteResponse *)request_buffer;
873                 if (!res->success)
874                 {
875                         dbg("  Failed, error code $l\n", (LONG)res->error_code);
876                         dp->dp_Res1 = total_written;
877                         dp->dp_Res2 = res->error_code;
878                         reply_packet(dp);
879                         return;
880                 }
881
882                 if (res->actual)
883                 {
884                         src += res->actual;
885                         total_written += res->actual;
886                         length -= res->actual;
887                 }
888
889                 if (res->actual < to_write)
890                         break;
891         }
892
893         dp->dp_Res1 = total_written;
894         dp->dp_Res2 = 0;
895         reply_packet(dp);
896 }
897
898 void action_seek(struct DosPacket *dp)
899 {
900         ULONG arg1 = dp->dp_Arg1;
901         LONG new_pos = dp->dp_Arg2;
902         LONG mode = dp->dp_Arg3;
903
904         dbg("ACTION_SEEK\n");
905         dbg("  arg1 = $l\n", arg1);
906         dbg("  new_pos = $l\n", new_pos);
907         dbg("  mode = $l\n", mode);
908
909         struct SeekRequest *req = (struct SeekRequest *)request_buffer;
910         req->has_response = 0;
911         req->type = dp->dp_Type;
912         req->arg1 = arg1;
913         req->new_pos = new_pos;
914         req->mode = mode;
915
916         write_req_and_wait_for_res(sizeof(struct SeekRequest));
917
918         struct SeekResponse *res = (struct SeekResponse *)request_buffer;
919         if (!res->success)
920         {
921                 dbg("  Failed, error code $l\n", (LONG)res->error_code);
922                 dp->dp_Res1 = -1;
923                 dp->dp_Res2 = res->error_code;
924         }
925         else
926         {
927                 dp->dp_Res1 = res->old_pos;
928                 dp->dp_Res2 = 0;
929         }
930
931         reply_packet(dp);
932 }
933
934 void action_end(struct DosPacket *dp)
935 {
936         ULONG arg1 = dp->dp_Arg1;
937
938         dbg("ACTION_END\n");
939         dbg("  arg1 = $l\n", arg1);
940
941         struct EndRequest *req = (struct EndRequest *)request_buffer;
942         req->has_response = 0;
943         req->type = dp->dp_Type;
944         req->arg1 = arg1;
945
946         write_req_and_wait_for_res(sizeof(struct EndRequest));
947
948         //struct EndResponse *res = (struct EndResponse *)request_buffer;
949
950         dp->dp_Res1 = DOSTRUE;
951         dp->dp_Res2 = 0;
952         reply_packet(dp);
953 }
954
955 void action_delete_object(struct DosPacket *dp)
956 {
957         struct FileLock *lock = (struct FileLock *)BADDR(dp->dp_Arg1);
958         unsigned char *name = (unsigned char *)BADDR(dp->dp_Arg2);
959
960         dbg("ACTION_DELETE_OBJECT\n");
961         dbg("  lock = $l\n", lock);
962         dbg("  name = $S\n", name);
963
964         struct DeleteObjectRequest *req = (struct DeleteObjectRequest *)request_buffer;
965         req->has_response = 0;
966         req->type = dp->dp_Type;
967         req->key = lock == NULL ? 0 : lock->fl_Key;
968
969         int nlen = *name;
970         memcpy(req->name, name, nlen + 1);
971
972         write_req_and_wait_for_res(sizeof(struct DeleteObjectRequest) + nlen);
973
974         struct DeleteObjectResponse *res = (struct DeleteObjectResponse *)request_buffer;
975         if (!res->success)
976         {
977                 dbg("  Failed, error code $l\n", (LONG)res->error_code);
978                 dp->dp_Res1 = DOSFALSE;
979                 dp->dp_Res2 = res->error_code;
980         }
981         else
982         {
983                 dp->dp_Res1 = DOSTRUE;
984                 dp->dp_Res2 = 0;
985         }
986
987         reply_packet(dp);
988 }
989
990 void action_rename_object(struct DosPacket *dp)
991 {
992         struct FileLock *lock = (struct FileLock *)BADDR(dp->dp_Arg1);
993         unsigned char *name = (unsigned char *)BADDR(dp->dp_Arg2);
994         struct FileLock *target_dir = (struct FileLock *)BADDR(dp->dp_Arg3);
995         unsigned char *new_name = (unsigned char *)BADDR(dp->dp_Arg4);
996
997         dbg("ACTION_RENAME_OBJECT\n");
998         dbg("  lock = $l\n", lock);
999         dbg("  name = $S\n", name);
1000         dbg("  target directory = $l\n", lock);
1001         dbg("  new name = $S\n", new_name);
1002
1003         struct RenameObjectRequest *req = (struct RenameObjectRequest *)request_buffer;
1004         req->has_response = 0;
1005         req->type = dp->dp_Type;
1006         req->key = lock == NULL ? 0 : lock->fl_Key;
1007         req->target_dir = target_dir == NULL ? 0 : target_dir->fl_Key;
1008
1009         int nlen = *name;
1010         int nnlen = *new_name;
1011
1012         req->name_len = nlen;
1013         req->new_name_len = nnlen;
1014
1015         unsigned char *p = &(req->new_name_len) + 1;
1016         memcpy(p, name + 1, nlen);
1017         p += nlen;
1018         memcpy(p, new_name + 1, nnlen);
1019
1020         write_req_and_wait_for_res(sizeof(struct RenameObjectRequest) + nlen + nnlen);
1021
1022         struct RenameObjectResponse *res = (struct RenameObjectResponse *)request_buffer;
1023         if (!res->success)
1024         {
1025                 dbg("  Failed, error code $l\n", (LONG)res->error_code);
1026                 dp->dp_Res1 = DOSFALSE;
1027                 dp->dp_Res2 = res->error_code;
1028         }
1029         else
1030         {
1031                 dp->dp_Res1 = DOSTRUE;
1032                 dp->dp_Res2 = 0;
1033         }
1034
1035         reply_packet(dp);
1036 }
1037
1038 void action_create_dir(struct DosPacket *dp)
1039 {
1040         struct FileLock *lock = (struct FileLock *)BADDR(dp->dp_Arg1);
1041         unsigned char *name = (unsigned char *)BADDR(dp->dp_Arg2);
1042
1043         dbg("ACTION_CREATE_DIR\n");
1044         dbg("  lock = $l\n", lock);
1045         dbg("  name = $S\n", name);
1046
1047         struct CreateDirRequest *req = (struct CreateDirRequest *)request_buffer;
1048         req->has_response = 0;
1049         req->type = dp->dp_Type;
1050         req->key = lock == NULL ? 0 : lock->fl_Key;
1051
1052         int nlen = *name;
1053         memcpy(req->name, name, nlen + 1);
1054
1055         write_req_and_wait_for_res(sizeof(struct CreateDirRequest) + nlen);
1056
1057         struct CreateDirResponse *res = (struct CreateDirResponse *)request_buffer;
1058         if (!res->success)
1059         {
1060                 dbg("  Failed, error code $l\n", (LONG)res->error_code);
1061                 dp->dp_Res1 = DOSFALSE;
1062                 dp->dp_Res2 = res->error_code;
1063         }
1064         else
1065         {
1066                 struct FileLock *lock = create_and_add_file_lock(res->key, SHARED_LOCK);
1067
1068                 dbg("  Returning lock $l\n", lock);
1069                 dp->dp_Res1 = MKBADDRU(lock);
1070                 dp->dp_Res2 = 0;
1071         }
1072
1073         reply_packet(dp);
1074 }
1075
1076 void action_set_protect(struct DosPacket *dp)
1077 {
1078         struct FileLock *lock = (struct FileLock *)BADDR(dp->dp_Arg2);
1079         unsigned char *name = (unsigned char *)BADDR(dp->dp_Arg3);
1080         long mask = dp->dp_Arg4;
1081
1082         dbg("ACTION_SET_PROTECT\n");
1083         dbg("  lock = $l\n", lock);
1084         dbg("  name = $S\n", name);
1085         dbg("  mask = $l\n", mask);
1086
1087         struct SetProtectRequest *req = (struct SetProtectRequest *)request_buffer;
1088         req->has_response = 0;
1089         req->type = dp->dp_Type;
1090         req->key = lock == NULL ? 0 : lock->fl_Key;
1091         req->mask = mask;
1092
1093         int nlen = *name;
1094         memcpy(req->name, name, nlen + 1);
1095
1096         write_req_and_wait_for_res(sizeof(struct SetProtectRequest) + nlen);
1097
1098         struct SetProtectResponse *res = (struct SetProtectResponse *)request_buffer;
1099         if (!res->success)
1100         {
1101                 dbg("  Failed, error code $l\n", (LONG)res->error_code);
1102                 dp->dp_Res1 = DOSFALSE;
1103                 dp->dp_Res2 = res->error_code;
1104         }
1105         else
1106         {
1107                 dp->dp_Res1 = DOSTRUE;
1108                 dp->dp_Res2 = 0;
1109         }
1110
1111         reply_packet(dp);
1112 }
1113
1114 void action_set_comment(struct DosPacket *dp)
1115 {
1116         struct FileLock *lock = (struct FileLock *)BADDR(dp->dp_Arg2);
1117         unsigned char *name = (unsigned char *)BADDR(dp->dp_Arg3);
1118         unsigned char *comment = (unsigned char *)BADDR(dp->dp_Arg4);
1119
1120         dbg("ACTION_SET_COMMENT\n");
1121         dbg("  lock = $l\n", lock);
1122         dbg("  name = $S\n", name);
1123         dbg("  comment = $S\n", comment);
1124
1125         struct SetCommentRequest *req = (struct SetCommentRequest *)request_buffer;
1126         req->has_response = 0;
1127         req->type = dp->dp_Type;
1128         req->key = lock == NULL ? 0 : lock->fl_Key;
1129
1130         int nlen = *name;
1131         int clen = *comment;
1132
1133         req->name_len = nlen;
1134         req->comment_len = clen;
1135
1136         unsigned char *p = &(req->comment_len) + 1;
1137         memcpy(p, name + 1, nlen);
1138         p += nlen;
1139         memcpy(p, comment + 1, clen);
1140
1141         write_req_and_wait_for_res(sizeof(struct SetCommentRequest) + nlen + clen);
1142
1143         struct SetCommentResponse *res = (struct SetCommentResponse *)request_buffer;
1144         if (!res->success)
1145         {
1146                 dbg("  Failed, error code $l\n", (LONG)res->error_code);
1147                 dp->dp_Res1 = DOSFALSE;
1148                 dp->dp_Res2 = res->error_code;
1149         }
1150         else
1151         {
1152                 dp->dp_Res1 = DOSTRUE;
1153                 dp->dp_Res2 = 0;
1154         }
1155
1156         reply_packet(dp);
1157 }
1158
1159 void action_same_lock(struct DosPacket *dp)
1160 {
1161         struct FileLock *lock1 = (struct FileLock *)BADDR(dp->dp_Arg1);
1162         struct FileLock *lock2 = (struct FileLock *)BADDR(dp->dp_Arg2);
1163
1164         dbg("ACTION_SAME_LOCK\n");
1165         dbg("  locks to compare = $l $l\n", lock1, lock2);
1166
1167         struct SameLockRequest *req = (struct SameLockRequest *)request_buffer;
1168         req->has_response = 0;
1169         req->type = dp->dp_Type;
1170         req->key1 = lock1->fl_Key;
1171         req->key2 = lock2->fl_Key;
1172
1173         write_req_and_wait_for_res(sizeof(struct SameLockRequest));
1174
1175         struct SameLockResponse *res = (struct SameLockResponse *)request_buffer;
1176         dp->dp_Res1 = res->success ? DOSTRUE : DOSFALSE;
1177         dp->dp_Res2 = res->error_code;
1178
1179         reply_packet(dp);
1180 }
1181
1182 void fill_info_data(struct InfoData *id)
1183 {
1184         memset(id, 0, sizeof(struct InfoData));
1185         id->id_DiskState = ID_VALIDATED;
1186         id->id_NumBlocks = 512 * 1024;
1187         id->id_NumBlocksUsed = 10;
1188         id->id_BytesPerBlock = 512;
1189         id->id_DiskType = my_volume->dl_DiskType;
1190         id->id_VolumeNode = MKBADDRU(my_volume);
1191         id->id_InUse = DOSTRUE;
1192 }
1193
1194 void action_info(struct DosPacket *dp)
1195 {
1196         struct FileLock *lock = (struct FileLock *)BADDR(dp->dp_Arg1);
1197         struct InfoData *id = (struct InfoData *)BADDR(dp->dp_Arg2);
1198
1199         dbg("ACTION_INFO\n");
1200         dbg("  lock = $l\n", lock);
1201
1202         fill_info_data(id);
1203
1204         dp->dp_Res1 = DOSTRUE;
1205         dp->dp_Res2 = 0;
1206         reply_packet(dp);
1207 }
1208
1209 void action_disk_info(struct DosPacket *dp)
1210 {
1211         struct InfoData *id = (struct InfoData *)BADDR(dp->dp_Arg1);
1212
1213         dbg("ACTION_DISK_INFO\n");
1214
1215         fill_info_data(id);
1216
1217         dp->dp_Res1 = DOSTRUE;
1218         dp->dp_Res2 = 0;
1219         reply_packet(dp);
1220 }
1221
1222 void action_unsupported(struct DosPacket *dp)
1223 {
1224         dbg("ACTION_UNSUPPORTED\n");
1225         dbg("  Unsupported action: $l\n", (ULONG)dp->dp_Type);
1226
1227         struct UnsupportedRequest *req = (struct UnsupportedRequest *)request_buffer;
1228         req->has_response = 0;
1229         req->type = ACTION_UNSUPPORTED;
1230         req->dp_Type = dp->dp_Type;
1231
1232         write_req_and_wait_for_res(sizeof(struct UnsupportedRequest));
1233
1234         struct UnsupportedResponse *res = (struct UnsupportedResponse *)request_buffer;
1235         dp->dp_Res1 = res->success ? DOSTRUE : DOSFALSE;
1236         dp->dp_Res2 = res->error_code;
1237         reply_packet(dp);
1238 }
1239
1240 void start(__reg("a0") struct DosPacket *startup_packet)
1241 {
1242         SysBase = *(struct ExecBase **)4;
1243         DOSBase = (struct DosLibrary *)OpenLibrary(DOSNAME, 0);
1244
1245         mp = MyCreatePort(NULL, 0);
1246
1247         startup_fs_handler(startup_packet);
1248
1249         while (1)
1250         {
1251                 WaitPort(mp);
1252                 struct StandardPacket *sp = (struct StandardPacket *)GetMsg(mp);
1253                 struct DosPacket *dp = (struct DosPacket *)(sp->sp_Msg.mn_Node.ln_Name);
1254
1255                 switch (dp->dp_Type)
1256                 {
1257                 case ACTION_LOCATE_OBJECT: action_locate_object(dp); break;
1258                 case ACTION_FREE_LOCK: action_free_lock(dp); break;
1259                 case ACTION_COPY_DIR: action_copy_dir(dp); break;
1260                 case ACTION_PARENT: action_parent(dp); break;
1261                 case ACTION_EXAMINE_OBJECT: action_examine_object(dp); break;
1262                 case ACTION_EXAMINE_NEXT: action_examine_next(dp); break;
1263                 case ACTION_EXAMINE_FH: action_examine_fh(dp); break;
1264
1265                 case ACTION_FINDUPDATE: action_findxxx(dp); break;
1266                 case ACTION_FINDINPUT: action_findxxx(dp); break;
1267                 case ACTION_FINDOUTPUT: action_findxxx(dp); break;
1268                 case ACTION_READ: action_read(dp); break;
1269                 case ACTION_WRITE: action_write(dp); break;
1270                 case ACTION_SEEK: action_seek(dp); break;
1271                 case ACTION_END: action_end(dp); break;
1272                 //case ACTION_TRUNCATE: action_truncate(dp); break;
1273
1274                 case ACTION_DELETE_OBJECT: action_delete_object(dp); break;
1275                 case ACTION_RENAME_OBJECT: action_rename_object(dp); break;
1276                 case ACTION_CREATE_DIR: action_create_dir(dp); break;
1277
1278                 case ACTION_SET_PROTECT: action_set_protect(dp); break;
1279                 case ACTION_SET_COMMENT: action_set_comment(dp); break;
1280                 //case ACTION_SET_DATE: action_set_date(dp); break;
1281
1282                 case ACTION_SAME_LOCK: action_same_lock(dp); break;
1283                 case ACTION_DISK_INFO: action_disk_info(dp); break;
1284                 case ACTION_INFO: action_info(dp); break;
1285
1286                 /*
1287                 case ACTION_CURRENT_VOLUME: action_current_volume(dp); break;
1288                 case ACTION_RENAME_DISK: action_rename_disk(dp); break;
1289
1290                 case ACTION_DIE: //action_die(dp); break;
1291                 case ACTION_MORE_CACHE: //action_more_cache(dp); break;
1292                 case ACTION_FLUSH: //action_flush(dp); break;
1293                 case ACTION_INHIBIT: //action_inhibit(dp); break;
1294                 case ACTION_WRITE_PROTECT: //action_write_protect(dp); break;
1295                 */
1296
1297                 default: action_unsupported(dp); break;
1298                 }
1299         }
1300
1301         dbg("Shutting down\n");
1302
1303         // More cleaning up is necessary if the handler is to exit.
1304         CloseLibrary((struct Library *)DOSBase);
1305 }