2 * fat.handler - FAT12/16/32 filesystem handler
4 * Copyright © 2006 Marek Szyprowski
5 * Copyright © 2007-2008 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.
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>
26 #include "fat_protos.h"
28 #define DEBUG DEBUG_PACKETS
31 void ProcessPackets(void) {
33 struct DosPacket
*pkt
;
36 while ((msg
= GetMsg(glob
->ourport
)) != NULL
) {
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 '", pkt
->dp_Arg1
,
49 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0);
50 RawPutChars(&path
[1], path
[0]); bug("' type %s\n",
51 pkt
->dp_Arg3
== EXCLUSIVE_LOCK
? "EXCLUSIVE" : "SHARED"));
53 if ((err
= TestLock(fl
)))
56 if ((err
= OpLockFile(fl
, &path
[1], path
[0], access
, &lock
)) == 0)
57 res
= (LONG
)MKBADDR(lock
);
62 case ACTION_FREE_LOCK
: {
63 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
);
65 D(bug("[fat] FREE_LOCK: lock 0x%08x (dir %ld/%ld)\n",
67 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0));
76 case ACTION_COPY_DIR_FH
: {
77 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
), *lock
;
79 D(bug("[fat] COPY_DIR: lock 0x%08x (dir %ld/%ld)\n",
81 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0));
83 if ((err
= TestLock(fl
)))
86 if ((err
= OpCopyLock(fl
, &lock
)) == 0)
87 res
= (LONG
)MKBADDR(lock
);
93 case ACTION_PARENT_FH
: {
94 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
), *lock
;
96 D(bug("[fat] ACTION_PARENT: lock 0x%08x (dir %ld/%ld)\n",
98 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0));
100 if ((err
= TestLock(fl
)))
103 if ((err
= OpLockParent(fl
, &lock
)) == 0)
104 res
= (LONG
)MKBADDR(lock
);
109 case ACTION_SAME_LOCK
: {
110 struct ExtFileLock
*fl1
= BADDR(pkt
->dp_Arg1
);
111 struct ExtFileLock
*fl2
= BADDR(pkt
->dp_Arg2
);
113 D(bug("[fat] ACTION_SAME_LOCK: lock #1 0x%08x (dir %ld/%ld) lock #2 0x%08x (dir %ld/%ld)\n",
115 fl1
!= NULL
? fl1
->gl
->dir_cluster
: 0, fl1
!= NULL
? fl1
->gl
->dir_entry
: 0,
117 fl2
!= NULL
? fl2
->gl
->dir_cluster
: 0, fl2
!= NULL
? fl2
->gl
->dir_entry
: 0));
121 if (fl1
== fl2
|| fl1
->gl
== fl2
->gl
)
127 case ACTION_EXAMINE_OBJECT
:
128 case ACTION_EXAMINE_FH
: {
129 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
);
130 struct FileInfoBlock
*fib
= BADDR(pkt
->dp_Arg2
);
132 D(bug("[fat] EXAMINE_OBJECT: lock 0x%08x (dir %ld/%ld)\n",
134 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0));
136 if ((err
= TestLock(fl
)))
139 if ((err
= FillFIB(fl
, fib
)) == 0)
145 case ACTION_EXAMINE_NEXT
: {
146 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
), *lock
;
147 struct FileInfoBlock
*fib
= BADDR(pkt
->dp_Arg2
);
151 D(bug("[fat] EXAMINE_NEXT: lock 0x%08x (dir %ld/%ld)\n",
153 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0));
155 if ((err
= TestLock(fl
)))
158 if ((err
= InitDirHandle(glob
->sb
, fl
->ioh
.first_cluster
, &dh
, FALSE
)) != 0)
161 dh
.cur_index
= fib
->fib_DiskKey
;
163 if ((err
= GetNextDirEntry(&dh
, &de
)) != 0) {
164 if (err
== ERROR_OBJECT_NOT_FOUND
)
165 err
= ERROR_NO_MORE_ENTRIES
;
166 ReleaseDirHandle(&dh
);
170 if ((err
= LockFile(fl
->ioh
.first_cluster
, dh
.cur_index
, SHARED_LOCK
, &lock
)) != 0) {
171 ReleaseDirHandle(&dh
);
175 if ((err
= FillFIB(lock
, fib
))) {
177 ReleaseDirHandle(&dh
);
181 fib
->fib_DiskKey
= dh
.cur_index
;
185 ReleaseDirHandle(&dh
);
192 case ACTION_FINDINPUT
:
193 case ACTION_FINDOUTPUT
:
194 case ACTION_FINDUPDATE
: {
195 struct FileHandle
*fh
= BADDR(pkt
->dp_Arg1
);
196 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg2
);
197 UBYTE
*path
= BADDR(pkt
->dp_Arg3
);
198 struct ExtFileLock
*lock
;
200 D(bug("[fat] %s: lock 0x%08x (dir %ld/%ld) path '",
201 pkt
->dp_Type
== ACTION_FINDINPUT
? "FINDINPUT" :
202 pkt
->dp_Type
== ACTION_FINDOUTPUT
? "FINDOUTPUT" :
205 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0);
206 RawPutChars(&path
[1], path
[0]); bug("'\n"));
208 if ((err
= TestLock(fl
)))
211 if ((err
= OpOpenFile(fl
, &path
[1], path
[0], pkt
->dp_Type
, &lock
)) != 0)
214 fh
->fh_Arg1
= (LONG
)MKBADDR(lock
);
215 fh
->fh_Port
= DOSFALSE
;
223 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
);
224 APTR buffer
= (APTR
)pkt
->dp_Arg2
;
225 ULONG want
= pkt
->dp_Arg3
;
227 D(bug("[fat] READ: lock 0x%08x (dir %ld/%ld pos %ld) want %ld\n",
229 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0,
233 if ((err
= TestLock(fl
))) {
238 if ((err
= OpRead(fl
, buffer
, want
, &res
)) != 0)
245 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
);
246 APTR buffer
= (APTR
)pkt
->dp_Arg2
;
247 ULONG want
= pkt
->dp_Arg3
;
249 D(bug("[fat] WRITE: lock 0x%08x (dir %ld/%ld pos %ld) want %ld\n",
251 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0,
255 if ((err
= TestLock(fl
))) {
260 if ((err
= OpWrite(fl
, buffer
, want
, &res
)) != 0)
267 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
);
268 LONG offset
= pkt
->dp_Arg2
;
269 ULONG whence
= pkt
->dp_Arg3
;
271 D(bug("[fat] SEEK: lock 0x%08x (dir %ld/%ld pos %ld) offset %ld whence %s\n",
273 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0,
276 whence
== OFFSET_BEGINNING
? "BEGINNING" :
277 whence
== OFFSET_END
? "END" :
278 whence
== OFFSET_CURRENT
? "CURRENT" :
281 if ((err
= TestLock(fl
))) {
289 if (whence
== OFFSET_BEGINNING
&&
291 offset
<= fl
->gl
->size
)
293 else if (whence
== OFFSET_CURRENT
&&
294 offset
+ fl
->pos
>= 0 &&
295 offset
+ fl
->pos
<= fl
->gl
->size
)
297 else if (whence
== OFFSET_END
299 && fl
->gl
->size
+ offset
>= 0)
300 fl
->pos
= fl
->gl
->size
+ offset
;
303 err
= ERROR_SEEK_ERROR
;
309 case ACTION_SET_FILE_SIZE
: {
310 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
);
311 LONG offset
= pkt
->dp_Arg2
;
312 LONG whence
= pkt
->dp_Arg3
;
314 D(bug("[fat] SET_FILE_SIZE: lock 0x%08x (dir %ld/%ld pos %ld) offset %ld whence %s\n",
316 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0,
319 whence
== OFFSET_BEGINNING
? "BEGINNING" :
320 whence
== OFFSET_END
? "END" :
321 whence
== OFFSET_CURRENT
? "CURRENT" :
324 if ((err
= TestLock(fl
))) {
329 if ((err
= OpSetFileSize(fl
, offset
, whence
, &res
)) != 0)
336 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
);
338 D(bug("[fat] END: lock 0x%08x (dir %ld/%ld)\n",
340 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0));
342 if ((err
= TestLock(fl
)))
351 case ACTION_IS_FILESYSTEM
:
352 D(bug("[fat] IS_FILESYSTEM\n"));
357 case ACTION_CURRENT_VOLUME
: {
358 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
);
360 D(bug("[fat] CURRENT_VOLUME: lock 0x%08x\n",
363 res
= (LONG
)((fl
) ? fl
->fl_Volume
: ((glob
->sb
!= NULL
) ? MKBADDR(glob
->sb
->doslist
) : NULL
));
368 case ACTION_DISK_INFO
: {
371 if (pkt
->dp_Type
== ACTION_INFO
) {
372 struct FileLock
*fl
= BADDR(pkt
->dp_Arg1
);
374 D(bug("[fat] INFO: lock 0x%08x\n",
377 if (fl
&& (glob
->sb
== NULL
|| fl
->fl_Volume
!= MKBADDR(glob
->sb
->doslist
))) {
378 err
= ERROR_DEVICE_NOT_MOUNTED
;
382 id
= BADDR(pkt
->dp_Arg2
);
385 D(bug("[fat] DISK_INFO\n"));
387 id
= BADDR(pkt
->dp_Arg1
);
396 case ACTION_INHIBIT
: {
397 LONG inhibit
= pkt
->dp_Arg1
;
399 D(bug("[fat] INHIBIT: %sinhibit\n",
400 inhibit
== DOSTRUE
? "" : "un"));
402 if (inhibit
== DOSTRUE
) {
403 glob
->disk_inhibited
++;
404 if (glob
->disk_inhibited
== 1)
407 else if (glob
->disk_inhibited
) {
408 glob
->disk_inhibited
--;
409 if (glob
->disk_inhibited
== 0)
418 D(bug("[fat] DIE\n"));
420 if (glob
->sblist
!= NULL
|| (glob
->sb
!= NULL
&& glob
->sb
->doslist
->dol_misc
.dol_volume
.dol_LockList
!= NULL
)) {
421 D(bug("\tThere are some locks/volumes left. Shutting down is not possible\n"));
422 err
= ERROR_OBJECT_IN_USE
;
426 D(bug("\tNo locks pending. Shutting down the handler\n"));
428 DoDiskRemove(); /* risky, because of async. volume remove, but works */
431 glob
->devnode
->dol_Task
= NULL
;
438 /* XXX AROS needs these ACTION_ headers defined in dos/dosextens.h */
440 case ACTION_GET_DISK_FSSM
: {
441 D(bug("\nGot ACTION_GET_DISK_FSSM\n"));
443 res
= (ULONG
) glob
->fssm
;
447 case ACTION_FREE_DISK_FSSM
: {
448 D(bug("\nGot ACTION_FREE_DISK_FSSM\n"));
456 case ACTION_DISK_CHANGE
: { /* internal */
457 struct DosList
*vol
= (struct DosList
*)pkt
->dp_Arg2
;
458 ULONG type
= pkt
->dp_Arg3
;
460 D(bug("[fat] DISK_CHANGE [INTERNAL]\n"));
462 if (pkt
->dp_Arg1
== ID_FAT_DISK
) { /* security check */
464 if (AttemptLockDosList(LDF_VOLUMES
|LDF_WRITE
)) {
466 if (type
== ACTION_VOLUME_ADD
) {
468 UnLockDosList(LDF_VOLUMES
|LDF_WRITE
);
470 SendEvent(IECLASS_DISKINSERTED
);
472 D(bug("\tVolume added successfuly\n"));
474 else if (type
== ACTION_VOLUME_REMOVE
) {
476 FreeVecPooled(glob
->mempool
, vol
);
477 UnLockDosList(LDF_VOLUMES
|LDF_WRITE
);
479 SendEvent(IECLASS_DISKREMOVED
);
481 D(bug("\tVolume removed successfuly.\n"));
484 FreeDosObject(DOS_STDPKT
, pkt
); /* cleanup */
487 D(bug("Packet destroyed\n"));
491 D(bug("\tDosList is locked\n"));
493 PutMsg(glob
->ourport
, pkt
->dp_Link
);
495 D(bug("Message moved to the end of the queue\n"));
499 err
= ERROR_OBJECT_WRONG_TYPE
;
504 case ACTION_RENAME_DISK
: {
505 UBYTE
*name
= BADDR(pkt
->dp_Arg1
);
507 D(bug("[fat] RENAME_DISK: name '"); RawPutChars(&name
[1], name
[0]); bug("'\n"));
509 if (glob
->sb
->doslist
== NULL
) {
510 err
= glob
->disk_inserted
? ERROR_NOT_A_DOS_DISK
: ERROR_NO_DISK
;
514 while (! AttemptLockDosList(LDF_VOLUMES
| LDF_WRITE
))
517 err
= SetVolumeName(glob
->sb
, name
);
518 UnLockDosList(LDF_VOLUMES
| LDF_WRITE
);
522 SendEvent(IECLASS_DISKINSERTED
);
529 case ACTION_DELETE_OBJECT
: {
530 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
);
531 UBYTE
*name
= BADDR(pkt
->dp_Arg2
);
533 D(bug("[fat] DELETE_OBJECT: lock 0x%08x (dir %ld/%ld) path '",
535 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0);
536 RawPutChars(&name
[1], name
[0]); bug("'\n"));
538 if ((err
= TestLock(fl
)))
541 err
= OpDeleteFile(fl
, &name
[1], name
[0]);
546 case ACTION_RENAME_OBJECT
: {
547 struct ExtFileLock
*sfl
= BADDR(pkt
->dp_Arg1
), *dfl
= BADDR(pkt
->dp_Arg3
);
548 UBYTE
*sname
= BADDR(pkt
->dp_Arg2
), *dname
= BADDR(pkt
->dp_Arg4
);
550 D(bug("[fat] RENAME_OBJECT: srclock 0x%08x (dir %ld/%ld) name '",
552 sfl
!= NULL
? sfl
->gl
->dir_cluster
: 0, sfl
!= NULL
? sfl
->gl
->dir_entry
: 0);
553 RawPutChars(&sname
[1], sname
[0]); bug("' destlock 0x%08x (dir %ld/%ld) name '",
555 dfl
!= NULL
? dfl
->gl
->dir_cluster
: 0, dfl
!= NULL
? dfl
->gl
->dir_entry
: 0);
556 RawPutChars(&dname
[1], dname
[0]); bug("'\n"));
558 if ((err
= TestLock(sfl
)) != 0 || (err
= TestLock(dfl
)) != 0)
561 err
= OpRenameFile(sfl
, &sname
[1], sname
[0], dfl
, &dname
[1], dname
[0]);
566 case ACTION_CREATE_DIR
: {
567 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
), *new;
568 UBYTE
*name
= BADDR(pkt
->dp_Arg2
);
570 D(bug("[fat] CREATE_DIR: lock 0x%08x (dir %ld/%ld) name '",
572 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0);
573 RawPutChars(&name
[1], name
[0]); bug("'\n"));
575 if ((err
= TestLock(fl
)))
578 if ((err
= OpCreateDir(fl
, &name
[1], name
[0], &new)) == 0)
579 res
= (LONG
)MKBADDR(new);
584 case ACTION_SET_PROTECT
: {
585 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg2
);
586 UBYTE
*name
= BADDR(pkt
->dp_Arg3
);
587 ULONG prot
= pkt
->dp_Arg4
;
589 D(bug("[fat] SET_PROTECT: lock 0x%08x (dir %ld/%ld) name '", pkt
->dp_Arg2
,
590 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0);
591 RawPutChars(&name
[1], name
[0]); bug("' prot 0x%08x\n", prot
));
592 if ((err
= TestLock(fl
)))
595 err
= OpSetProtect(fl
, &name
[1], name
[0], prot
);
600 case ACTION_SET_DATE
: {
601 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg2
);
602 UBYTE
*name
= BADDR(pkt
->dp_Arg3
);
603 struct DateStamp
*ds
= (struct DateStamp
*)pkt
->dp_Arg4
;
605 #if defined(DEBUG) && DEBUG != 0
608 char datestr
[LEN_DATSTRING
];
611 dt
.dat_Format
= FORMAT_DOS
;
613 dt
.dat_StrDay
= NULL
;
614 dt
.dat_StrDate
= datestr
;
615 dt
.dat_StrTime
= NULL
;
618 D(bug("[fat] SET_DATE: lock 0x%08x (dir %ld/%ld) name '",
620 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0);
621 RawPutChars(&name
[1], name
[0]); bug("' ds '%s'\n", datestr
));
625 if ((err
= TestLock(fl
)))
628 err
= OpSetDate(fl
, &name
[1], name
[0], ds
);
633 case ACTION_ADD_NOTIFY
: {
634 struct NotifyRequest
*nr
= (struct NotifyRequest
*)pkt
->dp_Arg1
;
636 D(bug("[fat] ADD_NOTIFY: nr 0x%08x name '%s'\n", nr
, nr
->nr_FullName
));
638 err
= OpAddNotify(nr
);
643 case ACTION_REMOVE_NOTIFY
: {
644 struct NotifyRequest
*nr
= (struct NotifyRequest
*)pkt
->dp_Arg1
;
646 D(bug("[fat] REMOVE_NOTIFY: nr 0x%08x name '%s'\n", nr
, nr
->nr_FullName
));
648 err
= OpRemoveNotify(nr
);
654 D(bug("[fat] got unknown packet type %ld\n", pkt
->dp_Type
));
656 err
= ERROR_ACTION_NOT_KNOWN
;
660 D(bug("[fat] replying to packet: result 0x%x, error 0x%x\n", res
, err
));
664 pkt
->dp_Port
= glob
->ourport
;
668 PutMsg(rp
, pkt
->dp_Link
);
671 #if defined(DEBUG_CACHESTATS) && DEBUG_CACHESTATS != 0
672 cache_stats(glob
->sb
->cache
);