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.
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
29 #include <aros/debug.h>
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 '%.*s' type %s\n",
50 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0,
52 pkt
->dp_Arg3
== EXCLUSIVE_LOCK
? "EXCLUSIVE" : "SHARED"));
54 if ((err
= TestLock(fl
)))
57 if ((err
= OpLockFile(fl
, &path
[1], path
[0], access
, &lock
)) == 0)
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",
68 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0));
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",
82 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0));
84 if ((err
= TestLock(fl
)))
87 if ((err
= OpCopyLock(fl
, &lock
)) == 0)
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",
99 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0));
101 if ((err
= TestLock(fl
)))
104 if ((err
= OpLockParent(fl
, &lock
)) == 0)
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",
116 fl1
!= NULL
? fl1
->gl
->dir_cluster
: 0, fl1
!= NULL
? fl1
->gl
->dir_entry
: 0,
118 fl2
!= NULL
? fl2
->gl
->dir_cluster
: 0, fl2
!= NULL
? fl2
->gl
->dir_entry
: 0));
122 if (fl1
== fl2
|| fl1
->gl
== fl2
->gl
)
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",
135 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0));
137 if ((err
= TestLock(fl
)))
140 if ((err
= FillFIB(fl
, fib
)) == 0)
146 case ACTION_EXAMINE_NEXT
: {
147 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
), *lock
;
148 struct FileInfoBlock
*fib
= BADDR(pkt
->dp_Arg2
);
152 D(bug("[fat] EXAMINE_NEXT: lock 0x%08x (dir %ld/%ld)\n",
154 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0));
156 if ((err
= TestLock(fl
)))
159 if ((err
= InitDirHandle(glob
->sb
, fl
->ioh
.first_cluster
, &dh
)) != 0)
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
);
171 if ((err
= LockFile(fl
->ioh
.first_cluster
, dh
.cur_index
, SHARED_LOCK
, &lock
)) != 0) {
172 ReleaseDirHandle(&dh
);
176 if ((err
= FillFIB(lock
, fib
))) {
178 ReleaseDirHandle(&dh
);
182 fib
->fib_DiskKey
= dh
.cur_index
;
186 ReleaseDirHandle(&dh
);
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" :
206 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0,
209 if ((err
= TestLock(fl
)))
212 if ((err
= OpOpenFile(fl
, &path
[1], path
[0], pkt
->dp_Type
, &lock
)) != 0)
215 fh
->fh_Arg1
= MKBADDR(lock
);
216 fh
->fh_Port
= DOSFALSE
;
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",
230 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0,
234 if ((err
= TestLock(fl
))) {
239 if ((err
= OpRead(fl
, buffer
, want
, &res
)) != 0)
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",
252 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0,
256 if ((err
= TestLock(fl
))) {
261 if ((err
= OpWrite(fl
, buffer
, want
, &res
)) != 0)
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",
274 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0,
277 whence
== OFFSET_BEGINNING
? "BEGINNING" :
278 whence
== OFFSET_END
? "END" :
279 whence
== OFFSET_CURRENT
? "CURRENT" :
282 if ((err
= TestLock(fl
))) {
290 if (whence
== OFFSET_BEGINNING
&&
292 offset
<= fl
->gl
->size
)
294 else if (whence
== OFFSET_CURRENT
&&
295 offset
+ fl
->pos
>= 0 &&
296 offset
+ fl
->pos
<= fl
->gl
->size
)
298 else if (whence
== OFFSET_END
300 && fl
->gl
->size
+ offset
>= 0)
301 fl
->pos
= fl
->gl
->size
+ offset
;
304 err
= ERROR_SEEK_ERROR
;
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",
317 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0,
320 whence
== OFFSET_BEGINNING
? "BEGINNING" :
321 whence
== OFFSET_END
? "END" :
322 whence
== OFFSET_CURRENT
? "CURRENT" :
325 if ((err
= TestLock(fl
))) {
330 if ((err
= OpSetFileSize(fl
, offset
, whence
, &res
)) != 0)
337 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
);
339 D(bug("[fat] END: lock 0x%08x (dir %ld/%ld)\n",
341 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0));
343 if ((err
= TestLock(fl
)))
352 case ACTION_IS_FILESYSTEM
:
353 D(bug("[fat] IS_FILESYSTEM\n"));
358 case ACTION_CURRENT_VOLUME
: {
359 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
);
361 D(bug("[fat] CURRENT_VOLUME: lock 0x%08x\n",
364 res
= (fl
) ? fl
->fl_Volume
: ((glob
->sb
!= NULL
) ? MKBADDR(glob
->sb
->doslist
) : NULL
);
369 case ACTION_DISK_INFO
: {
372 if (pkt
->dp_Type
== ACTION_INFO
) {
373 struct FileLock
*fl
= BADDR(pkt
->dp_Arg1
);
375 D(bug("[fat] INFO: lock 0x%08x\n",
378 if (fl
&& (glob
->sb
== NULL
|| fl
->fl_Volume
!= MKBADDR(glob
->sb
->doslist
))) {
379 err
= ERROR_DEVICE_NOT_MOUNTED
;
383 id
= BADDR(pkt
->dp_Arg2
);
386 D(bug("[fat] DISK_INFO\n"));
388 id
= BADDR(pkt
->dp_Arg1
);
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)
409 glob
->disk_inhibited
--;
410 if (glob
->disk_inhibited
== 0)
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
;
427 D(bug("\tNo locks pending. Shutting down the handler\n"));
429 DoDiskRemove(); /* risky, because of async. volume remove, but works */
432 glob
->devnode
->dol_Task
= NULL
;
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
;
448 case ACTION_FREE_DISK_FSSM
: {
449 D(bug("\nGot ACTION_FREE_DISK_FSSM\n"));
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
) {
469 UnLockDosList(LDF_VOLUMES
|LDF_WRITE
);
471 SendEvent(IECLASS_DISKINSERTED
);
473 D(bug("\tVolume added successfuly\n"));
475 else if (type
== ACTION_VOLUME_REMOVE
) {
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 */
488 D(bug("Packet destroyed\n"));
492 D(bug("\tDosList is locked\n"));
494 PutMsg(glob
->ourport
, pkt
->dp_Link
);
496 D(bug("Message moved to the end of the queue\n"));
500 err
= ERROR_OBJECT_WRONG_TYPE
;
505 case ACTION_RENAME_DISK
: {
506 UBYTE
*name
= BADDR(pkt
->dp_Arg1
);
508 D(bug("[fat] RENAME_DISK: name '%.*s'\n",
511 if (glob
->sb
->doslist
== NULL
) {
512 err
= glob
->disk_inserted
? ERROR_NOT_A_DOS_DISK
: ERROR_NO_DISK
;
516 while (! AttemptLockDosList(LDF_VOLUMES
| LDF_WRITE
))
519 err
= SetVolumeName(glob
->sb
, name
);
520 UnLockDosList(LDF_VOLUMES
| LDF_WRITE
);
524 SendEvent(IECLASS_DISKINSERTED
);
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",
537 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0,
540 if ((err
= TestLock(fl
)))
543 err
= OpDeleteFile(fl
, &name
[1], name
[0]);
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",
554 sfl
!= NULL
? sfl
->gl
->dir_cluster
: 0, sfl
!= NULL
? sfl
->gl
->dir_entry
: 0,
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)
563 err
= OpRenameFile(sfl
, &sname
[1], sname
[0], dfl
, &dname
[1], dname
[0]);
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",
574 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0,
577 if ((err
= TestLock(fl
)))
580 if ((err
= OpCreateDir(fl
, &name
[1], name
[0], &new)) == 0)
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",
593 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0,
597 if ((err
= TestLock(fl
)))
600 err
= OpSetProtect(fl
, &name
[1], name
[0], prot
);
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
613 char datestr
[LEN_DATSTRING
];
616 dt
.dat_Format
= FORMAT_DOS
;
618 dt
.dat_StrDay
= NULL
;
619 dt
.dat_StrDate
= datestr
;
620 dt
.dat_StrTime
= NULL
;
623 D(bug("[fat] SET_DATE: lock 0x%08x (dir %ld/%ld) name '%.*s' ds '%s'\n",
625 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0,
631 if ((err
= TestLock(fl
)))
634 err
= OpSetDate(fl
, &name
[1], name
[0], ds
);
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
);
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
);
660 D(bug("[fat] got unknown packet type %ld\n", pkt
->dp_Type
));
662 err
= ERROR_ACTION_NOT_KNOWN
;
666 D(bug("[fat] replying to packet: result 0x%x, error 0x%x\n", res
, err
));
670 pkt
->dp_Port
= glob
->ourport
;
674 PutMsg(rp
, pkt
->dp_Link
);
677 #if defined(DEBUG_CACHESTATS) && DEBUG_CACHESTATS != 0
678 cache_stats(glob
->sb
->cache
);