added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / workbench / fs / fat / packet.c
bloba43a2c1995119138691a56ee93390df9e818b029
1 /*
2 * fat.handler - FAT12/16/32 filesystem handler
4 * Copyright © 2006 Marek Szyprowski
5 * Copyright © 2007 The AROS Development Team
7 * This program is free software; you can redistribute it and/or modify it
8 * under the same terms as AROS itself.
10 * $Id$
13 #include <exec/types.h>
14 #include <exec/execbase.h>
15 #include <dos/dosextens.h>
16 #include <dos/filehandler.h>
17 #include <dos/notify.h>
18 #include <devices/inputevent.h>
20 #include <proto/exec.h>
21 #include <proto/dos.h>
23 #include <string.h>
25 #include "fat_fs.h"
26 #include "fat_protos.h"
28 #define DEBUG DEBUG_PACKETS
29 #include <aros/debug.h>
31 void ProcessPackets(void) {
32 struct Message *msg;
33 struct DosPacket *pkt;
34 struct MsgPort *rp;
36 while ((msg = GetMsg(glob->ourport)) != NULL) {
37 LONG res = DOSFALSE;
38 LONG err = 0;
40 pkt = (struct DosPacket *) msg->mn_Node.ln_Name;
42 switch(pkt->dp_Type) {
43 case ACTION_LOCATE_OBJECT: {
44 struct ExtFileLock *fl = BADDR(pkt->dp_Arg1), *lock;
45 UBYTE *path = BADDR(pkt->dp_Arg2);
46 LONG access = pkt->dp_Arg3;
48 D(bug("[fat] LOCATE_OBJECT: lock 0x%08x (dir %ld/%ld) name '%.*s' type %s\n",
49 pkt->dp_Arg1,
50 fl != NULL ? fl->gl->dir_cluster : 0, fl != NULL ? fl->gl->dir_entry : 0,
51 path[0], &path[1],
52 pkt->dp_Arg3 == EXCLUSIVE_LOCK ? "EXCLUSIVE" : "SHARED"));
54 if ((err = TestLock(fl)))
55 break;
57 if ((err = OpLockFile(fl, &path[1], path[0], access, &lock)) == 0)
58 res = MKBADDR(lock);
60 break;
63 case ACTION_FREE_LOCK: {
64 struct ExtFileLock *fl = BADDR(pkt->dp_Arg1);
66 D(bug("[fat] FREE_LOCK: lock 0x%08x (dir %ld/%ld)\n",
67 pkt->dp_Arg1,
68 fl != NULL ? fl->gl->dir_cluster : 0, fl != NULL ? fl->gl->dir_entry : 0));
70 OpUnlockFile(fl);
72 res = DOSTRUE;
73 break;
76 case ACTION_COPY_DIR:
77 case ACTION_COPY_DIR_FH: {
78 struct ExtFileLock *fl = BADDR(pkt->dp_Arg1), *lock;
80 D(bug("[fat] COPY_DIR: lock 0x%08x (dir %ld/%ld)\n",
81 pkt->dp_Arg1,
82 fl != NULL ? fl->gl->dir_cluster : 0, fl != NULL ? fl->gl->dir_entry : 0));
84 if ((err = TestLock(fl)))
85 break;
87 if ((err = OpCopyLock(fl, &lock)) == 0)
88 res = MKBADDR(lock);
90 break;
93 case ACTION_PARENT:
94 case ACTION_PARENT_FH: {
95 struct ExtFileLock *fl = BADDR(pkt->dp_Arg1), *lock;
97 D(bug("[fat] ACTION_PARENT: lock 0x%08x (dir %ld/%ld)\n",
98 pkt->dp_Arg1,
99 fl != NULL ? fl->gl->dir_cluster : 0, fl != NULL ? fl->gl->dir_entry : 0));
101 if ((err = TestLock(fl)))
102 break;
104 if ((err = OpLockParent(fl, &lock)) == 0)
105 res = MKBADDR(lock);
107 break;
110 case ACTION_SAME_LOCK: {
111 struct ExtFileLock *fl1 = BADDR(pkt->dp_Arg1);
112 struct ExtFileLock *fl2 = BADDR(pkt->dp_Arg2);
114 D(bug("[fat] ACTION_SAME_LOCK: lock #1 0x%08x (dir %ld/%ld) lock #2 0x%08x (dir %ld/%ld)\n",
115 pkt->dp_Arg1,
116 fl1 != NULL ? fl1->gl->dir_cluster : 0, fl1 != NULL ? fl1->gl->dir_entry : 0,
117 pkt->dp_Arg2,
118 fl2 != NULL ? fl2->gl->dir_cluster : 0, fl2 != NULL ? fl2->gl->dir_entry : 0));
120 err = 0;
122 if (fl1 == fl2 || fl1->gl == fl2->gl)
123 res = DOSTRUE;
125 break;
128 case ACTION_EXAMINE_OBJECT:
129 case ACTION_EXAMINE_FH: {
130 struct ExtFileLock *fl = BADDR(pkt->dp_Arg1);
131 struct FileInfoBlock *fib = BADDR(pkt->dp_Arg2);
133 D(bug("[fat] EXAMINE_OBJECT: lock 0x%08x (dir %ld/%ld)\n",
134 pkt->dp_Arg1,
135 fl != NULL ? fl->gl->dir_cluster : 0, fl != NULL ? fl->gl->dir_entry : 0));
137 if ((err = TestLock(fl)))
138 break;
140 if ((err = FillFIB(fl, fib)) == 0)
141 res = DOSTRUE;
143 break;
146 case ACTION_EXAMINE_NEXT: {
147 struct ExtFileLock *fl = BADDR(pkt->dp_Arg1), *lock;
148 struct FileInfoBlock *fib = BADDR(pkt->dp_Arg2);
149 struct DirHandle dh;
150 struct DirEntry de;
152 D(bug("[fat] EXAMINE_NEXT: lock 0x%08x (dir %ld/%ld)\n",
153 pkt->dp_Arg1,
154 fl != NULL ? fl->gl->dir_cluster : 0, fl != NULL ? fl->gl->dir_entry : 0));
156 if ((err = TestLock(fl)))
157 break;
159 if ((err = InitDirHandle(glob->sb, fl->ioh.first_cluster, &dh)) != 0)
160 break;
162 dh.cur_index = fib->fib_DiskKey;
164 if ((err = GetNextDirEntry(&dh, &de)) != 0) {
165 if (err == ERROR_OBJECT_NOT_FOUND)
166 err = ERROR_NO_MORE_ENTRIES;
167 ReleaseDirHandle(&dh);
168 break;
171 if ((err = LockFile(fl->ioh.first_cluster, dh.cur_index, SHARED_LOCK, &lock)) != 0) {
172 ReleaseDirHandle(&dh);
173 break;
176 if ((err = FillFIB(lock, fib))) {
177 FreeLock(lock);
178 ReleaseDirHandle(&dh);
179 break;
182 fib->fib_DiskKey = dh.cur_index;
184 FreeLock(lock);
186 ReleaseDirHandle(&dh);
188 res = DOSTRUE;
190 break;
193 case ACTION_FINDINPUT:
194 case ACTION_FINDOUTPUT:
195 case ACTION_FINDUPDATE: {
196 struct FileHandle *fh = BADDR(pkt->dp_Arg1);
197 struct ExtFileLock *fl = BADDR(pkt->dp_Arg2);
198 UBYTE *path = BADDR(pkt->dp_Arg3);
199 struct ExtFileLock *lock;
201 D(bug("[fat] %s: lock 0x%08x (dir %ld/%ld) path '%.*s'\n",
202 pkt->dp_Type == ACTION_FINDINPUT ? "FINDINPUT" :
203 pkt->dp_Type == ACTION_FINDOUTPUT ? "FINDOUTPUT" :
204 "FINDUPDATE",
205 pkt->dp_Arg2,
206 fl != NULL ? fl->gl->dir_cluster : 0, fl != NULL ? fl->gl->dir_entry : 0,
207 path[0], &path[1]));
209 if ((err = TestLock(fl)))
210 break;
212 if ((err = OpOpenFile(fl, &path[1], path[0], pkt->dp_Type, &lock)) != 0)
213 break;
215 fh->fh_Arg1 = MKBADDR(lock);
216 fh->fh_Port = DOSFALSE;
218 res = DOSTRUE;
220 break;
223 case ACTION_READ: {
224 struct ExtFileLock *fl = BADDR(pkt->dp_Arg1);
225 APTR buffer = (APTR)pkt->dp_Arg2;
226 ULONG want = pkt->dp_Arg3;
228 D(bug("[fat] READ: lock 0x%08x (dir %ld/%ld pos %ld) want %ld\n",
229 pkt->dp_Arg1,
230 fl != NULL ? fl->gl->dir_cluster : 0, fl != NULL ? fl->gl->dir_entry : 0,
231 fl->pos,
232 want));
234 if ((err = TestLock(fl))) {
235 res = -1;
236 break;
239 if ((err = OpRead(fl, buffer, want, &res)) != 0)
240 res = -1;
242 break;
245 case ACTION_WRITE: {
246 struct ExtFileLock *fl = BADDR(pkt->dp_Arg1);
247 APTR buffer = (APTR)pkt->dp_Arg2;
248 ULONG want = pkt->dp_Arg3;
250 D(bug("[fat] WRITE: lock 0x%08x (dir %ld/%ld pos %ld) want %ld\n",
251 pkt->dp_Arg1,
252 fl != NULL ? fl->gl->dir_cluster : 0, fl != NULL ? fl->gl->dir_entry : 0,
253 fl->pos,
254 want));
256 if ((err = TestLock(fl))) {
257 res = -1;
258 break;
261 if ((err = OpWrite(fl, buffer, want, &res)) != 0)
262 res = -1;
264 break;
267 case ACTION_SEEK: {
268 struct ExtFileLock *fl = BADDR(pkt->dp_Arg1);
269 LONG offset = pkt->dp_Arg2;
270 ULONG whence = pkt->dp_Arg3;
272 D(bug("[fat] SEEK: lock 0x%08x (dir %ld/%ld pos %ld) offset %ld whence %s\n",
273 pkt->dp_Arg1,
274 fl != NULL ? fl->gl->dir_cluster : 0, fl != NULL ? fl->gl->dir_entry : 0,
275 fl->pos,
276 offset,
277 whence == OFFSET_BEGINNING ? "BEGINNING" :
278 whence == OFFSET_END ? "END" :
279 whence == OFFSET_CURRENT ? "CURRENT" :
280 "(unknown)"));
282 if ((err = TestLock(fl))) {
283 res = -1;
284 break;
287 res = fl->pos;
288 err = 0;
290 if (whence == OFFSET_BEGINNING &&
291 offset >= 0 &&
292 offset <= fl->gl->size)
293 fl->pos = offset;
294 else if (whence == OFFSET_CURRENT &&
295 offset + fl->pos >= 0 &&
296 offset + fl->pos <= fl->gl->size)
297 fl->pos += offset;
298 else if (whence == OFFSET_END
299 && offset <= 0
300 && fl->gl->size + offset >= 0)
301 fl->pos = fl->gl->size + offset;
302 else {
303 res = -1;
304 err = ERROR_SEEK_ERROR;
307 break;
310 case ACTION_SET_FILE_SIZE: {
311 struct ExtFileLock *fl = BADDR(pkt->dp_Arg1);
312 LONG offset = pkt->dp_Arg2;
313 LONG whence = pkt->dp_Arg3;
315 D(bug("[fat] SET_FILE_SIZE: lock 0x%08x (dir %ld/%ld pos %ld) offset %ld whence %s\n",
316 pkt->dp_Arg1,
317 fl != NULL ? fl->gl->dir_cluster : 0, fl != NULL ? fl->gl->dir_entry : 0,
318 fl->pos,
319 offset,
320 whence == OFFSET_BEGINNING ? "BEGINNING" :
321 whence == OFFSET_END ? "END" :
322 whence == OFFSET_CURRENT ? "CURRENT" :
323 "(unknown)"));
325 if ((err = TestLock(fl))) {
326 res = -1;
327 break;
330 if ((err = OpSetFileSize(fl, offset, whence, &res)) != 0)
331 res = -1;
333 break;
336 case ACTION_END: {
337 struct ExtFileLock *fl = BADDR(pkt->dp_Arg1);
339 D(bug("[fat] END: lock 0x%08x (dir %ld/%ld)\n",
340 pkt->dp_Arg1,
341 fl != NULL ? fl->gl->dir_cluster : 0, fl != NULL ? fl->gl->dir_entry : 0));
343 if ((err = TestLock(fl)))
344 break;
346 FreeLock(fl);
348 res = DOSTRUE;
349 break;
352 case ACTION_IS_FILESYSTEM:
353 D(bug("[fat] IS_FILESYSTEM\n"));
355 res = DOSTRUE;
356 break;
358 case ACTION_CURRENT_VOLUME: {
359 struct ExtFileLock *fl = BADDR(pkt->dp_Arg1);
361 D(bug("[fat] CURRENT_VOLUME: lock 0x%08x\n",
362 pkt->dp_Arg1));
364 res = (fl) ? fl->fl_Volume : ((glob->sb != NULL) ? MKBADDR(glob->sb->doslist) : NULL);
365 break;
368 case ACTION_INFO:
369 case ACTION_DISK_INFO: {
370 struct InfoData *id;
372 if (pkt->dp_Type == ACTION_INFO) {
373 struct FileLock *fl = BADDR(pkt->dp_Arg1);
375 D(bug("[fat] INFO: lock 0x%08x\n",
376 pkt->dp_Arg1));
378 if (fl && (glob->sb == NULL || fl->fl_Volume != MKBADDR(glob->sb->doslist))) {
379 err = ERROR_DEVICE_NOT_MOUNTED;
380 break;
383 id = BADDR(pkt->dp_Arg2);
385 else {
386 D(bug("[fat] DISK_INFO\n"));
388 id = BADDR(pkt->dp_Arg1);
391 FillDiskInfo(id);
393 res = DOSTRUE;
394 break;
397 case ACTION_INHIBIT: {
398 LONG inhibit = pkt->dp_Arg1;
400 D(bug("[fat] INHIBIT: %sinhibit\n",
401 inhibit == DOSTRUE ? "" : "un"));
403 if (inhibit == DOSTRUE) {
404 glob->disk_inhibited++;
405 if (glob->disk_inhibited == 1)
406 DoDiskRemove();
408 else {
409 glob->disk_inhibited--;
410 if (glob->disk_inhibited == 0)
411 ProcessDiskChange();
414 res = DOSTRUE;
415 break;
418 case ACTION_DIE: {
419 D(bug("[fat] DIE\n"));
421 if (glob->sblist != NULL || (glob->sb != NULL && glob->sb->doslist->dol_misc.dol_volume.dol_LockList != NULL)) {
422 D(bug("\tThere are some locks/volumes left. Shutting down is not possible\n"));
423 err = ERROR_OBJECT_IN_USE;
424 break;
427 D(bug("\tNo locks pending. Shutting down the handler\n"));
429 DoDiskRemove(); /* risky, because of async. volume remove, but works */
431 glob->quit = TRUE;
432 glob->devnode->dol_Task = NULL;
434 res = DOSTRUE;
435 break;
438 #if 0
439 /* XXX AROS needs these ACTION_ headers defined in dos/dosextens.h */
441 case ACTION_GET_DISK_FSSM: {
442 D(bug("\nGot ACTION_GET_DISK_FSSM\n"));
444 res = (ULONG) glob->fssm;
445 break;
448 case ACTION_FREE_DISK_FSSM: {
449 D(bug("\nGot ACTION_FREE_DISK_FSSM\n"));
451 res = DOSTRUE;
452 break;
455 #endif
457 case ACTION_DISK_CHANGE: { /* internal */
458 struct DosList *vol = (struct DosList *)pkt->dp_Arg2;
459 ULONG type = pkt->dp_Arg3;
461 D(bug("[fat] DISK_CHANGE [INTERNAL]\n"));
463 if (pkt->dp_Arg1 == ID_FAT_DISK) { /* security check */
465 if (AttemptLockDosList(LDF_VOLUMES|LDF_WRITE)) {
467 if (type == ACTION_VOLUME_ADD) {
468 AddDosEntry(vol);
469 UnLockDosList(LDF_VOLUMES|LDF_WRITE);
471 SendEvent(IECLASS_DISKINSERTED);
473 D(bug("\tVolume added successfuly\n"));
475 else if (type == ACTION_VOLUME_REMOVE) {
476 RemDosEntry(vol);
477 FreeVecPooled(glob->mempool, vol);
478 UnLockDosList(LDF_VOLUMES|LDF_WRITE);
480 SendEvent(IECLASS_DISKREMOVED);
482 D(bug("\tVolume removed successfuly.\n"));
485 FreeDosObject(DOS_STDPKT, pkt); /* cleanup */
487 pkt = NULL;
488 D(bug("Packet destroyed\n"));
491 else {
492 D(bug("\tDosList is locked\n"));
493 Delay(5);
494 PutMsg(glob->ourport, pkt->dp_Link);
495 pkt = NULL;
496 D(bug("Message moved to the end of the queue\n"));
499 else
500 err = ERROR_OBJECT_WRONG_TYPE;
502 break;
505 case ACTION_RENAME_DISK: {
506 UBYTE *name = BADDR(pkt->dp_Arg1);
508 D(bug("[fat] RENAME_DISK: name '%.*s'\n",
509 name[0], &name[1]));
511 if (glob->sb->doslist == NULL) {
512 err = glob->disk_inserted ? ERROR_NOT_A_DOS_DISK : ERROR_NO_DISK;
513 break;
516 while (! AttemptLockDosList(LDF_VOLUMES | LDF_WRITE))
517 ProcessPackets();
519 err = SetVolumeName(glob->sb, name);
520 UnLockDosList(LDF_VOLUMES | LDF_WRITE);
521 if (err != 0)
522 break;
524 SendEvent(IECLASS_DISKINSERTED);
526 res = DOSTRUE;
528 break;
531 case ACTION_DELETE_OBJECT: {
532 struct ExtFileLock *fl = BADDR(pkt->dp_Arg1);
533 UBYTE *name = BADDR(pkt->dp_Arg2);
535 D(bug("[fat] DELETE_OBJECT: lock 0x%08x (dir %ld/%ld) path '%.*s'\n",
536 pkt->dp_Arg1,
537 fl != NULL ? fl->gl->dir_cluster : 0, fl != NULL ? fl->gl->dir_entry : 0,
538 name[0], &name[1]));
540 if ((err = TestLock(fl)))
541 break;
543 err = OpDeleteFile(fl, &name[1], name[0]);
545 break;
548 case ACTION_RENAME_OBJECT: {
549 struct ExtFileLock *sfl = BADDR(pkt->dp_Arg1), *dfl = BADDR(pkt->dp_Arg3);
550 UBYTE *sname = BADDR(pkt->dp_Arg2), *dname = BADDR(pkt->dp_Arg4);
552 D(bug("[fat] RENAME_OBJECT: srclock 0x%08x (dir %ld/%ld) name '%.*s' destlock 0x%08x (dir %ld/%ld) name '%.*s'\n",
553 pkt->dp_Arg1,
554 sfl != NULL ? sfl->gl->dir_cluster : 0, sfl != NULL ? sfl->gl->dir_entry : 0,
555 sname[0], &sname[1],
556 pkt->dp_Arg3,
557 dfl != NULL ? dfl->gl->dir_cluster : 0, dfl != NULL ? dfl->gl->dir_entry : 0,
558 dname[0], &dname[1]));
560 if ((err = TestLock(sfl)) != 0 || (err = TestLock(dfl)) != 0)
561 break;
563 err = OpRenameFile(sfl, &sname[1], sname[0], dfl, &dname[1], dname[0]);
565 break;
568 case ACTION_CREATE_DIR: {
569 struct ExtFileLock *fl = BADDR(pkt->dp_Arg1), *new;
570 UBYTE *name = BADDR(pkt->dp_Arg2);
572 D(bug("[fat] CREATE_DIR: lock 0x%08x (dir %ld/%ld) name '%.*s'\n",
573 pkt->dp_Arg1,
574 fl != NULL ? fl->gl->dir_cluster : 0, fl != NULL ? fl->gl->dir_entry : 0,
575 name[0], &name[1]));
577 if ((err = TestLock(fl)))
578 break;
580 if ((err = OpCreateDir(fl, &name[1], name[0], &new)) == 0)
581 res = MKBADDR(new);
583 break;
586 case ACTION_SET_PROTECT: {
587 struct ExtFileLock *fl = BADDR(pkt->dp_Arg2);
588 UBYTE *name = BADDR(pkt->dp_Arg3);
589 ULONG prot = pkt->dp_Arg4;
591 D(bug("[fat] SET_PROTECT: lock 0x%08x (dir %ld/%ld) name '%.*s' prot 0x%08x\n",
592 pkt->dp_Arg2,
593 fl != NULL ? fl->gl->dir_cluster : 0, fl != NULL ? fl->gl->dir_entry : 0,
594 name[0], &name[1],
595 prot));
597 if ((err = TestLock(fl)))
598 break;
600 err = OpSetProtect(fl, &name[1], name[0], prot);
602 break;
605 case ACTION_SET_DATE: {
606 struct ExtFileLock *fl = BADDR(pkt->dp_Arg2);
607 UBYTE *name = BADDR(pkt->dp_Arg3);
608 struct DateStamp *ds = pkt->dp_Arg4;
610 #if defined(DEBUG) && DEBUG != 0
612 struct DateTime dt;
613 char datestr[LEN_DATSTRING];
615 dt.dat_Stamp = *ds;
616 dt.dat_Format = FORMAT_DOS;
617 dt.dat_Flags = 0;
618 dt.dat_StrDay = NULL;
619 dt.dat_StrDate = datestr;
620 dt.dat_StrTime = NULL;
621 DateToStr(&dt);
623 D(bug("[fat] SET_DATE: lock 0x%08x (dir %ld/%ld) name '%.*s' ds '%s'\n",
624 pkt->dp_Arg2,
625 fl != NULL ? fl->gl->dir_cluster : 0, fl != NULL ? fl->gl->dir_entry : 0,
626 name[0], &name[1],
627 datestr));
629 #endif
631 if ((err = TestLock(fl)))
632 break;
634 err = OpSetDate(fl, &name[1], name[0], ds);
636 break;
639 case ACTION_ADD_NOTIFY: {
640 struct NotifyRequest *nr = pkt->dp_Arg1;
642 D(bug("[fat] ADD_NOTIFY: nr 0x%08x name '%s'\n", nr, nr->nr_FullName));
644 err = OpAddNotify(nr);
646 break;
649 case ACTION_REMOVE_NOTIFY: {
650 struct NotifyRequest *nr = pkt->dp_Arg1;
652 D(bug("[fat] REMOVE_NOTIFY: nr 0x%08x name '%s'\n", nr, nr->nr_FullName));
654 err = OpRemoveNotify(nr);
656 break;
659 default:
660 D(bug("[fat] got unknown packet type %ld\n", pkt->dp_Type));
662 err = ERROR_ACTION_NOT_KNOWN;
665 if (pkt != NULL) {
666 D(bug("[fat] replying to packet: result 0x%x, error 0x%x\n", res, err));
668 rp = pkt->dp_Port;
670 pkt->dp_Port = glob->ourport;
671 pkt->dp_Res1 = res;
672 pkt->dp_Res2 = err;
674 PutMsg(rp, pkt->dp_Link);
677 #if defined(DEBUG_CACHESTATS) && DEBUG_CACHESTATS != 0
678 cache_stats(glob->sb->cache);
679 #endif