2 * fat.handler - FAT12/16/32 filesystem handler
4 * Copyright © 2006 Marek Szyprowski
5 * Copyright © 2007-2014 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
;
35 while ((msg
= GetMsg(glob
->ourport
)) != NULL
) {
39 pkt
= (struct DosPacket
*) msg
->mn_Node
.ln_Name
;
41 switch(pkt
->dp_Type
) {
42 case ACTION_LOCATE_OBJECT
: {
43 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
), *lock
;
44 UBYTE
*path
= BADDR(pkt
->dp_Arg2
);
45 LONG access
= pkt
->dp_Arg3
;
47 D(bug("[FAT] LOCATE_OBJECT: lock 0x%08x (dir %ld/%ld) name '", pkt
->dp_Arg1
,
48 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0);
49 RawPutChars(AROS_BSTR_ADDR(path
), AROS_BSTR_strlen(path
)); bug("' type %s\n",
50 pkt
->dp_Arg3
== EXCLUSIVE_LOCK
? "EXCLUSIVE" : "SHARED"));
52 if ((err
= TestLock(fl
)))
55 if ((err
= OpLockFile(fl
, AROS_BSTR_ADDR(path
), AROS_BSTR_strlen(path
), access
, &lock
)) == 0)
56 res
= (IPTR
)MKBADDR(lock
);
61 case ACTION_FREE_LOCK
: {
62 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
);
64 D(bug("[FAT] FREE_LOCK: lock 0x%08x (dir %ld/%ld)\n",
66 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0));
75 case ACTION_COPY_DIR_FH
: {
76 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
), *lock
;
78 D(bug("[FAT] COPY_DIR: lock 0x%08x (dir %ld/%ld)\n",
80 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0));
82 if ((err
= TestLock(fl
)))
85 if ((err
= OpCopyLock(fl
, &lock
)) == 0)
86 res
= (IPTR
)MKBADDR(lock
);
92 case ACTION_PARENT_FH
: {
93 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
), *lock
;
95 D(bug("[FAT] ACTION_PARENT: lock 0x%08x (dir %ld/%ld)\n",
97 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0));
99 if ((err
= TestLock(fl
)))
102 if ((err
= OpLockParent(fl
, &lock
)) == 0)
103 res
= (IPTR
)MKBADDR(lock
);
108 case ACTION_SAME_LOCK
: {
109 struct ExtFileLock
*fl1
= BADDR(pkt
->dp_Arg1
);
110 struct ExtFileLock
*fl2
= BADDR(pkt
->dp_Arg2
);
112 D(bug("[FAT] ACTION_SAME_LOCK: lock #1 0x%08x (dir %ld/%ld) lock #2 0x%08x (dir %ld/%ld)\n",
114 fl1
!= NULL
? fl1
->gl
->dir_cluster
: 0, fl1
!= NULL
? fl1
->gl
->dir_entry
: 0,
116 fl2
!= NULL
? fl2
->gl
->dir_cluster
: 0, fl2
!= NULL
? fl2
->gl
->dir_entry
: 0));
120 if (fl1
== fl2
|| fl1
->gl
== fl2
->gl
)
126 case ACTION_EXAMINE_OBJECT
:
127 case ACTION_EXAMINE_FH
: {
128 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
);
129 struct FileInfoBlock
*fib
= BADDR(pkt
->dp_Arg2
);
131 D(bug("[FAT] EXAMINE_OBJECT: lock 0x%08x (dir %ld/%ld)\n",
133 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0));
135 if ((err
= TestLock(fl
)))
138 if ((err
= FillFIB(fl
, fib
)) == 0)
144 case ACTION_EXAMINE_NEXT
: {
145 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
), *lock
;
146 struct FileInfoBlock
*fib
= BADDR(pkt
->dp_Arg2
);
150 D(bug("[FAT] EXAMINE_NEXT: lock 0x%08x (dir %ld/%ld)\n",
152 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0));
154 if ((err
= TestLock(fl
)))
157 if ((err
= InitDirHandle(glob
->sb
, fl
->ioh
.first_cluster
, &dh
, FALSE
)) != 0)
160 dh
.cur_index
= fib
->fib_DiskKey
;
162 if ((err
= GetNextDirEntry(&dh
, &de
)) != 0) {
163 if (err
== ERROR_OBJECT_NOT_FOUND
)
164 err
= ERROR_NO_MORE_ENTRIES
;
165 ReleaseDirHandle(&dh
);
169 if ((err
= LockFile(fl
->ioh
.first_cluster
, dh
.cur_index
, SHARED_LOCK
, &lock
)) != 0) {
170 ReleaseDirHandle(&dh
);
174 if (!(err
= FillFIB(lock
, fib
))) {
175 fib
->fib_DiskKey
= dh
.cur_index
;
180 ReleaseDirHandle(&dh
);
185 case ACTION_FINDINPUT
:
186 case ACTION_FINDOUTPUT
:
187 case ACTION_FINDUPDATE
: {
188 struct FileHandle
*fh
= BADDR(pkt
->dp_Arg1
);
189 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg2
);
190 UBYTE
*path
= BADDR(pkt
->dp_Arg3
);
191 struct ExtFileLock
*lock
;
193 D(bug("[FAT] %s: lock 0x%08x (dir %ld/%ld) path '",
194 pkt
->dp_Type
== ACTION_FINDINPUT
? "FINDINPUT" :
195 pkt
->dp_Type
== ACTION_FINDOUTPUT
? "FINDOUTPUT" :
198 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0);
199 RawPutChars(AROS_BSTR_ADDR(path
), AROS_BSTR_strlen(path
)); bug("'\n"));
201 if ((err
= TestLock(fl
)))
204 if ((err
= OpOpenFile(fl
, AROS_BSTR_ADDR(path
), AROS_BSTR_strlen(path
), pkt
->dp_Type
, &lock
)) != 0)
207 fh
->fh_Arg1
= (IPTR
)MKBADDR(lock
);
208 fh
->fh_Port
= DOSFALSE
;
216 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
);
217 APTR buffer
= (APTR
)pkt
->dp_Arg2
;
218 ULONG want
= pkt
->dp_Arg3
, read
;
220 D(bug("[FAT] READ: lock 0x%08x (dir %ld/%ld pos %ld) want %ld\n",
222 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0,
226 if ((err
= TestLock(fl
))) {
231 if ((err
= OpRead(fl
, buffer
, want
, &read
)) != 0)
240 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
);
241 APTR buffer
= (APTR
)pkt
->dp_Arg2
;
242 ULONG want
= pkt
->dp_Arg3
, written
;
244 D(bug("[FAT] WRITE: lock 0x%08x (dir %ld/%ld pos %ld) want %ld\n",
246 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0,
250 if ((err
= TestLock(fl
))) {
255 if ((err
= OpWrite(fl
, buffer
, want
, &written
)) != 0)
264 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
);
265 LONG offset
= pkt
->dp_Arg2
;
266 ULONG whence
= pkt
->dp_Arg3
;
268 D(bug("[FAT] SEEK: lock 0x%08x (dir %ld/%ld pos %ld) offset %ld whence %s\n",
270 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0,
273 whence
== OFFSET_BEGINNING
? "BEGINNING" :
274 whence
== OFFSET_END
? "END" :
275 whence
== OFFSET_CURRENT
? "CURRENT" :
278 if ((err
= TestLock(fl
))) {
286 if (whence
== OFFSET_BEGINNING
&&
288 offset
<= fl
->gl
->size
)
290 else if (whence
== OFFSET_CURRENT
&&
291 offset
+ fl
->pos
>= 0 &&
292 offset
+ fl
->pos
<= fl
->gl
->size
)
294 else if (whence
== OFFSET_END
296 && fl
->gl
->size
+ offset
>= 0)
297 fl
->pos
= fl
->gl
->size
+ offset
;
300 err
= ERROR_SEEK_ERROR
;
306 case ACTION_SET_FILE_SIZE
: {
307 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
);
308 LONG offset
= pkt
->dp_Arg2
;
309 LONG whence
= pkt
->dp_Arg3
;
312 D(bug("[FAT] SET_FILE_SIZE: lock 0x%08x (dir %ld/%ld pos %ld) offset %ld whence %s\n",
314 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0,
317 whence
== OFFSET_BEGINNING
? "BEGINNING" :
318 whence
== OFFSET_END
? "END" :
319 whence
== OFFSET_CURRENT
? "CURRENT" :
322 if ((err
= TestLock(fl
))) {
327 if ((err
= OpSetFileSize(fl
, offset
, whence
, &newsize
)) != 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
= (IPTR
)((fl
) ? fl
->fl_Volume
: ((glob
->sb
!= NULL
) ? MKBADDR(glob
->sb
->doslist
) : BNULL
));
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)
419 struct NotifyNode
*nn
;
421 D(bug("[FAT] DIE\n"));
423 /* clear our message port from notification requests so DOS won't send
424 * notification-end packets to us after we're gone */
425 ForeachNode(&glob
->sblist
, sb
) {
426 ForeachNode(&sb
->info
->notifies
, nn
) {
427 nn
->nr
->nr_Handler
= NULL
;
431 if ((glob
->sb
!= NULL
432 && !(IsListEmpty(&glob
->sb
->info
->locks
)
433 && IsListEmpty(&glob
->sb
->info
->notifies
)))) {
435 D(bug("\tThere are remaining locks or notification "
436 "requests. Shutting down is not possible\n"));
438 err
= ERROR_OBJECT_IN_USE
;
442 D(bug("\tNothing pending. Shutting down the handler\n"));
444 DoDiskRemove(); /* risky, because of async. volume remove, but works */
447 glob
->death_packet
= pkt
;
448 glob
->devnode
->dol_Task
= NULL
;
455 /* XXX AROS needs these ACTION_ headers defined in dos/dosextens.h */
457 case ACTION_GET_DISK_FSSM
: {
458 D(bug("\nGot ACTION_GET_DISK_FSSM\n"));
460 res
= (ULONG
) glob
->fssm
;
464 case ACTION_FREE_DISK_FSSM
: {
465 D(bug("\nGot ACTION_FREE_DISK_FSSM\n"));
473 case ACTION_DISK_CHANGE
: { /* internal */
474 struct DosList
*vol
= (struct DosList
*)pkt
->dp_Arg2
;
475 struct VolumeInfo
*vol_info
=
476 BADDR(vol
->dol_misc
.dol_volume
.dol_LockList
);
477 ULONG type
= pkt
->dp_Arg3
;
479 D(bug("[FAT] DISK_CHANGE [INTERNAL]\n"));
481 if (pkt
->dp_Arg1
== ID_FAT_DISK
) { /* security check */
483 if (AttemptLockDosList(LDF_VOLUMES
|LDF_WRITE
)) {
485 if (type
== ACTION_VOLUME_ADD
) {
487 UnLockDosList(LDF_VOLUMES
|LDF_WRITE
);
489 SendEvent(IECLASS_DISKINSERTED
);
491 D(bug("\tVolume added successfuly\n"));
493 else if (type
== ACTION_VOLUME_REMOVE
) {
495 DeletePool(vol_info
->mem_pool
);
496 UnLockDosList(LDF_VOLUMES
|LDF_WRITE
);
498 SendEvent(IECLASS_DISKREMOVED
);
500 D(bug("\tVolume removed successfuly.\n"));
503 FreeDosObject(DOS_STDPKT
, pkt
); /* cleanup */
506 D(bug("Packet destroyed\n"));
510 D(bug("\tDosList is locked\n"));
512 PutMsg(glob
->ourport
, pkt
->dp_Link
);
514 D(bug("Message moved to the end of the queue\n"));
518 err
= ERROR_OBJECT_WRONG_TYPE
;
523 case ACTION_RENAME_DISK
: {
524 UBYTE
*name
= BADDR(pkt
->dp_Arg1
);
526 D(bug("[FAT] RENAME_DISK: name '"); RawPutChars(AROS_BSTR_ADDR(name
), AROS_BSTR_strlen(name
)); bug("'\n"));
528 if (glob
->sb
->doslist
== NULL
) {
529 err
= glob
->disk_inserted
? ERROR_NOT_A_DOS_DISK
: ERROR_NO_DISK
;
533 while (! AttemptLockDosList(LDF_VOLUMES
| LDF_WRITE
))
536 err
= SetVolumeName(glob
->sb
, name
);
537 UnLockDosList(LDF_VOLUMES
| LDF_WRITE
);
541 #ifdef AROS_FAST_BPTR
542 /* ReadFATSuper() sets a null byte after the
543 * string, so this should be fine */
544 CopyMem(glob
->sb
->volume
.name
+ 1, glob
->sb
->doslist
->dol_Name
,
545 glob
->sb
->volume
.name
[0] + 1);
547 CopyMem(glob
->sb
->volume
.name
, BADDR(glob
->sb
->doslist
->dol_Name
),
548 glob
->sb
->volume
.name
[0] + 2);
551 SendEvent(IECLASS_DISKINSERTED
);
558 case ACTION_DELETE_OBJECT
: {
559 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
);
560 UBYTE
*name
= BADDR(pkt
->dp_Arg2
);
562 D(bug("[FAT] DELETE_OBJECT: lock 0x%08x (dir %ld/%ld) path '",
564 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0);
565 RawPutChars(AROS_BSTR_ADDR(name
), AROS_BSTR_strlen(name
)); bug("'\n"));
567 if ((err
= TestLock(fl
)))
570 err
= OpDeleteFile(fl
, AROS_BSTR_ADDR(name
), AROS_BSTR_strlen(name
));
577 case ACTION_RENAME_OBJECT
: {
578 struct ExtFileLock
*sfl
= BADDR(pkt
->dp_Arg1
), *dfl
= BADDR(pkt
->dp_Arg3
);
579 UBYTE
*sname
= BADDR(pkt
->dp_Arg2
), *dname
= BADDR(pkt
->dp_Arg4
);
581 D(bug("[FAT] RENAME_OBJECT: srclock 0x%08x (dir %ld/%ld) name '",
583 sfl
!= NULL
? sfl
->gl
->dir_cluster
: 0, sfl
!= NULL
? sfl
->gl
->dir_entry
: 0);
584 RawPutChars(AROS_BSTR_ADDR(sname
), AROS_BSTR_strlen(sname
)); bug("' destlock 0x%08x (dir %ld/%ld) name '",
586 dfl
!= NULL
? dfl
->gl
->dir_cluster
: 0, dfl
!= NULL
? dfl
->gl
->dir_entry
: 0);
587 RawPutChars(AROS_BSTR_ADDR(dname
), AROS_BSTR_strlen(dname
)); bug("'\n"));
589 if ((err
= TestLock(sfl
)) != 0 || (err
= TestLock(dfl
)) != 0)
592 err
= OpRenameFile(sfl
, AROS_BSTR_ADDR(sname
), AROS_BSTR_strlen(sname
), dfl
, AROS_BSTR_ADDR(dname
), AROS_BSTR_strlen(dname
));
599 case ACTION_CREATE_DIR
: {
600 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg1
), *new;
601 UBYTE
*name
= BADDR(pkt
->dp_Arg2
);
603 D(bug("[FAT] CREATE_DIR: lock 0x%08x (dir %ld/%ld) name '",
605 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0);
606 RawPutChars(AROS_BSTR_ADDR(name
), AROS_BSTR_strlen(name
)); bug("'\n"));
608 if ((err
= TestLock(fl
)))
611 if ((err
= OpCreateDir(fl
, AROS_BSTR_ADDR(name
), AROS_BSTR_strlen(name
), &new)) == 0)
612 res
= (IPTR
)MKBADDR(new);
617 case ACTION_SET_PROTECT
: {
618 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg2
);
619 UBYTE
*name
= BADDR(pkt
->dp_Arg3
);
620 ULONG prot
= pkt
->dp_Arg4
;
622 D(bug("[FAT] SET_PROTECT: lock 0x%08x (dir %ld/%ld) name '", pkt
->dp_Arg2
,
623 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0);
624 RawPutChars(AROS_BSTR_ADDR(name
), AROS_BSTR_strlen(name
)); bug("' prot 0x%08x\n", prot
));
625 if ((err
= TestLock(fl
)))
628 err
= OpSetProtect(fl
, AROS_BSTR_ADDR(name
), AROS_BSTR_strlen(name
), prot
);
633 case ACTION_SET_DATE
: {
634 struct ExtFileLock
*fl
= BADDR(pkt
->dp_Arg2
);
635 UBYTE
*name
= BADDR(pkt
->dp_Arg3
);
636 struct DateStamp
*ds
= (struct DateStamp
*)pkt
->dp_Arg4
;
638 #if defined(DEBUG) && DEBUG != 0
641 char datestr
[LEN_DATSTRING
];
644 dt
.dat_Format
= FORMAT_DOS
;
646 dt
.dat_StrDay
= NULL
;
647 dt
.dat_StrDate
= datestr
;
648 dt
.dat_StrTime
= NULL
;
651 D(bug("[FAT] SET_DATE: lock 0x%08x (dir %ld/%ld) name '",
653 fl
!= NULL
? fl
->gl
->dir_cluster
: 0, fl
!= NULL
? fl
->gl
->dir_entry
: 0);
654 RawPutChars(AROS_BSTR_ADDR(name
), AROS_BSTR_strlen(name
)); bug("' ds '%s'\n", datestr
));
658 if ((err
= TestLock(fl
)))
661 err
= OpSetDate(fl
, AROS_BSTR_ADDR(name
), AROS_BSTR_strlen(name
), ds
);
666 case ACTION_ADD_NOTIFY
: {
667 struct NotifyRequest
*nr
= (struct NotifyRequest
*)pkt
->dp_Arg1
;
669 D(bug("[FAT] ADD_NOTIFY: nr 0x%08x name '%s'\n", nr
, nr
->nr_FullName
));
671 err
= OpAddNotify(nr
);
676 case ACTION_REMOVE_NOTIFY
: {
677 struct NotifyRequest
*nr
= (struct NotifyRequest
*)pkt
->dp_Arg1
;
679 D(bug("[FAT] REMOVE_NOTIFY: nr 0x%08x name '%s'\n", nr
, nr
->nr_FullName
));
681 err
= OpRemoveNotify(nr
);
687 D(bug("[FAT] got unknown packet type %ld\n", pkt
->dp_Type
));
689 err
= ERROR_ACTION_NOT_KNOWN
;
696 D(bug("[FAT] replying to packet: result 0x%x, error 0x%x\n",
706 void ReplyPacket(struct DosPacket
*pkt
) {
711 pkt
->dp_Port
= glob
->ourport
;
713 PutMsg(rp
, pkt
->dp_Link
);