2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
9 #include <aros/debug.h>
11 #include <exec/errors.h>
12 #include <exec/types.h>
13 #include <exec/resident.h>
14 #include <exec/memory.h>
15 #include <exec/semaphores.h>
16 #include <utility/tagitem.h>
17 #include <utility/utility.h>
18 #include <proto/exec.h>
19 #include <proto/utility.h>
20 #include <proto/alib.h>
21 #include <proto/dos.h>
23 #include <dos/dosextens.h>
24 #include <dos/dosasl.h>
25 #include <dos/exall.h>
26 #include <dos/filesystem.h>
27 #include <aros/libcall.h>
28 #include <aros/symbolsets.h>
30 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
31 #include "ram_handler_gcc.h"
36 #include "HashTable.h"
38 static void deventry();
40 #include LC_LIBDEFS_FILE
42 #define NRF_NOT_REPLIED NRF_MAGIC
49 LONG type
; /* ST_LINKDIR */
50 STRPTR name
; /* Link's name */
51 struct cnode
*self
; /* Pointer to top of structure */
52 struct hnode
*link
; /* NULL */
53 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
54 ULONG protect
; /* 0 */
55 STRPTR comment
; /* NULL */
56 struct vnode
*volume
; /* Pointer to volume */
57 struct DosList
*doslist
; /* Pointer to doslist entry */
64 LONG type
; /* ST_USERDIR */
65 STRPTR name
; /* Directory name */
66 struct vnode
*self
; /* Points to top of structure */
67 struct hnode
*link
; /* This one is linked to me */
68 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
69 ULONG protect
; /* 0 */
70 STRPTR comment
; /* NULL */
71 struct MinList receivers
;
72 struct DateStamp date
;
73 struct MinList list
; /* Contents of directory */
74 ULONG volcount
; /* number of handles on this volume */
75 struct DosList
*doslist
; /* Pointer to doslist entry */
82 LONG type
; /* ST_USERDIR */
83 STRPTR name
; /* Directory name */
84 struct vnode
*volume
; /* Volume's root directory */
85 struct hnode
*link
; /* This one is linked to me */
86 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
87 ULONG protect
; /* protection bits */
88 STRPTR comment
; /* Some comment */
89 struct MinList receivers
;
90 struct DateStamp date
;
91 struct MinList list
; /* Contents of directory */
98 LONG type
; /* ST_FILE */
99 STRPTR name
; /* Filename */
100 struct vnode
*volume
; /* Volume's root directory */
101 struct hnode
*link
; /* This one is linked to me */
102 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
103 ULONG protect
; /* protection bits */
104 STRPTR comment
; /* Some file comment */
105 struct MinList receivers
;
106 struct DateStamp date
;
108 LONG size
; /* Filesize */
109 UBYTE
*blocks
[16]; /* Upto 0x1000 bytes */
110 UBYTE
**iblocks
[4]; /* Upto 0x41000 bytes */
111 UBYTE
***i2block
; /* Upto 0x1041000 bytes */
112 UBYTE
****i3block
; /* Upto 0x101041000 bytes */
119 LONG type
; /* ST_SOFTLINK */
120 STRPTR name
; /* Link's name */
121 struct vnode
*volume
; /* Volume's root directory */
122 struct hnode
*link
; /* This one is hardlinked to me */
123 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
124 ULONG protect
; /* protection bits */
125 STRPTR comment
; /* Some file comment */
126 char *contents
; /* Contents of soft link */
133 LONG type
; /* ST_LINKDIR */
134 STRPTR name
; /* Link's name */
135 struct vnode
*volume
; /* Volume's root directory */
136 struct hnode
*link
; /* This one is hardlinked to me */
137 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
138 ULONG protect
; /* protection bits */
139 STRPTR comment
; /* Some file comment */
140 struct hnode
*orig
; /* original object */
143 /*****************************************************************************/
145 #define FILEFLAGS_Changed 1
147 static STRPTR
getName(struct rambase
*rambase
, struct dnode
*dn
);
158 void Notify_notifyTasks(struct rambase
*rambase
,
159 struct MinList
*notifications
);
161 BOOL
Notify_initialize(struct rambase
*rambase
);
162 void Notify_fileChange(struct rambase
*rambase
, NType type
,
164 void Notify_directoryChange(struct rambase
*rambase
, NType type
,
168 BOOL
Notify_addNotification(struct rambase
*rambase
, struct dnode
*dn
,
169 struct NotifyRequest
*nr
);
170 void Notify_removeNotification(struct rambase
*rambase
,
171 struct NotifyRequest
*nr
);
173 /****************************************************************************/
176 #define BLOCKSIZE 256
177 #define PBLOCKSIZE (256*sizeof(UBYTE *))
185 /* Use This from now on */
189 #define DOSBase rambase->dosbase
191 static int OpenDev(LIBBASETYPEPTR rambase
, struct IOFileSys
*iofs
);
193 static int GM_UNIQUENAME(Init
)(LIBBASETYPEPTR rambase
)
195 /* This function is single-threaded by exec by calling Forbid. */
197 struct MsgPort
*port
;
199 struct SignalSemaphore
*semaphore
;
202 rambase
->dosbase
= (struct DosLibrary
*)OpenLibrary(DOSNAME
, 39);
204 if (rambase
->dosbase
!= NULL
)
206 rambase
->utilitybase
= (struct UtilityBase
*)OpenLibrary(UTILITYNAME
, 39);
208 if (rambase
->utilitybase
!= NULL
)
210 port
= (struct MsgPort
*)AllocMem(sizeof(struct MsgPort
),
211 MEMF_PUBLIC
| MEMF_CLEAR
);
214 rambase
->port
= port
;
215 NewList(&port
->mp_MsgList
);
216 port
->mp_Node
.ln_Type
= NT_MSGPORT
;
217 port
->mp_SigBit
= SIGB_SINGLE
;
219 task
= (struct Task
*)AllocMem(sizeof(struct Task
),
220 MEMF_PUBLIC
| MEMF_CLEAR
);
224 port
->mp_SigTask
= task
;
225 port
->mp_Flags
= PA_IGNORE
;
226 NewList(&task
->tc_MemEntry
);
227 task
->tc_Node
.ln_Type
= NT_TASK
;
228 task
->tc_Node
.ln_Name
= "ram.handler task";
230 stack
= AllocMem(AROS_STACKSIZE
, MEMF_PUBLIC
);
234 struct TagItem tasktags
[] =
236 {TASKTAG_ARG1
, (IPTR
)rambase
},
240 task
->tc_SPLower
= stack
;
241 task
->tc_SPUpper
= (BYTE
*)stack
+ AROS_STACKSIZE
;
242 #if AROS_STACK_GROWS_DOWNWARDS
243 task
->tc_SPReg
= (BYTE
*)task
->tc_SPUpper
- SP_OFFSET
;
245 task
->tc_SPReg
= (BYTE
*)task
->tc_SPLower
+ SP_OFFSET
;
248 semaphore
= (struct SignalSemaphore
*)AllocMem(sizeof(struct SignalSemaphore
),
249 MEMF_PUBLIC
| MEMF_CLEAR
);
251 if (semaphore
!= NULL
)
253 rambase
->sigsem
= semaphore
;
254 InitSemaphore(semaphore
);
256 if (rambase
->seglist
==NULL
) /* Are we a ROM module? */
258 struct DeviceNode
*dn
;
259 /* Install RAM: handler into device list
261 * KLUDGE: ram.handler should create only one device node, depending on
262 * the startup packet it gets. The mountlists for RAM: should be into dos.library bootstrap
266 if((dn
= AllocMem(sizeof (struct DeviceNode
) + 4 + 3 + 2, MEMF_CLEAR
|MEMF_PUBLIC
)))
268 struct IOFileSys dummyiofs
;
270 if (OpenDev(rambase
, &dummyiofs
))
272 BSTR s
= MKBADDR(((IPTR
)dn
+ sizeof(struct DeviceNode
) + 4) & ~3);
274 rambase
->device
.dd_Library
.lib_OpenCnt
++;
276 AROS_BSTR_putchar(s
, 0, 'R');
277 AROS_BSTR_putchar(s
, 1, 'A');
278 AROS_BSTR_putchar(s
, 2, 'M');
279 AROS_BSTR_putchar(s
, 3, 0);
280 AROS_BSTR_setstrlen(s
, 3);
282 dn
->dn_Type
= DLT_DEVICE
;
283 dn
->dn_Ext
.dn_AROS
.dn_Unit
= dummyiofs
.IOFS
.io_Unit
;
284 dn
->dn_Ext
.dn_AROS
.dn_Device
= dummyiofs
.IOFS
.io_Device
;
285 dn
->dn_Handler
= NULL
;
286 dn
->dn_Startup
= NULL
;
288 dn
->dn_Ext
.dn_AROS
.dn_DevName
= AROS_BSTR_ADDR(dn
->dn_Name
);
290 if (AddDosEntry((struct DosList
*)dn
))
291 if (NewAddTask(task
, deventry
, NULL
, tasktags
) != NULL
)
295 FreeMem(dn
, sizeof (struct DeviceNode
));
299 if (NewAddTask(task
, deventry
, NULL
, tasktags
) != NULL
)
302 FreeMem(semaphore
, sizeof(struct SignalSemaphore
));
305 FreeMem(stack
, AROS_STACKSIZE
);
308 FreeMem(task
, sizeof(struct Task
));
311 FreeMem(port
, sizeof(struct MsgPort
));
314 CloseLibrary((struct Library
*)rambase
->utilitybase
);
317 CloseLibrary((struct Library
*)rambase
->dosbase
);
326 #define UtilityBase rambase->utilitybase
329 /***************************************************************************/
331 void nullDelete(struct rambase
*rambase
, void *key
, struct List
*list
)
333 // struct Receiver *rr;
334 // struct Node *tempNode;
336 // ForeachNodeSafe(list, rr, tempNode)
338 // Remove(&rr->node);
344 /* The list is part of the HashNode so we shouldn't free that */
348 ULONG
stringHash(struct rambase
*rambase
, const void *key
)
350 STRPTR str
= (STRPTR
)key
;
355 val
*= ToLower(*str
++);
363 my_strcasecmp(struct rambase
*rambase
, const void *s1
, const void *s2
)
365 return strcasecmp(s1
, s2
);
368 /****************************************************************************/
371 STRPTR
Strdup(struct rambase
*rambase
, CONST_STRPTR string
)
373 CONST_STRPTR s2
= string
;
379 s3
= (STRPTR
)AllocVec(s2
- string
, MEMF_ANY
);
383 CopyMem(string
, s3
, s2
- string
);
390 void Strfree(struct rambase
*rambase
, STRPTR string
)
396 static int GM_UNIQUENAME(Open
)
398 LIBBASETYPEPTR rambase
,
399 struct IOFileSys
*iofs
,
404 /* Mark Message as recently used. */
405 iofs
->IOFS
.io_Message
.mn_Node
.ln_Type
= NT_REPLYMSG
;
407 return OpenDev(rambase
, iofs
);
411 static int OpenDev(LIBBASETYPEPTR rambase
, struct IOFileSys
*iofs
)
413 struct filehandle
*fhv
, *fhc
;
418 iofs
->IOFS
.io_Error
= ERROR_NO_FREE_STORE
;
420 fhv
= (struct filehandle
*)AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
424 fhc
= (struct filehandle
*)AllocMem(sizeof(struct filehandle
),
429 vol
= (struct vnode
*)AllocMem(sizeof(struct vnode
), MEMF_CLEAR
);
433 dev
= (struct cnode
*)AllocMem(sizeof(struct cnode
),
438 vol
->name
= Strdup(rambase
, "Ram Disk");
440 if (vol
->name
!= NULL
)
442 dlv
= MakeDosEntry("Ram Disk", DLT_VOLUME
);
446 vol
->type
= ST_USERDIR
;
450 NewList((struct List
*)&vol
->list
);
451 NewList((struct List
*)&vol
->receivers
);
452 fhv
->node
= (struct dnode
*)vol
;
453 dlv
->dol_Ext
.dol_AROS
.dol_Unit
= (struct Unit
*)fhv
;
454 dlv
->dol_Ext
.dol_AROS
.dol_Device
= &rambase
->device
;
455 dev
->type
= ST_LINKDIR
;
458 fhc
->node
= (struct dnode
*)dev
;
459 iofs
->IOFS
.io_Unit
= (struct Unit
*)fhc
;
460 iofs
->IOFS
.io_Device
= &rambase
->device
;
463 iofs
->IOFS
.io_Error
= 0;
465 rambase
->notifications
=
466 HashTable_new(rambase
, 100, stringHash
,
467 my_strcasecmp
, nullDelete
);
472 Strfree(rambase
, vol
->name
);
475 FreeMem(dev
, sizeof(struct cnode
));
478 FreeMem(vol
, sizeof(struct vnode
));
481 FreeMem(fhc
, sizeof(struct filehandle
));
484 FreeMem(fhv
, sizeof(struct filehandle
));
487 iofs
->IOFS
.io_Error
= IOERR_OPENFAIL
;
492 static int GM_UNIQUENAME(Expunge
)(LIBBASETYPEPTR rambase
)
495 This function is single-threaded by exec by calling Forbid.
496 Never break the Forbid() or strange things might happen.
499 /* Kill device task and free all resources */
500 RemTask(rambase
->port
->mp_SigTask
);
501 FreeMem(rambase
->sigsem
, sizeof(struct SignalSemaphore
));
502 FreeMem(((struct Task
*)rambase
->port
->mp_SigTask
)->tc_SPLower
,
504 FreeMem(rambase
->port
->mp_SigTask
, sizeof(struct Task
));
505 FreeMem(rambase
->port
, sizeof(struct MsgPort
));
506 CloseLibrary((struct Library
*)rambase
->utilitybase
);
507 CloseLibrary((struct Library
*)rambase
->dosbase
);
513 AROS_LH1(void, beginio
,
514 AROS_LHA(struct IOFileSys
*, iofs
, A1
),
515 struct rambase
*, rambase
, 5, Ram
)
519 /* WaitIO will look into this */
520 iofs
->IOFS
.io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
522 /* Nothing is done quick */
523 iofs
->IOFS
.io_Flags
&= ~IOF_QUICK
;
525 /* So let the device task do it */
526 PutMsg(rambase
->port
, &iofs
->IOFS
.io_Message
);
532 AROS_LH1(LONG
, abortio
,
533 AROS_LHA(struct IOFileSys
*, iofs
, A1
),
534 struct rambase
*, rambase
, 6, Ram
)
542 static LONG
getblock(struct rambase
*rambase
, struct fnode
*file
, LONG block
,
543 int mode
, UBYTE
**result
)
550 p
= &file
->blocks
[block
];
554 else if (block
< 0x410)
557 p
= (UBYTE
**)&file
->iblocks
[block
/0x100];
561 else if(block
< 0x10410)
564 p
= (UBYTE
**)&file
->i2block
;
570 p
= (UBYTE
**)&file
->i3block
;
586 while (i
-- && p
!= NULL
)
588 a
= (block
>> i
*8) & 0xff;
591 if (!(block
& ((1 << i
*8) - 1)))
597 FreeMem(p
, PBLOCKSIZE
);
606 FreeMem(p
, BLOCKSIZE
);
614 while (i
-- && p
!= NULL
)
616 p
= ((UBYTE
***)p
)[(block
>> i
*8) & 0xff];
619 *result
= (UBYTE
*)p
;
627 *p
= AllocMem(PBLOCKSIZE
, MEMF_CLEAR
);
631 return ERROR_NO_FREE_STORE
;
635 p
= (UBYTE
**)*p
+ ((block
>> i
*8) & 0xff);
640 *p
= AllocMem(BLOCKSIZE
, MEMF_CLEAR
);
644 return ERROR_NO_FREE_STORE
;
650 } /* switch (mode) */
656 static void zerofill(UBYTE
*address
, ULONG size
)
665 static void shrinkfile(struct rambase
*rambase
, struct fnode
*file
, LONG size
)
670 blocks
= (size
+ BLOCKSIZE
- 1)/BLOCKSIZE
;
671 block
= (file
->size
+ BLOCKSIZE
- 1)/BLOCKSIZE
;
673 for(;block
-- > blocks
;)
675 (void)getblock(rambase
, file
, block
, -1, &p
);
680 (void)getblock(rambase
, file
, size
, 0, &p
);
684 zerofill(p
+ (size
& 0xff), -size
& 0xff);
692 static void delete(struct rambase
*rambase
, struct fnode
*file
)
694 struct hnode
*link
, *new, *more
;
697 Strfree(rambase
, file
->name
);
698 Strfree(rambase
, file
->comment
);
699 Remove((struct Node
*)file
);
701 if (file
->type
== ST_LINKDIR
)
703 /* It is a link. Remove it from the chain. */
705 link
= ((struct hnode
*)file
)->orig
;
706 ((struct hnode
*)file
)->orig
= NULL
;
707 file
->type
= link
->type
;
709 while((struct fnode
*)link
->link
!= file
)
714 link
->link
= file
->link
;
716 else if (file
->link
!= NULL
)
718 /* If there is a hard link to the object make the link the original */
721 link
->type
= file
->type
;
733 while((node
= RemHead((struct List
*)&((struct dnode
*)file
)->list
)) != NULL
)
734 AddTail((struct List
*)&((struct dnode
*)file
)->list
, node
);
738 CopyMemQuick(&file
->size
, &((struct fnode
*)new)->size
,
739 sizeof(struct fnode
) - offsetof(struct fnode
, size
));
740 zerofill((UBYTE
*)&file
->size
,
741 sizeof(struct fnode
) - offsetof(struct fnode
, size
));
745 ((struct snode
*)new)->contents
= ((struct snode
*)file
)->contents
;
746 ((struct snode
*)file
)->contents
= NULL
;
749 } /* else if (file->link != NULL) */
754 Notify_directoryChange(rambase
, NOTIFY_Delete
, (struct dnode
*)file
);
756 FreeMem(file
, sizeof(struct dnode
));
761 Notify_fileChange(rambase
, NOTIFY_Delete
, file
);
763 shrinkfile(rambase
, file
, 0);
764 FreeMem(file
, sizeof(struct fnode
));
769 Strfree(rambase
, ((struct snode
*)file
)->contents
);
770 FreeMem(file
, sizeof(struct snode
));
777 static int fstrcmp(struct rambase
*rambase
, CONST_STRPTR s1
, CONST_STRPTR s2
)
781 if (ToLower(*s1
) != ToLower(*s2
))
783 return *s1
|| *s2
!= '/';
797 /* Find a node for a given name */
798 static LONG
findname(struct rambase
*rambase
, CONST_STRPTR
*name
,
799 struct dnode
**dnode
)
801 struct dnode
*cur
= *dnode
;
802 CONST_STRPTR rest
= *name
;
806 if (cur
->type
== ST_LINKDIR
)
808 cur
= (struct dnode
*)((struct hnode
*)cur
)->orig
;
818 if ((struct dnode
*)cur
->volume
== cur
)
820 return ERROR_OBJECT_NOT_FOUND
;
823 while (cur
->node
.mln_Pred
!= NULL
)
825 cur
= (struct dnode
*)cur
->node
.mln_Pred
;
828 cur
= (struct dnode
*)((BYTE
*)cur
- offsetof(struct dnode
, list
));
832 if (cur
->type
== ST_SOFTLINK
)
837 return ERROR_IS_SOFT_LINK
;
840 if (cur
->type
!= ST_USERDIR
)
842 return ERROR_DIR_NOT_FOUND
;
846 cur
= (struct dnode
*)cur
->list
.mlh_Head
;
850 if (cur
->node
.mln_Succ
== NULL
)
854 return ERROR_OBJECT_NOT_FOUND
;
857 if (!fstrcmp(rambase
, cur
->name
, rest
))
862 cur
= (struct dnode
*)cur
->node
.mln_Succ
;
881 static LONG
set_file_size(struct rambase
*rambase
, struct filehandle
*handle
,
882 QUAD
*offp
, LONG mode
)
884 struct fnode
*file
= (struct fnode
*)handle
->node
;
887 if (file
->type
!= ST_FILE
)
889 return ERROR_OBJECT_WRONG_TYPE
;
894 case OFFSET_BEGINNING
:
898 size
+= handle
->position
;
906 return ERROR_NOT_IMPLEMENTED
;
911 return ERROR_SEEK_ERROR
;
914 if (size
< file
->size
)
916 shrinkfile(rambase
, file
, size
);
919 file
->size
= *offp
= size
;
925 static LONG
read(struct rambase
*rambase
, struct filehandle
*handle
,
926 APTR buffer
, LONG
*numbytes
)
928 struct fnode
*file
= (struct fnode
*)handle
->node
;
929 ULONG num
= *numbytes
;
930 ULONG size
= file
->size
;
932 UBYTE
*buf
= buffer
, *p
;
934 if (handle
->position
>= size
)
938 else if (handle
->position
+ num
> size
)
940 num
= size
- handle
->position
;
943 block
= handle
->position
/BLOCKSIZE
;
944 offset
= handle
->position
& (BLOCKSIZE
- 1);
945 size
= BLOCKSIZE
- offset
;
954 (void)getblock(rambase
, file
, block
, 0, &p
);
958 CopyMem(p
+ offset
, buffer
, size
);
962 zerofill(buffer
, size
);
972 *numbytes
= (UBYTE
*)buffer
- buf
;
973 handle
->position
+= *numbytes
;
979 static LONG
write(struct rambase
*rambase
, struct filehandle
*handle
,
980 UBYTE
*buffer
, LONG
*numbytes
)
982 struct fnode
*file
= (struct fnode
*)handle
->node
;
983 ULONG num
= *numbytes
;
984 ULONG size
= file
->size
;
986 UBYTE
*buf
= buffer
, *p
;
989 if ((LONG
)(handle
->position
+ num
) < 0)
991 return ERROR_OBJECT_TOO_LARGE
;
994 Notify_fileChange(rambase
, NOTIFY_Write
, file
);
996 block
= handle
->position
/BLOCKSIZE
;
997 offset
= handle
->position
& (BLOCKSIZE
- 1);
998 size
= BLOCKSIZE
- offset
;
1007 error
= getblock(rambase
, file
, block
, 1, &p
);
1014 CopyMem(buffer
, p
+ offset
, size
);
1022 *numbytes
= (UBYTE
*)buffer
- buf
;
1023 handle
->position
+= *numbytes
;
1024 DateStamp(&file
->date
);
1026 if (handle
->position
> file
->size
)
1028 file
->size
= handle
->position
;
1035 static LONG
lock(struct dnode
*dir
, ULONG mode
)
1037 if ((mode
& FMF_EXECUTE
) && (dir
->protect
& FMF_EXECUTE
))
1039 return ERROR_NOT_EXECUTABLE
;
1042 if ((mode
& FMF_WRITE
) && (dir
->protect
& FMF_WRITE
))
1044 return ERROR_WRITE_PROTECTED
;
1047 if ((mode
& FMF_READ
) && (dir
->protect
& FMF_READ
))
1049 return ERROR_READ_PROTECTED
;
1052 if (mode
& FMF_LOCK
)
1056 return ERROR_OBJECT_IN_USE
;
1059 dir
->usecount
= ((ULONG
)~0)/2 + 1;
1063 if (dir
->usecount
< 0)
1065 return ERROR_OBJECT_IN_USE
;
1070 dir
->volume
->volcount
++;
1076 static LONG
open_(struct rambase
*rambase
, struct filehandle
**handle
,
1077 CONST_STRPTR name
, ULONG mode
)
1079 struct dnode
*dir
= (*handle
)->node
;
1080 struct filehandle
*fh
;
1083 fh
= (struct filehandle
*)AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
1087 error
= findname(rambase
, &name
, &dir
);
1091 error
= lock(dir
, mode
);
1098 if (dir
->type
== ST_FILE
)
1100 Notify_fileChange(rambase
, NOTIFY_Open
,
1101 (struct fnode
*)dir
);
1103 else if (dir
->type
== ST_USERDIR
)
1105 D(kprintf("Notifying OPEN at dir %s\n", dir
->name
));
1106 Notify_directoryChange(rambase
, NOTIFY_Open
, dir
);
1113 FreeMem(fh
, sizeof(struct filehandle
));
1117 error
= ERROR_NO_FREE_STORE
;
1124 static LONG
open_file(struct rambase
*rambase
, struct filehandle
**handle
,
1125 CONST_STRPTR name
, ULONG mode
, ULONG protect
)
1127 struct dnode
*dir
= (*handle
)->node
;
1128 struct filehandle
*fh
;
1131 fh
= AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
1135 error
= findname(rambase
, &name
, &dir
);
1137 if ((mode
& FMF_CREATE
) && error
== ERROR_OBJECT_NOT_FOUND
)
1139 CONST_STRPTR s
= name
;
1150 file
= (struct fnode
*)AllocMem(sizeof(struct fnode
), MEMF_CLEAR
);
1151 DateStamp(&file
->date
);
1155 file
->name
= Strdup(rambase
, name
);
1157 if (file
->name
!= NULL
)
1159 file
->type
= ST_FILE
;
1160 file
->protect
= protect
;
1161 file
->volume
= dir
->volume
;
1162 NewList((struct List
*)&file
->receivers
);
1163 AddTail((struct List
*)&dir
->list
, (struct Node
*)file
);
1164 error
= lock((struct dnode
*)file
, mode
);
1168 fh
->node
= (struct dnode
*)file
;
1171 Notify_fileChange(rambase
, NOTIFY_Add
, file
);
1176 Strfree(rambase
, file
->name
);
1179 FreeMem(file
,sizeof(struct fnode
));
1182 error
= ERROR_NO_FREE_STORE
;
1186 if (dir
->type
!= ST_FILE
)
1188 error
= ERROR_OBJECT_WRONG_TYPE
;
1192 error
= lock(dir
, mode
);
1197 if (mode
& FMF_CLEAR
)
1199 shrinkfile(rambase
, (struct fnode
*)dir
, 0);
1200 dir
->protect
= protect
;
1210 } /* else if (!error) */
1212 FreeMem(fh
, sizeof(struct filehandle
));
1219 static LONG
create_dir(struct rambase
*rambase
, struct filehandle
**handle
,
1220 CONST_STRPTR name
, ULONG protect
)
1222 struct dnode
*dir
= (*handle
)->node
, *new;
1223 struct filehandle
*fh
;
1226 if (dir
->protect
& FIBF_WRITE
)
1228 return ERROR_WRITE_PROTECTED
;
1231 error
= findname(rambase
, &name
, &dir
);
1235 return ERROR_OBJECT_EXISTS
;
1238 if (error
!= ERROR_OBJECT_NOT_FOUND
)
1243 if (strchr(name
, '/') != NULL
)
1248 fh
= AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
1252 new = (struct dnode
*)AllocMem(sizeof(struct dnode
), MEMF_CLEAR
);
1256 new->name
= Strdup(rambase
, name
);
1258 if (new->name
!= NULL
)
1260 new->type
= ST_USERDIR
;
1261 new->protect
= protect
;
1262 new->volume
= dir
->volume
;
1263 new->volume
->volcount
++;
1264 new->usecount
= ((ULONG
)~0)/2 + 2;
1265 NewList((struct List
*)&new->list
);
1266 NewList((struct List
*)&new->receivers
);
1267 AddTail((struct List
*)&dir
->list
, (struct Node
*)new);
1270 DateStamp(&new->date
);
1272 D(bug("New (%p): Name = %s\n", new, new->name
));
1273 Notify_directoryChange(rambase
, NOTIFY_Add
, new);
1278 FreeMem(new, sizeof(struct dnode
));
1281 FreeMem(fh
, sizeof(struct filehandle
));
1284 return ERROR_NO_FREE_STORE
;
1288 static LONG
free_lock(struct rambase
*rambase
, struct filehandle
*filehandle
)
1290 struct dnode
*dnode
= filehandle
->node
;
1292 dnode
->usecount
= (dnode
->usecount
- 1) & ((ULONG
)~0)/2;
1293 FreeMem(filehandle
, sizeof(struct filehandle
));
1294 dnode
->volume
->volcount
--;
1300 static LONG
seek(struct rambase
*rambase
, struct filehandle
*filehandle
,
1301 QUAD
*posp
, LONG mode
)
1303 struct fnode
*file
= (struct fnode
*)filehandle
->node
;
1306 if (file
->type
!= ST_FILE
)
1308 return ERROR_OBJECT_WRONG_TYPE
;
1313 case OFFSET_BEGINNING
:
1316 case OFFSET_CURRENT
:
1317 pos
+= filehandle
->position
;
1325 return ERROR_NOT_IMPLEMENTED
;
1330 return ERROR_SEEK_ERROR
;
1333 *posp
= filehandle
->position
;
1334 filehandle
->position
= pos
;
1340 static const ULONG sizes
[]=
1343 offsetof(struct ExAllData
,ed_Type
),
1344 offsetof(struct ExAllData
,ed_Size
),
1345 offsetof(struct ExAllData
,ed_Prot
),
1346 offsetof(struct ExAllData
,ed_Days
),
1347 offsetof(struct ExAllData
,ed_Comment
),
1348 offsetof(struct ExAllData
,ed_OwnerUID
),
1349 sizeof(struct ExAllData
)
1353 static LONG
examine(struct fnode
*file
,
1354 struct ExAllData
*ead
,
1359 STRPTR next
, end
, name
;
1361 if (type
> ED_OWNER
)
1363 return ERROR_BAD_NUMBER
;
1366 next
= (STRPTR
)ead
+ sizes
[type
];
1367 end
= (STRPTR
)ead
+ size
;
1369 if(next
>end
) /* > is correct. Not >= */
1370 return ERROR_BUFFER_OVERFLOW
;
1372 /* Use *dirpos to store information for ExNext()
1373 * *dirpos is copied to fib->fib_DiskKey in Examine()
1375 if (file
->type
== ST_USERDIR
)
1377 *dirpos
= (LONG
)(((struct dnode
*)file
)->list
.mlh_Head
);
1381 /* ExNext() should not be called in this case anyway */
1382 *dirpos
= (LONG
)file
;
1388 ead
->ed_OwnerUID
= 0;
1389 ead
->ed_OwnerGID
= 0;
1393 if (file
->comment
!= NULL
)
1395 ead
->ed_Comment
= next
;
1396 name
= file
->comment
;
1402 return ERROR_BUFFER_OVERFLOW
;
1405 if (!(*next
++ = *name
++))
1413 ead
->ed_Comment
= NULL
;
1418 ead
->ed_Days
= file
->date
.ds_Days
;
1419 ead
->ed_Mins
= file
->date
.ds_Minute
;
1420 ead
->ed_Ticks
= file
->date
.ds_Tick
;
1424 ead
->ed_Prot
= file
->protect
;
1428 ead
->ed_Size
= file
->size
;
1432 ead
->ed_Type
= file
->type
;
1434 if (((struct vnode
*)file
)->self
== (struct vnode
*)file
)
1436 ead
->ed_Type
=ST_ROOT
;
1441 ead
->ed_Name
= next
;
1448 return ERROR_BUFFER_OVERFLOW
;
1451 if (!(*next
++ = *name
++))
1459 ead
->ed_Next
= (struct ExAllData
*)(((IPTR
)next
+ AROS_PTRALIGN
- 1) & ~(AROS_PTRALIGN
- 1));
1466 static LONG
examine_next(struct rambase
*rambase
,
1467 struct filehandle
*dir
,
1468 struct FileInfoBlock
*FIB
)
1470 struct fnode
*file
= (struct fnode
*)FIB
->fib_DiskKey
;
1472 ASSERT_VALID_PTR_OR_NULL(file
);
1474 if (file
->node
.mln_Succ
== NULL
)
1476 return ERROR_NO_MORE_ENTRIES
;
1479 FIB
->fib_OwnerUID
= 0;
1480 FIB
->fib_OwnerGID
= 0;
1482 FIB
->fib_Date
.ds_Days
= file
->date
.ds_Days
;
1483 FIB
->fib_Date
.ds_Minute
= file
->date
.ds_Minute
;
1484 FIB
->fib_Date
.ds_Tick
= file
->date
.ds_Tick
;
1485 FIB
->fib_Protection
= file
->protect
;
1486 FIB
->fib_Size
= file
->size
;
1487 FIB
->fib_DirEntryType
= file
->type
;
1489 strncpy(FIB
->fib_FileName
, file
->name
, MAXFILENAMELENGTH
- 1);
1490 strncpy(FIB
->fib_Comment
, file
->comment
!= NULL
? file
->comment
: "",
1491 MAXCOMMENTLENGTH
- 1);
1493 FIB
->fib_DiskKey
= (LONG
)file
->node
.mln_Succ
;
1499 static LONG
examine_all(struct filehandle
*dir
,
1500 struct ExAllData
*ead
,
1501 struct ExAllControl
*eac
,
1506 struct ExAllData
*last
=NULL
;
1509 LONG dummy
; /* not anything is done with this value but passed to examine */
1510 end
= (STRPTR
)ead
+ size
;
1512 eac
->eac_Entries
= 0;
1513 if (dir
->node
->type
!= ST_USERDIR
)
1515 return ERROR_OBJECT_WRONG_TYPE
;
1518 ent
= (struct fnode
*)eac
->eac_LastKey
;
1522 ent
= (struct fnode
*)dir
->node
->list
.mlh_Head
;
1523 if (ent
->node
.mln_Succ
) ent
->usecount
++;
1526 if (ent
->node
.mln_Succ
== NULL
)
1528 return ERROR_NO_MORE_ENTRIES
;
1535 error
= examine(ent
, ead
, end
- (STRPTR
)ead
, type
, &dummy
);
1537 if (error
== ERROR_BUFFER_OVERFLOW
)
1545 last
->ed_Next
= NULL
;
1546 eac
->eac_LastKey
= (IPTR
)ent
;
1553 ent
= (struct fnode
*)ent
->node
.mln_Succ
;
1555 } while (ent
->node
.mln_Succ
!= NULL
);
1557 last
->ed_Next
= NULL
;
1558 eac
->eac_LastKey
= (IPTR
)ent
;
1560 return ERROR_NO_MORE_ENTRIES
;
1564 static LONG
rename_object(struct rambase
*rambase
,
1565 struct filehandle
*filehandle
,
1566 CONST_STRPTR namea
, CONST_STRPTR nameb
)
1568 struct dnode
*file
= filehandle
->node
;
1571 struct dnode
*nodea
= filehandle
->node
, *nodeb
;
1572 STRPTR dira
, dirb
, pos
= nameb
;
1574 error
= findname(rambase
, &pos
, &nodea
);
1576 return ERROR_OBJECT_EXISTS
;
1578 error
= findname(rambase
, &namea
, &file
);
1582 if ((struct dnode
*)file
->volume
== file
)
1583 return ERROR_OBJECT_WRONG_TYPE
;
1585 if (file
->usecount
!= 0)
1586 return ERROR_OBJECT_IN_USE
;
1588 dira
= Strdup(rambase
, namea
);
1589 dirb
= Strdup(rambase
, nameb
);
1591 pos
= strrchr(dira
, '/');
1600 pos
= strrchr(dirb
, '/');
1609 D(bug("[Ram] rename (%s,%s)=>(%s,%s)\n", dira
, namea
, dirb
, nameb
));
1611 if (*dira
== '\0' && *dirb
== '\0')
1613 Strfree(rambase
, file
->name
);
1614 file
->name
= Strdup(rambase
, nameb
);
1618 nodea
= filehandle
->node
;
1619 error
= findname(rambase
, &dira
, &nodea
);
1623 nodeb
= filehandle
->node
;
1624 error
= findname(rambase
, &dirb
, &nodeb
);
1630 Remove((struct Node
*)file
);
1631 AddTail((struct List
*)&nodeb
->list
, (struct Node
*)file
);
1634 Strfree(rambase
, file
->name
);
1635 file
->name
= Strdup(rambase
, nameb
);
1638 DateStamp(&file
->date
);
1643 Notify_fileChange(rambase
, NOTIFY_Delete
, (struct fnode
*)file
);
1644 Notify_fileChange(rambase
, NOTIFY_Add
, (struct fnode
*)file
);
1648 Notify_directoryChange(rambase
, NOTIFY_Delete
, file
);
1649 Notify_directoryChange(rambase
, NOTIFY_Add
, file
);
1654 Strfree(rambase
, dirb
);
1655 Strfree(rambase
, dira
);
1660 static LONG
delete_object(struct rambase
*rambase
,
1661 struct filehandle
*filehandle
, CONST_STRPTR name
)
1663 struct dnode
*file
= filehandle
->node
;
1666 error
= findname(rambase
, &name
, &file
);
1673 if ((struct dnode
*)file
->volume
== file
)
1675 return ERROR_OBJECT_WRONG_TYPE
;
1678 if (file
->usecount
!= 0)
1680 return ERROR_OBJECT_IN_USE
;
1683 if (file
->protect
& FIBF_DELETE
)
1685 return ERROR_DELETE_PROTECTED
;
1688 if (file
->type
== ST_USERDIR
&& file
->list
.mlh_Head
->mln_Succ
!= NULL
)
1690 return ERROR_DIRECTORY_NOT_EMPTY
;
1693 delete(rambase
, (struct fnode
*)file
);
1699 static int GM_UNIQUENAME(Close
)
1701 LIBBASETYPEPTR rambase
,
1702 struct IOFileSys
*iofs
1710 struct filehandle
*handle
;
1712 handle
= (struct filehandle
*)iofs
->IOFS
.io_Unit
;
1713 dev
= (struct cnode
*)handle
->node
;
1716 if (dev
->type
!= ST_LINKDIR
|| dev
->self
!= dev
)
1718 iofs
->io_DosError
= ERROR_OBJECT_WRONG_TYPE
;
1725 iofs
->io_DosError
= ERROR_OBJECT_IN_USE
;
1730 free_lock(rambase
, handle
);
1731 RemDosEntry(vol
->doslist
);
1732 FreeDosEntry(vol
->doslist
);
1734 while (vol
->list
.mlh_Head
->mln_Succ
!= NULL
)
1736 dir
= (struct dnode
*)vol
->list
.mlh_Head
;
1738 if (dir
->type
== ST_USERDIR
)
1740 while((file
= (struct fnode
*)RemHead((struct List
*)&dir
->list
)) != NULL
)
1742 AddTail((struct List
*)&vol
->list
, (struct Node
*)dir
);
1746 delete(rambase
, (struct fnode
*)dir
);
1749 Strfree(rambase
, vol
->name
);
1750 FreeMem(vol
, sizeof(struct vnode
));
1752 Strfree(rambase
, dev
->name
);
1753 FreeMem(dev
, sizeof(struct cnode
));
1755 iofs
->io_DosError
= 0;
1761 void processFSM(struct rambase
*rambase
);
1764 static void deventry(struct rambase
*rambase
)
1768 struct Message
*msg
;
1771 Init device port. AllocSignal() cannot fail because this is a
1772 freshly created task with all signal bits still free.
1775 rambase
->port
->mp_SigBit
= AllocSignal(-1);
1776 rambase
->port
->mp_Flags
= PA_SIGNAL
;
1778 /* Check if there are pending messages that we missed */
1779 if ((msg
= GetMsg(rambase
->port
))) PutMsg(rambase
->port
, msg
);
1781 Notify_initialize(rambase
);
1783 notifyMask
= 1 << rambase
->notifyPort
->mp_SigBit
;
1785 fileOpMask
= 1 << rambase
->port
->mp_SigBit
;
1791 flags
= Wait(fileOpMask
| notifyMask
);
1793 if (flags
& notifyMask
)
1795 struct NotifyMessage
*nMessage
;
1797 D(kprintf("Got replied notify message\n"));
1799 while ((nMessage
= (struct NotifyMessage
*)GetMsg(rambase
->notifyPort
)) != NULL
)
1801 nMessage
->nm_NReq
->nr_Flags
&= ~NRF_NOT_REPLIED
;
1806 if (flags
& fileOpMask
)
1808 processFSM(rambase
);
1814 void processFSM(struct rambase
*rambase
)
1816 struct IOFileSys
*iofs
;
1821 /* Get and process the messages. */
1822 while ((iofs
= (struct IOFileSys
*)GetMsg(rambase
->port
)) != NULL
)
1824 D(bug("Ram.handler initialized %u\n", iofs
->IOFS
.io_Command
));
1826 switch (iofs
->IOFS
.io_Command
)
1830 get handle on a file or directory
1831 Unit *current; current directory / new handle on return
1832 STRPTR name; file- or directoryname
1833 LONG mode; open mode
1836 error
= open_(rambase
,
1837 (struct filehandle
**)&iofs
->IOFS
.io_Unit
,
1838 iofs
->io_Union
.io_OPEN
.io_Filename
,
1839 iofs
->io_Union
.io_OPEN
.io_FileMode
);
1844 open a file or create a new one
1845 Unit *current; current directory / new handle on return
1846 STRPTR name; file- or directoryname
1847 LONG mode; open mode
1848 LONG protect; protection flags if a new file is created
1851 error
= open_file(rambase
,
1852 (struct filehandle
**)&iofs
->IOFS
.io_Unit
,
1853 iofs
->io_Union
.io_OPEN_FILE
.io_Filename
,
1854 iofs
->io_Union
.io_OPEN_FILE
.io_FileMode
,
1855 iofs
->io_Union
.io_OPEN_FILE
.io_Protection
);
1860 read a number of bytes from a file
1861 Unit *current; filehandle
1863 LONG numbytes; number of bytes to read /
1864 number of bytes read on return,
1865 0 if there are no more bytes in the file
1867 error
= read(rambase
,
1868 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1869 iofs
->io_Union
.io_READ
.io_Buffer
,
1870 &iofs
->io_Union
.io_READ
.io_Length
);
1875 write a number of bytes to a file
1876 Unit *current; filehandle
1878 LONG numbytes; number of bytes to write /
1879 number of bytes written on return
1881 error
= write(rambase
,
1882 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1883 iofs
->io_Union
.io_WRITE
.io_Buffer
,
1884 &iofs
->io_Union
.io_WRITE
.io_Length
);
1889 set / read position in file
1890 Unit *current; filehandle
1892 LONG posl; relative position /
1893 old position on return
1894 LONG mode; one of OFFSET_BEGINNING, OFFSET_CURRENT,
1897 error
= seek(rambase
,
1898 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1899 &iofs
->io_Union
.io_SEEK
.io_Offset
,
1900 iofs
->io_Union
.io_SEEK
.io_SeekMode
);
1905 /* Get rid of a handle
1906 Unit *current; filehandle */
1908 struct filehandle
*handle
=
1909 (struct filehandle
*)iofs
->IOFS
.io_Unit
;
1911 Notify_fileChange(rambase
, NOTIFY_Close
,
1912 (struct fnode
*)handle
->node
);
1913 error
= free_lock(rambase
, handle
);
1919 Get information about the current object
1920 Unit *current; current object
1921 struct ExAllData *ead; buffer to be filled
1922 ULONG size; size of the buffer
1923 ULONG type; type of information to get
1924 iofs->io_DirPos; leave current position so
1925 ExNext() knows where to find
1928 error
= examine((struct fnode
*)((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
,
1929 iofs
->io_Union
.io_EXAMINE
.io_ead
,
1930 iofs
->io_Union
.io_EXAMINE
.io_Size
,
1931 iofs
->io_Union
.io_EXAMINE
.io_Mode
,
1932 &(iofs
->io_DirPos
));
1935 case FSA_EXAMINE_NEXT
:
1937 Get information about the next object
1938 Unit *current; current object
1939 struct FileInfoBlock *fib;
1941 error
= examine_next(rambase
,
1942 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1943 iofs
->io_Union
.io_EXAMINE_NEXT
.io_fib
);
1946 case FSA_EXAMINE_ALL
:
1948 Read the current directory
1949 Unit *current; current directory
1950 struct ExAllData *ead; buffer to be filled
1951 ULONG size; size of the buffer
1952 ULONG type; type of information to get
1954 error
= examine_all((struct filehandle
*)iofs
->IOFS
.io_Unit
,
1955 iofs
->io_Union
.io_EXAMINE_ALL
.io_ead
,
1956 iofs
->io_Union
.io_EXAMINE_ALL
.io_eac
,
1957 iofs
->io_Union
.io_EXAMINE_ALL
.io_Size
,
1958 iofs
->io_Union
.io_EXAMINE_ALL
.io_Mode
);
1961 case FSA_CREATE_DIR
:
1963 Build lock and open a new directory
1964 Unit *current; current directory
1965 STRPTR name; name of the dir to create
1966 LONG protect; Protection flags for the new dir
1969 // kprintf("Creating directory %s\n",
1970 // iofs->io_Union.io_CREATE_DIR.io_Filename);
1973 error
= create_dir(rambase
,
1974 (struct filehandle
**)&iofs
->IOFS
.io_Unit
,
1975 iofs
->io_Union
.io_CREATE_DIR
.io_Filename
,
1976 iofs
->io_Union
.io_CREATE_DIR
.io_Protection
);
1979 case FSA_DELETE_OBJECT
:
1981 Delete file or directory
1982 Unit *current; current directory
1983 STRPTR name; filename
1985 error
= delete_object(rambase
,
1986 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1987 iofs
->io_Union
.io_DELETE_OBJECT
.io_Filename
);
1990 case FSA_SET_PROTECT
:
1993 Set protection bits for a certain file or directory.
1994 Unit *current; current directory
1995 STRPTR name; filename
1996 ULONG protect; new protection bits
1999 CONST_STRPTR name
= iofs
->io_Union
.io_SET_PROTECT
.io_Filename
;
2001 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
2002 error
= findname(rambase
, &name
, &dir
);
2006 dir
->protect
= iofs
->io_Union
.io_SET_PROTECT
.io_Protection
;
2015 Set owner and group of the file or directory
2016 Unit *current; current directory
2017 STRPTR name; filename
2022 CONST_STRPTR name
= iofs
->io_Union
.io_SET_OWNER
.io_Filename
;
2024 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
2025 error
= findname(rambase
, &name
, &dir
);
2037 Set creation date of the file
2038 Unit *current; current directory
2039 STRPTR name; filename
2042 ULONG ticks; timestamp
2045 CONST_STRPTR name
= iofs
->io_Union
.io_SET_DATE
.io_Filename
;
2047 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
2048 error
= findname(rambase
, &name
, &dir
);
2052 dir
->date
= iofs
->io_Union
.io_SET_DATE
.io_Date
;
2058 case FSA_SET_COMMENT
:
2061 Set a comment for the file or directory;
2062 Unit *current; current directory
2063 STRPTR name; filename
2064 STRPTR comment; NUL terminated C string or NULL.
2067 CONST_STRPTR name
= iofs
->io_Union
.io_SET_COMMENT
.io_Filename
;
2069 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
2070 error
= findname(rambase
, &name
, &dir
);
2074 if (iofs
->io_Union
.io_SET_COMMENT
.io_Comment
)
2076 STRPTR s
= Strdup(rambase
,
2077 iofs
->io_Union
.io_SET_COMMENT
.io_Comment
);
2080 Strfree(rambase
, dir
->comment
);
2085 error
= ERROR_NO_FREE_STORE
;
2090 Strfree(rambase
, dir
->comment
);
2091 dir
->comment
= NULL
;
2098 case FSA_SET_FILE_SIZE
:
2100 Set a new size for the file.
2101 Unit *file; filehandle
2103 LONG offl; offset to current position/
2105 LONG mode; relative to what (see Seek)
2107 error
= set_file_size(rambase
,
2108 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
2109 &iofs
->io_Union
.io_SET_FILE_SIZE
.io_Offset
,
2110 iofs
->io_Union
.io_SET_FILE_SIZE
.io_SeekMode
);
2113 case FSA_IS_FILESYSTEM
:
2114 iofs
->io_Union
.io_IS_FILESYSTEM
.io_IsFilesystem
= TRUE
;
2120 struct InfoData
*id
= iofs
->io_Union
.io_INFO
.io_Info
;
2122 id
->id_NumSoftErrors
= 0;
2123 id
->id_UnitNumber
= 0;
2124 id
->id_DiskState
= ID_VALIDATED
;
2125 id
->id_NumBlocks
= AvailMem(MEMF_TOTAL
| MEMF_PUBLIC
)/BLOCKSIZE
;
2126 id
->id_NumBlocksUsed
= id
->id_NumBlocks
- AvailMem(MEMF_PUBLIC
)/BLOCKSIZE
;
2127 id
->id_BytesPerBlock
= BLOCKSIZE
;
2128 id
->id_DiskType
= ID_DOS_DISK
;
2129 id
->id_VolumeNode
= NULL
; /* What is this? */
2130 id
->id_InUse
= (LONG
)TRUE
;
2138 case FSA_ADD_NOTIFY
:
2141 struct NotifyRequest
*nr
=
2142 iofs
->io_Union
.io_NOTIFY
.io_NotificationRequest
;
2143 struct filehandle
*fh
= (struct filehandle
*)iofs
->IOFS
.io_Unit
;
2145 D(kprintf("Adding notification for entity (nr = %s)\n",
2148 ok
= Notify_addNotification(rambase
, fh
->node
, nr
);
2152 error
= ERROR_NO_FREE_STORE
;
2155 D(kprintf("Notification now added!\n"));
2159 case FSA_REMOVE_NOTIFY
:
2161 struct NotifyRequest
*nr
=
2162 iofs
->io_Union
.io_NOTIFY
.io_NotificationRequest
;
2164 Notify_removeNotification(rambase
, nr
);
2169 error
= rename_object(rambase
,
2170 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
2171 iofs
->io_Union
.io_RENAME
.io_Filename
,
2172 iofs
->io_Union
.io_RENAME
.io_NewName
);
2175 case FSA_IS_INTERACTIVE
:
2176 iofs
->io_Union
.io_IS_INTERACTIVE
.io_IsInteractive
= 0;
2180 error
= ERROR_NOT_IMPLEMENTED
;
2182 D(kprintf("ram_handler, unimplemented FSA: %ld\n", iofs
->IOFS
.io_Command
));
2186 Change or read the mode of a single filehandle
2187 Unit *current; filehandle to change
2188 ULONG newmode; new mode/old mode on return
2189 ULONG mask; bits affected
2192 Change or read the mode of the filesystem
2193 Unit *current; filesystem to change
2194 ULONG newmode; new mode/old mode on return
2195 ULONG mask; bits affected
2196 STRPTR passwd; password for MMF_LOCKED
2199 Create a hard link on a file, directory or soft link
2200 Unit *current; current directory
2201 STRPTR name; softlink name
2202 Unit *target; target handle
2205 Create a soft link to another object
2206 Unit *current; current directory
2207 STRPTR name; softlink name
2208 STRPTR target; target name
2227 iofs
->io_DosError
= error
;
2228 ReplyMsg(&iofs
->IOFS
.io_Message
);
2232 if (rambase
->iofs
!= NULL
)
2234 iofs
= rambase
->iofs
;
2236 if (iofs
->IOFS
.io_Message
.mn_Node
.ln_Type
== NT_MESSAGE
)
2238 abort_notify(rambase
, iofs
);
2239 iofs
->io_DosError
= ERROR_BREAK
;
2240 rambase
->iofs
= NULL
;
2241 ReplyMsg(&iofs
->IOFS
.io_Message
);
2245 rambase
->iofs
= NULL
;
2256 /***************************************************************************
2257 ****************************************************************************/
2259 /** Notification stuff **/
2262 * Immediate notification:
2264 * ACTION_RENAME_OBJECT
2265 * ACTION_RENAME_DISK
2267 * ACTION_DELETE_OBJECT
2271 * Session semantics notification:
2276 * ACTION_SET_FILE_SIZE
2279 * For ram-handler, the only FSA actions currently implemented/affected are
2280 * FSA_WRITE, FSA_CREATE_DIR, FSA_DELETE (and implicitly FSA_OPEN, FSA_CLOSE)
2285 BOOL
Notify_initialize(struct rambase
*rambase
)
2287 rambase
->notifyPort
= CreateMsgPort();
2289 if (rambase
->notifyPort
== NULL
)
2298 void Notify_fileChange(struct rambase
*rambase
, NType type
, struct fnode
*file
)
2306 D(bug("Setting write flag!\n"));
2307 file
->flags
|= FILEFLAGS_Changed
;
2311 /* Only notify in case the file was changed */
2312 if (file
->flags
& FILEFLAGS_Changed
)
2314 D(bug("Notification on close (file was changed).\n"));
2315 file
->flags
&= ~FILEFLAGS_Changed
;
2316 Notify_notifyTasks(rambase
, &file
->receivers
);
2323 struct List
*receivers
;
2325 fullName
= getName(rambase
, (struct dnode
*)file
);
2327 D(kprintf("Found full name: %s\n", fullName
));
2329 receivers
= HashTable_find(rambase
, rambase
->notifications
,
2332 if (receivers
!= NULL
)
2334 D(kprintf("Found notification for created file!\n"));
2336 while (!IsListEmpty(receivers
))
2338 AddHead((struct List
*)&file
->receivers
,
2339 RemHead(receivers
));
2343 HashTable_remove(rambase
, rambase
->notifications
, fullName
);
2345 D(bug("Notifying file receivers!\n"));
2346 Notify_notifyTasks(rambase
, &file
->receivers
);
2353 /* It's the same thing as for directories... */
2354 Notify_directoryChange(rambase
, NOTIFY_Delete
, (struct dnode
*)file
);
2364 void Notify_directoryChange(struct rambase
*rambase
, NType type
,
2373 fullName
= getName(rambase
, dir
);
2375 /* TODO: HashTable_apply(ht, fullName, dir); */
2384 struct List
*receivers
;
2386 fullName
= getName(rambase
, dir
);
2388 D(kprintf("Found full name: %s\n", fullName
));
2390 receivers
= HashTable_find(rambase
, rambase
->notifications
,
2393 if (receivers
!= NULL
)
2395 D(kprintf("Found notification for created directory!\n"));
2397 while (!IsListEmpty(receivers
))
2399 AddHead((struct List
*)&dir
->receivers
,
2400 RemHead(receivers
));
2404 HashTable_remove(rambase
, rambase
->notifications
, fullName
);
2409 D(kprintf("Notifying dir receivers!\n"));
2410 Notify_notifyTasks(rambase
, &dir
->receivers
);
2415 /* As we have deleted a file, we must move the requests for
2416 this file to the hash table */
2417 struct List
*receivers
= (struct List
*)&dir
->receivers
;
2419 Notify_notifyTasks(rambase
, &dir
->receivers
);
2421 /* Move the Notification request to the hash table as we're going
2422 to delete this directory */
2423 while (!IsListEmpty(receivers
))
2425 struct Receiver
*rr
= (struct Receiver
*)RemHead(receivers
);
2427 HashTable_insert(rambase
, rambase
->notifications
,
2428 rr
->nr
->nr_FullName
, rr
);
2439 // kprintf("Returning from Notify_dirChange()\n");
2443 /* TODO: Implement support for NRF_WAIT_REPLY */
2444 void Notify_notifyTasks(struct rambase
*rambase
, struct MinList
*notifications
)
2446 struct Receiver
*rr
;
2448 // kprintf("Inside notifytasks, not = %p\n", notifications);
2450 ForeachNode((struct List
*)notifications
, rr
)
2452 struct NotifyRequest
*nr
= rr
->nr
;
2454 if (nr
->nr_Flags
& NRF_SEND_MESSAGE
&&
2455 !(nr
->nr_Flags
& NRF_WAIT_REPLY
&& nr
->nr_Flags
& NRF_NOT_REPLIED
))
2457 struct NotifyMessage
*nm
= AllocVec(sizeof(struct NotifyMessage
),
2458 MEMF_PUBLIC
| MEMF_CLEAR
);
2465 nm
->nm_ExecMessage
.mn_ReplyPort
= rambase
->notifyPort
;
2466 nm
->nm_ExecMessage
.mn_Length
= sizeof(struct NotifyMessage
);
2468 nr
->nr_Flags
|= NRF_NOT_REPLIED
;
2470 PutMsg(nr
->nr_stuff
.nr_Msg
.nr_Port
, &nm
->nm_ExecMessage
);
2472 else if (nr
->nr_Flags
& NRF_SEND_SIGNAL
)
2474 Signal(nr
->nr_stuff
.nr_Signal
.nr_Task
,
2475 1 << nr
->nr_stuff
.nr_Signal
.nr_SignalNum
);
2480 /* also defined in rom/dos/filesystem_support.c */
2481 STRPTR
RamStripVolume(STRPTR name
)
2483 STRPTR path
= strchr(name
, ':');
2491 BOOL
Notify_addNotification(struct rambase
*rambase
, struct dnode
*dn
,
2492 struct NotifyRequest
*nr
)
2494 struct dnode
*dnTemp
= dn
;
2495 HashTable
*ht
= rambase
->notifications
;
2496 STRPTR name
= nr
->nr_FullName
;
2497 CONST_STRPTR tname
= RamStripVolume(name
);
2499 /* First: Check if the file is opened */
2500 D(bug("Checking existence of %s\n", tname
));
2502 if (findname(rambase
, &tname
, &dnTemp
) == 0)
2504 /* This file was already opened (or at least known by the file
2507 struct Receiver
*rr
= AllocVec(sizeof(struct Receiver
), MEMF_CLEAR
);
2516 if (nr
->nr_Flags
& NRF_NOTIFY_INITIAL
)
2518 struct MinList tempList
;
2520 /* Create a temporary list on the stack and add the receiver to
2521 it. Then forget about this and add the node to the receiver
2522 list (below this block). */
2523 NewList((struct List
*)&tempList
);
2524 AddHead((struct List
*)&tempList
, &rr
->node
);
2525 Notify_notifyTasks(rambase
, &tempList
);
2528 /* Add the receiver node to the file's/directory's list of receivers */
2529 AddTail((struct List
*)&dnTemp
->receivers
, &rr
->node
);
2531 D(bug("Notification added to node: %s\n", name
));
2537 /* This file is not opened */
2539 struct Receiver
*rr
= AllocVec(sizeof(struct Receiver
), MEMF_CLEAR
);
2548 HashTable_insert(rambase
, ht
, name
, rr
);
2555 void Notify_removeNotification(struct rambase
*rambase
,
2556 struct NotifyRequest
*nr
)
2558 struct dnode
*dn
= (struct dnode
*)rambase
->root
;
2559 struct Receiver
*rr
, *rrTemp
;
2560 STRPTR name
= nr
->nr_FullName
;
2561 CONST_STRPTR tname
= RamStripVolume(name
);
2562 struct List
*receivers
;
2563 BOOL fromTable
= FALSE
;
2565 if (findname(rambase
, &tname
, &dn
) == 0)
2567 receivers
= (struct List
*)&dn
->receivers
;
2571 /* This was a request for an entity that doesn't exist yet */
2572 receivers
= HashTable_find(rambase
, rambase
->notifications
, name
);
2574 if (receivers
== NULL
)
2576 D(bug("Ram: This should not happen! -- buggy application...\n"));
2583 ForeachNodeSafe(&receivers
, rr
, rrTemp
)
2587 Remove((struct Node
*)rr
);
2595 /* If we removed a request for a file that doesn't exist yet --
2596 if this was the only notification request for that file, remove
2597 also the hash entry. */
2598 if (IsListEmpty((struct List
*)receivers
))
2600 HashTable_remove(rambase
, rambase
->notifications
, name
);
2605 static STRPTR
getName(struct rambase
*rambase
, struct dnode
*dn
)
2607 struct dnode
*dnTemp
= dn
;
2611 CONST_STRPTR slash
= "/";
2612 CONST_STRPTR nextSlash
= slash
;
2615 /* First, calculate the size of the complete filename */
2616 length
= strlen(dn
->name
) + 2; /* Add trailing 0 byte and possible '/' */
2618 while (findname(rambase
, &slash
, &dnTemp
) == 0)
2621 length
+= 1 + strlen(dnTemp
->name
); /* Add '/' byte */
2624 /* The MEMF_CLEAR is necessary for the while loop below to work */
2625 fullName
= AllocVec(length
, MEMF_PUBLIC
| MEMF_CLEAR
);
2627 if (fullName
== NULL
)
2633 fullName
+= length
- 1;
2635 fullName
-= strlen(dn
->name
) + 1;
2636 strcpy(fullName
, dn
->name
);
2640 while (findname(rambase
, &slash
, &dnTemp
) != ERROR_OBJECT_NOT_FOUND
)
2643 partLen
= strlen(dnTemp
->name
);
2645 fullName
-= partLen
+ 1;
2646 strcpy(fullName
, dnTemp
->name
);
2648 if ((struct vnode
*)dnTemp
== dnTemp
->volume
)
2649 fullName
[partLen
] = ':'; /* Root of Ram Disk */
2651 fullName
[partLen
] = '/'; /* Replace 0 with '/' */
2657 ADD2INITLIB(GM_UNIQUENAME(Init
),0)
2658 ADD2OPENDEV(GM_UNIQUENAME(Open
),0)
2659 ADD2CLOSEDEV(GM_UNIQUENAME(Close
),0)
2660 ADD2EXPUNGELIB(GM_UNIQUENAME(Expunge
),0)