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 */
197 #define DOSBase rambase->dosbase
199 static int OpenDev(LIBBASETYPEPTR rambase
, struct IOFileSys
*iofs
);
201 static int GM_UNIQUENAME(Init
)(LIBBASETYPEPTR rambase
)
203 /* This function is single-threaded by exec by calling Forbid. */
205 struct MsgPort
*port
;
207 struct SignalSemaphore
*semaphore
;
210 rambase
->dosbase
= (struct DosLibrary
*)OpenLibrary("dos.library",39);
212 if (rambase
->dosbase
!= NULL
)
214 rambase
->utilitybase
= (struct UtilityBase
*)OpenLibrary("utility.library",39);
216 if (rambase
->utilitybase
!=NULL
)
218 port
= (struct MsgPort
*)AllocMem(sizeof(struct MsgPort
),
219 MEMF_PUBLIC
| MEMF_CLEAR
);
222 rambase
->port
= port
;
223 NewList(&port
->mp_MsgList
);
224 port
->mp_Node
.ln_Type
= NT_MSGPORT
;
225 port
->mp_SigBit
= SIGB_SINGLE
;
227 task
= (struct Task
*)AllocMem(sizeof(struct Task
),
228 MEMF_PUBLIC
| MEMF_CLEAR
);
232 port
->mp_SigTask
= task
;
233 port
->mp_Flags
= PA_IGNORE
;
234 NewList(&task
->tc_MemEntry
);
235 task
->tc_Node
.ln_Type
= NT_TASK
;
236 task
->tc_Node
.ln_Name
= "ram.handler task";
238 stack
= AllocMem(AROS_STACKSIZE
, MEMF_PUBLIC
);
242 struct TagItem tasktags
[] =
244 {TASKTAG_ARG1
, (IPTR
)rambase
},
248 task
->tc_SPLower
= stack
;
249 task
->tc_SPUpper
= (BYTE
*)stack
+ AROS_STACKSIZE
;
250 #if AROS_STACK_GROWS_DOWNWARDS
251 task
->tc_SPReg
= (BYTE
*)task
->tc_SPUpper
- SP_OFFSET
;
253 task
->tc_SPReg
= (BYTE
*)task
->tc_SPLower
+ SP_OFFSET
;
256 semaphore
= (struct SignalSemaphore
*)AllocMem(sizeof(struct SignalSemaphore
),
257 MEMF_PUBLIC
| MEMF_CLEAR
);
259 if (semaphore
!= NULL
)
261 rambase
->sigsem
= semaphore
;
262 InitSemaphore(semaphore
);
264 if (rambase
->seglist
==NULL
) /* Are we a ROM module? */
266 struct DeviceNode
*dn
;
267 /* Install RAM: handler into device list
269 * KLUDGE: ram.handler should create only one device node, depending on
270 * the startup packet it gets. The mountlists for RAM: should be into dos.library bootstrap
274 if((dn
= AllocMem(sizeof (struct DeviceNode
) + 4 + 3 + 2, MEMF_CLEAR
|MEMF_PUBLIC
)))
276 struct IOFileSys dummyiofs
;
278 if (OpenDev(rambase
, &dummyiofs
))
280 BSTR s
= MKBADDR(((IPTR
)dn
+ sizeof(struct DeviceNode
) + 4) & ~3);
282 rambase
->device
.dd_Library
.lib_OpenCnt
++;
284 AROS_BSTR_putchar(s
, 0, 'R');
285 AROS_BSTR_putchar(s
, 1, 'A');
286 AROS_BSTR_putchar(s
, 2, 'M');
287 AROS_BSTR_putchar(s
, 3, 0);
288 AROS_BSTR_setstrlen(s
, 3);
290 dn
->dn_Type
= DLT_DEVICE
;
291 dn
->dn_Ext
.dn_AROS
.dn_Unit
= dummyiofs
.IOFS
.io_Unit
;
292 dn
->dn_Ext
.dn_AROS
.dn_Device
= dummyiofs
.IOFS
.io_Device
;
293 dn
->dn_Handler
= NULL
;
294 dn
->dn_Startup
= NULL
;
296 dn
->dn_Ext
.dn_AROS
.dn_DevName
= AROS_BSTR_ADDR(dn
->dn_Name
);
298 if (AddDosEntry((struct DosList
*)dn
))
299 if (NewAddTask(task
, deventry
, NULL
, tasktags
) != NULL
)
303 FreeMem(dn
, sizeof (struct DeviceNode
));
307 if (NewAddTask(task
, deventry
, NULL
, tasktags
) != NULL
)
310 FreeMem(semaphore
, sizeof(struct SignalSemaphore
));
313 FreeMem(stack
, AROS_STACKSIZE
);
316 FreeMem(task
, sizeof(struct Task
));
319 FreeMem(port
, sizeof(struct MsgPort
));
322 CloseLibrary((struct Library
*)rambase
->utilitybase
);
325 CloseLibrary((struct Library
*)rambase
->dosbase
);
334 #define UtilityBase rambase->utilitybase
337 /***************************************************************************/
339 void nullDelete(struct rambase
*rambase
, void *key
, struct List
*list
)
341 // struct Receiver *rr;
342 // struct Node *tempNode;
344 // ForeachNodeSafe(list, rr, tempNode)
346 // Remove(&rr->node);
352 /* The list is part of the HashNode so we shouldn't free that */
356 ULONG
stringHash(struct rambase
*rambase
, const void *key
)
358 STRPTR str
= (STRPTR
)key
;
363 val
*= ToLower(*str
++);
371 my_strcasecmp(struct rambase
*rambase
, const void *s1
, const void *s2
)
373 return strcasecmp(s1
, s2
);
376 /****************************************************************************/
379 static STRPTR
Strdup(struct rambase
*rambase
, STRPTR string
)
381 STRPTR s2
= string
,s3
;
386 s3
= (STRPTR
)AllocVec(s2
- string
, MEMF_ANY
);
390 CopyMem(string
, s3
, s2
- string
);
397 static void Strfree(struct rambase
*rambase
, STRPTR string
)
403 static int GM_UNIQUENAME(Open
)
405 LIBBASETYPEPTR rambase
,
406 struct IOFileSys
*iofs
,
411 /* Mark Message as recently used. */
412 iofs
->IOFS
.io_Message
.mn_Node
.ln_Type
= NT_REPLYMSG
;
414 return OpenDev(rambase
, iofs
);
418 static int OpenDev(LIBBASETYPEPTR rambase
, struct IOFileSys
*iofs
)
420 struct filehandle
*fhv
, *fhc
;
425 iofs
->IOFS
.io_Error
= ERROR_NO_FREE_STORE
;
427 fhv
= (struct filehandle
*)AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
431 fhc
= (struct filehandle
*)AllocMem(sizeof(struct filehandle
),
436 vol
= (struct vnode
*)AllocMem(sizeof(struct vnode
), MEMF_CLEAR
);
440 dev
= (struct cnode
*)AllocMem(sizeof(struct cnode
),
445 vol
->name
= Strdup(rambase
, "Ram Disk");
447 if (vol
->name
!= NULL
)
449 dlv
= MakeDosEntry("Ram Disk", DLT_VOLUME
);
453 vol
->type
= ST_USERDIR
;
457 NewList((struct List
*)&vol
->list
);
458 NewList((struct List
*)&vol
->receivers
);
459 fhv
->node
= (struct dnode
*)vol
;
460 dlv
->dol_Ext
.dol_AROS
.dol_Unit
= (struct Unit
*)fhv
;
461 dlv
->dol_Ext
.dol_AROS
.dol_Device
= &rambase
->device
;
462 dev
->type
= ST_LINKDIR
;
465 fhc
->node
= (struct dnode
*)dev
;
466 iofs
->IOFS
.io_Unit
= (struct Unit
*)fhc
;
467 iofs
->IOFS
.io_Device
= &rambase
->device
;
470 iofs
->IOFS
.io_Error
= 0;
472 rambase
->notifications
=
473 HashTable_new(rambase
, 100, stringHash
,
474 my_strcasecmp
, nullDelete
);
479 Strfree(rambase
, vol
->name
);
482 FreeMem(dev
, sizeof(struct cnode
));
485 FreeMem(vol
, sizeof(struct vnode
));
488 FreeMem(fhc
, sizeof(struct filehandle
));
491 FreeMem(fhv
, sizeof(struct filehandle
));
494 iofs
->IOFS
.io_Error
= IOERR_OPENFAIL
;
499 static int GM_UNIQUENAME(Expunge
)(LIBBASETYPEPTR rambase
)
502 This function is single-threaded by exec by calling Forbid.
503 Never break the Forbid() or strange things might happen.
506 /* Kill device task and free all resources */
507 RemTask(rambase
->port
->mp_SigTask
);
508 FreeMem(rambase
->sigsem
, sizeof(struct SignalSemaphore
));
509 FreeMem(((struct Task
*)rambase
->port
->mp_SigTask
)->tc_SPLower
,
511 FreeMem(rambase
->port
->mp_SigTask
, sizeof(struct Task
));
512 FreeMem(rambase
->port
, sizeof(struct MsgPort
));
513 CloseLibrary((struct Library
*)rambase
->utilitybase
);
514 CloseLibrary((struct Library
*)rambase
->dosbase
);
520 AROS_LH1(void, beginio
,
521 AROS_LHA(struct IOFileSys
*, iofs
, A1
),
522 struct rambase
*, rambase
, 5, Ram
)
526 /* WaitIO will look into this */
527 iofs
->IOFS
.io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
529 /* Nothing is done quick */
530 iofs
->IOFS
.io_Flags
&= ~IOF_QUICK
;
532 /* So let the device task do it */
533 PutMsg(rambase
->port
, &iofs
->IOFS
.io_Message
);
539 AROS_LH1(LONG
, abortio
,
540 AROS_LHA(struct IOFileSys
*, iofs
, A1
),
541 struct rambase
*, rambase
, 6, Ram
)
549 static LONG
getblock(struct rambase
*rambase
, struct fnode
*file
, LONG block
,
550 int mode
, UBYTE
**result
)
557 p
= &file
->blocks
[block
];
561 else if (block
< 0x410)
564 p
= (UBYTE
**)&file
->iblocks
[block
/0x100];
568 else if(block
< 0x10410)
571 p
= (UBYTE
**)&file
->i2block
;
577 p
= (UBYTE
**)&file
->i3block
;
593 while (i
-- && p
!= NULL
)
595 a
= (block
>> i
*8) & 0xff;
598 if (!(block
& ((1 << i
*8) - 1)))
604 FreeMem(p
, PBLOCKSIZE
);
613 FreeMem(p
, BLOCKSIZE
);
621 while (i
-- && p
!= NULL
)
623 p
= ((UBYTE
***)p
)[(block
>> i
*8) & 0xff];
626 *result
= (UBYTE
*)p
;
634 *p
= AllocMem(PBLOCKSIZE
, MEMF_CLEAR
);
638 return ERROR_NO_FREE_STORE
;
642 p
= (UBYTE
**)*p
+ ((block
>> i
*8) & 0xff);
647 *p
= AllocMem(BLOCKSIZE
, MEMF_CLEAR
);
651 return ERROR_NO_FREE_STORE
;
657 } /* switch (mode) */
663 static void zerofill(UBYTE
*address
, ULONG size
)
672 static void shrinkfile(struct rambase
*rambase
, struct fnode
*file
, LONG size
)
677 blocks
= (size
+ BLOCKSIZE
- 1)/BLOCKSIZE
;
678 block
= (file
->size
+ BLOCKSIZE
- 1)/BLOCKSIZE
;
680 for(;block
-- > blocks
;)
682 (void)getblock(rambase
, file
, block
, -1, &p
);
687 (void)getblock(rambase
, file
, size
, 0, &p
);
691 zerofill(p
+ (size
& 0xff), -size
& 0xff);
699 static void delete(struct rambase
*rambase
, struct fnode
*file
)
701 struct hnode
*link
, *new, *more
;
704 Strfree(rambase
, file
->name
);
705 Strfree(rambase
, file
->comment
);
706 Remove((struct Node
*)file
);
708 if (file
->type
== ST_LINKDIR
)
710 /* It is a link. Remove it from the chain. */
712 link
= ((struct hnode
*)file
)->orig
;
713 ((struct hnode
*)file
)->orig
= NULL
;
714 file
->type
= link
->type
;
716 while((struct fnode
*)link
->link
!= file
)
721 link
->link
= file
->link
;
723 else if (file
->link
!= NULL
)
725 /* If there is a hard link to the object make the link the original */
728 link
->type
= file
->type
;
740 while((node
= RemHead((struct List
*)&((struct dnode
*)file
)->list
)) != NULL
)
741 AddTail((struct List
*)&((struct dnode
*)file
)->list
, node
);
745 CopyMemQuick(&file
->size
, &((struct fnode
*)new)->size
,
746 sizeof(struct fnode
) - offsetof(struct fnode
, size
));
747 zerofill((UBYTE
*)&file
->size
,
748 sizeof(struct fnode
) - offsetof(struct fnode
, size
));
752 ((struct snode
*)new)->contents
= ((struct snode
*)file
)->contents
;
753 ((struct snode
*)file
)->contents
= NULL
;
756 } /* else if (file->link != NULL) */
761 Notify_directoryChange(rambase
, NOTIFY_Delete
, (struct dnode
*)file
);
763 FreeMem(file
, sizeof(struct dnode
));
768 Notify_fileChange(rambase
, NOTIFY_Delete
, file
);
770 shrinkfile(rambase
, file
, 0);
771 FreeMem(file
, sizeof(struct fnode
));
776 Strfree(rambase
, ((struct snode
*)file
)->contents
);
777 FreeMem(file
, sizeof(struct snode
));
784 static int fstrcmp(struct rambase
*rambase
, char *s1
, char *s2
)
788 if (ToLower(*s1
) != ToLower(*s2
))
790 return *s1
|| *s2
!= '/';
804 /* Find a node for a given name */
805 static LONG
findname(struct rambase
*rambase
, STRPTR
*name
,
806 struct dnode
**dnode
)
808 struct dnode
*cur
= *dnode
;
813 if (cur
->type
== ST_LINKDIR
)
815 cur
= (struct dnode
*)((struct hnode
*)cur
)->orig
;
825 if ((struct dnode
*)cur
->volume
== cur
)
827 return ERROR_OBJECT_NOT_FOUND
;
830 while (cur
->node
.mln_Pred
!= NULL
)
832 cur
= (struct dnode
*)cur
->node
.mln_Pred
;
835 cur
= (struct dnode
*)((BYTE
*)cur
- offsetof(struct dnode
, list
));
839 if (cur
->type
== ST_SOFTLINK
)
844 return ERROR_IS_SOFT_LINK
;
847 if (cur
->type
!= ST_USERDIR
)
849 return ERROR_DIR_NOT_FOUND
;
853 cur
= (struct dnode
*)cur
->list
.mlh_Head
;
857 if (cur
->node
.mln_Succ
== NULL
)
861 return ERROR_OBJECT_NOT_FOUND
;
864 if (!fstrcmp(rambase
, cur
->name
, rest
))
869 cur
= (struct dnode
*)cur
->node
.mln_Succ
;
888 static LONG
set_file_size(struct rambase
*rambase
, struct filehandle
*handle
,
889 QUAD
*offp
, LONG mode
)
891 struct fnode
*file
= (struct fnode
*)handle
->node
;
894 if (file
->type
!= ST_FILE
)
896 return ERROR_OBJECT_WRONG_TYPE
;
901 case OFFSET_BEGINNING
:
905 size
+= handle
->position
;
913 return ERROR_NOT_IMPLEMENTED
;
918 return ERROR_SEEK_ERROR
;
921 if (size
< file
->size
)
923 shrinkfile(rambase
, file
, size
);
926 file
->size
= *offp
= size
;
932 static LONG
read(struct rambase
*rambase
, struct filehandle
*handle
,
933 APTR buffer
, LONG
*numbytes
)
935 struct fnode
*file
= (struct fnode
*)handle
->node
;
936 ULONG num
= *numbytes
;
937 ULONG size
= file
->size
;
939 UBYTE
*buf
= buffer
, *p
;
941 if (handle
->position
>= size
)
945 else if (handle
->position
+ num
> size
)
947 num
= size
- handle
->position
;
950 block
= handle
->position
/BLOCKSIZE
;
951 offset
= handle
->position
& (BLOCKSIZE
- 1);
952 size
= BLOCKSIZE
- offset
;
961 (void)getblock(rambase
, file
, block
, 0, &p
);
965 CopyMem(p
+ offset
, buffer
, size
);
969 zerofill(buffer
, size
);
979 *numbytes
= (UBYTE
*)buffer
- buf
;
980 handle
->position
+= *numbytes
;
986 static LONG
write(struct rambase
*rambase
, struct filehandle
*handle
,
987 UBYTE
*buffer
, LONG
*numbytes
)
989 struct fnode
*file
= (struct fnode
*)handle
->node
;
990 ULONG num
= *numbytes
;
991 ULONG size
= file
->size
;
993 UBYTE
*buf
= buffer
, *p
;
996 if ((LONG
)(handle
->position
+ num
) < 0)
998 return ERROR_OBJECT_TOO_LARGE
;
1001 Notify_fileChange(rambase
, NOTIFY_Write
, file
);
1003 block
= handle
->position
/BLOCKSIZE
;
1004 offset
= handle
->position
& (BLOCKSIZE
- 1);
1005 size
= BLOCKSIZE
- offset
;
1014 error
= getblock(rambase
, file
, block
, 1, &p
);
1021 CopyMem(buffer
, p
+ offset
, size
);
1029 *numbytes
= (UBYTE
*)buffer
- buf
;
1030 handle
->position
+= *numbytes
;
1032 if (handle
->position
> file
->size
)
1034 file
->size
= handle
->position
;
1041 static LONG
lock(struct dnode
*dir
, ULONG mode
)
1043 if ((mode
& FMF_EXECUTE
) && (dir
->protect
& FMF_EXECUTE
))
1045 return ERROR_NOT_EXECUTABLE
;
1048 if ((mode
& FMF_WRITE
) && (dir
->protect
& FMF_WRITE
))
1050 return ERROR_WRITE_PROTECTED
;
1053 if ((mode
& FMF_READ
) && (dir
->protect
& FMF_READ
))
1055 return ERROR_READ_PROTECTED
;
1058 if (mode
& FMF_LOCK
)
1062 return ERROR_OBJECT_IN_USE
;
1065 dir
->usecount
= ~0ul/2 + 1;
1069 if (dir
->usecount
< 0)
1071 return ERROR_OBJECT_IN_USE
;
1076 dir
->volume
->volcount
++;
1082 static LONG
open_(struct rambase
*rambase
, struct filehandle
**handle
,
1083 STRPTR name
, ULONG mode
)
1085 struct dnode
*dir
= (*handle
)->node
;
1086 struct filehandle
*fh
;
1089 fh
= (struct filehandle
*)AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
1093 error
= findname(rambase
, &name
, &dir
);
1097 error
= lock(dir
, mode
);
1104 if (dir
->type
== ST_FILE
)
1106 Notify_fileChange(rambase
, NOTIFY_Open
,
1107 (struct fnode
*)dir
);
1109 else if (dir
->type
== ST_USERDIR
)
1111 D(kprintf("Notifying OPEN at dir %s\n", dir
->name
));
1112 Notify_directoryChange(rambase
, NOTIFY_Open
, dir
);
1119 FreeMem(fh
, sizeof(struct filehandle
));
1123 error
= ERROR_NO_FREE_STORE
;
1130 static LONG
open_file(struct rambase
*rambase
, struct filehandle
**handle
,
1131 STRPTR name
, ULONG mode
, ULONG protect
)
1133 struct dnode
*dir
= (*handle
)->node
;
1134 struct filehandle
*fh
;
1137 fh
= AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
1141 error
= findname(rambase
, &name
, &dir
);
1143 if ((mode
& FMF_CREATE
) && error
== ERROR_OBJECT_NOT_FOUND
)
1156 file
= (struct fnode
*)AllocMem(sizeof(struct fnode
), MEMF_CLEAR
);
1160 file
->name
= Strdup(rambase
, name
);
1162 if (file
->name
!= NULL
)
1164 file
->type
= ST_FILE
;
1165 file
->protect
= protect
;
1166 file
->volume
= dir
->volume
;
1167 NewList((struct List
*)&file
->receivers
);
1168 AddTail((struct List
*)&dir
->list
, (struct Node
*)file
);
1169 error
= lock((struct dnode
*)file
, mode
);
1173 fh
->node
= (struct dnode
*)file
;
1176 Notify_fileChange(rambase
, NOTIFY_Add
, file
);
1181 Strfree(rambase
, file
->name
);
1184 FreeMem(file
,sizeof(struct fnode
));
1187 error
= ERROR_NO_FREE_STORE
;
1191 if (dir
->type
!= ST_FILE
)
1193 error
= ERROR_OBJECT_WRONG_TYPE
;
1197 error
= lock(dir
, mode
);
1202 if (mode
& FMF_CLEAR
)
1204 shrinkfile(rambase
, (struct fnode
*)dir
, 0);
1205 dir
->protect
= protect
;
1215 } /* else if (!error) */
1217 FreeMem(fh
, sizeof(struct filehandle
));
1224 static LONG
create_dir(struct rambase
*rambase
, struct filehandle
**handle
,
1225 STRPTR name
, ULONG protect
)
1227 struct dnode
*dir
= (*handle
)->node
, *new;
1228 struct filehandle
*fh
;
1231 if (dir
->protect
& FIBF_WRITE
)
1233 return ERROR_WRITE_PROTECTED
;
1236 error
= findname(rambase
, &name
, &dir
);
1240 return ERROR_OBJECT_EXISTS
;
1243 if (error
!= ERROR_OBJECT_NOT_FOUND
)
1248 if (strchr(name
, '/') != NULL
)
1253 fh
= AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
1257 new = (struct dnode
*)AllocMem(sizeof(struct dnode
), MEMF_CLEAR
);
1261 new->name
= Strdup(rambase
, name
);
1263 if (new->name
!= NULL
)
1265 new->type
= ST_USERDIR
;
1266 new->protect
= protect
;
1267 new->volume
= dir
->volume
;
1268 new->volume
->volcount
++;
1269 new->usecount
= ~0ul/2 + 2;
1270 NewList((struct List
*)&new->list
);
1271 NewList((struct List
*)&new->receivers
);
1272 AddTail((struct List
*)&dir
->list
, (struct Node
*)new);
1276 // kprintf("New (%p): Name = %s\n", new, new->name);
1277 Notify_directoryChange(rambase
, NOTIFY_Add
, new);
1282 FreeMem(new, sizeof(struct dnode
));
1285 FreeMem(fh
, sizeof(struct filehandle
));
1288 return ERROR_NO_FREE_STORE
;
1292 static LONG
free_lock(struct rambase
*rambase
, struct filehandle
*filehandle
)
1294 struct dnode
*dnode
= filehandle
->node
;
1296 dnode
->usecount
= (dnode
->usecount
- 1) & ~0ul/2;
1297 FreeMem(filehandle
, sizeof(struct filehandle
));
1298 dnode
->volume
->volcount
--;
1304 static LONG
seek(struct rambase
*rambase
, struct filehandle
*filehandle
,
1305 QUAD
*posp
, LONG mode
)
1307 struct fnode
*file
= (struct fnode
*)filehandle
->node
;
1310 if (file
->type
!= ST_FILE
)
1312 return ERROR_OBJECT_WRONG_TYPE
;
1317 case OFFSET_BEGINNING
:
1320 case OFFSET_CURRENT
:
1321 pos
+= filehandle
->position
;
1329 return ERROR_NOT_IMPLEMENTED
;
1334 return ERROR_SEEK_ERROR
;
1337 *posp
= filehandle
->position
;
1338 filehandle
->position
= pos
;
1344 static const ULONG sizes
[]=
1347 offsetof(struct ExAllData
,ed_Type
),
1348 offsetof(struct ExAllData
,ed_Size
),
1349 offsetof(struct ExAllData
,ed_Prot
),
1350 offsetof(struct ExAllData
,ed_Days
),
1351 offsetof(struct ExAllData
,ed_Comment
),
1352 offsetof(struct ExAllData
,ed_OwnerUID
),
1353 sizeof(struct ExAllData
)
1357 static LONG
examine(struct fnode
*file
,
1358 struct ExAllData
*ead
,
1363 STRPTR next
, end
, name
;
1365 if (type
> ED_OWNER
)
1367 return ERROR_BAD_NUMBER
;
1370 next
= (STRPTR
)ead
+ sizes
[type
];
1371 end
= (STRPTR
)ead
+ size
;
1373 if(next
>end
) /* > is correct. Not >= */
1374 return ERROR_BUFFER_OVERFLOW
;
1376 /* Use *dirpos to store information for ExNext()
1377 * *dirpos is copied to fib->fib_DiskKey in Examine()
1379 if (file
->type
== ST_USERDIR
)
1381 *dirpos
= (LONG
)(((struct dnode
*)file
)->list
.mlh_Head
);
1385 /* ExNext() should not be called in this case anyway */
1386 *dirpos
= (LONG
)file
;
1392 ead
->ed_OwnerUID
= 0;
1393 ead
->ed_OwnerGID
= 0;
1397 if (file
->comment
!= NULL
)
1399 ead
->ed_Comment
= next
;
1400 name
= file
->comment
;
1406 return ERROR_BUFFER_OVERFLOW
;
1409 if (!(*next
++ = *name
++))
1417 ead
->ed_Comment
= NULL
;
1428 ead
->ed_Prot
= file
->protect
;
1432 ead
->ed_Size
= file
->size
;
1436 ead
->ed_Type
= file
->type
;
1438 if (((struct vnode
*)file
)->self
== (struct vnode
*)file
)
1440 ead
->ed_Type
=ST_ROOT
;
1445 ead
->ed_Name
= next
;
1452 return ERROR_BUFFER_OVERFLOW
;
1455 if (!(*next
++ = *name
++))
1463 ead
->ed_Next
= (struct ExAllData
*)(((IPTR
)next
+ AROS_PTRALIGN
- 1) & ~(AROS_PTRALIGN
- 1));
1470 static LONG
examine_next(struct rambase
*rambase
,
1471 struct filehandle
*dir
,
1472 struct FileInfoBlock
*FIB
)
1474 struct fnode
*file
= (struct fnode
*)FIB
->fib_DiskKey
;
1476 ASSERT_VALID_PTR_OR_NULL(file
);
1478 if (file
->node
.mln_Succ
== NULL
)
1480 return ERROR_NO_MORE_ENTRIES
;
1483 FIB
->fib_OwnerUID
= 0;
1484 FIB
->fib_OwnerGID
= 0;
1486 FIB
->fib_Date
.ds_Days
= 0;
1487 FIB
->fib_Date
.ds_Minute
= 0;
1488 FIB
->fib_Date
.ds_Tick
= 0;
1489 FIB
->fib_Protection
= file
->protect
;
1490 FIB
->fib_Size
= file
->size
;
1491 FIB
->fib_DirEntryType
= file
->type
;
1493 strncpy(FIB
->fib_FileName
, file
->name
, MAXFILENAMELENGTH
- 1);
1494 strncpy(FIB
->fib_Comment
, file
->comment
!= NULL
? file
->comment
: "",
1495 MAXCOMMENTLENGTH
- 1);
1497 FIB
->fib_DiskKey
= (LONG
)file
->node
.mln_Succ
;
1503 static LONG
examine_all(struct filehandle
*dir
,
1504 struct ExAllData
*ead
,
1505 struct ExAllControl
*eac
,
1510 struct ExAllData
*last
=NULL
;
1513 LONG dummy
; /* not anything is done with this value but passed to examine */
1514 end
= (STRPTR
)ead
+ size
;
1516 eac
->eac_Entries
= 0;
1517 if (dir
->node
->type
!= ST_USERDIR
)
1519 return ERROR_OBJECT_WRONG_TYPE
;
1522 ent
= (struct fnode
*)eac
->eac_LastKey
;
1526 ent
= (struct fnode
*)dir
->node
->list
.mlh_Head
;
1527 if (ent
->node
.mln_Succ
) ent
->usecount
++;
1530 if (ent
->node
.mln_Succ
== NULL
)
1532 return ERROR_NO_MORE_ENTRIES
;
1539 error
= examine(ent
, ead
, end
- (STRPTR
)ead
, type
, &dummy
);
1541 if (error
== ERROR_BUFFER_OVERFLOW
)
1549 last
->ed_Next
= NULL
;
1550 eac
->eac_LastKey
= (IPTR
)ent
;
1557 ent
= (struct fnode
*)ent
->node
.mln_Succ
;
1559 } while (ent
->node
.mln_Succ
!= NULL
);
1561 last
->ed_Next
= NULL
;
1562 eac
->eac_LastKey
= (IPTR
)ent
;
1564 return ERROR_NO_MORE_ENTRIES
;
1568 static LONG
delete_object(struct rambase
*rambase
,
1569 struct filehandle
*filehandle
, STRPTR name
)
1571 struct dnode
*file
= filehandle
->node
;
1574 error
= findname(rambase
, &name
, &file
);
1581 if ((struct dnode
*)file
->volume
== file
)
1583 return ERROR_OBJECT_WRONG_TYPE
;
1586 if (file
->usecount
!= 0)
1588 return ERROR_OBJECT_IN_USE
;
1591 if (file
->protect
& FIBF_DELETE
)
1593 return ERROR_DELETE_PROTECTED
;
1596 if (file
->type
== ST_USERDIR
&& file
->list
.mlh_Head
->mln_Succ
!= NULL
)
1598 return ERROR_DIRECTORY_NOT_EMPTY
;
1601 delete(rambase
, (struct fnode
*)file
);
1607 static int GM_UNIQUENAME(Close
)
1609 LIBBASETYPEPTR rambase
,
1610 struct IOFileSys
*iofs
1618 struct filehandle
*handle
;
1620 handle
= (struct filehandle
*)iofs
->IOFS
.io_Unit
;
1621 dev
= (struct cnode
*)handle
->node
;
1624 if (dev
->type
!= ST_LINKDIR
|| dev
->self
!= dev
)
1626 iofs
->io_DosError
= ERROR_OBJECT_WRONG_TYPE
;
1633 iofs
->io_DosError
= ERROR_OBJECT_IN_USE
;
1638 free_lock(rambase
, handle
);
1639 RemDosEntry(vol
->doslist
);
1640 FreeDosEntry(vol
->doslist
);
1642 while (vol
->list
.mlh_Head
->mln_Succ
!= NULL
)
1644 dir
= (struct dnode
*)vol
->list
.mlh_Head
;
1646 if (dir
->type
== ST_USERDIR
)
1648 while((file
= (struct fnode
*)RemHead((struct List
*)&dir
->list
)) != NULL
)
1650 AddTail((struct List
*)&vol
->list
, (struct Node
*)dir
);
1654 delete(rambase
, (struct fnode
*)dir
);
1657 Strfree(rambase
, vol
->name
);
1658 FreeMem(vol
, sizeof(struct vnode
));
1660 Strfree(rambase
, dev
->name
);
1661 FreeMem(dev
, sizeof(struct cnode
));
1663 iofs
->io_DosError
= 0;
1669 void processFSM(struct rambase
*rambase
);
1672 void deventry(struct rambase
*rambase
)
1676 struct Message
*msg
;
1679 Init device port. AllocSignal() cannot fail because this is a
1680 freshly created task with all signal bits still free.
1683 rambase
->port
->mp_SigBit
= AllocSignal(-1);
1684 rambase
->port
->mp_Flags
= PA_SIGNAL
;
1686 /* Check if there are pending messages that we missed */
1687 if ((msg
= GetMsg(rambase
->port
))) PutMsg(rambase
->port
, msg
);
1689 Notify_initialize(rambase
);
1691 notifyMask
= 1 << rambase
->notifyPort
->mp_SigBit
;
1693 fileOpMask
= 1 << rambase
->port
->mp_SigBit
;
1699 flags
= Wait(fileOpMask
| notifyMask
);
1701 if (flags
& notifyMask
)
1703 struct NotifyMessage
*nMessage
;
1705 D(kprintf("Got replied notify message\n"));
1707 while ((nMessage
= (struct NotifyMessage
*)GetMsg(rambase
->notifyPort
)) != NULL
)
1709 nMessage
->nm_NReq
->nr_Flags
&= ~NRF_NOT_REPLIED
;
1714 if (flags
& fileOpMask
)
1716 processFSM(rambase
);
1722 void processFSM(struct rambase
*rambase
)
1724 struct IOFileSys
*iofs
;
1730 /* Get and process the messages. */
1731 while ((iofs
= (struct IOFileSys
*)GetMsg(rambase
->port
)) != NULL
)
1733 // kprintf("Ram.handler initialized %u\n", iofs->IOFS.io_Command);
1735 switch (iofs
->IOFS
.io_Command
)
1739 get handle on a file or directory
1740 Unit *current; current directory / new handle on return
1741 STRPTR name; file- or directoryname
1742 LONG mode; open mode
1745 error
= open_(rambase
,
1746 (struct filehandle
**)&iofs
->IOFS
.io_Unit
,
1747 iofs
->io_Union
.io_OPEN
.io_Filename
,
1748 iofs
->io_Union
.io_OPEN
.io_FileMode
);
1753 open a file or create a new one
1754 Unit *current; current directory / new handle on return
1755 STRPTR name; file- or directoryname
1756 LONG mode; open mode
1757 LONG protect; protection flags if a new file is created
1760 error
= open_file(rambase
,
1761 (struct filehandle
**)&iofs
->IOFS
.io_Unit
,
1762 iofs
->io_Union
.io_OPEN_FILE
.io_Filename
,
1763 iofs
->io_Union
.io_OPEN_FILE
.io_FileMode
,
1764 iofs
->io_Union
.io_OPEN_FILE
.io_Protection
);
1769 read a number of bytes from a file
1770 Unit *current; filehandle
1772 LONG numbytes; number of bytes to read /
1773 number of bytes read on return,
1774 0 if there are no more bytes in the file
1776 error
= read(rambase
,
1777 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1778 iofs
->io_Union
.io_READ
.io_Buffer
,
1779 &iofs
->io_Union
.io_READ
.io_Length
);
1784 write a number of bytes to a file
1785 Unit *current; filehandle
1787 LONG numbytes; number of bytes to write /
1788 number of bytes written on return
1790 error
= write(rambase
,
1791 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1792 iofs
->io_Union
.io_WRITE
.io_Buffer
,
1793 &iofs
->io_Union
.io_WRITE
.io_Length
);
1798 set / read position in file
1799 Unit *current; filehandle
1801 LONG posl; relative position /
1802 old position on return
1803 LONG mode; one of OFFSET_BEGINNING, OFFSET_CURRENT,
1806 error
= seek(rambase
,
1807 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1808 &iofs
->io_Union
.io_SEEK
.io_Offset
,
1809 iofs
->io_Union
.io_SEEK
.io_SeekMode
);
1814 /* Get rid of a handle
1815 Unit *current; filehandle */
1817 struct filehandle
*handle
=
1818 (struct filehandle
*)iofs
->IOFS
.io_Unit
;
1820 Notify_fileChange(rambase
, NOTIFY_Close
,
1821 (struct fnode
*)handle
->node
);
1822 error
= free_lock(rambase
, handle
);
1828 Get information about the current object
1829 Unit *current; current object
1830 struct ExAllData *ead; buffer to be filled
1831 ULONG size; size of the buffer
1832 ULONG type; type of information to get
1833 iofs->io_DirPos; leave current position so
1834 ExNext() knows where to find
1837 error
= examine((struct fnode
*)((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
,
1838 iofs
->io_Union
.io_EXAMINE
.io_ead
,
1839 iofs
->io_Union
.io_EXAMINE
.io_Size
,
1840 iofs
->io_Union
.io_EXAMINE
.io_Mode
,
1841 &(iofs
->io_DirPos
));
1844 case FSA_EXAMINE_NEXT
:
1846 Get information about the next object
1847 Unit *current; current object
1848 struct FileInfoBlock *fib;
1850 error
= examine_next(rambase
,
1851 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1852 iofs
->io_Union
.io_EXAMINE_NEXT
.io_fib
);
1855 case FSA_EXAMINE_ALL
:
1857 Read the current directory
1858 Unit *current; current directory
1859 struct ExAllData *ead; buffer to be filled
1860 ULONG size; size of the buffer
1861 ULONG type; type of information to get
1863 error
= examine_all((struct filehandle
*)iofs
->IOFS
.io_Unit
,
1864 iofs
->io_Union
.io_EXAMINE_ALL
.io_ead
,
1865 iofs
->io_Union
.io_EXAMINE_ALL
.io_eac
,
1866 iofs
->io_Union
.io_EXAMINE_ALL
.io_Size
,
1867 iofs
->io_Union
.io_EXAMINE_ALL
.io_Mode
);
1870 case FSA_CREATE_DIR
:
1872 Build lock and open a new directory
1873 Unit *current; current directory
1874 STRPTR name; name of the dir to create
1875 LONG protect; Protection flags for the new dir
1878 // kprintf("Creating directory %s\n",
1879 // iofs->io_Union.io_CREATE_DIR.io_Filename);
1882 error
= create_dir(rambase
,
1883 (struct filehandle
**)&iofs
->IOFS
.io_Unit
,
1884 iofs
->io_Union
.io_CREATE_DIR
.io_Filename
,
1885 iofs
->io_Union
.io_CREATE_DIR
.io_Protection
);
1888 case FSA_DELETE_OBJECT
:
1890 Delete file or directory
1891 Unit *current; current directory
1892 STRPTR name; filename
1894 error
= delete_object(rambase
,
1895 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1896 iofs
->io_Union
.io_DELETE_OBJECT
.io_Filename
);
1899 case FSA_SET_PROTECT
:
1902 Set protection bits for a certain file or directory.
1903 Unit *current; current directory
1904 STRPTR name; filename
1905 ULONG protect; new protection bits
1908 STRPTR realName
= iofs
->io_Union
.io_SET_PROTECT
.io_Filename
;
1910 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
1911 error
= findname(rambase
, &realName
, &dir
);
1915 dir
->protect
= iofs
->io_Union
.io_SET_PROTECT
.io_Protection
;
1924 Set owner and group of the file or directory
1925 Unit *current; current directory
1926 STRPTR name; filename
1931 STRPTR realName
= iofs
->io_Union
.io_SET_OWNER
.io_Filename
;
1933 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
1934 error
= findname(rambase
, &realName
, &dir
);
1946 Set creation date of the file
1947 Unit *current; current directory
1948 STRPTR name; filename
1951 ULONG ticks; timestamp
1954 STRPTR realName
= iofs
->io_Union
.io_SET_DATE
.io_Filename
;
1956 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
1957 error
= findname(rambase
, &realName
, &dir
);
1966 case FSA_SET_COMMENT
:
1969 Set a comment for the file or directory;
1970 Unit *current; current directory
1971 STRPTR name; filename
1972 STRPTR comment; NUL terminated C string or NULL.
1975 STRPTR realName
= iofs
->io_Union
.io_SET_COMMENT
.io_Filename
;
1977 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
1978 error
= findname(rambase
, &realName
, &dir
);
1982 if (iofs
->io_Union
.io_SET_COMMENT
.io_Comment
)
1984 STRPTR s
= Strdup(rambase
,
1985 iofs
->io_Union
.io_SET_COMMENT
.io_Comment
);
1988 Strfree(rambase
, dir
->comment
);
1993 error
= ERROR_NO_FREE_STORE
;
1998 Strfree(rambase
, dir
->comment
);
1999 dir
->comment
= NULL
;
2006 case FSA_SET_FILE_SIZE
:
2008 Set a new size for the file.
2009 Unit *file; filehandle
2011 LONG offl; offset to current position/
2013 LONG mode; relative to what (see Seek)
2015 error
= set_file_size(rambase
,
2016 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
2017 &iofs
->io_Union
.io_SET_FILE_SIZE
.io_Offset
,
2018 iofs
->io_Union
.io_SET_FILE_SIZE
.io_SeekMode
);
2021 case FSA_IS_FILESYSTEM
:
2022 iofs
->io_Union
.io_IS_FILESYSTEM
.io_IsFilesystem
= TRUE
;
2028 struct InfoData
*id
= iofs
->io_Union
.io_INFO
.io_Info
;
2030 id
->id_NumSoftErrors
= 0;
2031 id
->id_UnitNumber
= 0;
2032 id
->id_DiskState
= ID_VALIDATED
;
2033 id
->id_NumBlocks
= AvailMem(MEMF_TOTAL
| MEMF_PUBLIC
)/BLOCKSIZE
;
2034 id
->id_NumBlocksUsed
= id
->id_NumBlocks
- AvailMem(MEMF_PUBLIC
)/BLOCKSIZE
;
2035 id
->id_BytesPerBlock
= BLOCKSIZE
;
2036 id
->id_DiskType
= ID_DOS_DISK
;
2037 id
->id_VolumeNode
= NULL
; /* What is this? */
2038 id
->id_InUse
= (LONG
)TRUE
;
2046 case FSA_ADD_NOTIFY
:
2049 struct NotifyRequest
*nr
=
2050 iofs
->io_Union
.io_NOTIFY
.io_NotificationRequest
;
2051 struct filehandle
*fh
= (struct filehandle
*)iofs
->IOFS
.io_Unit
;
2053 D(kprintf("Adding notification for entity (nr = %s)\n",
2056 ok
= Notify_addNotification(rambase
, fh
->node
, nr
);
2060 error
= ERROR_NO_FREE_STORE
;
2063 D(kprintf("Notification now added!\n"));
2067 case FSA_REMOVE_NOTIFY
:
2069 struct NotifyRequest
*nr
=
2070 iofs
->io_Union
.io_NOTIFY
.io_NotificationRequest
;
2072 Notify_removeNotification(rambase
, nr
);
2077 error
= ERROR_NOT_IMPLEMENTED
;
2079 D(kprintf("ram_handler, unimplemented FSA: %ld\n", iofs
->IOFS
.io_Command
));
2083 Change or read the mode of a single filehandle
2084 Unit *current; filehandle to change
2085 ULONG newmode; new mode/old mode on return
2086 ULONG mask; bits affected
2089 Change or read the mode of the filesystem
2090 Unit *current; filesystem to change
2091 ULONG newmode; new mode/old mode on return
2092 ULONG mask; bits affected
2093 STRPTR passwd; password for MMF_LOCKED
2096 Create a hard link on a file, directory or soft link
2097 Unit *current; current directory
2098 STRPTR name; softlink name
2099 Unit *target; target handle
2102 Create a soft link to another object
2103 Unit *current; current directory
2104 STRPTR name; softlink name
2105 STRPTR target; target name
2125 iofs
->io_DosError
= error
;
2126 ReplyMsg(&iofs
->IOFS
.io_Message
);
2130 if (rambase
->iofs
!= NULL
)
2132 iofs
= rambase
->iofs
;
2134 if (iofs
->IOFS
.io_Message
.mn_Node
.ln_Type
== NT_MESSAGE
)
2136 abort_notify(rambase
, iofs
);
2137 iofs
->io_DosError
= ERROR_BREAK
;
2138 rambase
->iofs
= NULL
;
2139 ReplyMsg(&iofs
->IOFS
.io_Message
);
2143 rambase
->iofs
= NULL
;
2154 /***************************************************************************
2155 ****************************************************************************/
2157 /** Notification stuff **/
2160 * Immediate notification:
2162 * ACTION_RENAME_OBJECT
2163 * ACTION_RENAME_DISK
2165 * ACTION_DELETE_OBJECT
2169 * Session semantics notification:
2174 * ACTION_SET_FILE_SIZE
2177 * For ram-handler, the only FSA actions currently implemented/affected are
2178 * FSA_WRITE, FSA_CREATE_DIR, FSA_DELETE (and implicitly FSA_OPEN, FSA_CLOSE)
2183 BOOL
Notify_initialize(struct rambase
*rambase
)
2185 rambase
->notifyPort
= CreateMsgPort();
2187 if (rambase
->notifyPort
== NULL
)
2196 void Notify_fileChange(struct rambase
*rambase
, NType type
, struct fnode
*file
)
2204 // kprintf("Setting write flag!\n");
2205 file
->flags
|= FILEFLAGS_Changed
;
2209 /* Only notify in case the file was changed */
2210 if (file
->flags
& FILEFLAGS_Changed
)
2212 // kprintf("Notification on close (file was changed).\n");
2213 file
->flags
&= ~FILEFLAGS_Changed
;
2214 Notify_notifyTasks(rambase
, &file
->receivers
);
2221 struct List
*receivers
;
2223 fullName
= getName(rambase
, (struct dnode
*)file
, "");
2225 D(kprintf("Found full name: %s\n", fullName
));
2227 receivers
= HashTable_find(rambase
, rambase
->notifications
,
2230 if (receivers
!= NULL
)
2232 D(kprintf("Found notification for created file!\n"));
2234 while (!IsListEmpty(receivers
))
2236 AddHead((struct List
*)&file
->receivers
,
2237 RemHead(receivers
));
2241 HashTable_remove(rambase
, rambase
->notifications
, fullName
);
2248 /* It's the same thing as for directories... */
2249 Notify_directoryChange(rambase
, NOTIFY_Delete
, (struct dnode
*)file
);
2259 void Notify_directoryChange(struct rambase
*rambase
, NType type
,
2268 fullName
= getName(rambase
, dir
, "");
2270 /* TODO: HashTable_apply(ht, fullName, dir); */
2279 struct List
*receivers
;
2281 fullName
= getName(rambase
, dir
, "");
2283 D(kprintf("Found full name: %s\n", fullName
));
2285 receivers
= HashTable_find(rambase
, rambase
->notifications
,
2288 if (receivers
!= NULL
)
2290 D(kprintf("Found notification for created directory!\n"));
2292 while (!IsListEmpty(receivers
))
2294 AddHead((struct List
*)&dir
->receivers
,
2295 RemHead(receivers
));
2299 HashTable_remove(rambase
, rambase
->notifications
, fullName
);
2304 D(kprintf("Notifying receivers!\n"));
2305 Notify_notifyTasks(rambase
, &dir
->receivers
);
2310 /* As we have deleted a file, we must move the requests for
2311 this file to the hash table */
2312 struct List
*receivers
= (struct List
*)&dir
->receivers
;
2314 Notify_notifyTasks(rambase
, &dir
->receivers
);
2316 /* Move the Notification request to the hash table as we're going
2317 to delete this directory */
2318 while (!IsListEmpty(receivers
))
2320 struct Receiver
*rr
= (struct Receiver
*)RemHead(receivers
);
2322 HashTable_insert(rambase
, rambase
->notifications
,
2323 rr
->nr
->nr_FullName
, rr
);
2334 // kprintf("Returning from Notify_dirChange()\n");
2338 /* TODO: Implement support for NRF_WAIT_REPLY */
2339 void Notify_notifyTasks(struct rambase
*rambase
, struct MinList
*notifications
)
2341 struct Receiver
*rr
;
2343 // kprintf("Inside notifytasks, not = %p\n", notifications);
2345 ForeachNode((struct List
*)notifications
, rr
)
2347 struct NotifyRequest
*nr
= rr
->nr
;
2349 if (nr
->nr_Flags
& NRF_SEND_MESSAGE
&&
2350 !(nr
->nr_Flags
& NRF_WAIT_REPLY
&& nr
->nr_Flags
& NRF_NOT_REPLIED
))
2352 struct NotifyMessage
*nm
= AllocVec(sizeof(struct NotifyMessage
),
2353 MEMF_PUBLIC
| MEMF_CLEAR
);
2360 nm
->nm_ExecMessage
.mn_ReplyPort
= rambase
->notifyPort
;
2361 nm
->nm_ExecMessage
.mn_Length
= sizeof(struct NotifyMessage
);
2363 nr
->nr_Flags
|= NRF_NOT_REPLIED
;
2365 PutMsg(nr
->nr_stuff
.nr_Msg
.nr_Port
, &nm
->nm_ExecMessage
);
2367 else if (nr
->nr_Flags
& NRF_SEND_SIGNAL
)
2369 Signal(nr
->nr_stuff
.nr_Signal
.nr_Task
,
2370 1 << nr
->nr_stuff
.nr_Signal
.nr_SignalNum
);
2376 BOOL
Notify_addNotification(struct rambase
*rambase
, struct dnode
*dn
,
2377 struct NotifyRequest
*nr
)
2379 struct dnode
*dnTemp
= dn
;
2380 HashTable
*ht
= rambase
->notifications
;
2381 STRPTR name
= nr
->nr_FullName
, colon
;
2383 colon
= strchr(name
, ':');
2387 /* First: Check if the file is opened */
2389 D(kprintf("Checking existence of %s\n", name
));
2391 if (findname(rambase
, &name
, &dnTemp
) == 0)
2393 /* This file was already opened (or at least known by the file
2396 struct Receiver
*rr
= AllocVec(sizeof(struct Receiver
), MEMF_CLEAR
);
2405 if (nr
->nr_Flags
& NRF_NOTIFY_INITIAL
)
2407 struct MinList tempList
;
2409 /* Create a temporary list on the stack and add the receiver to
2410 it. Then forget about this and add the node to the receiver
2411 list (below this block). */
2412 NewList((struct List
*)&tempList
);
2413 AddHead((struct List
*)&tempList
, &rr
->node
);
2414 Notify_notifyTasks(rambase
, &tempList
);
2417 /* Add the receiver node to the file's/directory's list of receivers */
2418 AddTail((struct List
*)&dnTemp
->receivers
, &rr
->node
);
2424 /* This file is not opened */
2426 struct Receiver
*rr
= AllocVec(sizeof(struct Receiver
), MEMF_CLEAR
);
2435 HashTable_insert(rambase
, ht
, name
, rr
);
2442 void Notify_removeNotification(struct rambase
*rambase
,
2443 struct NotifyRequest
*nr
)
2445 struct dnode
*dn
= (struct dnode
*)rambase
->root
;
2446 struct Receiver
*rr
, *rrTemp
;
2447 /* STRPTR name = strchr(nr->nr_FullName, '/') + 1; */
2448 STRPTR name
= nr
->nr_FullName
;
2449 struct List
*receivers
;
2450 BOOL fromTable
= FALSE
;
2453 colon
= strchr(name
, ':');
2455 /* Take care of absolute names in nr_Name */
2461 if (findname(rambase
, &name
, &dn
) == 0)
2463 receivers
= (struct List
*)&dn
->receivers
;
2467 /* This was a request for an entity that doesn't exist yet */
2468 receivers
= HashTable_find(rambase
, rambase
->notifications
, name
);
2470 if (receivers
== NULL
)
2472 kprintf("Ram: This should not happen! -- buggy application...\n");
2480 ForeachNodeSafe(&receivers
, rr
, rrTemp
)
2484 Remove((struct Node
*)rr
);
2492 /* If we removed a request for a file that doesn't exist yet --
2493 if this was the only notification request for that file, remove
2494 also the hash entry. */
2495 if (IsListEmpty((struct List
*)receivers
))
2497 HashTable_remove(rambase
, rambase
->notifications
, name
);
2503 STRPTR
getAbsoluteName(struct rambase
*rambase
, STRPTR name
)
2505 int length
= strlen(name
) + 1 + 1;
2506 STRPTR fullName
= AllocVec(length
, MEMF_CLEAR
| MEMF_PUBLIC
);
2508 if (fullName
== NULL
)
2513 strcpy(fullName
, name
);
2514 *strchr(fullName
, ':') = '/';
2516 if (fullName
[strlen(fullName
) - 1] != '/')
2518 strcat(fullName
, "/");
2525 STRPTR
getName(struct rambase
*rambase
, struct dnode
*dn
, STRPTR name
)
2527 struct dnode
*dnTemp
= dn
;
2531 STRPTR fullNameTemp
;
2533 STRPTR nextSlash
= slash
;
2535 /* First, calculate the size of the complete filename */
2537 if (strchr(name
, ':') != NULL
)
2539 return getAbsoluteName(rambase
, name
);
2543 length
= strlen(name
) + 1 + 1 + 1; /* Add trailing 0 byte and possible '/' */
2544 length
+= strlen(dn
->name
) + 1;
2546 while (findname(rambase
, &slash
, &dnTemp
) == 0)
2549 length
+= 1 + strlen(dnTemp
->name
); /* Add '/' byte */
2552 /* The MEMF_CLEAR is necessary for the while loop below to work */
2553 fullName
= AllocVec(length
, MEMF_PUBLIC
| MEMF_CLEAR
);
2555 if (fullName
== NULL
)
2560 fullNameTemp
= fullName
;
2563 fullName
+= length
- 1 - 1;
2566 int temp
= strlen(name
);
2568 if (temp
> 0 && name
[temp
- 1] != '/')
2574 fullName
-= strlen(name
);
2575 strncpy(fullName
, name
, strlen(name
));
2577 fullName
-= strlen(dn
->name
) + 1;
2578 strcpy(fullName
, dn
->name
);
2579 fullName
[strlen(dn
->name
)] = '/';
2584 STRPTR nextSlash
= slash
;
2586 while (findname(rambase
, &slash
, &dnTemp
) != ERROR_OBJECT_NOT_FOUND
)
2589 partLen
= strlen(dnTemp
->name
);
2591 fullName
-= partLen
+ 1;
2592 strcpy(fullName
, dnTemp
->name
);
2593 fullName
[partLen
] = '/'; /* Replace 0 with '/' */
2597 if (fullName
!= fullNameTemp
)
2600 while((fullNameTemp
[length
] = fullName
[length
])) length
++;
2603 return fullNameTemp
;
2607 HashNode
*find(struct rambase
*rambase
, HashTable
*ht
,
2608 void *key
, struct List
*list
);
2611 HashTable
*HashTable_new(struct rambase
*rambase
, ULONG size
,
2612 ULONG (*hash
)(struct rambase
*rambase
,
2614 int (*compare
)(struct rambase
*rambase
,
2617 void (*delete)(struct rambase
*rambase
,
2621 ULONG i
; /* Loop variable */
2622 HashTable
*ht
= AllocVec(sizeof(HashTable
), MEMF_ANY
);
2631 ht
->array
= AllocVec(sizeof(struct List
)*size
, MEMF_ANY
);
2633 if (ht
->array
== NULL
)
2641 ht
->compare
= compare
;
2642 ht
->delete = delete;
2644 for (i
= 0; i
< size
; i
++)
2646 NewList(&ht
->array
[i
]);
2653 /* TODO: Fix the double list thing, remove the (void *) hack */
2654 void HashTable_delete(struct rambase
*rambase
, HashTable
*ht
)
2658 for (i
= 0; i
< ht
->size
; i
++)
2660 while (!IsListEmpty(&ht
->array
[i
]))
2662 HashNode
*hn
= (HashNode
*)RemHead(&ht
->array
[i
]);
2664 ht
->delete(rambase
, hn
->key
, (void *)&hn
->requests
);
2673 void HashTable_insert(struct rambase
*rambase
, HashTable
*ht
, void *key
,
2674 struct Receiver
*rr
)
2679 pos
= ht
->hash(rambase
, key
) % ht
->size
;
2681 hn
= find(rambase
, ht
, key
, &ht
->array
[pos
]);
2685 /* There was no previous request for this entity */
2686 hn
= AllocVec(sizeof(HashNode
), MEMF_ANY
);
2693 hn
->key
= Strdup(rambase
, key
);
2695 if (hn
->key
== NULL
)
2701 NewList(&hn
->requests
);
2702 AddHead(&ht
->array
[pos
], &hn
->node
);
2705 AddHead(&hn
->requests
, &rr
->node
);
2711 void HashTable_remove(struct rambase
*rambase
, HashTable
*ht
, void *key
)
2715 struct Node
*tempNode
;
2718 pos
= ht
->hash(rambase
, key
) % ht
->size
;
2719 list
= &ht
->array
[pos
];
2721 ForeachNodeSafe(list
, hn
, tempNode
)
2723 if (ht
->compare(rambase
, key
, hn
->key
) == 0)
2726 ht
->delete(rambase
, hn
->key
, (void *)&hn
->requests
);
2735 struct rambase
*rambase
, HashTable
*ht
,
2736 void *key
, struct List
*list
)
2738 HashNode
*hn
; /* Loop variable */
2740 ForeachNode(list
, hn
)
2742 if (ht
->compare(rambase
, key
, hn
->key
) == 0)
2752 struct List
*HashTable_find(struct rambase
*rambase
, HashTable
*ht
, void *key
)
2757 pos
= ht
->hash(rambase
, key
) % ht
->size
;
2758 hn
= find(rambase
, ht
, key
, &ht
->array
[pos
]);
2762 return &hn
->requests
;
2769 return NULL
; /* Make the compiler happy */
2773 inline ULONG
HashTable_size(HashTable
*ht
)
2778 ADD2INITLIB(GM_UNIQUENAME(Init
),0)
2779 ADD2OPENDEV(GM_UNIQUENAME(Open
),0)
2780 ADD2CLOSEDEV(GM_UNIQUENAME(Close
),0)
2781 ADD2EXPUNGELIB(GM_UNIQUENAME(Expunge
),0)