2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
9 #include <aros/debug.h>
11 #include <exec/errors.h>
12 #include <exec/types.h>
13 #include <exec/resident.h>
14 #include <exec/memory.h>
15 #include <exec/semaphores.h>
16 #include <utility/tagitem.h>
17 #include <utility/utility.h>
18 #include <proto/exec.h>
19 #include <proto/utility.h>
20 #include <proto/alib.h>
21 #include <proto/dos.h>
23 #include <dos/dosextens.h>
24 #include <dos/dosasl.h>
25 #include <dos/exall.h>
26 #include <dos/filesystem.h>
27 #include <aros/libcall.h>
28 #include <aros/symbolsets.h>
30 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
31 #include "ram_handler_gcc.h"
36 #include "HashTable.h"
38 static void deventry();
40 #include LC_LIBDEFS_FILE
42 #define NRF_NOT_REPLIED NRF_MAGIC
49 LONG type
; /* ST_LINKDIR */
50 STRPTR name
; /* Link's name */
51 struct cnode
*self
; /* Pointer to top of structure */
52 struct hnode
*link
; /* NULL */
53 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
54 ULONG protect
; /* 0 */
55 STRPTR comment
; /* NULL */
56 struct vnode
*volume
; /* Pointer to volume */
57 struct DosList
*doslist
; /* Pointer to doslist entry */
64 LONG type
; /* ST_USERDIR */
65 STRPTR name
; /* Directory name */
66 struct vnode
*self
; /* Points to top of structure */
67 struct hnode
*link
; /* This one is linked to me */
68 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
69 ULONG protect
; /* 0 */
70 STRPTR comment
; /* NULL */
71 struct MinList receivers
;
72 struct DateStamp date
;
73 struct MinList list
; /* Contents of directory */
74 ULONG volcount
; /* number of handles on this volume */
75 struct DosList
*doslist
; /* Pointer to doslist entry */
82 LONG type
; /* ST_USERDIR */
83 STRPTR name
; /* Directory name */
84 struct vnode
*volume
; /* Volume's root directory */
85 struct hnode
*link
; /* This one is linked to me */
86 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
87 ULONG protect
; /* protection bits */
88 STRPTR comment
; /* Some comment */
89 struct MinList receivers
;
90 struct DateStamp date
;
91 struct MinList list
; /* Contents of directory */
98 LONG type
; /* ST_FILE */
99 STRPTR name
; /* Filename */
100 struct vnode
*volume
; /* Volume's root directory */
101 struct hnode
*link
; /* This one is linked to me */
102 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
103 ULONG protect
; /* protection bits */
104 STRPTR comment
; /* Some file comment */
105 struct MinList receivers
;
106 struct DateStamp date
;
108 LONG size
; /* Filesize */
109 UBYTE
*blocks
[16]; /* Upto 0x1000 bytes */
110 UBYTE
**iblocks
[4]; /* Upto 0x41000 bytes */
111 UBYTE
***i2block
; /* Upto 0x1041000 bytes */
112 UBYTE
****i3block
; /* Upto 0x101041000 bytes */
119 LONG type
; /* ST_SOFTLINK */
120 STRPTR name
; /* Link's name */
121 struct vnode
*volume
; /* Volume's root directory */
122 struct hnode
*link
; /* This one is hardlinked to me */
123 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
124 ULONG protect
; /* protection bits */
125 STRPTR comment
; /* Some file comment */
126 char *contents
; /* Contents of soft link */
133 LONG type
; /* ST_LINKDIR */
134 STRPTR name
; /* Link's name */
135 struct vnode
*volume
; /* Volume's root directory */
136 struct hnode
*link
; /* This one is hardlinked to me */
137 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
138 ULONG protect
; /* protection bits */
139 STRPTR comment
; /* Some file comment */
140 struct hnode
*orig
; /* original object */
143 /*****************************************************************************/
145 #define FILEFLAGS_Changed 1
147 static STRPTR
getName(struct rambase
*rambase
, struct dnode
*dn
);
158 void Notify_notifyTasks(struct rambase
*rambase
,
159 struct MinList
*notifications
);
161 BOOL
Notify_initialize(struct rambase
*rambase
);
162 void Notify_fileChange(struct rambase
*rambase
, NType type
,
164 void Notify_directoryChange(struct rambase
*rambase
, NType type
,
168 BOOL
Notify_addNotification(struct rambase
*rambase
, struct dnode
*dn
,
169 struct NotifyRequest
*nr
);
170 void Notify_removeNotification(struct rambase
*rambase
,
171 struct NotifyRequest
*nr
);
173 /****************************************************************************/
176 #define BLOCKSIZE 256
177 #define PBLOCKSIZE (256*sizeof(UBYTE *))
185 /* Use This from now on */
189 #define DOSBase rambase->dosbase
191 static int OpenDev(LIBBASETYPEPTR rambase
, struct IOFileSys
*iofs
);
193 static int GM_UNIQUENAME(Init
)(LIBBASETYPEPTR rambase
)
195 /* This function is single-threaded by exec by calling Forbid. */
197 struct MsgPort
*port
;
199 struct SignalSemaphore
*semaphore
;
202 rambase
->dosbase
= (struct DosLibrary
*)OpenLibrary(DOSNAME
, 39);
204 if (rambase
->dosbase
!= NULL
)
206 rambase
->utilitybase
= (struct UtilityBase
*)OpenLibrary(UTILITYNAME
, 39);
208 if (rambase
->utilitybase
!= NULL
)
210 port
= (struct MsgPort
*)AllocMem(sizeof(struct MsgPort
),
211 MEMF_PUBLIC
| MEMF_CLEAR
);
214 rambase
->port
= port
;
215 NewList(&port
->mp_MsgList
);
216 port
->mp_Node
.ln_Type
= NT_MSGPORT
;
217 port
->mp_SigBit
= SIGB_SINGLE
;
219 task
= (struct Task
*)AllocMem(sizeof(struct Task
),
220 MEMF_PUBLIC
| MEMF_CLEAR
);
224 port
->mp_SigTask
= task
;
225 port
->mp_Flags
= PA_IGNORE
;
226 NewList(&task
->tc_MemEntry
);
227 task
->tc_Node
.ln_Type
= NT_TASK
;
228 task
->tc_Node
.ln_Name
= "ram.handler task";
230 stack
= AllocMem(AROS_STACKSIZE
, MEMF_PUBLIC
);
234 struct TagItem tasktags
[] =
236 {TASKTAG_ARG1
, (IPTR
)rambase
},
240 task
->tc_SPLower
= stack
;
241 task
->tc_SPUpper
= (BYTE
*)stack
+ AROS_STACKSIZE
;
242 #if AROS_STACK_GROWS_DOWNWARDS
243 task
->tc_SPReg
= (BYTE
*)task
->tc_SPUpper
- SP_OFFSET
;
245 task
->tc_SPReg
= (BYTE
*)task
->tc_SPLower
+ SP_OFFSET
;
248 semaphore
= (struct SignalSemaphore
*)AllocMem(sizeof(struct SignalSemaphore
),
249 MEMF_PUBLIC
| MEMF_CLEAR
);
251 if (semaphore
!= NULL
)
253 rambase
->sigsem
= semaphore
;
254 InitSemaphore(semaphore
);
256 if (rambase
->seglist
==NULL
) /* Are we a ROM module? */
258 struct DeviceNode
*dn
;
259 /* Install RAM: handler into device list
261 * KLUDGE: ram.handler should create only one device node, depending on
262 * the startup packet it gets. The mountlists for RAM: should be into dos.library bootstrap
266 if((dn
= AllocMem(sizeof (struct DeviceNode
) + 4 + 3 + 2, MEMF_CLEAR
|MEMF_PUBLIC
)))
268 struct IOFileSys dummyiofs
;
270 if (OpenDev(rambase
, &dummyiofs
))
272 BSTR s
= MKBADDR(((IPTR
)dn
+ sizeof(struct DeviceNode
) + 3) & ~3);
274 rambase
->device
.dd_Library
.lib_OpenCnt
++;
276 AROS_BSTR_putchar(s
, 0, 'R');
277 AROS_BSTR_putchar(s
, 1, 'A');
278 AROS_BSTR_putchar(s
, 2, 'M');
279 AROS_BSTR_setstrlen(s
, 3);
281 dn
->dn_Type
= DLT_DEVICE
;
282 dn
->dn_Ext
.dn_AROS
.dn_Unit
= dummyiofs
.IOFS
.io_Unit
;
283 dn
->dn_Ext
.dn_AROS
.dn_Device
= dummyiofs
.IOFS
.io_Device
;
284 dn
->dn_Handler
= NULL
;
285 dn
->dn_Startup
= NULL
;
287 dn
->dn_Ext
.dn_AROS
.dn_DevName
= AROS_BSTR_ADDR(dn
->dn_Name
);
289 if (AddDosEntry((struct DosList
*)dn
))
290 if (NewAddTask(task
, deventry
, NULL
, tasktags
) != NULL
)
294 FreeMem(dn
, sizeof (struct DeviceNode
));
298 if (NewAddTask(task
, deventry
, NULL
, tasktags
) != NULL
)
301 FreeMem(semaphore
, sizeof(struct SignalSemaphore
));
304 FreeMem(stack
, AROS_STACKSIZE
);
307 FreeMem(task
, sizeof(struct Task
));
310 FreeMem(port
, sizeof(struct MsgPort
));
313 CloseLibrary((struct Library
*)rambase
->utilitybase
);
316 CloseLibrary((struct Library
*)rambase
->dosbase
);
325 #define UtilityBase rambase->utilitybase
328 /***************************************************************************/
330 void nullDelete(struct rambase
*rambase
, void *key
, struct List
*list
)
332 // struct Receiver *rr;
333 // struct Node *tempNode;
335 // ForeachNodeSafe(list, rr, tempNode)
337 // Remove(&rr->node);
343 /* The list is part of the HashNode so we shouldn't free that */
347 ULONG
stringHash(struct rambase
*rambase
, const void *key
)
349 STRPTR str
= (STRPTR
)key
;
354 val
*= ToLower(*str
++);
362 my_strcasecmp(struct rambase
*rambase
, const void *s1
, const void *s2
)
364 return strcasecmp(s1
, s2
);
367 /****************************************************************************/
370 STRPTR
Strdup(struct rambase
*rambase
, CONST_STRPTR string
)
372 CONST_STRPTR s2
= string
;
378 s3
= (STRPTR
)AllocVec(s2
- string
, MEMF_ANY
);
382 CopyMem(string
, s3
, s2
- string
);
389 void Strfree(struct rambase
*rambase
, STRPTR string
)
395 static int GM_UNIQUENAME(Open
)
397 LIBBASETYPEPTR rambase
,
398 struct IOFileSys
*iofs
,
403 /* Mark Message as recently used. */
404 iofs
->IOFS
.io_Message
.mn_Node
.ln_Type
= NT_REPLYMSG
;
406 return OpenDev(rambase
, iofs
);
410 static int OpenDev(LIBBASETYPEPTR rambase
, struct IOFileSys
*iofs
)
412 struct filehandle
*fhv
, *fhc
;
417 iofs
->IOFS
.io_Error
= ERROR_NO_FREE_STORE
;
419 fhv
= (struct filehandle
*)AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
423 fhc
= (struct filehandle
*)AllocMem(sizeof(struct filehandle
),
428 vol
= (struct vnode
*)AllocMem(sizeof(struct vnode
), MEMF_CLEAR
);
432 dev
= (struct cnode
*)AllocMem(sizeof(struct cnode
),
437 vol
->name
= Strdup(rambase
, "Ram Disk");
439 if (vol
->name
!= NULL
)
441 dlv
= MakeDosEntry("Ram Disk", DLT_VOLUME
);
445 vol
->type
= ST_USERDIR
;
449 NewList((struct List
*)&vol
->list
);
450 NewList((struct List
*)&vol
->receivers
);
451 fhv
->node
= (struct dnode
*)vol
;
452 dlv
->dol_Ext
.dol_AROS
.dol_Unit
= (struct Unit
*)fhv
;
453 dlv
->dol_Ext
.dol_AROS
.dol_Device
= &rambase
->device
;
454 dev
->type
= ST_LINKDIR
;
457 fhc
->node
= (struct dnode
*)dev
;
458 iofs
->IOFS
.io_Unit
= (struct Unit
*)fhc
;
459 iofs
->IOFS
.io_Device
= &rambase
->device
;
462 iofs
->IOFS
.io_Error
= 0;
464 rambase
->notifications
=
465 HashTable_new(rambase
, 100, stringHash
,
466 my_strcasecmp
, nullDelete
);
471 Strfree(rambase
, vol
->name
);
474 FreeMem(dev
, sizeof(struct cnode
));
477 FreeMem(vol
, sizeof(struct vnode
));
480 FreeMem(fhc
, sizeof(struct filehandle
));
483 FreeMem(fhv
, sizeof(struct filehandle
));
486 iofs
->IOFS
.io_Error
= IOERR_OPENFAIL
;
491 static int GM_UNIQUENAME(Expunge
)(LIBBASETYPEPTR rambase
)
494 This function is single-threaded by exec by calling Forbid.
495 Never break the Forbid() or strange things might happen.
498 /* Kill device task and free all resources */
499 RemTask(rambase
->port
->mp_SigTask
);
500 FreeMem(rambase
->sigsem
, sizeof(struct SignalSemaphore
));
501 FreeMem(((struct Task
*)rambase
->port
->mp_SigTask
)->tc_SPLower
,
503 FreeMem(rambase
->port
->mp_SigTask
, sizeof(struct Task
));
504 FreeMem(rambase
->port
, sizeof(struct MsgPort
));
505 CloseLibrary((struct Library
*)rambase
->utilitybase
);
506 CloseLibrary((struct Library
*)rambase
->dosbase
);
512 AROS_LH1(void, beginio
,
513 AROS_LHA(struct IOFileSys
*, iofs
, A1
),
514 struct rambase
*, rambase
, 5, Ram
)
518 /* WaitIO will look into this */
519 iofs
->IOFS
.io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
521 /* Nothing is done quick */
522 iofs
->IOFS
.io_Flags
&= ~IOF_QUICK
;
524 /* So let the device task do it */
525 PutMsg(rambase
->port
, &iofs
->IOFS
.io_Message
);
531 AROS_LH1(LONG
, abortio
,
532 AROS_LHA(struct IOFileSys
*, iofs
, A1
),
533 struct rambase
*, rambase
, 6, Ram
)
541 static LONG
getblock(struct rambase
*rambase
, struct fnode
*file
, LONG block
,
542 int mode
, UBYTE
**result
)
549 p
= &file
->blocks
[block
];
553 else if (block
< 0x410)
556 p
= (UBYTE
**)&file
->iblocks
[block
/0x100];
560 else if(block
< 0x10410)
563 p
= (UBYTE
**)&file
->i2block
;
569 p
= (UBYTE
**)&file
->i3block
;
585 while (i
-- && p
!= NULL
)
587 a
= (block
>> i
*8) & 0xff;
590 if (!(block
& ((1 << i
*8) - 1)))
596 FreeMem(p
, PBLOCKSIZE
);
605 FreeMem(p
, BLOCKSIZE
);
613 while (i
-- && p
!= NULL
)
615 p
= ((UBYTE
***)p
)[(block
>> i
*8) & 0xff];
618 *result
= (UBYTE
*)p
;
626 *p
= AllocMem(PBLOCKSIZE
, MEMF_CLEAR
);
630 return ERROR_NO_FREE_STORE
;
634 p
= (UBYTE
**)*p
+ ((block
>> i
*8) & 0xff);
639 *p
= AllocMem(BLOCKSIZE
, MEMF_CLEAR
);
643 return ERROR_NO_FREE_STORE
;
649 } /* switch (mode) */
655 static void zerofill(UBYTE
*address
, ULONG size
)
664 static void shrinkfile(struct rambase
*rambase
, struct fnode
*file
, LONG size
)
669 blocks
= (size
+ BLOCKSIZE
- 1)/BLOCKSIZE
;
670 block
= (file
->size
+ BLOCKSIZE
- 1)/BLOCKSIZE
;
672 for(;block
-- > blocks
;)
674 (void)getblock(rambase
, file
, block
, -1, &p
);
679 (void)getblock(rambase
, file
, size
, 0, &p
);
683 zerofill(p
+ (size
& 0xff), -size
& 0xff);
691 static void delete(struct rambase
*rambase
, struct fnode
*file
)
693 struct hnode
*link
, *new, *more
;
696 Strfree(rambase
, file
->name
);
697 Strfree(rambase
, file
->comment
);
698 Remove((struct Node
*)file
);
700 if (file
->type
== ST_LINKDIR
)
702 /* It is a link. Remove it from the chain. */
704 link
= ((struct hnode
*)file
)->orig
;
705 ((struct hnode
*)file
)->orig
= NULL
;
706 file
->type
= link
->type
;
708 while((struct fnode
*)link
->link
!= file
)
713 link
->link
= file
->link
;
715 else if (file
->link
!= NULL
)
717 /* If there is a hard link to the object make the link the original */
720 link
->type
= file
->type
;
732 while((node
= RemHead((struct List
*)&((struct dnode
*)file
)->list
)) != NULL
)
733 AddTail((struct List
*)&((struct dnode
*)file
)->list
, node
);
737 CopyMemQuick(&file
->size
, &((struct fnode
*)new)->size
,
738 sizeof(struct fnode
) - offsetof(struct fnode
, size
));
739 zerofill((UBYTE
*)&file
->size
,
740 sizeof(struct fnode
) - offsetof(struct fnode
, size
));
744 ((struct snode
*)new)->contents
= ((struct snode
*)file
)->contents
;
745 ((struct snode
*)file
)->contents
= NULL
;
748 } /* else if (file->link != NULL) */
753 Notify_directoryChange(rambase
, NOTIFY_Delete
, (struct dnode
*)file
);
755 FreeMem(file
, sizeof(struct dnode
));
760 Notify_fileChange(rambase
, NOTIFY_Delete
, file
);
762 shrinkfile(rambase
, file
, 0);
763 FreeMem(file
, sizeof(struct fnode
));
768 Strfree(rambase
, ((struct snode
*)file
)->contents
);
769 FreeMem(file
, sizeof(struct snode
));
776 static int fstrcmp(struct rambase
*rambase
, CONST_STRPTR s1
, CONST_STRPTR s2
)
780 if (ToLower(*s1
) != ToLower(*s2
))
782 return *s1
|| *s2
!= '/';
796 /* Find a node for a given name */
797 static LONG
findname(struct rambase
*rambase
, CONST_STRPTR
*name
,
798 struct dnode
**dnode
)
800 struct dnode
*cur
= *dnode
;
801 CONST_STRPTR rest
= *name
;
805 if (cur
->type
== ST_LINKDIR
)
807 cur
= (struct dnode
*)((struct hnode
*)cur
)->orig
;
817 if ((struct dnode
*)cur
->volume
== cur
)
819 return ERROR_OBJECT_NOT_FOUND
;
822 while (cur
->node
.mln_Pred
!= NULL
)
824 cur
= (struct dnode
*)cur
->node
.mln_Pred
;
827 cur
= (struct dnode
*)((BYTE
*)cur
- offsetof(struct dnode
, list
));
831 if (cur
->type
== ST_SOFTLINK
)
836 return ERROR_IS_SOFT_LINK
;
839 if (cur
->type
!= ST_USERDIR
)
841 return ERROR_DIR_NOT_FOUND
;
845 cur
= (struct dnode
*)cur
->list
.mlh_Head
;
849 if (cur
->node
.mln_Succ
== NULL
)
853 return ERROR_OBJECT_NOT_FOUND
;
856 if (!fstrcmp(rambase
, cur
->name
, rest
))
861 cur
= (struct dnode
*)cur
->node
.mln_Succ
;
880 static LONG
set_file_size(struct rambase
*rambase
, struct filehandle
*handle
,
881 QUAD
*offp
, LONG mode
)
883 struct fnode
*file
= (struct fnode
*)handle
->node
;
886 if (file
->type
!= ST_FILE
)
888 return ERROR_OBJECT_WRONG_TYPE
;
893 case OFFSET_BEGINNING
:
897 size
+= handle
->position
;
905 return ERROR_NOT_IMPLEMENTED
;
910 return ERROR_SEEK_ERROR
;
913 if (size
< file
->size
)
915 shrinkfile(rambase
, file
, size
);
918 file
->size
= *offp
= size
;
924 static LONG
read(struct rambase
*rambase
, struct filehandle
*handle
,
925 APTR buffer
, LONG
*numbytes
)
927 struct fnode
*file
= (struct fnode
*)handle
->node
;
928 ULONG num
= *numbytes
;
929 ULONG size
= file
->size
;
931 UBYTE
*buf
= buffer
, *p
;
933 if (handle
->position
>= size
)
937 else if (handle
->position
+ num
> size
)
939 num
= size
- handle
->position
;
942 block
= handle
->position
/BLOCKSIZE
;
943 offset
= handle
->position
& (BLOCKSIZE
- 1);
944 size
= BLOCKSIZE
- offset
;
953 (void)getblock(rambase
, file
, block
, 0, &p
);
957 CopyMem(p
+ offset
, buffer
, size
);
961 zerofill(buffer
, size
);
971 *numbytes
= (UBYTE
*)buffer
- buf
;
972 handle
->position
+= *numbytes
;
978 static LONG
write(struct rambase
*rambase
, struct filehandle
*handle
,
979 UBYTE
*buffer
, LONG
*numbytes
)
981 struct fnode
*file
= (struct fnode
*)handle
->node
;
982 ULONG num
= *numbytes
;
983 ULONG size
= file
->size
;
985 UBYTE
*buf
= buffer
, *p
;
988 if ((LONG
)(handle
->position
+ num
) < 0)
990 return ERROR_OBJECT_TOO_LARGE
;
993 Notify_fileChange(rambase
, NOTIFY_Write
, file
);
995 block
= handle
->position
/BLOCKSIZE
;
996 offset
= handle
->position
& (BLOCKSIZE
- 1);
997 size
= BLOCKSIZE
- offset
;
1006 error
= getblock(rambase
, file
, block
, 1, &p
);
1013 CopyMem(buffer
, p
+ offset
, size
);
1021 *numbytes
= (UBYTE
*)buffer
- buf
;
1022 handle
->position
+= *numbytes
;
1023 DateStamp(&file
->date
);
1025 if (handle
->position
> file
->size
)
1027 file
->size
= handle
->position
;
1034 static LONG
lock(struct dnode
*dir
, ULONG mode
)
1036 if ((mode
& FMF_EXECUTE
) && (dir
->protect
& FMF_EXECUTE
))
1038 return ERROR_NOT_EXECUTABLE
;
1041 if ((mode
& FMF_WRITE
) && (dir
->protect
& FMF_WRITE
))
1043 return ERROR_WRITE_PROTECTED
;
1046 if ((mode
& FMF_READ
) && (dir
->protect
& FMF_READ
))
1048 return ERROR_READ_PROTECTED
;
1051 if (mode
& FMF_LOCK
)
1055 return ERROR_OBJECT_IN_USE
;
1058 dir
->usecount
= ((ULONG
)~0)/2 + 1;
1062 if (dir
->usecount
< 0)
1064 return ERROR_OBJECT_IN_USE
;
1069 dir
->volume
->volcount
++;
1075 static LONG
open_(struct rambase
*rambase
, struct filehandle
**handle
,
1076 CONST_STRPTR name
, ULONG mode
)
1078 struct dnode
*dir
= (*handle
)->node
;
1079 struct filehandle
*fh
;
1082 fh
= (struct filehandle
*)AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
1086 error
= findname(rambase
, &name
, &dir
);
1090 error
= lock(dir
, mode
);
1097 if (dir
->type
== ST_FILE
)
1099 Notify_fileChange(rambase
, NOTIFY_Open
,
1100 (struct fnode
*)dir
);
1102 else if (dir
->type
== ST_USERDIR
)
1104 D(kprintf("Notifying OPEN at dir %s\n", dir
->name
));
1105 Notify_directoryChange(rambase
, NOTIFY_Open
, dir
);
1112 FreeMem(fh
, sizeof(struct filehandle
));
1116 error
= ERROR_NO_FREE_STORE
;
1123 static LONG
open_file(struct rambase
*rambase
, struct filehandle
**handle
,
1124 CONST_STRPTR name
, ULONG mode
, ULONG protect
)
1126 struct dnode
*dir
= (*handle
)->node
;
1127 struct filehandle
*fh
;
1130 fh
= AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
1134 error
= findname(rambase
, &name
, &dir
);
1136 if ((mode
& FMF_CREATE
) && error
== ERROR_OBJECT_NOT_FOUND
)
1138 CONST_STRPTR s
= name
;
1149 file
= (struct fnode
*)AllocMem(sizeof(struct fnode
), MEMF_CLEAR
);
1150 DateStamp(&file
->date
);
1154 file
->name
= Strdup(rambase
, name
);
1156 if (file
->name
!= NULL
)
1158 file
->type
= ST_FILE
;
1159 file
->protect
= protect
;
1160 file
->volume
= dir
->volume
;
1161 NewList((struct List
*)&file
->receivers
);
1162 AddTail((struct List
*)&dir
->list
, (struct Node
*)file
);
1163 error
= lock((struct dnode
*)file
, mode
);
1167 fh
->node
= (struct dnode
*)file
;
1170 Notify_fileChange(rambase
, NOTIFY_Add
, file
);
1175 Strfree(rambase
, file
->name
);
1178 FreeMem(file
,sizeof(struct fnode
));
1181 error
= ERROR_NO_FREE_STORE
;
1185 if (dir
->type
!= ST_FILE
)
1187 error
= ERROR_OBJECT_WRONG_TYPE
;
1191 error
= lock(dir
, mode
);
1196 if (mode
& FMF_CLEAR
)
1198 shrinkfile(rambase
, (struct fnode
*)dir
, 0);
1199 dir
->protect
= protect
;
1209 } /* else if (!error) */
1211 FreeMem(fh
, sizeof(struct filehandle
));
1218 static LONG
create_dir(struct rambase
*rambase
, struct filehandle
**handle
,
1219 CONST_STRPTR name
, ULONG protect
)
1221 struct dnode
*dir
= (*handle
)->node
, *new;
1222 struct filehandle
*fh
;
1225 if (dir
->protect
& FIBF_WRITE
)
1227 return ERROR_WRITE_PROTECTED
;
1230 error
= findname(rambase
, &name
, &dir
);
1234 return ERROR_OBJECT_EXISTS
;
1237 if (error
!= ERROR_OBJECT_NOT_FOUND
)
1242 if (strchr(name
, '/') != NULL
)
1247 fh
= AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
1251 new = (struct dnode
*)AllocMem(sizeof(struct dnode
), MEMF_CLEAR
);
1255 new->name
= Strdup(rambase
, name
);
1257 if (new->name
!= NULL
)
1259 new->type
= ST_USERDIR
;
1260 new->protect
= protect
;
1261 new->volume
= dir
->volume
;
1262 new->volume
->volcount
++;
1263 new->usecount
= ((ULONG
)~0)/2 + 2;
1264 NewList((struct List
*)&new->list
);
1265 NewList((struct List
*)&new->receivers
);
1266 AddTail((struct List
*)&dir
->list
, (struct Node
*)new);
1269 DateStamp(&new->date
);
1271 D(bug("New (%p): Name = %s\n", new, new->name
));
1272 Notify_directoryChange(rambase
, NOTIFY_Add
, new);
1277 FreeMem(new, sizeof(struct dnode
));
1280 FreeMem(fh
, sizeof(struct filehandle
));
1283 return ERROR_NO_FREE_STORE
;
1287 static LONG
free_lock(struct rambase
*rambase
, struct filehandle
*filehandle
)
1289 struct dnode
*dnode
= filehandle
->node
;
1291 dnode
->usecount
= (dnode
->usecount
- 1) & ((ULONG
)~0)/2;
1292 FreeMem(filehandle
, sizeof(struct filehandle
));
1293 dnode
->volume
->volcount
--;
1299 static LONG
seek(struct rambase
*rambase
, struct filehandle
*filehandle
,
1300 QUAD
*posp
, LONG mode
)
1302 struct fnode
*file
= (struct fnode
*)filehandle
->node
;
1305 if (file
->type
!= ST_FILE
)
1307 return ERROR_OBJECT_WRONG_TYPE
;
1312 case OFFSET_BEGINNING
:
1315 case OFFSET_CURRENT
:
1316 pos
+= filehandle
->position
;
1324 return ERROR_NOT_IMPLEMENTED
;
1329 return ERROR_SEEK_ERROR
;
1332 *posp
= filehandle
->position
;
1333 filehandle
->position
= pos
;
1339 static const ULONG sizes
[]=
1342 offsetof(struct ExAllData
,ed_Type
),
1343 offsetof(struct ExAllData
,ed_Size
),
1344 offsetof(struct ExAllData
,ed_Prot
),
1345 offsetof(struct ExAllData
,ed_Days
),
1346 offsetof(struct ExAllData
,ed_Comment
),
1347 offsetof(struct ExAllData
,ed_OwnerUID
),
1348 sizeof(struct ExAllData
)
1352 static LONG
examine(struct fnode
*file
,
1353 struct ExAllData
*ead
,
1358 STRPTR next
, end
, name
;
1360 if (type
> ED_OWNER
)
1362 return ERROR_BAD_NUMBER
;
1365 next
= (STRPTR
)ead
+ sizes
[type
];
1366 end
= (STRPTR
)ead
+ size
;
1368 if(next
>end
) /* > is correct. Not >= */
1369 return ERROR_BUFFER_OVERFLOW
;
1371 /* Use *dirpos to store information for ExNext()
1372 * *dirpos is copied to fib->fib_DiskKey in Examine()
1374 if (file
->type
== ST_USERDIR
)
1376 *dirpos
= (LONG
)(((struct dnode
*)file
)->list
.mlh_Head
);
1380 /* ExNext() should not be called in this case anyway */
1381 *dirpos
= (LONG
)file
;
1387 ead
->ed_OwnerUID
= 0;
1388 ead
->ed_OwnerGID
= 0;
1392 if (file
->comment
!= NULL
)
1394 ead
->ed_Comment
= next
;
1395 name
= file
->comment
;
1401 return ERROR_BUFFER_OVERFLOW
;
1404 if (!(*next
++ = *name
++))
1412 ead
->ed_Comment
= NULL
;
1417 ead
->ed_Days
= file
->date
.ds_Days
;
1418 ead
->ed_Mins
= file
->date
.ds_Minute
;
1419 ead
->ed_Ticks
= file
->date
.ds_Tick
;
1423 ead
->ed_Prot
= file
->protect
;
1427 ead
->ed_Size
= file
->size
;
1431 ead
->ed_Type
= file
->type
;
1433 if (((struct vnode
*)file
)->self
== (struct vnode
*)file
)
1435 ead
->ed_Type
=ST_ROOT
;
1440 ead
->ed_Name
= next
;
1447 return ERROR_BUFFER_OVERFLOW
;
1450 if (!(*next
++ = *name
++))
1458 ead
->ed_Next
= (struct ExAllData
*)(((IPTR
)next
+ AROS_PTRALIGN
- 1) & ~(AROS_PTRALIGN
- 1));
1465 static LONG
examine_next(struct rambase
*rambase
,
1466 struct filehandle
*dir
,
1467 struct FileInfoBlock
*FIB
)
1469 struct fnode
*file
= (struct fnode
*)FIB
->fib_DiskKey
;
1471 ASSERT_VALID_PTR_OR_NULL(file
);
1473 if (file
->node
.mln_Succ
== NULL
)
1475 return ERROR_NO_MORE_ENTRIES
;
1478 FIB
->fib_OwnerUID
= 0;
1479 FIB
->fib_OwnerGID
= 0;
1481 FIB
->fib_Date
.ds_Days
= file
->date
.ds_Days
;
1482 FIB
->fib_Date
.ds_Minute
= file
->date
.ds_Minute
;
1483 FIB
->fib_Date
.ds_Tick
= file
->date
.ds_Tick
;
1484 FIB
->fib_Protection
= file
->protect
;
1485 FIB
->fib_Size
= file
->size
;
1486 FIB
->fib_DirEntryType
= file
->type
;
1488 strncpy(FIB
->fib_FileName
, file
->name
, MAXFILENAMELENGTH
- 1);
1489 strncpy(FIB
->fib_Comment
, file
->comment
!= NULL
? file
->comment
: "",
1490 MAXCOMMENTLENGTH
- 1);
1492 FIB
->fib_DiskKey
= (LONG
)file
->node
.mln_Succ
;
1498 static LONG
examine_all(struct filehandle
*dir
,
1499 struct ExAllData
*ead
,
1500 struct ExAllControl
*eac
,
1505 struct ExAllData
*last
=NULL
;
1508 LONG dummy
; /* not anything is done with this value but passed to examine */
1509 end
= (STRPTR
)ead
+ size
;
1511 eac
->eac_Entries
= 0;
1512 if (dir
->node
->type
!= ST_USERDIR
)
1514 return ERROR_OBJECT_WRONG_TYPE
;
1517 ent
= (struct fnode
*)eac
->eac_LastKey
;
1521 ent
= (struct fnode
*)dir
->node
->list
.mlh_Head
;
1522 if (ent
->node
.mln_Succ
) ent
->usecount
++;
1525 if (ent
->node
.mln_Succ
== NULL
)
1527 return ERROR_NO_MORE_ENTRIES
;
1534 error
= examine(ent
, ead
, end
- (STRPTR
)ead
, type
, &dummy
);
1536 if (error
== ERROR_BUFFER_OVERFLOW
)
1544 last
->ed_Next
= NULL
;
1545 eac
->eac_LastKey
= (IPTR
)ent
;
1552 ent
= (struct fnode
*)ent
->node
.mln_Succ
;
1554 } while (ent
->node
.mln_Succ
!= NULL
);
1556 last
->ed_Next
= NULL
;
1557 eac
->eac_LastKey
= (IPTR
)ent
;
1559 return ERROR_NO_MORE_ENTRIES
;
1563 static LONG
rename_object(struct rambase
*rambase
,
1564 struct filehandle
*filehandle
,
1565 CONST_STRPTR namea
, CONST_STRPTR nameb
)
1567 struct dnode
*file
= filehandle
->node
;
1570 struct dnode
*nodea
= filehandle
->node
, *nodeb
;
1571 STRPTR dira
, dirb
, pos
= nameb
;
1573 error
= findname(rambase
, &pos
, &nodea
);
1575 return ERROR_OBJECT_EXISTS
;
1577 error
= findname(rambase
, &namea
, &file
);
1581 if ((struct dnode
*)file
->volume
== file
)
1582 return ERROR_OBJECT_WRONG_TYPE
;
1584 if (file
->usecount
!= 0)
1585 return ERROR_OBJECT_IN_USE
;
1587 dira
= Strdup(rambase
, namea
);
1588 dirb
= Strdup(rambase
, nameb
);
1590 pos
= strrchr(dira
, '/');
1599 pos
= strrchr(dirb
, '/');
1608 D(bug("[Ram] rename (%s,%s)=>(%s,%s)\n", dira
, namea
, dirb
, nameb
));
1610 if (*dira
== '\0' && *dirb
== '\0')
1612 Strfree(rambase
, file
->name
);
1613 file
->name
= Strdup(rambase
, nameb
);
1617 nodea
= filehandle
->node
;
1618 error
= findname(rambase
, &dira
, &nodea
);
1622 nodeb
= filehandle
->node
;
1623 error
= findname(rambase
, &dirb
, &nodeb
);
1629 Remove((struct Node
*)file
);
1630 AddTail((struct List
*)&nodeb
->list
, (struct Node
*)file
);
1633 Strfree(rambase
, file
->name
);
1634 file
->name
= Strdup(rambase
, nameb
);
1637 DateStamp(&file
->date
);
1642 Notify_fileChange(rambase
, NOTIFY_Delete
, (struct fnode
*)file
);
1643 Notify_fileChange(rambase
, NOTIFY_Add
, (struct fnode
*)file
);
1647 Notify_directoryChange(rambase
, NOTIFY_Delete
, file
);
1648 Notify_directoryChange(rambase
, NOTIFY_Add
, file
);
1653 Strfree(rambase
, dirb
);
1654 Strfree(rambase
, dira
);
1659 static LONG
delete_object(struct rambase
*rambase
,
1660 struct filehandle
*filehandle
, CONST_STRPTR name
)
1662 struct dnode
*file
= filehandle
->node
;
1665 error
= findname(rambase
, &name
, &file
);
1672 if ((struct dnode
*)file
->volume
== file
)
1674 return ERROR_OBJECT_WRONG_TYPE
;
1677 if (file
->usecount
!= 0)
1679 return ERROR_OBJECT_IN_USE
;
1682 if (file
->protect
& FIBF_DELETE
)
1684 return ERROR_DELETE_PROTECTED
;
1687 if (file
->type
== ST_USERDIR
&& file
->list
.mlh_Head
->mln_Succ
!= NULL
)
1689 return ERROR_DIRECTORY_NOT_EMPTY
;
1692 delete(rambase
, (struct fnode
*)file
);
1698 static int GM_UNIQUENAME(Close
)
1700 LIBBASETYPEPTR rambase
,
1701 struct IOFileSys
*iofs
1709 struct filehandle
*handle
;
1711 handle
= (struct filehandle
*)iofs
->IOFS
.io_Unit
;
1712 dev
= (struct cnode
*)handle
->node
;
1715 if (dev
->type
!= ST_LINKDIR
|| dev
->self
!= dev
)
1717 iofs
->io_DosError
= ERROR_OBJECT_WRONG_TYPE
;
1724 iofs
->io_DosError
= ERROR_OBJECT_IN_USE
;
1729 free_lock(rambase
, handle
);
1730 RemDosEntry(vol
->doslist
);
1731 FreeDosEntry(vol
->doslist
);
1733 while (vol
->list
.mlh_Head
->mln_Succ
!= NULL
)
1735 dir
= (struct dnode
*)vol
->list
.mlh_Head
;
1737 if (dir
->type
== ST_USERDIR
)
1739 while((file
= (struct fnode
*)RemHead((struct List
*)&dir
->list
)) != NULL
)
1741 AddTail((struct List
*)&vol
->list
, (struct Node
*)dir
);
1745 delete(rambase
, (struct fnode
*)dir
);
1748 Strfree(rambase
, vol
->name
);
1749 FreeMem(vol
, sizeof(struct vnode
));
1751 Strfree(rambase
, dev
->name
);
1752 FreeMem(dev
, sizeof(struct cnode
));
1754 iofs
->io_DosError
= 0;
1760 void processFSM(struct rambase
*rambase
);
1763 static void deventry(struct rambase
*rambase
)
1767 struct Message
*msg
;
1770 Init device port. AllocSignal() cannot fail because this is a
1771 freshly created task with all signal bits still free.
1774 rambase
->port
->mp_SigBit
= AllocSignal(-1);
1775 rambase
->port
->mp_Flags
= PA_SIGNAL
;
1777 /* Check if there are pending messages that we missed */
1778 if ((msg
= GetMsg(rambase
->port
))) PutMsg(rambase
->port
, msg
);
1780 Notify_initialize(rambase
);
1782 notifyMask
= 1 << rambase
->notifyPort
->mp_SigBit
;
1784 fileOpMask
= 1 << rambase
->port
->mp_SigBit
;
1790 flags
= Wait(fileOpMask
| notifyMask
);
1792 if (flags
& notifyMask
)
1794 struct NotifyMessage
*nMessage
;
1796 D(kprintf("Got replied notify message\n"));
1798 while ((nMessage
= (struct NotifyMessage
*)GetMsg(rambase
->notifyPort
)) != NULL
)
1800 nMessage
->nm_NReq
->nr_Flags
&= ~NRF_NOT_REPLIED
;
1805 if (flags
& fileOpMask
)
1807 processFSM(rambase
);
1813 void processFSM(struct rambase
*rambase
)
1815 struct IOFileSys
*iofs
;
1820 /* Get and process the messages. */
1821 while ((iofs
= (struct IOFileSys
*)GetMsg(rambase
->port
)) != NULL
)
1823 D(bug("Ram.handler initialized %u\n", iofs
->IOFS
.io_Command
));
1825 switch (iofs
->IOFS
.io_Command
)
1829 get handle on a file or directory
1830 Unit *current; current directory / new handle on return
1831 STRPTR name; file- or directoryname
1832 LONG mode; open mode
1835 error
= open_(rambase
,
1836 (struct filehandle
**)&iofs
->IOFS
.io_Unit
,
1837 iofs
->io_Union
.io_OPEN
.io_Filename
,
1838 iofs
->io_Union
.io_OPEN
.io_FileMode
);
1843 open a file or create a new one
1844 Unit *current; current directory / new handle on return
1845 STRPTR name; file- or directoryname
1846 LONG mode; open mode
1847 LONG protect; protection flags if a new file is created
1850 error
= open_file(rambase
,
1851 (struct filehandle
**)&iofs
->IOFS
.io_Unit
,
1852 iofs
->io_Union
.io_OPEN_FILE
.io_Filename
,
1853 iofs
->io_Union
.io_OPEN_FILE
.io_FileMode
,
1854 iofs
->io_Union
.io_OPEN_FILE
.io_Protection
);
1859 read a number of bytes from a file
1860 Unit *current; filehandle
1862 LONG numbytes; number of bytes to read /
1863 number of bytes read on return,
1864 0 if there are no more bytes in the file
1866 error
= read(rambase
,
1867 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1868 iofs
->io_Union
.io_READ
.io_Buffer
,
1869 &iofs
->io_Union
.io_READ
.io_Length
);
1874 write a number of bytes to a file
1875 Unit *current; filehandle
1877 LONG numbytes; number of bytes to write /
1878 number of bytes written on return
1880 error
= write(rambase
,
1881 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1882 iofs
->io_Union
.io_WRITE
.io_Buffer
,
1883 &iofs
->io_Union
.io_WRITE
.io_Length
);
1888 set / read position in file
1889 Unit *current; filehandle
1891 LONG posl; relative position /
1892 old position on return
1893 LONG mode; one of OFFSET_BEGINNING, OFFSET_CURRENT,
1896 error
= seek(rambase
,
1897 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1898 &iofs
->io_Union
.io_SEEK
.io_Offset
,
1899 iofs
->io_Union
.io_SEEK
.io_SeekMode
);
1904 /* Get rid of a handle
1905 Unit *current; filehandle */
1907 struct filehandle
*handle
=
1908 (struct filehandle
*)iofs
->IOFS
.io_Unit
;
1910 Notify_fileChange(rambase
, NOTIFY_Close
,
1911 (struct fnode
*)handle
->node
);
1912 error
= free_lock(rambase
, handle
);
1918 Get information about the current object
1919 Unit *current; current object
1920 struct ExAllData *ead; buffer to be filled
1921 ULONG size; size of the buffer
1922 ULONG type; type of information to get
1923 iofs->io_DirPos; leave current position so
1924 ExNext() knows where to find
1927 error
= examine((struct fnode
*)((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
,
1928 iofs
->io_Union
.io_EXAMINE
.io_ead
,
1929 iofs
->io_Union
.io_EXAMINE
.io_Size
,
1930 iofs
->io_Union
.io_EXAMINE
.io_Mode
,
1931 &(iofs
->io_DirPos
));
1934 case FSA_EXAMINE_NEXT
:
1936 Get information about the next object
1937 Unit *current; current object
1938 struct FileInfoBlock *fib;
1940 error
= examine_next(rambase
,
1941 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1942 iofs
->io_Union
.io_EXAMINE_NEXT
.io_fib
);
1945 case FSA_EXAMINE_ALL
:
1947 Read the current directory
1948 Unit *current; current directory
1949 struct ExAllData *ead; buffer to be filled
1950 ULONG size; size of the buffer
1951 ULONG type; type of information to get
1953 error
= examine_all((struct filehandle
*)iofs
->IOFS
.io_Unit
,
1954 iofs
->io_Union
.io_EXAMINE_ALL
.io_ead
,
1955 iofs
->io_Union
.io_EXAMINE_ALL
.io_eac
,
1956 iofs
->io_Union
.io_EXAMINE_ALL
.io_Size
,
1957 iofs
->io_Union
.io_EXAMINE_ALL
.io_Mode
);
1960 case FSA_CREATE_DIR
:
1962 Build lock and open a new directory
1963 Unit *current; current directory
1964 STRPTR name; name of the dir to create
1965 LONG protect; Protection flags for the new dir
1968 // kprintf("Creating directory %s\n",
1969 // iofs->io_Union.io_CREATE_DIR.io_Filename);
1972 error
= create_dir(rambase
,
1973 (struct filehandle
**)&iofs
->IOFS
.io_Unit
,
1974 iofs
->io_Union
.io_CREATE_DIR
.io_Filename
,
1975 iofs
->io_Union
.io_CREATE_DIR
.io_Protection
);
1978 case FSA_DELETE_OBJECT
:
1980 Delete file or directory
1981 Unit *current; current directory
1982 STRPTR name; filename
1984 error
= delete_object(rambase
,
1985 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1986 iofs
->io_Union
.io_DELETE_OBJECT
.io_Filename
);
1989 case FSA_SET_PROTECT
:
1992 Set protection bits for a certain file or directory.
1993 Unit *current; current directory
1994 STRPTR name; filename
1995 ULONG protect; new protection bits
1998 CONST_STRPTR name
= iofs
->io_Union
.io_SET_PROTECT
.io_Filename
;
2000 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
2001 error
= findname(rambase
, &name
, &dir
);
2005 dir
->protect
= iofs
->io_Union
.io_SET_PROTECT
.io_Protection
;
2014 Set owner and group of the file or directory
2015 Unit *current; current directory
2016 STRPTR name; filename
2021 CONST_STRPTR name
= iofs
->io_Union
.io_SET_OWNER
.io_Filename
;
2023 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
2024 error
= findname(rambase
, &name
, &dir
);
2036 Set creation date of the file
2037 Unit *current; current directory
2038 STRPTR name; filename
2041 ULONG ticks; timestamp
2044 CONST_STRPTR name
= iofs
->io_Union
.io_SET_DATE
.io_Filename
;
2046 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
2047 error
= findname(rambase
, &name
, &dir
);
2051 dir
->date
= iofs
->io_Union
.io_SET_DATE
.io_Date
;
2057 case FSA_SET_COMMENT
:
2060 Set a comment for the file or directory;
2061 Unit *current; current directory
2062 STRPTR name; filename
2063 STRPTR comment; NUL terminated C string or NULL.
2066 CONST_STRPTR name
= iofs
->io_Union
.io_SET_COMMENT
.io_Filename
;
2068 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
2069 error
= findname(rambase
, &name
, &dir
);
2073 if (iofs
->io_Union
.io_SET_COMMENT
.io_Comment
)
2075 STRPTR s
= Strdup(rambase
,
2076 iofs
->io_Union
.io_SET_COMMENT
.io_Comment
);
2079 Strfree(rambase
, dir
->comment
);
2084 error
= ERROR_NO_FREE_STORE
;
2089 Strfree(rambase
, dir
->comment
);
2090 dir
->comment
= NULL
;
2097 case FSA_SET_FILE_SIZE
:
2099 Set a new size for the file.
2100 Unit *file; filehandle
2102 LONG offl; offset to current position/
2104 LONG mode; relative to what (see Seek)
2106 error
= set_file_size(rambase
,
2107 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
2108 &iofs
->io_Union
.io_SET_FILE_SIZE
.io_Offset
,
2109 iofs
->io_Union
.io_SET_FILE_SIZE
.io_SeekMode
);
2112 case FSA_IS_FILESYSTEM
:
2113 iofs
->io_Union
.io_IS_FILESYSTEM
.io_IsFilesystem
= TRUE
;
2119 struct InfoData
*id
= iofs
->io_Union
.io_INFO
.io_Info
;
2121 id
->id_NumSoftErrors
= 0;
2122 id
->id_UnitNumber
= 0;
2123 id
->id_DiskState
= ID_VALIDATED
;
2124 id
->id_NumBlocks
= AvailMem(MEMF_TOTAL
| MEMF_PUBLIC
)/BLOCKSIZE
;
2125 id
->id_NumBlocksUsed
= id
->id_NumBlocks
- AvailMem(MEMF_PUBLIC
)/BLOCKSIZE
;
2126 id
->id_BytesPerBlock
= BLOCKSIZE
;
2127 id
->id_DiskType
= ID_DOS_DISK
;
2128 id
->id_VolumeNode
= NULL
; /* What is this? */
2129 id
->id_InUse
= (LONG
)TRUE
;
2137 case FSA_ADD_NOTIFY
:
2140 struct NotifyRequest
*nr
=
2141 iofs
->io_Union
.io_NOTIFY
.io_NotificationRequest
;
2142 struct filehandle
*fh
= (struct filehandle
*)iofs
->IOFS
.io_Unit
;
2144 D(kprintf("Adding notification for entity (nr = %s)\n",
2147 ok
= Notify_addNotification(rambase
, fh
->node
, nr
);
2151 error
= ERROR_NO_FREE_STORE
;
2154 D(kprintf("Notification now added!\n"));
2158 case FSA_REMOVE_NOTIFY
:
2160 struct NotifyRequest
*nr
=
2161 iofs
->io_Union
.io_NOTIFY
.io_NotificationRequest
;
2163 Notify_removeNotification(rambase
, nr
);
2168 error
= rename_object(rambase
,
2169 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
2170 iofs
->io_Union
.io_RENAME
.io_Filename
,
2171 iofs
->io_Union
.io_RENAME
.io_NewName
);
2174 case FSA_IS_INTERACTIVE
:
2175 iofs
->io_Union
.io_IS_INTERACTIVE
.io_IsInteractive
= 0;
2179 error
= ERROR_NOT_IMPLEMENTED
;
2181 D(kprintf("ram_handler, unimplemented FSA: %ld\n", iofs
->IOFS
.io_Command
));
2185 Change or read the mode of a single filehandle
2186 Unit *current; filehandle to change
2187 ULONG newmode; new mode/old mode on return
2188 ULONG mask; bits affected
2191 Change or read the mode of the filesystem
2192 Unit *current; filesystem to change
2193 ULONG newmode; new mode/old mode on return
2194 ULONG mask; bits affected
2195 STRPTR passwd; password for MMF_LOCKED
2198 Create a hard link on a file, directory or soft link
2199 Unit *current; current directory
2200 STRPTR name; softlink name
2201 Unit *target; target handle
2204 Create a soft link to another object
2205 Unit *current; current directory
2206 STRPTR name; softlink name
2207 STRPTR target; target name
2226 iofs
->io_DosError
= error
;
2227 ReplyMsg(&iofs
->IOFS
.io_Message
);
2231 if (rambase
->iofs
!= NULL
)
2233 iofs
= rambase
->iofs
;
2235 if (iofs
->IOFS
.io_Message
.mn_Node
.ln_Type
== NT_MESSAGE
)
2237 abort_notify(rambase
, iofs
);
2238 iofs
->io_DosError
= ERROR_BREAK
;
2239 rambase
->iofs
= NULL
;
2240 ReplyMsg(&iofs
->IOFS
.io_Message
);
2244 rambase
->iofs
= NULL
;
2255 /***************************************************************************
2256 ****************************************************************************/
2258 /** Notification stuff **/
2261 * Immediate notification:
2263 * ACTION_RENAME_OBJECT
2264 * ACTION_RENAME_DISK
2266 * ACTION_DELETE_OBJECT
2270 * Session semantics notification:
2275 * ACTION_SET_FILE_SIZE
2278 * For ram-handler, the only FSA actions currently implemented/affected are
2279 * FSA_WRITE, FSA_CREATE_DIR, FSA_DELETE (and implicitly FSA_OPEN, FSA_CLOSE)
2284 BOOL
Notify_initialize(struct rambase
*rambase
)
2286 rambase
->notifyPort
= CreateMsgPort();
2288 if (rambase
->notifyPort
== NULL
)
2297 void Notify_fileChange(struct rambase
*rambase
, NType type
, struct fnode
*file
)
2305 D(bug("Setting write flag!\n"));
2306 file
->flags
|= FILEFLAGS_Changed
;
2310 /* Only notify in case the file was changed */
2311 if (file
->flags
& FILEFLAGS_Changed
)
2313 D(bug("Notification on close (file was changed).\n"));
2314 file
->flags
&= ~FILEFLAGS_Changed
;
2315 Notify_notifyTasks(rambase
, &file
->receivers
);
2322 struct List
*receivers
;
2324 fullName
= getName(rambase
, (struct dnode
*)file
);
2326 D(kprintf("Found full name: %s\n", fullName
));
2328 receivers
= HashTable_find(rambase
, rambase
->notifications
,
2331 if (receivers
!= NULL
)
2333 D(kprintf("Found notification for created file!\n"));
2335 while (!IsListEmpty(receivers
))
2337 AddHead((struct List
*)&file
->receivers
,
2338 RemHead(receivers
));
2342 HashTable_remove(rambase
, rambase
->notifications
, fullName
);
2344 D(bug("Notifying file receivers!\n"));
2345 Notify_notifyTasks(rambase
, &file
->receivers
);
2352 /* It's the same thing as for directories... */
2353 Notify_directoryChange(rambase
, NOTIFY_Delete
, (struct dnode
*)file
);
2363 void Notify_directoryChange(struct rambase
*rambase
, NType type
,
2372 fullName
= getName(rambase
, dir
);
2374 /* TODO: HashTable_apply(ht, fullName, dir); */
2383 struct List
*receivers
;
2385 fullName
= getName(rambase
, dir
);
2387 D(kprintf("Found full name: %s\n", fullName
));
2389 receivers
= HashTable_find(rambase
, rambase
->notifications
,
2392 if (receivers
!= NULL
)
2394 D(kprintf("Found notification for created directory!\n"));
2396 while (!IsListEmpty(receivers
))
2398 AddHead((struct List
*)&dir
->receivers
,
2399 RemHead(receivers
));
2403 HashTable_remove(rambase
, rambase
->notifications
, fullName
);
2408 D(kprintf("Notifying dir receivers!\n"));
2409 Notify_notifyTasks(rambase
, &dir
->receivers
);
2414 /* As we have deleted a file, we must move the requests for
2415 this file to the hash table */
2416 struct List
*receivers
= (struct List
*)&dir
->receivers
;
2418 Notify_notifyTasks(rambase
, &dir
->receivers
);
2420 /* Move the Notification request to the hash table as we're going
2421 to delete this directory */
2422 while (!IsListEmpty(receivers
))
2424 struct Receiver
*rr
= (struct Receiver
*)RemHead(receivers
);
2426 HashTable_insert(rambase
, rambase
->notifications
,
2427 rr
->nr
->nr_FullName
, rr
);
2438 // kprintf("Returning from Notify_dirChange()\n");
2442 /* TODO: Implement support for NRF_WAIT_REPLY */
2443 void Notify_notifyTasks(struct rambase
*rambase
, struct MinList
*notifications
)
2445 struct Receiver
*rr
;
2447 // kprintf("Inside notifytasks, not = %p\n", notifications);
2449 ForeachNode((struct List
*)notifications
, rr
)
2451 struct NotifyRequest
*nr
= rr
->nr
;
2453 if (nr
->nr_Flags
& NRF_SEND_MESSAGE
&&
2454 !(nr
->nr_Flags
& NRF_WAIT_REPLY
&& nr
->nr_Flags
& NRF_NOT_REPLIED
))
2456 struct NotifyMessage
*nm
= AllocVec(sizeof(struct NotifyMessage
),
2457 MEMF_PUBLIC
| MEMF_CLEAR
);
2464 nm
->nm_ExecMessage
.mn_ReplyPort
= rambase
->notifyPort
;
2465 nm
->nm_ExecMessage
.mn_Length
= sizeof(struct NotifyMessage
);
2467 nr
->nr_Flags
|= NRF_NOT_REPLIED
;
2469 PutMsg(nr
->nr_stuff
.nr_Msg
.nr_Port
, &nm
->nm_ExecMessage
);
2471 else if (nr
->nr_Flags
& NRF_SEND_SIGNAL
)
2473 Signal(nr
->nr_stuff
.nr_Signal
.nr_Task
,
2474 1 << nr
->nr_stuff
.nr_Signal
.nr_SignalNum
);
2479 /* also defined in rom/dos/filesystem_support.c */
2480 STRPTR
RamStripVolume(STRPTR name
)
2482 STRPTR path
= strchr(name
, ':');
2490 BOOL
Notify_addNotification(struct rambase
*rambase
, struct dnode
*dn
,
2491 struct NotifyRequest
*nr
)
2493 struct dnode
*dnTemp
= dn
;
2494 HashTable
*ht
= rambase
->notifications
;
2495 STRPTR name
= nr
->nr_FullName
;
2496 CONST_STRPTR tname
= RamStripVolume(name
);
2498 /* First: Check if the file is opened */
2499 D(bug("Checking existence of %s\n", tname
));
2501 if (findname(rambase
, &tname
, &dnTemp
) == 0)
2503 /* This file was already opened (or at least known by the file
2506 struct Receiver
*rr
= AllocVec(sizeof(struct Receiver
), MEMF_CLEAR
);
2515 if (nr
->nr_Flags
& NRF_NOTIFY_INITIAL
)
2517 struct MinList tempList
;
2519 /* Create a temporary list on the stack and add the receiver to
2520 it. Then forget about this and add the node to the receiver
2521 list (below this block). */
2522 NewList((struct List
*)&tempList
);
2523 AddHead((struct List
*)&tempList
, &rr
->node
);
2524 Notify_notifyTasks(rambase
, &tempList
);
2527 /* Add the receiver node to the file's/directory's list of receivers */
2528 AddTail((struct List
*)&dnTemp
->receivers
, &rr
->node
);
2530 D(bug("Notification added to node: %s\n", name
));
2536 /* This file is not opened */
2538 struct Receiver
*rr
= AllocVec(sizeof(struct Receiver
), MEMF_CLEAR
);
2547 HashTable_insert(rambase
, ht
, name
, rr
);
2554 void Notify_removeNotification(struct rambase
*rambase
,
2555 struct NotifyRequest
*nr
)
2557 struct dnode
*dn
= (struct dnode
*)rambase
->root
;
2558 struct Receiver
*rr
, *rrTemp
;
2559 STRPTR name
= nr
->nr_FullName
;
2560 CONST_STRPTR tname
= RamStripVolume(name
);
2561 struct List
*receivers
;
2562 BOOL fromTable
= FALSE
;
2564 if (findname(rambase
, &tname
, &dn
) == 0)
2566 receivers
= (struct List
*)&dn
->receivers
;
2570 /* This was a request for an entity that doesn't exist yet */
2571 receivers
= HashTable_find(rambase
, rambase
->notifications
, name
);
2573 if (receivers
== NULL
)
2575 D(bug("Ram: This should not happen! -- buggy application...\n"));
2582 ForeachNodeSafe(&receivers
, rr
, rrTemp
)
2586 Remove((struct Node
*)rr
);
2594 /* If we removed a request for a file that doesn't exist yet --
2595 if this was the only notification request for that file, remove
2596 also the hash entry. */
2597 if (IsListEmpty((struct List
*)receivers
))
2599 HashTable_remove(rambase
, rambase
->notifications
, name
);
2604 static STRPTR
getName(struct rambase
*rambase
, struct dnode
*dn
)
2606 struct dnode
*dnTemp
= dn
;
2610 CONST_STRPTR slash
= "/";
2611 CONST_STRPTR nextSlash
= slash
;
2614 /* First, calculate the size of the complete filename */
2615 length
= strlen(dn
->name
) + 2; /* Add trailing 0 byte and possible '/' */
2617 while (findname(rambase
, &slash
, &dnTemp
) == 0)
2620 length
+= 1 + strlen(dnTemp
->name
); /* Add '/' byte */
2623 /* The MEMF_CLEAR is necessary for the while loop below to work */
2624 fullName
= AllocVec(length
, MEMF_PUBLIC
| MEMF_CLEAR
);
2626 if (fullName
== NULL
)
2632 fullName
+= length
- 1;
2634 fullName
-= strlen(dn
->name
) + 1;
2635 strcpy(fullName
, dn
->name
);
2639 while (findname(rambase
, &slash
, &dnTemp
) != ERROR_OBJECT_NOT_FOUND
)
2642 partLen
= strlen(dnTemp
->name
);
2644 fullName
-= partLen
+ 1;
2645 strcpy(fullName
, dnTemp
->name
);
2647 if ((struct vnode
*)dnTemp
== dnTemp
->volume
)
2648 fullName
[partLen
] = ':'; /* Root of Ram Disk */
2650 fullName
[partLen
] = '/'; /* Replace 0 with '/' */
2656 ADD2INITLIB(GM_UNIQUENAME(Init
),0)
2657 ADD2OPENDEV(GM_UNIQUENAME(Open
),0)
2658 ADD2CLOSEDEV(GM_UNIQUENAME(Close
),0)
2659 ADD2EXPUNGELIB(GM_UNIQUENAME(Expunge
),0)