2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
12 #include <aros/debug.h>
14 #include <exec/errors.h>
15 #include <exec/types.h>
16 #include <exec/resident.h>
17 #include <exec/memory.h>
18 #include <exec/semaphores.h>
19 #include <utility/tagitem.h>
20 #include <proto/exec.h>
21 #include <proto/utility.h>
22 #include <proto/alib.h>
23 #include <proto/dos.h>
25 #include <dos/dosextens.h>
26 #include <dos/dosasl.h>
27 #include <dos/exall.h>
28 #include <dos/filesystem.h>
29 #include <aros/libcall.h>
30 #include <aros/symbolsets.h>
32 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
33 #include "ram_handler_gcc.h"
39 #include "HashTable.h"
41 extern void deventry();
43 #include LC_LIBDEFS_FILE
45 #define NRF_NOT_REPLIED NRF_MAGIC
52 LONG type
; /* ST_LINKDIR */
53 char *name
; /* Link's name */
54 struct cnode
*self
; /* Pointer to top of structure */
55 struct hnode
*link
; /* NULL */
56 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
57 ULONG protect
; /* 0 */
58 char *comment
; /* NULL */
59 struct vnode
*volume
; /* Pointer to volume */
60 struct DosList
*doslist
; /* Pointer to doslist entry */
67 LONG type
; /* ST_USERDIR */
68 char *name
; /* Directory name */
69 struct vnode
*self
; /* Points to top of structure */
70 struct hnode
*link
; /* This one is linked to me */
71 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
72 ULONG protect
; /* 0 */
73 char *comment
; /* NULL */
74 struct MinList receivers
;
75 struct MinList list
; /* Contents of directory */
76 ULONG volcount
; /* number of handles on this volume */
77 struct DosList
*doslist
; /* Pointer to doslist entry */
84 LONG type
; /* ST_USERDIR */
85 char *name
; /* Directory name */
86 struct vnode
*volume
; /* Volume's root directory */
87 struct hnode
*link
; /* This one is linked to me */
88 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
89 ULONG protect
; /* protection bits */
90 char *comment
; /* Some comment */
91 struct MinList receivers
;
92 struct MinList list
; /* Contents of directory */
99 LONG type
; /* ST_FILE */
100 char *name
; /* Filename */
101 struct vnode
*volume
; /* Volume's root directory */
102 struct hnode
*link
; /* This one is linked to me */
103 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
104 ULONG protect
; /* protection bits */
105 char *comment
; /* Some file comment */
106 struct MinList receivers
;
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 char *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 char *comment
; /* Some file comment */
126 char *contents
; /* Contents of soft link */
133 LONG type
; /* ST_LINKDIR */
134 char *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 char *comment
; /* Some file comment */
140 struct hnode
*orig
; /* original object */
143 /*****************************************************************************/
145 #define FILEFLAGS_Changed 1
147 STRPTR
getName(struct rambase
*rambase
, struct dnode
*dn
, STRPTR name
);
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 typedef struct _HashNode
177 struct List requests
;
181 /****************************************************************************/
184 #define BLOCKSIZE 256
185 #define PBLOCKSIZE (256*sizeof(UBYTE *))
193 /* Use This from now on */
200 #define SysBase rambase->sysbase
201 #define DOSBase rambase->dosbase
203 static int OpenDev(LIBBASETYPEPTR rambase
, struct IOFileSys
*iofs
);
205 static int GM_UNIQUENAME(Init
)(LIBBASETYPEPTR rambase
)
207 /* This function is single-threaded by exec by calling Forbid. */
209 struct MsgPort
*port
;
211 struct SignalSemaphore
*semaphore
;
214 rambase
->dosbase
= (struct DosLibrary
*)OpenLibrary("dos.library",39);
216 if (rambase
->dosbase
!= NULL
)
218 rambase
->utilitybase
= (struct UtilityBase
*)OpenLibrary("utility.library",39);
220 if (rambase
->utilitybase
!=NULL
)
222 port
= (struct MsgPort
*)AllocMem(sizeof(struct MsgPort
),
223 MEMF_PUBLIC
| MEMF_CLEAR
);
226 rambase
->port
= port
;
227 NewList(&port
->mp_MsgList
);
228 port
->mp_Node
.ln_Type
= NT_MSGPORT
;
229 port
->mp_SigBit
= SIGB_SINGLE
;
231 task
= (struct Task
*)AllocMem(sizeof(struct Task
),
232 MEMF_PUBLIC
| MEMF_CLEAR
);
236 port
->mp_SigTask
= task
;
237 port
->mp_Flags
= PA_IGNORE
;
238 NewList(&task
->tc_MemEntry
);
239 task
->tc_Node
.ln_Type
= NT_TASK
;
240 task
->tc_Node
.ln_Name
= "ram.handler task";
242 stack
= AllocMem(AROS_STACKSIZE
, MEMF_PUBLIC
);
246 struct TagItem tasktags
[] =
248 {TASKTAG_ARG1
, (IPTR
)rambase
},
252 task
->tc_SPLower
= stack
;
253 task
->tc_SPUpper
= (BYTE
*)stack
+ AROS_STACKSIZE
;
254 #if AROS_STACK_GROWS_DOWNWARDS
255 task
->tc_SPReg
= (BYTE
*)task
->tc_SPUpper
- SP_OFFSET
;
257 task
->tc_SPReg
= (BYTE
*)task
->tc_SPLower
+ SP_OFFSET
;
260 semaphore
= (struct SignalSemaphore
*)AllocMem(sizeof(struct SignalSemaphore
),
261 MEMF_PUBLIC
| MEMF_CLEAR
);
263 if (semaphore
!= NULL
)
265 rambase
->sigsem
= semaphore
;
266 InitSemaphore(semaphore
);
268 if (rambase
->seglist
==NULL
) /* Are we a ROM module? */
270 struct DeviceNode
*dn
;
271 /* Install RAM: handler into device list
273 * KLUDGE: ram.handler should create only one device node, depending on
274 * the startup packet it gets. The mountlists for RAM: should be into dos.library bootstrap
278 if((dn
= AllocMem(sizeof (struct DeviceNode
) + 4 + 3 + 2, MEMF_CLEAR
|MEMF_PUBLIC
)))
280 struct IOFileSys dummyiofs
;
282 if (OpenDev(rambase
, &dummyiofs
))
284 BSTR s
= MKBADDR(((IPTR
)dn
+ sizeof(struct DeviceNode
) + 4) & ~3);
286 rambase
->device
.dd_Library
.lib_OpenCnt
++;
288 AROS_BSTR_putchar(s
, 0, 'R');
289 AROS_BSTR_putchar(s
, 1, 'A');
290 AROS_BSTR_putchar(s
, 2, 'M');
291 AROS_BSTR_putchar(s
, 3, 0);
292 AROS_BSTR_setstrlen(s
, 3);
294 dn
->dn_Type
= DLT_DEVICE
;
295 dn
->dn_Ext
.dn_AROS
.dn_Unit
= dummyiofs
.IOFS
.io_Unit
;
296 dn
->dn_Ext
.dn_AROS
.dn_Device
= dummyiofs
.IOFS
.io_Device
;
297 dn
->dn_Handler
= NULL
;
298 dn
->dn_Startup
= NULL
;
300 dn
->dn_Ext
.dn_AROS
.dn_DevName
= AROS_BSTR_ADDR(dn
->dn_Name
);
302 if (AddDosEntry((struct DosList
*)dn
))
303 if (NewAddTask(task
, deventry
, NULL
, tasktags
) != NULL
)
307 FreeMem(dn
, sizeof (struct DeviceNode
));
311 if (NewAddTask(task
, deventry
, NULL
, tasktags
) != NULL
)
314 FreeMem(semaphore
, sizeof(struct SignalSemaphore
));
317 FreeMem(stack
, AROS_STACKSIZE
);
320 FreeMem(task
, sizeof(struct Task
));
323 FreeMem(port
, sizeof(struct MsgPort
));
326 CloseLibrary((struct Library
*)rambase
->utilitybase
);
329 CloseLibrary((struct Library
*)rambase
->dosbase
);
338 #define UtilityBase rambase->utilitybase
341 /***************************************************************************/
343 void nullDelete(struct rambase
*rambase
, void *key
, struct List
*list
)
345 // struct Receiver *rr;
346 // struct Node *tempNode;
348 // ForeachNodeSafe(list, rr, tempNode)
350 // Remove(&rr->node);
356 /* The list is part of the HashNode so we shouldn't free that */
360 ULONG
stringHash(struct rambase
*rambase
, const void *key
)
362 STRPTR str
= (STRPTR
)key
;
367 val
*= ToLower(*str
++);
375 my_strcasecmp(struct rambase
*rambase
, const void *s1
, const void *s2
)
377 return strcasecmp(s1
, s2
);
380 /****************************************************************************/
383 static STRPTR
Strdup(struct rambase
*rambase
, STRPTR string
)
385 STRPTR s2
= string
,s3
;
390 s3
= (STRPTR
)AllocVec(s2
- string
, MEMF_ANY
);
394 CopyMem(string
, s3
, s2
- string
);
401 static void Strfree(struct rambase
*rambase
, STRPTR string
)
407 static int GM_UNIQUENAME(Open
)
409 LIBBASETYPEPTR rambase
,
410 struct IOFileSys
*iofs
,
415 /* Mark Message as recently used. */
416 iofs
->IOFS
.io_Message
.mn_Node
.ln_Type
= NT_REPLYMSG
;
418 return OpenDev(rambase
, iofs
);
422 static int OpenDev(LIBBASETYPEPTR rambase
, struct IOFileSys
*iofs
)
424 struct filehandle
*fhv
, *fhc
;
429 iofs
->IOFS
.io_Error
= ERROR_NO_FREE_STORE
;
431 fhv
= (struct filehandle
*)AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
435 fhc
= (struct filehandle
*)AllocMem(sizeof(struct filehandle
),
440 vol
= (struct vnode
*)AllocMem(sizeof(struct vnode
), MEMF_CLEAR
);
444 dev
= (struct cnode
*)AllocMem(sizeof(struct cnode
),
449 vol
->name
= Strdup(rambase
, "Ram Disk");
451 if (vol
->name
!= NULL
)
453 dlv
= MakeDosEntry("Ram Disk", DLT_VOLUME
);
457 vol
->type
= ST_USERDIR
;
461 NewList((struct List
*)&vol
->list
);
462 NewList((struct List
*)&vol
->receivers
);
463 fhv
->node
= (struct dnode
*)vol
;
464 dlv
->dol_Ext
.dol_AROS
.dol_Unit
= (struct Unit
*)fhv
;
465 dlv
->dol_Ext
.dol_AROS
.dol_Device
= &rambase
->device
;
466 dev
->type
= ST_LINKDIR
;
469 fhc
->node
= (struct dnode
*)dev
;
470 iofs
->IOFS
.io_Unit
= (struct Unit
*)fhc
;
471 iofs
->IOFS
.io_Device
= &rambase
->device
;
474 iofs
->IOFS
.io_Error
= 0;
476 rambase
->notifications
=
477 HashTable_new(rambase
, 100, stringHash
,
478 my_strcasecmp
, nullDelete
);
483 Strfree(rambase
, vol
->name
);
486 FreeMem(dev
, sizeof(struct cnode
));
489 FreeMem(vol
, sizeof(struct vnode
));
492 FreeMem(fhc
, sizeof(struct filehandle
));
495 FreeMem(fhv
, sizeof(struct filehandle
));
498 iofs
->IOFS
.io_Error
= IOERR_OPENFAIL
;
503 static int GM_UNIQUENAME(Expunge
)(LIBBASETYPEPTR rambase
)
506 This function is single-threaded by exec by calling Forbid.
507 Never break the Forbid() or strange things might happen.
510 /* Kill device task and free all resources */
511 RemTask(rambase
->port
->mp_SigTask
);
512 FreeMem(rambase
->sigsem
, sizeof(struct SignalSemaphore
));
513 FreeMem(((struct Task
*)rambase
->port
->mp_SigTask
)->tc_SPLower
,
515 FreeMem(rambase
->port
->mp_SigTask
, sizeof(struct Task
));
516 FreeMem(rambase
->port
, sizeof(struct MsgPort
));
517 CloseLibrary((struct Library
*)rambase
->utilitybase
);
518 CloseLibrary((struct Library
*)rambase
->dosbase
);
524 AROS_LH1(void, beginio
,
525 AROS_LHA(struct IOFileSys
*, iofs
, A1
),
526 struct rambase
*, rambase
, 5, Ram
)
530 /* WaitIO will look into this */
531 iofs
->IOFS
.io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
533 /* Nothing is done quick */
534 iofs
->IOFS
.io_Flags
&= ~IOF_QUICK
;
536 /* So let the device task do it */
537 PutMsg(rambase
->port
, &iofs
->IOFS
.io_Message
);
543 AROS_LH1(LONG
, abortio
,
544 AROS_LHA(struct IOFileSys
*, iofs
, A1
),
545 struct rambase
*, rambase
, 6, Ram
)
553 static LONG
getblock(struct rambase
*rambase
, struct fnode
*file
, LONG block
,
554 int mode
, UBYTE
**result
)
561 p
= &file
->blocks
[block
];
565 else if (block
< 0x410)
568 p
= (UBYTE
**)&file
->iblocks
[block
/0x100];
572 else if(block
< 0x10410)
575 p
= (UBYTE
**)&file
->i2block
;
581 p
= (UBYTE
**)&file
->i3block
;
597 while (i
-- && p
!= NULL
)
599 a
= (block
>> i
*8) & 0xff;
602 if (!(block
& ((1 << i
*8) - 1)))
608 FreeMem(p
, PBLOCKSIZE
);
617 FreeMem(p
, BLOCKSIZE
);
625 while (i
-- && p
!= NULL
)
627 p
= ((UBYTE
***)p
)[(block
>> i
*8) & 0xff];
630 *result
= (UBYTE
*)p
;
638 *p
= AllocMem(PBLOCKSIZE
, MEMF_CLEAR
);
642 return ERROR_NO_FREE_STORE
;
646 p
= (UBYTE
**)*p
+ ((block
>> i
*8) & 0xff);
651 *p
= AllocMem(BLOCKSIZE
, MEMF_CLEAR
);
655 return ERROR_NO_FREE_STORE
;
661 } /* switch (mode) */
667 static void zerofill(UBYTE
*address
, ULONG size
)
676 static void shrinkfile(struct rambase
*rambase
, struct fnode
*file
, LONG size
)
681 blocks
= (size
+ BLOCKSIZE
- 1)/BLOCKSIZE
;
682 block
= (file
->size
+ BLOCKSIZE
- 1)/BLOCKSIZE
;
684 for(;block
-- > blocks
;)
686 (void)getblock(rambase
, file
, block
, -1, &p
);
691 (void)getblock(rambase
, file
, size
, 0, &p
);
695 zerofill(p
+ (size
& 0xff), -size
& 0xff);
703 static void delete(struct rambase
*rambase
, struct fnode
*file
)
705 struct hnode
*link
, *new, *more
;
708 Strfree(rambase
, file
->name
);
709 Strfree(rambase
, file
->comment
);
710 Remove((struct Node
*)file
);
712 if (file
->type
== ST_LINKDIR
)
714 /* It is a link. Remove it from the chain. */
716 link
= ((struct hnode
*)file
)->orig
;
717 ((struct hnode
*)file
)->orig
= NULL
;
718 file
->type
= link
->type
;
720 while((struct fnode
*)link
->link
!= file
)
725 link
->link
= file
->link
;
727 else if (file
->link
!= NULL
)
729 /* If there is a hard link to the object make the link the original */
732 link
->type
= file
->type
;
744 while((node
= RemHead((struct List
*)&((struct dnode
*)file
)->list
)) != NULL
)
745 AddTail((struct List
*)&((struct dnode
*)file
)->list
, node
);
749 CopyMemQuick(&file
->size
, &((struct fnode
*)new)->size
,
750 sizeof(struct fnode
) - offsetof(struct fnode
, size
));
751 zerofill((UBYTE
*)&file
->size
,
752 sizeof(struct fnode
) - offsetof(struct fnode
, size
));
756 ((struct snode
*)new)->contents
= ((struct snode
*)file
)->contents
;
757 ((struct snode
*)file
)->contents
= NULL
;
760 } /* else if (file->link != NULL) */
765 Notify_directoryChange(rambase
, NOTIFY_Delete
, (struct dnode
*)file
);
767 FreeMem(file
, sizeof(struct dnode
));
772 Notify_fileChange(rambase
, NOTIFY_Delete
, file
);
774 shrinkfile(rambase
, file
, 0);
775 FreeMem(file
, sizeof(struct fnode
));
780 Strfree(rambase
, ((struct snode
*)file
)->contents
);
781 FreeMem(file
, sizeof(struct snode
));
788 static int fstrcmp(struct rambase
*rambase
, char *s1
, char *s2
)
792 if (ToLower(*s1
) != ToLower(*s2
))
794 return *s1
|| *s2
!= '/';
808 /* Find a node for a given name */
809 static LONG
findname(struct rambase
*rambase
, STRPTR
*name
,
810 struct dnode
**dnode
)
812 struct dnode
*cur
= *dnode
;
817 if (cur
->type
== ST_LINKDIR
)
819 cur
= (struct dnode
*)((struct hnode
*)cur
)->orig
;
829 if ((struct dnode
*)cur
->volume
== cur
)
831 return ERROR_OBJECT_NOT_FOUND
;
834 while (cur
->node
.mln_Pred
!= NULL
)
836 cur
= (struct dnode
*)cur
->node
.mln_Pred
;
839 cur
= (struct dnode
*)((BYTE
*)cur
- offsetof(struct dnode
, list
));
843 if (cur
->type
== ST_SOFTLINK
)
848 return ERROR_IS_SOFT_LINK
;
851 if (cur
->type
!= ST_USERDIR
)
853 return ERROR_DIR_NOT_FOUND
;
857 cur
= (struct dnode
*)cur
->list
.mlh_Head
;
861 if (cur
->node
.mln_Succ
== NULL
)
865 return ERROR_OBJECT_NOT_FOUND
;
868 if (!fstrcmp(rambase
, cur
->name
, rest
))
873 cur
= (struct dnode
*)cur
->node
.mln_Succ
;
892 static LONG
set_file_size(struct rambase
*rambase
, struct filehandle
*handle
,
893 QUAD
*offp
, LONG mode
)
895 struct fnode
*file
= (struct fnode
*)handle
->node
;
898 if (file
->type
!= ST_FILE
)
900 return ERROR_OBJECT_WRONG_TYPE
;
905 case OFFSET_BEGINNING
:
909 size
+= handle
->position
;
917 return ERROR_NOT_IMPLEMENTED
;
922 return ERROR_SEEK_ERROR
;
925 if (size
< file
->size
)
927 shrinkfile(rambase
, file
, size
);
930 file
->size
= *offp
= size
;
936 static LONG
read(struct rambase
*rambase
, struct filehandle
*handle
,
937 APTR buffer
, LONG
*numbytes
)
939 struct fnode
*file
= (struct fnode
*)handle
->node
;
940 ULONG num
= *numbytes
;
941 ULONG size
= file
->size
;
943 UBYTE
*buf
= buffer
, *p
;
945 if (handle
->position
>= size
)
949 else if (handle
->position
+ num
> size
)
951 num
= size
- handle
->position
;
954 block
= handle
->position
/BLOCKSIZE
;
955 offset
= handle
->position
& (BLOCKSIZE
- 1);
956 size
= BLOCKSIZE
- offset
;
965 (void)getblock(rambase
, file
, block
, 0, &p
);
969 CopyMem(p
+ offset
, buffer
, size
);
973 zerofill(buffer
, size
);
983 *numbytes
= (UBYTE
*)buffer
- buf
;
984 handle
->position
+= *numbytes
;
990 static LONG
write(struct rambase
*rambase
, struct filehandle
*handle
,
991 UBYTE
*buffer
, LONG
*numbytes
)
993 struct fnode
*file
= (struct fnode
*)handle
->node
;
994 ULONG num
= *numbytes
;
995 ULONG size
= file
->size
;
997 UBYTE
*buf
= buffer
, *p
;
1000 if ((LONG
)(handle
->position
+ num
) < 0)
1002 return ERROR_OBJECT_TOO_LARGE
;
1005 Notify_fileChange(rambase
, NOTIFY_Write
, file
);
1007 block
= handle
->position
/BLOCKSIZE
;
1008 offset
= handle
->position
& (BLOCKSIZE
- 1);
1009 size
= BLOCKSIZE
- offset
;
1018 error
= getblock(rambase
, file
, block
, 1, &p
);
1025 CopyMem(buffer
, p
+ offset
, size
);
1033 *numbytes
= (UBYTE
*)buffer
- buf
;
1034 handle
->position
+= *numbytes
;
1036 if (handle
->position
> file
->size
)
1038 file
->size
= handle
->position
;
1045 static LONG
lock(struct dnode
*dir
, ULONG mode
)
1047 if ((mode
& FMF_EXECUTE
) && (dir
->protect
& FMF_EXECUTE
))
1049 return ERROR_NOT_EXECUTABLE
;
1052 if ((mode
& FMF_WRITE
) && (dir
->protect
& FMF_WRITE
))
1054 return ERROR_WRITE_PROTECTED
;
1057 if ((mode
& FMF_READ
) && (dir
->protect
& FMF_READ
))
1059 return ERROR_READ_PROTECTED
;
1062 if (mode
& FMF_LOCK
)
1066 return ERROR_OBJECT_IN_USE
;
1069 dir
->usecount
= ~0ul/2 + 1;
1073 if (dir
->usecount
< 0)
1075 return ERROR_OBJECT_IN_USE
;
1080 dir
->volume
->volcount
++;
1086 static LONG
open_(struct rambase
*rambase
, struct filehandle
**handle
,
1087 STRPTR name
, ULONG mode
)
1089 struct dnode
*dir
= (*handle
)->node
;
1090 struct filehandle
*fh
;
1093 fh
= (struct filehandle
*)AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
1097 error
= findname(rambase
, &name
, &dir
);
1101 error
= lock(dir
, mode
);
1108 if (dir
->type
== ST_FILE
)
1110 Notify_fileChange(rambase
, NOTIFY_Open
,
1111 (struct fnode
*)dir
);
1113 else if (dir
->type
== ST_USERDIR
)
1115 D(kprintf("Notifying OPEN at dir %s\n", dir
->name
));
1116 Notify_directoryChange(rambase
, NOTIFY_Open
, dir
);
1123 FreeMem(fh
, sizeof(struct filehandle
));
1127 error
= ERROR_NO_FREE_STORE
;
1134 static LONG
open_file(struct rambase
*rambase
, struct filehandle
**handle
,
1135 STRPTR name
, ULONG mode
, ULONG protect
)
1137 struct dnode
*dir
= (*handle
)->node
;
1138 struct filehandle
*fh
;
1141 fh
= AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
1145 error
= findname(rambase
, &name
, &dir
);
1147 if ((mode
& FMF_CREATE
) && error
== ERROR_OBJECT_NOT_FOUND
)
1160 file
= (struct fnode
*)AllocMem(sizeof(struct fnode
), MEMF_CLEAR
);
1164 file
->name
= Strdup(rambase
, name
);
1166 if (file
->name
!= NULL
)
1168 file
->type
= ST_FILE
;
1169 file
->protect
= protect
;
1170 file
->volume
= dir
->volume
;
1171 NewList((struct List
*)&file
->receivers
);
1172 AddTail((struct List
*)&dir
->list
, (struct Node
*)file
);
1173 error
= lock((struct dnode
*)file
, mode
);
1177 fh
->node
= (struct dnode
*)file
;
1180 Notify_fileChange(rambase
, NOTIFY_Add
, file
);
1185 Strfree(rambase
, file
->name
);
1188 FreeMem(file
,sizeof(struct fnode
));
1191 error
= ERROR_NO_FREE_STORE
;
1195 if (dir
->type
!= ST_FILE
)
1197 error
= ERROR_OBJECT_WRONG_TYPE
;
1201 error
= lock(dir
, mode
);
1206 if (mode
& FMF_CLEAR
)
1208 shrinkfile(rambase
, (struct fnode
*)dir
, 0);
1209 dir
->protect
= protect
;
1219 } /* else if (!error) */
1221 FreeMem(fh
, sizeof(struct filehandle
));
1228 static LONG
create_dir(struct rambase
*rambase
, struct filehandle
**handle
,
1229 STRPTR name
, ULONG protect
)
1231 struct dnode
*dir
= (*handle
)->node
, *new;
1232 struct filehandle
*fh
;
1235 if (dir
->protect
& FIBF_WRITE
)
1237 return ERROR_WRITE_PROTECTED
;
1240 error
= findname(rambase
, &name
, &dir
);
1244 return ERROR_OBJECT_EXISTS
;
1247 if (error
!= ERROR_OBJECT_NOT_FOUND
)
1252 if (strchr(name
, '/') != NULL
)
1257 fh
= AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
1261 new = (struct dnode
*)AllocMem(sizeof(struct dnode
), MEMF_CLEAR
);
1265 new->name
= Strdup(rambase
, name
);
1267 if (new->name
!= NULL
)
1269 new->type
= ST_USERDIR
;
1270 new->protect
= protect
;
1271 new->volume
= dir
->volume
;
1272 new->volume
->volcount
++;
1273 new->usecount
= ~0ul/2 + 2;
1274 NewList((struct List
*)&new->list
);
1275 NewList((struct List
*)&new->receivers
);
1276 AddTail((struct List
*)&dir
->list
, (struct Node
*)new);
1280 // kprintf("New (%p): Name = %s\n", new, new->name);
1281 Notify_directoryChange(rambase
, NOTIFY_Add
, new);
1286 FreeMem(new, sizeof(struct dnode
));
1289 FreeMem(fh
, sizeof(struct filehandle
));
1292 return ERROR_NO_FREE_STORE
;
1296 static LONG
free_lock(struct rambase
*rambase
, struct filehandle
*filehandle
)
1298 struct dnode
*dnode
= filehandle
->node
;
1300 dnode
->usecount
= (dnode
->usecount
- 1) & ~0ul/2;
1301 FreeMem(filehandle
, sizeof(struct filehandle
));
1302 dnode
->volume
->volcount
--;
1308 static LONG
seek(struct rambase
*rambase
, struct filehandle
*filehandle
,
1309 QUAD
*posp
, LONG mode
)
1311 struct fnode
*file
= (struct fnode
*)filehandle
->node
;
1314 if (file
->type
!= ST_FILE
)
1316 return ERROR_OBJECT_WRONG_TYPE
;
1321 case OFFSET_BEGINNING
:
1324 case OFFSET_CURRENT
:
1325 pos
+= filehandle
->position
;
1333 return ERROR_NOT_IMPLEMENTED
;
1338 return ERROR_SEEK_ERROR
;
1341 *posp
= filehandle
->position
;
1342 filehandle
->position
= pos
;
1348 static const ULONG sizes
[]=
1351 offsetof(struct ExAllData
,ed_Type
),
1352 offsetof(struct ExAllData
,ed_Size
),
1353 offsetof(struct ExAllData
,ed_Prot
),
1354 offsetof(struct ExAllData
,ed_Days
),
1355 offsetof(struct ExAllData
,ed_Comment
),
1356 offsetof(struct ExAllData
,ed_OwnerUID
),
1357 sizeof(struct ExAllData
)
1361 static LONG
examine(struct fnode
*file
,
1362 struct ExAllData
*ead
,
1367 STRPTR next
, end
, name
;
1369 if (type
> ED_OWNER
)
1371 return ERROR_BAD_NUMBER
;
1374 next
= (STRPTR
)ead
+ sizes
[type
];
1375 end
= (STRPTR
)ead
+ size
;
1377 if(next
>end
) /* > is correct. Not >= */
1378 return ERROR_BUFFER_OVERFLOW
;
1380 /* Use *dirpos to store information for ExNext()
1381 * *dirpos is copied to fib->fib_DiskKey in Examine()
1383 if (file
->type
== ST_USERDIR
)
1385 *dirpos
= (LONG
)(((struct dnode
*)file
)->list
.mlh_Head
);
1389 /* ExNext() should not be called in this case anyway */
1390 *dirpos
= (LONG
)file
;
1396 ead
->ed_OwnerUID
= 0;
1397 ead
->ed_OwnerGID
= 0;
1401 if (file
->comment
!= NULL
)
1403 ead
->ed_Comment
= next
;
1404 name
= file
->comment
;
1410 return ERROR_BUFFER_OVERFLOW
;
1413 if (!(*next
++ = *name
++))
1421 ead
->ed_Comment
= NULL
;
1432 ead
->ed_Prot
= file
->protect
;
1436 ead
->ed_Size
= file
->size
;
1440 ead
->ed_Type
= file
->type
;
1442 if (((struct vnode
*)file
)->self
== (struct vnode
*)file
)
1444 ead
->ed_Type
=ST_ROOT
;
1449 ead
->ed_Name
= next
;
1456 return ERROR_BUFFER_OVERFLOW
;
1459 if (!(*next
++ = *name
++))
1467 ead
->ed_Next
= (struct ExAllData
*)(((IPTR
)next
+ AROS_PTRALIGN
- 1) & ~(AROS_PTRALIGN
- 1));
1474 static LONG
examine_next(struct rambase
*rambase
,
1475 struct filehandle
*dir
,
1476 struct FileInfoBlock
*FIB
)
1478 struct fnode
*file
= (struct fnode
*)FIB
->fib_DiskKey
;
1480 ASSERT_VALID_PTR_OR_NULL(file
);
1482 if (file
->node
.mln_Succ
== NULL
)
1484 return ERROR_NO_MORE_ENTRIES
;
1487 FIB
->fib_OwnerUID
= 0;
1488 FIB
->fib_OwnerGID
= 0;
1490 FIB
->fib_Date
.ds_Days
= 0;
1491 FIB
->fib_Date
.ds_Minute
= 0;
1492 FIB
->fib_Date
.ds_Tick
= 0;
1493 FIB
->fib_Protection
= file
->protect
;
1494 FIB
->fib_Size
= file
->size
;
1495 FIB
->fib_DirEntryType
= file
->type
;
1497 strncpy(FIB
->fib_FileName
, file
->name
, MAXFILENAMELENGTH
- 1);
1498 strncpy(FIB
->fib_Comment
, file
->comment
!= NULL
? file
->comment
: "",
1499 MAXCOMMENTLENGTH
- 1);
1501 FIB
->fib_DiskKey
= (LONG
)file
->node
.mln_Succ
;
1507 static LONG
examine_all(struct filehandle
*dir
,
1508 struct ExAllData
*ead
,
1509 struct ExAllControl
*eac
,
1514 struct ExAllData
*last
=NULL
;
1517 LONG dummy
; /* not anything is done with this value but passed to examine */
1518 end
= (STRPTR
)ead
+ size
;
1520 eac
->eac_Entries
= 0;
1521 if (dir
->node
->type
!= ST_USERDIR
)
1523 return ERROR_OBJECT_WRONG_TYPE
;
1526 ent
= (struct fnode
*)eac
->eac_LastKey
;
1530 ent
= (struct fnode
*)dir
->node
->list
.mlh_Head
;
1531 if (ent
->node
.mln_Succ
) ent
->usecount
++;
1534 if (ent
->node
.mln_Succ
== NULL
)
1536 return ERROR_NO_MORE_ENTRIES
;
1543 error
= examine(ent
, ead
, end
- (STRPTR
)ead
, type
, &dummy
);
1545 if (error
== ERROR_BUFFER_OVERFLOW
)
1553 last
->ed_Next
= NULL
;
1554 eac
->eac_LastKey
= (IPTR
)ent
;
1561 ent
= (struct fnode
*)ent
->node
.mln_Succ
;
1563 } while (ent
->node
.mln_Succ
!= NULL
);
1565 last
->ed_Next
= NULL
;
1566 eac
->eac_LastKey
= (IPTR
)ent
;
1568 return ERROR_NO_MORE_ENTRIES
;
1572 static LONG
delete_object(struct rambase
*rambase
,
1573 struct filehandle
*filehandle
, STRPTR name
)
1575 struct dnode
*file
= filehandle
->node
;
1578 error
= findname(rambase
, &name
, &file
);
1585 if ((struct dnode
*)file
->volume
== file
)
1587 return ERROR_OBJECT_WRONG_TYPE
;
1590 if (file
->usecount
!= 0)
1592 return ERROR_OBJECT_IN_USE
;
1595 if (file
->protect
& FIBF_DELETE
)
1597 return ERROR_DELETE_PROTECTED
;
1600 if (file
->type
== ST_USERDIR
&& file
->list
.mlh_Head
->mln_Succ
!= NULL
)
1602 return ERROR_DIRECTORY_NOT_EMPTY
;
1605 delete(rambase
, (struct fnode
*)file
);
1611 static int GM_UNIQUENAME(Close
)
1613 LIBBASETYPEPTR rambase
,
1614 struct IOFileSys
*iofs
1622 struct filehandle
*handle
;
1624 handle
= (struct filehandle
*)iofs
->IOFS
.io_Unit
;
1625 dev
= (struct cnode
*)handle
->node
;
1628 if (dev
->type
!= ST_LINKDIR
|| dev
->self
!= dev
)
1630 iofs
->io_DosError
= ERROR_OBJECT_WRONG_TYPE
;
1637 iofs
->io_DosError
= ERROR_OBJECT_IN_USE
;
1642 free_lock(rambase
, handle
);
1643 RemDosEntry(vol
->doslist
);
1644 FreeDosEntry(vol
->doslist
);
1646 while (vol
->list
.mlh_Head
->mln_Succ
!= NULL
)
1648 dir
= (struct dnode
*)vol
->list
.mlh_Head
;
1650 if (dir
->type
== ST_USERDIR
)
1652 while((file
= (struct fnode
*)RemHead((struct List
*)&dir
->list
)) != NULL
)
1654 AddTail((struct List
*)&vol
->list
, (struct Node
*)dir
);
1658 delete(rambase
, (struct fnode
*)dir
);
1661 Strfree(rambase
, vol
->name
);
1662 FreeMem(vol
, sizeof(struct vnode
));
1664 Strfree(rambase
, dev
->name
);
1665 FreeMem(dev
, sizeof(struct cnode
));
1667 iofs
->io_DosError
= 0;
1673 void processFSM(struct rambase
*rambase
);
1676 void deventry(struct rambase
*rambase
)
1680 struct Message
*msg
;
1683 Init device port. AllocSignal() cannot fail because this is a
1684 freshly created task with all signal bits still free.
1687 rambase
->port
->mp_SigBit
= AllocSignal(-1);
1688 rambase
->port
->mp_Flags
= PA_SIGNAL
;
1690 /* Check if there are pending messages that we missed */
1691 if ((msg
= GetMsg(rambase
->port
))) PutMsg(rambase
->port
, msg
);
1693 Notify_initialize(rambase
);
1695 notifyMask
= 1 << rambase
->notifyPort
->mp_SigBit
;
1697 fileOpMask
= 1 << rambase
->port
->mp_SigBit
;
1703 flags
= Wait(fileOpMask
| notifyMask
);
1705 if (flags
& notifyMask
)
1707 struct NotifyMessage
*nMessage
;
1709 D(kprintf("Got replied notify message\n"));
1711 while ((nMessage
= (struct NotifyMessage
*)GetMsg(rambase
->notifyPort
)) != NULL
)
1713 nMessage
->nm_NReq
->nr_Flags
&= ~NRF_NOT_REPLIED
;
1718 if (flags
& fileOpMask
)
1720 processFSM(rambase
);
1726 void processFSM(struct rambase
*rambase
)
1728 struct IOFileSys
*iofs
;
1734 /* Get and process the messages. */
1735 while ((iofs
= (struct IOFileSys
*)GetMsg(rambase
->port
)) != NULL
)
1737 // kprintf("Ram.handler initialized %u\n", iofs->IOFS.io_Command);
1739 switch (iofs
->IOFS
.io_Command
)
1743 get handle on a file or directory
1744 Unit *current; current directory / new handle on return
1745 STRPTR name; file- or directoryname
1746 LONG mode; open mode
1749 error
= open_(rambase
,
1750 (struct filehandle
**)&iofs
->IOFS
.io_Unit
,
1751 iofs
->io_Union
.io_OPEN
.io_Filename
,
1752 iofs
->io_Union
.io_OPEN
.io_FileMode
);
1757 open a file or create a new one
1758 Unit *current; current directory / new handle on return
1759 STRPTR name; file- or directoryname
1760 LONG mode; open mode
1761 LONG protect; protection flags if a new file is created
1764 error
= open_file(rambase
,
1765 (struct filehandle
**)&iofs
->IOFS
.io_Unit
,
1766 iofs
->io_Union
.io_OPEN_FILE
.io_Filename
,
1767 iofs
->io_Union
.io_OPEN_FILE
.io_FileMode
,
1768 iofs
->io_Union
.io_OPEN_FILE
.io_Protection
);
1773 read a number of bytes from a file
1774 Unit *current; filehandle
1776 LONG numbytes; number of bytes to read /
1777 number of bytes read on return,
1778 0 if there are no more bytes in the file
1780 error
= read(rambase
,
1781 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1782 iofs
->io_Union
.io_READ
.io_Buffer
,
1783 &iofs
->io_Union
.io_READ
.io_Length
);
1788 write a number of bytes to a file
1789 Unit *current; filehandle
1791 LONG numbytes; number of bytes to write /
1792 number of bytes written on return
1794 error
= write(rambase
,
1795 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1796 iofs
->io_Union
.io_WRITE
.io_Buffer
,
1797 &iofs
->io_Union
.io_WRITE
.io_Length
);
1802 set / read position in file
1803 Unit *current; filehandle
1805 LONG posl; relative position /
1806 old position on return
1807 LONG mode; one of OFFSET_BEGINNING, OFFSET_CURRENT,
1810 error
= seek(rambase
,
1811 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1812 &iofs
->io_Union
.io_SEEK
.io_Offset
,
1813 iofs
->io_Union
.io_SEEK
.io_SeekMode
);
1818 /* Get rid of a handle
1819 Unit *current; filehandle */
1821 struct filehandle
*handle
=
1822 (struct filehandle
*)iofs
->IOFS
.io_Unit
;
1824 Notify_fileChange(rambase
, NOTIFY_Close
,
1825 (struct fnode
*)handle
->node
);
1826 error
= free_lock(rambase
, handle
);
1832 Get information about the current object
1833 Unit *current; current object
1834 struct ExAllData *ead; buffer to be filled
1835 ULONG size; size of the buffer
1836 ULONG type; type of information to get
1837 iofs->io_DirPos; leave current position so
1838 ExNext() knows where to find
1841 error
= examine((struct fnode
*)((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
,
1842 iofs
->io_Union
.io_EXAMINE
.io_ead
,
1843 iofs
->io_Union
.io_EXAMINE
.io_Size
,
1844 iofs
->io_Union
.io_EXAMINE
.io_Mode
,
1845 &(iofs
->io_DirPos
));
1848 case FSA_EXAMINE_NEXT
:
1850 Get information about the next object
1851 Unit *current; current object
1852 struct FileInfoBlock *fib;
1854 error
= examine_next(rambase
,
1855 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1856 iofs
->io_Union
.io_EXAMINE_NEXT
.io_fib
);
1859 case FSA_EXAMINE_ALL
:
1861 Read the current directory
1862 Unit *current; current directory
1863 struct ExAllData *ead; buffer to be filled
1864 ULONG size; size of the buffer
1865 ULONG type; type of information to get
1867 error
= examine_all((struct filehandle
*)iofs
->IOFS
.io_Unit
,
1868 iofs
->io_Union
.io_EXAMINE_ALL
.io_ead
,
1869 iofs
->io_Union
.io_EXAMINE_ALL
.io_eac
,
1870 iofs
->io_Union
.io_EXAMINE_ALL
.io_Size
,
1871 iofs
->io_Union
.io_EXAMINE_ALL
.io_Mode
);
1874 case FSA_CREATE_DIR
:
1876 Build lock and open a new directory
1877 Unit *current; current directory
1878 STRPTR name; name of the dir to create
1879 LONG protect; Protection flags for the new dir
1882 // kprintf("Creating directory %s\n",
1883 // iofs->io_Union.io_CREATE_DIR.io_Filename);
1886 error
= create_dir(rambase
,
1887 (struct filehandle
**)&iofs
->IOFS
.io_Unit
,
1888 iofs
->io_Union
.io_CREATE_DIR
.io_Filename
,
1889 iofs
->io_Union
.io_CREATE_DIR
.io_Protection
);
1892 case FSA_DELETE_OBJECT
:
1894 Delete file or directory
1895 Unit *current; current directory
1896 STRPTR name; filename
1898 error
= delete_object(rambase
,
1899 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1900 iofs
->io_Union
.io_DELETE_OBJECT
.io_Filename
);
1903 case FSA_SET_PROTECT
:
1906 Set protection bits for a certain file or directory.
1907 Unit *current; current directory
1908 STRPTR name; filename
1909 ULONG protect; new protection bits
1912 STRPTR realName
= iofs
->io_Union
.io_SET_PROTECT
.io_Filename
;
1914 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
1915 error
= findname(rambase
, &realName
, &dir
);
1919 dir
->protect
= iofs
->io_Union
.io_SET_PROTECT
.io_Protection
;
1928 Set owner and group of the file or directory
1929 Unit *current; current directory
1930 STRPTR name; filename
1935 STRPTR realName
= iofs
->io_Union
.io_SET_OWNER
.io_Filename
;
1937 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
1938 error
= findname(rambase
, &realName
, &dir
);
1950 Set creation date of the file
1951 Unit *current; current directory
1952 STRPTR name; filename
1955 ULONG ticks; timestamp
1958 STRPTR realName
= iofs
->io_Union
.io_SET_DATE
.io_Filename
;
1960 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
1961 error
= findname(rambase
, &realName
, &dir
);
1970 case FSA_SET_COMMENT
:
1973 Set a comment for the file or directory;
1974 Unit *current; current directory
1975 STRPTR name; filename
1976 STRPTR comment; NUL terminated C string or NULL.
1979 STRPTR realName
= iofs
->io_Union
.io_SET_COMMENT
.io_Filename
;
1981 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
1982 error
= findname(rambase
, &realName
, &dir
);
1986 if (iofs
->io_Union
.io_SET_COMMENT
.io_Comment
)
1988 STRPTR s
= Strdup(rambase
,
1989 iofs
->io_Union
.io_SET_COMMENT
.io_Comment
);
1992 Strfree(rambase
, dir
->comment
);
1997 error
= ERROR_NO_FREE_STORE
;
2002 Strfree(rambase
, dir
->comment
);
2003 dir
->comment
= NULL
;
2010 case FSA_SET_FILE_SIZE
:
2012 Set a new size for the file.
2013 Unit *file; filehandle
2015 LONG offl; offset to current position/
2017 LONG mode; relative to what (see Seek)
2019 error
= set_file_size(rambase
,
2020 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
2021 &iofs
->io_Union
.io_SET_FILE_SIZE
.io_Offset
,
2022 iofs
->io_Union
.io_SET_FILE_SIZE
.io_SeekMode
);
2025 case FSA_IS_FILESYSTEM
:
2026 iofs
->io_Union
.io_IS_FILESYSTEM
.io_IsFilesystem
= TRUE
;
2032 struct InfoData
*id
= iofs
->io_Union
.io_INFO
.io_Info
;
2034 id
->id_NumSoftErrors
= 0;
2035 id
->id_UnitNumber
= 0;
2036 id
->id_DiskState
= ID_VALIDATED
;
2037 id
->id_NumBlocks
= AvailMem(MEMF_TOTAL
| MEMF_PUBLIC
)/BLOCKSIZE
;
2038 id
->id_NumBlocksUsed
= id
->id_NumBlocks
- AvailMem(MEMF_PUBLIC
)/BLOCKSIZE
;
2039 id
->id_BytesPerBlock
= BLOCKSIZE
;
2040 id
->id_DiskType
= ID_DOS_DISK
;
2041 id
->id_VolumeNode
= NULL
; /* What is this? */
2042 id
->id_InUse
= (LONG
)TRUE
;
2050 case FSA_ADD_NOTIFY
:
2053 struct NotifyRequest
*nr
=
2054 iofs
->io_Union
.io_NOTIFY
.io_NotificationRequest
;
2055 struct filehandle
*fh
= (struct filehandle
*)iofs
->IOFS
.io_Unit
;
2057 D(kprintf("Adding notification for entity (nr = %s)\n",
2060 ok
= Notify_addNotification(rambase
, fh
->node
, nr
);
2064 error
= ERROR_NO_FREE_STORE
;
2067 D(kprintf("Notification now added!\n"));
2071 case FSA_REMOVE_NOTIFY
:
2073 struct NotifyRequest
*nr
=
2074 iofs
->io_Union
.io_NOTIFY
.io_NotificationRequest
;
2076 Notify_removeNotification(rambase
, nr
);
2081 error
= ERROR_NOT_IMPLEMENTED
;
2083 D(kprintf("ram_handler, unimplemented FSA: %ld\n", iofs
->IOFS
.io_Command
));
2087 Change or read the mode of a single filehandle
2088 Unit *current; filehandle to change
2089 ULONG newmode; new mode/old mode on return
2090 ULONG mask; bits affected
2093 Change or read the mode of the filesystem
2094 Unit *current; filesystem to change
2095 ULONG newmode; new mode/old mode on return
2096 ULONG mask; bits affected
2097 STRPTR passwd; password for MMF_LOCKED
2100 Create a hard link on a file, directory or soft link
2101 Unit *current; current directory
2102 STRPTR name; softlink name
2103 Unit *target; target handle
2106 Create a soft link to another object
2107 Unit *current; current directory
2108 STRPTR name; softlink name
2109 STRPTR target; target name
2129 iofs
->io_DosError
= error
;
2130 ReplyMsg(&iofs
->IOFS
.io_Message
);
2134 if (rambase
->iofs
!= NULL
)
2136 iofs
= rambase
->iofs
;
2138 if (iofs
->IOFS
.io_Message
.mn_Node
.ln_Type
== NT_MESSAGE
)
2140 abort_notify(rambase
, iofs
);
2141 iofs
->io_DosError
= ERROR_BREAK
;
2142 rambase
->iofs
= NULL
;
2143 ReplyMsg(&iofs
->IOFS
.io_Message
);
2147 rambase
->iofs
= NULL
;
2158 /***************************************************************************
2159 ****************************************************************************/
2161 /** Notification stuff **/
2164 * Immediate notification:
2166 * ACTION_RENAME_OBJECT
2167 * ACTION_RENAME_DISK
2169 * ACTION_DELETE_OBJECT
2173 * Session semantics notification:
2178 * ACTION_SET_FILE_SIZE
2181 * For ram-handler, the only FSA actions currently implemented/affected are
2182 * FSA_WRITE, FSA_CREATE_DIR, FSA_DELETE (and implicitly FSA_OPEN, FSA_CLOSE)
2187 BOOL
Notify_initialize(struct rambase
*rambase
)
2189 rambase
->notifyPort
= CreateMsgPort();
2191 if (rambase
->notifyPort
== NULL
)
2200 void Notify_fileChange(struct rambase
*rambase
, NType type
, struct fnode
*file
)
2208 // kprintf("Setting write flag!\n");
2209 file
->flags
|= FILEFLAGS_Changed
;
2213 /* Only notify in case the file was changed */
2214 if (file
->flags
& FILEFLAGS_Changed
)
2216 // kprintf("Notification on close (file was changed).\n");
2217 file
->flags
&= ~FILEFLAGS_Changed
;
2218 Notify_notifyTasks(rambase
, &file
->receivers
);
2225 struct List
*receivers
;
2227 fullName
= getName(rambase
, (struct dnode
*)file
, "");
2229 D(kprintf("Found full name: %s\n", fullName
));
2231 receivers
= HashTable_find(rambase
, rambase
->notifications
,
2234 if (receivers
!= NULL
)
2236 D(kprintf("Found notification for created file!\n"));
2238 while (!IsListEmpty(receivers
))
2240 AddHead((struct List
*)&file
->receivers
,
2241 RemHead(receivers
));
2245 HashTable_remove(rambase
, rambase
->notifications
, fullName
);
2252 /* It's the same thing as for directories... */
2253 Notify_directoryChange(rambase
, NOTIFY_Delete
, (struct dnode
*)file
);
2263 void Notify_directoryChange(struct rambase
*rambase
, NType type
,
2272 fullName
= getName(rambase
, dir
, "");
2274 /* TODO: HashTable_apply(ht, fullName, dir); */
2283 struct List
*receivers
;
2285 fullName
= getName(rambase
, dir
, "");
2287 D(kprintf("Found full name: %s\n", fullName
));
2289 receivers
= HashTable_find(rambase
, rambase
->notifications
,
2292 if (receivers
!= NULL
)
2294 D(kprintf("Found notification for created directory!\n"));
2296 while (!IsListEmpty(receivers
))
2298 AddHead((struct List
*)&dir
->receivers
,
2299 RemHead(receivers
));
2303 HashTable_remove(rambase
, rambase
->notifications
, fullName
);
2308 D(kprintf("Notifying receivers!\n"));
2309 Notify_notifyTasks(rambase
, &dir
->receivers
);
2314 /* As we have deleted a file, we must move the requests for
2315 this file to the hash table */
2316 struct List
*receivers
= (struct List
*)&dir
->receivers
;
2318 Notify_notifyTasks(rambase
, &dir
->receivers
);
2320 /* Move the Notification request to the hash table as we're going
2321 to delete this directory */
2322 while (!IsListEmpty(receivers
))
2324 struct Receiver
*rr
= (struct Receiver
*)RemHead(receivers
);
2326 HashTable_insert(rambase
, rambase
->notifications
,
2327 rr
->nr
->nr_FullName
, rr
);
2338 // kprintf("Returning from Notify_dirChange()\n");
2342 /* TODO: Implement support for NRF_WAIT_REPLY */
2343 void Notify_notifyTasks(struct rambase
*rambase
, struct MinList
*notifications
)
2345 struct Receiver
*rr
;
2347 // kprintf("Inside notifytasks, not = %p\n", notifications);
2349 ForeachNode((struct List
*)notifications
, rr
)
2351 struct NotifyRequest
*nr
= rr
->nr
;
2353 if (nr
->nr_Flags
& NRF_SEND_MESSAGE
&&
2354 !(nr
->nr_Flags
& NRF_WAIT_REPLY
&& nr
->nr_Flags
& NRF_NOT_REPLIED
))
2356 struct NotifyMessage
*nm
= AllocVec(sizeof(struct NotifyMessage
),
2357 MEMF_PUBLIC
| MEMF_CLEAR
);
2364 nm
->nm_ExecMessage
.mn_ReplyPort
= rambase
->notifyPort
;
2365 nm
->nm_ExecMessage
.mn_Length
= sizeof(struct NotifyMessage
);
2367 nr
->nr_Flags
|= NRF_NOT_REPLIED
;
2369 PutMsg(nr
->nr_stuff
.nr_Msg
.nr_Port
, &nm
->nm_ExecMessage
);
2371 else if (nr
->nr_Flags
& NRF_SEND_SIGNAL
)
2373 Signal(nr
->nr_stuff
.nr_Signal
.nr_Task
,
2374 1 << nr
->nr_stuff
.nr_Signal
.nr_SignalNum
);
2380 BOOL
Notify_addNotification(struct rambase
*rambase
, struct dnode
*dn
,
2381 struct NotifyRequest
*nr
)
2383 struct dnode
*dnTemp
= dn
;
2384 HashTable
*ht
= rambase
->notifications
;
2385 STRPTR name
= nr
->nr_FullName
, colon
;
2387 colon
= strchr(name
, ':');
2391 /* First: Check if the file is opened */
2393 D(kprintf("Checking existence of %s\n", name
));
2395 if (findname(rambase
, &name
, &dnTemp
) == 0)
2397 /* This file was already opened (or at least known by the file
2400 struct Receiver
*rr
= AllocVec(sizeof(struct Receiver
), MEMF_CLEAR
);
2409 if (nr
->nr_Flags
& NRF_NOTIFY_INITIAL
)
2411 struct MinList tempList
;
2413 /* Create a temporary list on the stack and add the receiver to
2414 it. Then forget about this and add the node to the receiver
2415 list (below this block). */
2416 NewList((struct List
*)&tempList
);
2417 AddHead((struct List
*)&tempList
, &rr
->node
);
2418 Notify_notifyTasks(rambase
, &tempList
);
2421 /* Add the receiver node to the file's/directory's list of receivers */
2422 AddTail((struct List
*)&dnTemp
->receivers
, &rr
->node
);
2428 /* This file is not opened */
2430 struct Receiver
*rr
= AllocVec(sizeof(struct Receiver
), MEMF_CLEAR
);
2439 HashTable_insert(rambase
, ht
, name
, rr
);
2446 void Notify_removeNotification(struct rambase
*rambase
,
2447 struct NotifyRequest
*nr
)
2449 struct dnode
*dn
= (struct dnode
*)rambase
->root
;
2450 struct Receiver
*rr
, *rrTemp
;
2451 /* STRPTR name = strchr(nr->nr_FullName, '/') + 1; */
2452 STRPTR name
= nr
->nr_FullName
;
2453 struct List
*receivers
;
2454 BOOL fromTable
= FALSE
;
2457 colon
= strchr(name
, ':');
2459 /* Take care of absolute names in nr_Name */
2465 if (findname(rambase
, &name
, &dn
) == 0)
2467 receivers
= (struct List
*)&dn
->receivers
;
2471 /* This was a request for an entity that doesn't exist yet */
2472 receivers
= HashTable_find(rambase
, rambase
->notifications
, name
);
2474 if (receivers
== NULL
)
2476 kprintf("Ram: This should not happen! -- buggy application...\n");
2484 ForeachNodeSafe(&receivers
, rr
, rrTemp
)
2488 Remove((struct Node
*)rr
);
2496 /* If we removed a request for a file that doesn't exist yet --
2497 if this was the only notification request for that file, remove
2498 also the hash entry. */
2499 if (IsListEmpty((struct List
*)receivers
))
2501 HashTable_remove(rambase
, rambase
->notifications
, name
);
2507 STRPTR
getAbsoluteName(struct rambase
*rambase
, STRPTR name
)
2509 int length
= strlen(name
) + 1 + 1;
2510 STRPTR fullName
= AllocVec(length
, MEMF_CLEAR
| MEMF_PUBLIC
);
2512 if (fullName
== NULL
)
2517 strcpy(fullName
, name
);
2518 *strchr(fullName
, ':') = '/';
2520 if (fullName
[strlen(fullName
) - 1] != '/')
2522 strcat(fullName
, "/");
2529 STRPTR
getName(struct rambase
*rambase
, struct dnode
*dn
, STRPTR name
)
2531 struct dnode
*dnTemp
= dn
;
2535 STRPTR fullNameTemp
;
2537 STRPTR nextSlash
= slash
;
2539 /* First, calculate the size of the complete filename */
2541 if (strchr(name
, ':') != NULL
)
2543 return getAbsoluteName(rambase
, name
);
2547 length
= strlen(name
) + 1 + 1 + 1; /* Add trailing 0 byte and possible '/' */
2548 length
+= strlen(dn
->name
) + 1;
2550 while (findname(rambase
, &slash
, &dnTemp
) == 0)
2553 length
+= 1 + strlen(dnTemp
->name
); /* Add '/' byte */
2556 /* The MEMF_CLEAR is necessary for the while loop below to work */
2557 fullName
= AllocVec(length
, MEMF_PUBLIC
| MEMF_CLEAR
);
2559 if (fullName
== NULL
)
2564 fullNameTemp
= fullName
;
2567 fullName
+= length
- 1 - 1;
2570 int temp
= strlen(name
);
2572 if (temp
> 0 && name
[temp
- 1] != '/')
2578 fullName
-= strlen(name
);
2579 strncpy(fullName
, name
, strlen(name
));
2581 fullName
-= strlen(dn
->name
) + 1;
2582 strcpy(fullName
, dn
->name
);
2583 fullName
[strlen(dn
->name
)] = '/';
2588 STRPTR nextSlash
= slash
;
2590 while (findname(rambase
, &slash
, &dnTemp
) != ERROR_OBJECT_NOT_FOUND
)
2593 partLen
= strlen(dnTemp
->name
);
2595 fullName
-= partLen
+ 1;
2596 strcpy(fullName
, dnTemp
->name
);
2597 fullName
[partLen
] = '/'; /* Replace 0 with '/' */
2601 if (fullName
!= fullNameTemp
)
2604 while((fullNameTemp
[length
] = fullName
[length
])) length
++;
2607 return fullNameTemp
;
2611 HashNode
*find(struct rambase
*rambase
, HashTable
*ht
,
2612 void *key
, struct List
*list
);
2615 HashTable
*HashTable_new(struct rambase
*rambase
, ULONG size
,
2616 ULONG (*hash
)(struct rambase
*rambase
,
2618 int (*compare
)(struct rambase
*rambase
,
2621 void (*delete)(struct rambase
*rambase
,
2625 ULONG i
; /* Loop variable */
2626 HashTable
*ht
= AllocVec(sizeof(HashTable
), MEMF_ANY
);
2635 ht
->array
= AllocVec(sizeof(struct List
)*size
, MEMF_ANY
);
2637 if (ht
->array
== NULL
)
2645 ht
->compare
= compare
;
2646 ht
->delete = delete;
2648 for (i
= 0; i
< size
; i
++)
2650 NewList(&ht
->array
[i
]);
2657 /* TODO: Fix the double list thing, remove the (void *) hack */
2658 void HashTable_delete(struct rambase
*rambase
, HashTable
*ht
)
2662 for (i
= 0; i
< ht
->size
; i
++)
2664 while (!IsListEmpty(&ht
->array
[i
]))
2666 HashNode
*hn
= (HashNode
*)RemHead(&ht
->array
[i
]);
2668 ht
->delete(rambase
, hn
->key
, (void *)&hn
->requests
);
2677 void HashTable_insert(struct rambase
*rambase
, HashTable
*ht
, void *key
,
2678 struct Receiver
*rr
)
2683 pos
= ht
->hash(rambase
, key
) % ht
->size
;
2685 hn
= find(rambase
, ht
, key
, &ht
->array
[pos
]);
2689 /* There was no previous request for this entity */
2690 hn
= AllocVec(sizeof(HashNode
), MEMF_ANY
);
2697 hn
->key
= Strdup(rambase
, key
);
2699 if (hn
->key
== NULL
)
2705 NewList(&hn
->requests
);
2706 AddHead(&ht
->array
[pos
], &hn
->node
);
2709 AddHead(&hn
->requests
, &rr
->node
);
2715 void HashTable_remove(struct rambase
*rambase
, HashTable
*ht
, void *key
)
2719 struct Node
*tempNode
;
2722 pos
= ht
->hash(rambase
, key
) % ht
->size
;
2723 list
= &ht
->array
[pos
];
2725 ForeachNodeSafe(list
, hn
, tempNode
)
2727 if (ht
->compare(rambase
, key
, hn
->key
) == 0)
2730 ht
->delete(rambase
, hn
->key
, (void *)&hn
->requests
);
2739 struct rambase
*rambase
, HashTable
*ht
,
2740 void *key
, struct List
*list
)
2742 HashNode
*hn
; /* Loop variable */
2744 ForeachNode(list
, hn
)
2746 if (ht
->compare(rambase
, key
, hn
->key
) == 0)
2756 struct List
*HashTable_find(struct rambase
*rambase
, HashTable
*ht
, void *key
)
2761 pos
= ht
->hash(rambase
, key
) % ht
->size
;
2762 hn
= find(rambase
, ht
, key
, &ht
->array
[pos
]);
2766 return &hn
->requests
;
2773 return NULL
; /* Make the compiler happy */
2777 inline ULONG
HashTable_size(HashTable
*ht
)
2782 ADD2INITLIB(GM_UNIQUENAME(Init
),0)
2783 ADD2OPENDEV(GM_UNIQUENAME(Open
),0)
2784 ADD2CLOSEDEV(GM_UNIQUENAME(Close
),0)
2785 ADD2EXPUNGELIB(GM_UNIQUENAME(Expunge
),0)