2 Copyright © 1995-2008, 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/battclock.h>
22 #include <proto/dos.h>
23 #include <resources/battclock.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"
38 #include "HashTable.h"
40 static void deventry();
42 #include LC_LIBDEFS_FILE
44 #define NRF_NOT_REPLIED NRF_MAGIC
51 LONG type
; /* ST_LINKDIR */
52 STRPTR name
; /* Link's name */
53 struct cnode
*self
; /* Pointer to top of structure */
54 struct hnode
*link
; /* NULL */
55 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
56 ULONG protect
; /* 0 */
57 STRPTR comment
; /* NULL */
58 struct vnode
*volume
; /* Pointer to volume */
59 struct DosList
*doslist
; /* Pointer to doslist entry */
66 LONG type
; /* ST_USERDIR */
67 STRPTR name
; /* Directory name */
68 struct vnode
*self
; /* Points to top of structure */
69 struct hnode
*link
; /* This one is linked to me */
70 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
71 ULONG protect
; /* 0 */
72 STRPTR comment
; /* NULL */
73 struct MinList receivers
;
74 struct DateStamp date
;
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 STRPTR 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 STRPTR comment
; /* Some comment */
91 struct MinList receivers
;
92 struct DateStamp date
;
93 struct MinList list
; /* Contents of directory */
100 LONG type
; /* ST_FILE */
101 STRPTR name
; /* Filename */
102 struct vnode
*volume
; /* Volume's root directory */
103 struct hnode
*link
; /* This one is linked to me */
104 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
105 ULONG protect
; /* protection bits */
106 STRPTR comment
; /* Some file comment */
107 struct MinList receivers
;
108 struct DateStamp date
;
110 LONG size
; /* Filesize */
111 UBYTE
*blocks
[16]; /* Upto 0x1000 bytes */
112 UBYTE
**iblocks
[4]; /* Upto 0x41000 bytes */
113 UBYTE
***i2block
; /* Upto 0x1041000 bytes */
114 UBYTE
****i3block
; /* Upto 0x101041000 bytes */
121 LONG type
; /* ST_SOFTLINK */
122 STRPTR name
; /* Link's name */
123 struct vnode
*volume
; /* Volume's root directory */
124 struct hnode
*link
; /* This one is hardlinked to me */
125 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
126 ULONG protect
; /* protection bits */
127 STRPTR comment
; /* Some file comment */
128 char *contents
; /* Contents of soft link */
135 LONG type
; /* ST_LINKDIR */
136 STRPTR name
; /* Link's name */
137 struct vnode
*volume
; /* Volume's root directory */
138 struct hnode
*link
; /* This one is hardlinked to me */
139 LONG usecount
; /* >0 usecount locked:+(~0ul/2+1) */
140 ULONG protect
; /* protection bits */
141 STRPTR comment
; /* Some file comment */
142 struct hnode
*orig
; /* original object */
145 /*****************************************************************************/
147 #define FILEFLAGS_Changed 1
149 static STRPTR
getName(struct rambase
*rambase
, struct dnode
*dn
);
160 void Notify_notifyTasks(struct rambase
*rambase
,
161 struct MinList
*notifications
);
163 BOOL
Notify_initialize(struct rambase
*rambase
);
164 void Notify_fileChange(struct rambase
*rambase
, NType type
,
166 void Notify_directoryChange(struct rambase
*rambase
, NType type
,
170 BOOL
Notify_addNotification(struct rambase
*rambase
, struct dnode
*dn
,
171 struct NotifyRequest
*nr
);
172 void Notify_removeNotification(struct rambase
*rambase
,
173 struct NotifyRequest
*nr
);
175 /****************************************************************************/
178 #define BLOCKSIZE 256
179 #define PBLOCKSIZE (256*sizeof(UBYTE *))
187 static int OpenDev(LIBBASETYPEPTR rambase
, struct IOFileSys
*iofs
);
189 static int GM_UNIQUENAME(Init
)(LIBBASETYPEPTR rambase
)
191 /* This function is single-threaded by exec by calling Forbid. */
193 struct MsgPort
*port
;
195 struct SignalSemaphore
*semaphore
;
198 port
= (struct MsgPort
*)AllocMem(sizeof(struct MsgPort
),
199 MEMF_PUBLIC
| MEMF_CLEAR
203 rambase
->port
= port
;
204 NewList(&port
->mp_MsgList
);
205 port
->mp_Node
.ln_Type
= NT_MSGPORT
;
206 port
->mp_SigBit
= SIGB_SINGLE
;
208 task
= (struct Task
*)AllocMem(sizeof(struct Task
),
209 MEMF_PUBLIC
| MEMF_CLEAR
214 port
->mp_SigTask
= task
;
215 port
->mp_Flags
= PA_IGNORE
;
216 NewList(&task
->tc_MemEntry
);
217 task
->tc_Node
.ln_Type
= NT_TASK
;
218 task
->tc_Node
.ln_Name
= "ram.handler task";
220 stack
= AllocMem(AROS_STACKSIZE
, MEMF_PUBLIC
);
224 struct TagItem tasktags
[] =
226 {TASKTAG_ARG1
, (IPTR
)rambase
},
230 task
->tc_SPLower
= stack
;
231 task
->tc_SPUpper
= (BYTE
*)stack
+ AROS_STACKSIZE
;
232 #if AROS_STACK_GROWS_DOWNWARDS
233 task
->tc_SPReg
= (BYTE
*)task
->tc_SPUpper
- SP_OFFSET
;
235 task
->tc_SPReg
= (BYTE
*)task
->tc_SPLower
+ SP_OFFSET
;
238 semaphore
= (struct SignalSemaphore
*)AllocMem(sizeof(struct SignalSemaphore
),
239 MEMF_PUBLIC
| MEMF_CLEAR
242 if (semaphore
!= NULL
)
244 rambase
->sigsem
= semaphore
;
245 InitSemaphore(semaphore
);
248 * Modules compiled with noexpunge always have seglist == NULL
249 * The seglist is not kept as it is not needed because the module never
251 if (rambase->seglist==NULL) /* Are we a ROM module? * /
254 struct DeviceNode
*dn
;
255 /* Install RAM: handler into device list
257 * KLUDGE: ram.handler should create only one device node, depending on
258 * the startup packet it gets. The mountlists for RAM: should be into dos.library bootstrap
262 if((dn
= AllocMem(sizeof (struct DeviceNode
) + 4 + 3 + 2, MEMF_CLEAR
|MEMF_PUBLIC
)))
264 struct IOFileSys dummyiofs
;
266 if (OpenDev(rambase
, &dummyiofs
))
268 BSTR s
= MKBADDR(((IPTR
)dn
+ sizeof(struct DeviceNode
) + 3) & ~3);
270 ((struct Library
*)rambase
)->lib_OpenCnt
++;
272 AROS_BSTR_putchar(s
, 0, 'R');
273 AROS_BSTR_putchar(s
, 1, 'A');
274 AROS_BSTR_putchar(s
, 2, 'M');
275 AROS_BSTR_setstrlen(s
, 3);
277 dn
->dn_Type
= DLT_DEVICE
;
278 dn
->dn_Ext
.dn_AROS
.dn_Unit
= dummyiofs
.IOFS
.io_Unit
;
279 dn
->dn_Ext
.dn_AROS
.dn_Device
= dummyiofs
.IOFS
.io_Device
;
280 dn
->dn_Handler
= NULL
;
281 dn
->dn_Startup
= NULL
;
283 dn
->dn_Ext
.dn_AROS
.dn_DevName
= AROS_BSTR_ADDR(dn
->dn_Name
);
285 if (AddDosEntry((struct DosList
*)dn
))
286 if (NewAddTask(task
, deventry
, NULL
, tasktags
) != NULL
)
290 FreeMem(dn
, sizeof (struct DeviceNode
));
294 if (NewAddTask(task, deventry, NULL, tasktags) != NULL)
297 FreeMem(semaphore
, sizeof(struct SignalSemaphore
));
300 FreeMem(stack
, AROS_STACKSIZE
);
303 FreeMem(task
, sizeof(struct Task
));
306 FreeMem(port
, sizeof(struct MsgPort
));
313 /***************************************************************************/
315 void nullDelete(struct rambase
*rambase
, void *key
, struct List
*list
)
317 // struct Receiver *rr;
318 // struct Node *tempNode;
320 // ForeachNodeSafe(list, rr, tempNode)
322 // Remove(&rr->node);
328 /* The list is part of the HashNode so we shouldn't free that */
332 ULONG
stringHash(struct rambase
*rambase
, const void *key
)
334 STRPTR str
= (STRPTR
)key
;
339 val
*= ToLower(*str
++);
347 my_strcasecmp(struct rambase
*rambase
, const void *s1
, const void *s2
)
349 return strcasecmp(s1
, s2
);
352 /****************************************************************************/
355 STRPTR
Strdup(struct rambase
*rambase
, CONST_STRPTR string
)
357 CONST_STRPTR s2
= string
;
363 s3
= (STRPTR
)AllocVec(s2
- string
, MEMF_ANY
);
367 CopyMem(string
, s3
, s2
- string
);
374 void Strfree(struct rambase
*rambase
, STRPTR string
)
380 static int GM_UNIQUENAME(Open
)
382 LIBBASETYPEPTR rambase
,
383 struct IOFileSys
*iofs
,
388 /* Mark Message as recently used. */
389 iofs
->IOFS
.io_Message
.mn_Node
.ln_Type
= NT_REPLYMSG
;
391 return OpenDev(rambase
, iofs
);
394 static void GetCurrentDate(LIBBASETYPEPTR rambase
, struct DateStamp
*date
)
396 APTR BattClockBase
= NULL
;
400 if (date
->ds_Days
!= 0)
403 BattClockBase
= OpenResource(BATTCLOCKNAME
);
405 secs
= ReadBattClock();
407 date
->ds_Days
= secs
/ (60 * 60 * 24);
408 secs
%= (60 * 60 * 24);
409 date
->ds_Minute
= secs
/ 60;
413 static int OpenDev(LIBBASETYPEPTR rambase
, struct IOFileSys
*iofs
)
415 struct filehandle
*fhv
, *fhc
;
418 struct DeviceList
*dlv
;
420 iofs
->IOFS
.io_Error
= ERROR_NO_FREE_STORE
;
422 fhv
= (struct filehandle
*)AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
426 fhc
= (struct filehandle
*)AllocMem(sizeof(struct filehandle
),
431 vol
= (struct vnode
*)AllocMem(sizeof(struct vnode
), MEMF_CLEAR
);
435 dev
= (struct cnode
*)AllocMem(sizeof(struct cnode
),
437 GetCurrentDate(rambase
, &vol
->date
);
441 vol
->name
= Strdup(rambase
, "Ram Disk");
443 if (vol
->name
!= NULL
)
445 dlv
= (struct DeviceList
*)MakeDosEntry("Ram Disk",
450 vol
->type
= ST_USERDIR
;
452 vol
->doslist
= (struct DosList
*)dlv
;
454 NewList((struct List
*)&vol
->list
);
455 NewList((struct List
*)&vol
->receivers
);
456 fhv
->node
= (struct dnode
*)vol
;
457 dlv
->dl_Ext
.dl_AROS
.dol_Unit
= (struct Unit
*)fhv
;
458 dlv
->dl_Ext
.dl_AROS
.dol_Device
= &rambase
->device
;
459 dlv
->dl_VolumeDate
= vol
->date
;
460 dev
->type
= ST_LINKDIR
;
463 fhc
->node
= (struct dnode
*)dev
;
464 iofs
->IOFS
.io_Unit
= (struct Unit
*)fhc
;
465 iofs
->IOFS
.io_Device
= &rambase
->device
;
466 AddDosEntry((struct DosList
*)dlv
);
468 iofs
->IOFS
.io_Error
= 0;
470 rambase
->notifications
=
471 HashTable_new(rambase
, 100, stringHash
,
472 my_strcasecmp
, nullDelete
);
477 Strfree(rambase
, vol
->name
);
480 FreeMem(dev
, sizeof(struct cnode
));
483 FreeMem(vol
, sizeof(struct vnode
));
486 FreeMem(fhc
, sizeof(struct filehandle
));
489 FreeMem(fhv
, sizeof(struct filehandle
));
492 iofs
->IOFS
.io_Error
= IOERR_OPENFAIL
;
497 static int GM_UNIQUENAME(Expunge
)(LIBBASETYPEPTR rambase
)
500 This function is single-threaded by exec by calling Forbid.
501 Never break the Forbid() or strange things might happen.
504 /* Kill device task and free all resources */
505 RemTask(rambase
->port
->mp_SigTask
);
506 FreeMem(rambase
->sigsem
, sizeof(struct SignalSemaphore
));
507 FreeMem(((struct Task
*)rambase
->port
->mp_SigTask
)->tc_SPLower
,
509 FreeMem(rambase
->port
->mp_SigTask
, sizeof(struct Task
));
510 FreeMem(rambase
->port
, sizeof(struct MsgPort
));
516 AROS_LH1(void, beginio
,
517 AROS_LHA(struct IOFileSys
*, iofs
, A1
),
518 struct rambase
*, rambase
, 5, Ram
)
522 /* WaitIO will look into this */
523 iofs
->IOFS
.io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
525 /* Nothing is done quick */
526 iofs
->IOFS
.io_Flags
&= ~IOF_QUICK
;
528 /* So let the device task do it */
529 PutMsg(rambase
->port
, &iofs
->IOFS
.io_Message
);
535 AROS_LH1(LONG
, abortio
,
536 AROS_LHA(struct IOFileSys
*, iofs
, A1
),
537 struct rambase
*, rambase
, 6, Ram
)
545 static LONG
getblock(struct rambase
*rambase
, struct fnode
*file
, LONG block
,
546 int mode
, UBYTE
**result
)
553 p
= &file
->blocks
[block
];
557 else if (block
< 0x410)
560 p
= (UBYTE
**)&file
->iblocks
[block
/0x100];
564 else if(block
< 0x10410)
567 p
= (UBYTE
**)&file
->i2block
;
573 p
= (UBYTE
**)&file
->i3block
;
589 while (i
-- && p
!= NULL
)
591 a
= (block
>> i
*8) & 0xff;
594 if (!(block
& ((1 << i
*8) - 1)))
600 FreeMem(p
, PBLOCKSIZE
);
609 FreeMem(p
, BLOCKSIZE
);
617 while (i
-- && p
!= NULL
)
619 p
= ((UBYTE
***)p
)[(block
>> i
*8) & 0xff];
622 *result
= (UBYTE
*)p
;
630 *p
= AllocMem(PBLOCKSIZE
, MEMF_CLEAR
);
634 return ERROR_NO_FREE_STORE
;
638 p
= (UBYTE
**)*p
+ ((block
>> i
*8) & 0xff);
643 *p
= AllocMem(BLOCKSIZE
, MEMF_CLEAR
);
647 return ERROR_NO_FREE_STORE
;
653 } /* switch (mode) */
659 static void zerofill(UBYTE
*address
, ULONG size
)
668 static void shrinkfile(struct rambase
*rambase
, struct fnode
*file
, LONG size
)
673 blocks
= (size
+ BLOCKSIZE
- 1)/BLOCKSIZE
;
674 block
= (file
->size
+ BLOCKSIZE
- 1)/BLOCKSIZE
;
676 for(;block
-- > blocks
;)
678 (void)getblock(rambase
, file
, block
, -1, &p
);
683 (void)getblock(rambase
, file
, size
, 0, &p
);
687 zerofill(p
+ (size
& 0xff), -size
& 0xff);
695 static void delete(struct rambase
*rambase
, struct fnode
*file
)
697 struct hnode
*link
, *new, *more
;
700 Strfree(rambase
, file
->name
);
701 Strfree(rambase
, file
->comment
);
702 Remove((struct Node
*)file
);
704 if (file
->type
== ST_LINKDIR
)
706 /* It is a link. Remove it from the chain. */
708 link
= ((struct hnode
*)file
)->orig
;
709 ((struct hnode
*)file
)->orig
= NULL
;
710 file
->type
= link
->type
;
712 while((struct fnode
*)link
->link
!= file
)
717 link
->link
= file
->link
;
719 else if (file
->link
!= NULL
)
721 /* If there is a hard link to the object make the link the original */
724 link
->type
= file
->type
;
736 while((node
= RemHead((struct List
*)&((struct dnode
*)file
)->list
)) != NULL
)
737 AddTail((struct List
*)&((struct dnode
*)file
)->list
, node
);
741 CopyMemQuick(&file
->size
, &((struct fnode
*)new)->size
,
742 sizeof(struct fnode
) - offsetof(struct fnode
, size
));
743 zerofill((UBYTE
*)&file
->size
,
744 sizeof(struct fnode
) - offsetof(struct fnode
, size
));
748 ((struct snode
*)new)->contents
= ((struct snode
*)file
)->contents
;
749 ((struct snode
*)file
)->contents
= NULL
;
752 } /* else if (file->link != NULL) */
757 Notify_directoryChange(rambase
, NOTIFY_Delete
, (struct dnode
*)file
);
759 FreeMem(file
, sizeof(struct dnode
));
764 Notify_fileChange(rambase
, NOTIFY_Delete
, file
);
766 shrinkfile(rambase
, file
, 0);
767 FreeMem(file
, sizeof(struct fnode
));
772 Strfree(rambase
, ((struct snode
*)file
)->contents
);
773 FreeMem(file
, sizeof(struct snode
));
780 static int fstrcmp(struct rambase
*rambase
, CONST_STRPTR s1
, CONST_STRPTR s2
)
784 if (ToLower(*s1
) != ToLower(*s2
))
786 return *s1
|| *s2
!= '/';
800 /* Find a node for a given name */
801 static LONG
findname(struct rambase
*rambase
, CONST_STRPTR
*name
,
802 struct dnode
**dnode
)
804 struct dnode
*cur
= *dnode
;
805 CONST_STRPTR rest
= *name
;
809 if (cur
->type
== ST_LINKDIR
)
811 cur
= (struct dnode
*)((struct hnode
*)cur
)->orig
;
821 if ((struct dnode
*)cur
->volume
== cur
)
823 return ERROR_OBJECT_NOT_FOUND
;
826 while (cur
->node
.mln_Pred
!= NULL
)
828 cur
= (struct dnode
*)cur
->node
.mln_Pred
;
831 cur
= (struct dnode
*)((BYTE
*)cur
- offsetof(struct dnode
, list
));
835 if (cur
->type
== ST_SOFTLINK
)
840 return ERROR_IS_SOFT_LINK
;
843 if (cur
->type
!= ST_USERDIR
)
845 return ERROR_DIR_NOT_FOUND
;
849 cur
= (struct dnode
*)cur
->list
.mlh_Head
;
853 if (cur
->node
.mln_Succ
== NULL
)
857 return ERROR_OBJECT_NOT_FOUND
;
860 if (!fstrcmp(rambase
, cur
->name
, rest
))
865 cur
= (struct dnode
*)cur
->node
.mln_Succ
;
884 static LONG
set_file_size(struct rambase
*rambase
, struct filehandle
*handle
,
885 QUAD
*offp
, LONG mode
)
887 struct fnode
*file
= (struct fnode
*)handle
->node
;
890 if (file
->type
!= ST_FILE
)
892 return ERROR_OBJECT_WRONG_TYPE
;
897 case OFFSET_BEGINNING
:
901 size
+= handle
->position
;
909 return ERROR_NOT_IMPLEMENTED
;
914 return ERROR_SEEK_ERROR
;
917 if (size
< file
->size
)
919 shrinkfile(rambase
, file
, size
);
922 file
->size
= *offp
= size
;
928 static LONG
read(struct rambase
*rambase
, struct filehandle
*handle
,
929 APTR buffer
, LONG
*numbytes
)
931 struct fnode
*file
= (struct fnode
*)handle
->node
;
932 ULONG num
= *numbytes
;
933 ULONG size
= file
->size
;
935 UBYTE
*buf
= buffer
, *p
;
937 if (handle
->position
>= size
)
941 else if (handle
->position
+ num
> size
)
943 num
= size
- handle
->position
;
946 block
= handle
->position
/BLOCKSIZE
;
947 offset
= handle
->position
& (BLOCKSIZE
- 1);
948 size
= BLOCKSIZE
- offset
;
957 (void)getblock(rambase
, file
, block
, 0, &p
);
961 CopyMem(p
+ offset
, buffer
, size
);
965 zerofill(buffer
, size
);
975 *numbytes
= (UBYTE
*)buffer
- buf
;
976 handle
->position
+= *numbytes
;
982 static LONG
write(struct rambase
*rambase
, struct filehandle
*handle
,
983 UBYTE
*buffer
, LONG
*numbytes
)
985 struct fnode
*file
= (struct fnode
*)handle
->node
;
986 ULONG num
= *numbytes
;
987 ULONG size
= file
->size
;
989 UBYTE
*buf
= buffer
, *p
;
992 if ((LONG
)(handle
->position
+ num
) < 0)
994 return ERROR_OBJECT_TOO_LARGE
;
997 Notify_fileChange(rambase
, NOTIFY_Write
, file
);
999 block
= handle
->position
/BLOCKSIZE
;
1000 offset
= handle
->position
& (BLOCKSIZE
- 1);
1001 size
= BLOCKSIZE
- offset
;
1010 error
= getblock(rambase
, file
, block
, 1, &p
);
1017 CopyMem(buffer
, p
+ offset
, size
);
1025 *numbytes
= (UBYTE
*)buffer
- buf
;
1026 handle
->position
+= *numbytes
;
1027 DateStamp(&file
->date
);
1029 if (handle
->position
> file
->size
)
1031 file
->size
= handle
->position
;
1038 static LONG
lock(struct dnode
*dir
, ULONG mode
)
1040 if ((mode
& FMF_EXECUTE
) && (dir
->protect
& FMF_EXECUTE
))
1042 return ERROR_NOT_EXECUTABLE
;
1045 if ((mode
& FMF_WRITE
) && (dir
->protect
& FMF_WRITE
))
1047 return ERROR_WRITE_PROTECTED
;
1050 if ((mode
& FMF_READ
) && (dir
->protect
& FMF_READ
))
1052 return ERROR_READ_PROTECTED
;
1055 if (mode
& FMF_LOCK
)
1059 return ERROR_OBJECT_IN_USE
;
1062 dir
->usecount
= ((ULONG
)~0)/2 + 1;
1066 if (dir
->usecount
< 0)
1068 return ERROR_OBJECT_IN_USE
;
1073 dir
->volume
->volcount
++;
1079 static LONG
open_(struct rambase
*rambase
, struct filehandle
**handle
,
1080 CONST_STRPTR name
, ULONG mode
)
1082 struct dnode
*dir
= (*handle
)->node
;
1083 struct filehandle
*fh
;
1086 fh
= (struct filehandle
*)AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
1090 error
= findname(rambase
, &name
, &dir
);
1094 error
= lock(dir
, mode
);
1101 if (dir
->type
== ST_FILE
)
1103 Notify_fileChange(rambase
, NOTIFY_Open
,
1104 (struct fnode
*)dir
);
1106 else if (dir
->type
== ST_USERDIR
)
1108 D(kprintf("Notifying OPEN at dir %s\n", dir
->name
));
1109 Notify_directoryChange(rambase
, NOTIFY_Open
, dir
);
1116 FreeMem(fh
, sizeof(struct filehandle
));
1120 error
= ERROR_NO_FREE_STORE
;
1127 static LONG
open_file(struct rambase
*rambase
, struct filehandle
**handle
,
1128 CONST_STRPTR name
, ULONG mode
, ULONG protect
)
1130 struct dnode
*dir
= (*handle
)->node
;
1131 struct filehandle
*fh
;
1134 fh
= AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
1138 error
= findname(rambase
, &name
, &dir
);
1140 if ((mode
& FMF_CREATE
) && error
== ERROR_OBJECT_NOT_FOUND
)
1142 CONST_STRPTR s
= name
;
1153 file
= (struct fnode
*)AllocMem(sizeof(struct fnode
), MEMF_CLEAR
);
1154 DateStamp(&file
->date
);
1158 file
->name
= Strdup(rambase
, name
);
1160 if (file
->name
!= NULL
)
1162 file
->type
= ST_FILE
;
1163 file
->protect
= protect
;
1164 file
->volume
= dir
->volume
;
1165 NewList((struct List
*)&file
->receivers
);
1166 AddTail((struct List
*)&dir
->list
, (struct Node
*)file
);
1167 error
= lock((struct dnode
*)file
, mode
);
1171 fh
->node
= (struct dnode
*)file
;
1174 Notify_fileChange(rambase
, NOTIFY_Add
, file
);
1179 Strfree(rambase
, file
->name
);
1182 FreeMem(file
,sizeof(struct fnode
));
1185 error
= ERROR_NO_FREE_STORE
;
1189 if (dir
->type
!= ST_FILE
)
1191 error
= ERROR_OBJECT_WRONG_TYPE
;
1195 error
= lock(dir
, mode
);
1200 if (mode
& FMF_CLEAR
)
1202 shrinkfile(rambase
, (struct fnode
*)dir
, 0);
1203 dir
->protect
= protect
;
1213 } /* else if (!error) */
1215 FreeMem(fh
, sizeof(struct filehandle
));
1222 static LONG
create_dir(struct rambase
*rambase
, struct filehandle
**handle
,
1223 CONST_STRPTR name
, ULONG protect
)
1225 struct dnode
*dir
= (*handle
)->node
, *new;
1226 struct filehandle
*fh
;
1229 if (dir
->protect
& FIBF_WRITE
)
1231 return ERROR_WRITE_PROTECTED
;
1234 error
= findname(rambase
, &name
, &dir
);
1238 return ERROR_OBJECT_EXISTS
;
1241 if (error
!= ERROR_OBJECT_NOT_FOUND
)
1246 if (strchr(name
, '/') != NULL
)
1251 fh
= AllocMem(sizeof(struct filehandle
), MEMF_CLEAR
);
1255 new = (struct dnode
*)AllocMem(sizeof(struct dnode
), MEMF_CLEAR
);
1259 new->name
= Strdup(rambase
, name
);
1261 if (new->name
!= NULL
)
1263 new->type
= ST_USERDIR
;
1264 new->protect
= protect
;
1265 new->volume
= dir
->volume
;
1266 new->volume
->volcount
++;
1267 new->usecount
= ((ULONG
)~0)/2 + 2;
1268 NewList((struct List
*)&new->list
);
1269 NewList((struct List
*)&new->receivers
);
1270 AddTail((struct List
*)&dir
->list
, (struct Node
*)new);
1273 DateStamp(&new->date
);
1275 D(bug("New (%p): Name = %s\n", new, new->name
));
1276 Notify_directoryChange(rambase
, NOTIFY_Add
, new);
1281 FreeMem(new, sizeof(struct dnode
));
1284 FreeMem(fh
, sizeof(struct filehandle
));
1287 return ERROR_NO_FREE_STORE
;
1291 static LONG
free_lock(struct rambase
*rambase
, struct filehandle
*filehandle
)
1293 struct dnode
*dnode
= filehandle
->node
;
1295 dnode
->usecount
= (dnode
->usecount
- 1) & ((ULONG
)~0)/2;
1296 FreeMem(filehandle
, sizeof(struct filehandle
));
1297 dnode
->volume
->volcount
--;
1303 static LONG
seek(struct rambase
*rambase
, struct filehandle
*filehandle
,
1304 QUAD
*posp
, LONG mode
)
1306 struct fnode
*file
= (struct fnode
*)filehandle
->node
;
1309 if (file
->type
!= ST_FILE
)
1311 return ERROR_OBJECT_WRONG_TYPE
;
1316 case OFFSET_BEGINNING
:
1319 case OFFSET_CURRENT
:
1320 pos
+= filehandle
->position
;
1328 return ERROR_NOT_IMPLEMENTED
;
1333 return ERROR_SEEK_ERROR
;
1336 *posp
= filehandle
->position
;
1337 filehandle
->position
= pos
;
1343 static const ULONG sizes
[]=
1346 offsetof(struct ExAllData
,ed_Type
),
1347 offsetof(struct ExAllData
,ed_Size
),
1348 offsetof(struct ExAllData
,ed_Prot
),
1349 offsetof(struct ExAllData
,ed_Days
),
1350 offsetof(struct ExAllData
,ed_Comment
),
1351 offsetof(struct ExAllData
,ed_OwnerUID
),
1352 sizeof(struct ExAllData
)
1356 static LONG
examine(struct fnode
*file
,
1357 struct ExAllData
*ead
,
1362 STRPTR next
, end
, name
;
1364 if (type
> ED_OWNER
)
1366 return ERROR_BAD_NUMBER
;
1369 next
= (STRPTR
)ead
+ sizes
[type
];
1370 end
= (STRPTR
)ead
+ size
;
1372 if(next
>end
) /* > is correct. Not >= */
1373 return ERROR_BUFFER_OVERFLOW
;
1375 /* Use *dirpos to store information for ExNext()
1376 * *dirpos is copied to fib->fib_DiskKey in Examine()
1378 if (file
->type
== ST_USERDIR
)
1380 *dirpos
= (LONG
)(((struct dnode
*)file
)->list
.mlh_Head
);
1384 /* ExNext() should not be called in this case anyway */
1385 *dirpos
= (LONG
)file
;
1391 ead
->ed_OwnerUID
= 0;
1392 ead
->ed_OwnerGID
= 0;
1396 if (file
->comment
!= NULL
)
1398 ead
->ed_Comment
= next
;
1399 name
= file
->comment
;
1405 return ERROR_BUFFER_OVERFLOW
;
1408 if (!(*next
++ = *name
++))
1416 ead
->ed_Comment
= NULL
;
1421 ead
->ed_Days
= file
->date
.ds_Days
;
1422 ead
->ed_Mins
= file
->date
.ds_Minute
;
1423 ead
->ed_Ticks
= file
->date
.ds_Tick
;
1427 ead
->ed_Prot
= file
->protect
;
1431 ead
->ed_Size
= file
->size
;
1435 ead
->ed_Type
= file
->type
;
1437 if (((struct vnode
*)file
)->self
== (struct vnode
*)file
)
1439 ead
->ed_Type
=ST_ROOT
;
1444 ead
->ed_Name
= next
;
1451 return ERROR_BUFFER_OVERFLOW
;
1454 if (!(*next
++ = *name
++))
1462 ead
->ed_Next
= (struct ExAllData
*)(((IPTR
)next
+ AROS_PTRALIGN
- 1) & ~(AROS_PTRALIGN
- 1));
1469 static LONG
examine_next(struct rambase
*rambase
,
1470 struct filehandle
*dir
,
1471 struct FileInfoBlock
*FIB
)
1473 struct fnode
*file
= (struct fnode
*)FIB
->fib_DiskKey
;
1475 ASSERT_VALID_PTR_OR_NULL(file
);
1477 if (file
->node
.mln_Succ
== NULL
)
1479 return ERROR_NO_MORE_ENTRIES
;
1482 FIB
->fib_OwnerUID
= 0;
1483 FIB
->fib_OwnerGID
= 0;
1485 FIB
->fib_Date
.ds_Days
= file
->date
.ds_Days
;
1486 FIB
->fib_Date
.ds_Minute
= file
->date
.ds_Minute
;
1487 FIB
->fib_Date
.ds_Tick
= file
->date
.ds_Tick
;
1488 FIB
->fib_Protection
= file
->protect
;
1489 FIB
->fib_Size
= file
->size
;
1490 FIB
->fib_DirEntryType
= file
->type
;
1492 strncpy(FIB
->fib_FileName
, file
->name
, MAXFILENAMELENGTH
- 1);
1493 strncpy(FIB
->fib_Comment
, file
->comment
!= NULL
? file
->comment
: "",
1494 MAXCOMMENTLENGTH
- 1);
1496 FIB
->fib_DiskKey
= (LONG
)file
->node
.mln_Succ
;
1502 static LONG
examine_all(struct filehandle
*dir
,
1503 struct ExAllData
*ead
,
1504 struct ExAllControl
*eac
,
1509 struct ExAllData
*last
=NULL
;
1512 LONG dummy
; /* not anything is done with this value but passed to examine */
1513 end
= (STRPTR
)ead
+ size
;
1515 eac
->eac_Entries
= 0;
1516 if (dir
->node
->type
!= ST_USERDIR
)
1518 return ERROR_OBJECT_WRONG_TYPE
;
1521 ent
= (struct fnode
*)eac
->eac_LastKey
;
1525 ent
= (struct fnode
*)dir
->node
->list
.mlh_Head
;
1526 if (ent
->node
.mln_Succ
) ent
->usecount
++;
1529 if (ent
->node
.mln_Succ
== NULL
)
1531 return ERROR_NO_MORE_ENTRIES
;
1538 error
= examine(ent
, ead
, end
- (STRPTR
)ead
, type
, &dummy
);
1540 if (error
== ERROR_BUFFER_OVERFLOW
)
1548 last
->ed_Next
= NULL
;
1549 eac
->eac_LastKey
= (IPTR
)ent
;
1556 ent
= (struct fnode
*)ent
->node
.mln_Succ
;
1558 } while (ent
->node
.mln_Succ
!= NULL
);
1560 last
->ed_Next
= NULL
;
1561 eac
->eac_LastKey
= (IPTR
)ent
;
1563 return ERROR_NO_MORE_ENTRIES
;
1567 static LONG
rename_object(struct rambase
*rambase
,
1568 struct filehandle
*filehandle
,
1569 CONST_STRPTR namea
, CONST_STRPTR nameb
)
1571 struct dnode
*file
= filehandle
->node
;
1574 struct dnode
*nodea
= filehandle
->node
, *nodeb
;
1575 STRPTR dira
, dirb
, pos
= nameb
;
1577 error
= findname(rambase
, &pos
, &nodea
);
1579 return ERROR_OBJECT_EXISTS
;
1581 error
= findname(rambase
, &namea
, &file
);
1585 if ((struct dnode
*)file
->volume
== file
)
1586 return ERROR_OBJECT_WRONG_TYPE
;
1588 if (file
->usecount
!= 0)
1589 return ERROR_OBJECT_IN_USE
;
1591 dira
= Strdup(rambase
, namea
);
1592 dirb
= Strdup(rambase
, nameb
);
1594 pos
= strrchr(dira
, '/');
1603 pos
= strrchr(dirb
, '/');
1612 D(bug("[Ram] rename (%s,%s)=>(%s,%s)\n", dira
, namea
, dirb
, nameb
));
1614 if (*dira
== '\0' && *dirb
== '\0')
1616 Strfree(rambase
, file
->name
);
1617 file
->name
= Strdup(rambase
, nameb
);
1621 nodea
= filehandle
->node
;
1622 error
= findname(rambase
, &dira
, &nodea
);
1626 nodeb
= filehandle
->node
;
1627 error
= findname(rambase
, &dirb
, &nodeb
);
1633 Remove((struct Node
*)file
);
1634 AddTail((struct List
*)&nodeb
->list
, (struct Node
*)file
);
1637 Strfree(rambase
, file
->name
);
1638 file
->name
= Strdup(rambase
, nameb
);
1641 DateStamp(&file
->date
);
1646 Notify_fileChange(rambase
, NOTIFY_Delete
, (struct fnode
*)file
);
1647 Notify_fileChange(rambase
, NOTIFY_Add
, (struct fnode
*)file
);
1651 Notify_directoryChange(rambase
, NOTIFY_Delete
, file
);
1652 Notify_directoryChange(rambase
, NOTIFY_Add
, file
);
1657 Strfree(rambase
, dirb
);
1658 Strfree(rambase
, dira
);
1663 static LONG
delete_object(struct rambase
*rambase
,
1664 struct filehandle
*filehandle
, CONST_STRPTR name
)
1666 struct dnode
*file
= filehandle
->node
;
1669 error
= findname(rambase
, &name
, &file
);
1676 if ((struct dnode
*)file
->volume
== file
)
1678 return ERROR_OBJECT_WRONG_TYPE
;
1681 if (file
->usecount
!= 0)
1683 return ERROR_OBJECT_IN_USE
;
1686 if (file
->protect
& FIBF_DELETE
)
1688 return ERROR_DELETE_PROTECTED
;
1691 if (file
->type
== ST_USERDIR
&& file
->list
.mlh_Head
->mln_Succ
!= NULL
)
1693 return ERROR_DIRECTORY_NOT_EMPTY
;
1696 delete(rambase
, (struct fnode
*)file
);
1702 static int GM_UNIQUENAME(Close
)
1704 LIBBASETYPEPTR rambase
,
1705 struct IOFileSys
*iofs
1713 struct filehandle
*handle
;
1715 handle
= (struct filehandle
*)iofs
->IOFS
.io_Unit
;
1716 dev
= (struct cnode
*)handle
->node
;
1719 if (dev
->type
!= ST_LINKDIR
|| dev
->self
!= dev
)
1721 iofs
->io_DosError
= ERROR_OBJECT_WRONG_TYPE
;
1728 iofs
->io_DosError
= ERROR_OBJECT_IN_USE
;
1733 free_lock(rambase
, handle
);
1734 RemDosEntry(vol
->doslist
);
1735 FreeDosEntry(vol
->doslist
);
1737 while (vol
->list
.mlh_Head
->mln_Succ
!= NULL
)
1739 dir
= (struct dnode
*)vol
->list
.mlh_Head
;
1741 if (dir
->type
== ST_USERDIR
)
1743 while((file
= (struct fnode
*)RemHead((struct List
*)&dir
->list
)) != NULL
)
1745 AddTail((struct List
*)&vol
->list
, (struct Node
*)dir
);
1749 delete(rambase
, (struct fnode
*)dir
);
1752 Strfree(rambase
, vol
->name
);
1753 FreeMem(vol
, sizeof(struct vnode
));
1755 Strfree(rambase
, dev
->name
);
1756 FreeMem(dev
, sizeof(struct cnode
));
1758 iofs
->io_DosError
= 0;
1764 void processFSM(struct rambase
*rambase
);
1767 static void deventry(struct rambase
*rambase
)
1771 struct Message
*msg
;
1774 Init device port. AllocSignal() cannot fail because this is a
1775 freshly created task with all signal bits still free.
1778 rambase
->port
->mp_SigBit
= AllocSignal(-1);
1779 rambase
->port
->mp_Flags
= PA_SIGNAL
;
1781 /* Check if there are pending messages that we missed */
1782 if ((msg
= GetMsg(rambase
->port
))) PutMsg(rambase
->port
, msg
);
1784 Notify_initialize(rambase
);
1786 notifyMask
= 1 << rambase
->notifyPort
->mp_SigBit
;
1788 fileOpMask
= 1 << rambase
->port
->mp_SigBit
;
1794 flags
= Wait(fileOpMask
| notifyMask
);
1796 if (flags
& notifyMask
)
1798 struct NotifyMessage
*nMessage
;
1800 D(kprintf("Got replied notify message\n"));
1802 while ((nMessage
= (struct NotifyMessage
*)GetMsg(rambase
->notifyPort
)) != NULL
)
1804 nMessage
->nm_NReq
->nr_Flags
&= ~NRF_NOT_REPLIED
;
1809 if (flags
& fileOpMask
)
1811 processFSM(rambase
);
1817 void processFSM(struct rambase
*rambase
)
1819 struct IOFileSys
*iofs
;
1824 /* Get and process the messages. */
1825 while ((iofs
= (struct IOFileSys
*)GetMsg(rambase
->port
)) != NULL
)
1827 D(bug("Ram.handler initialized %u\n", iofs
->IOFS
.io_Command
));
1829 switch (iofs
->IOFS
.io_Command
)
1833 get handle on a file or directory
1834 Unit *current; current directory / new handle on return
1835 STRPTR name; file- or directoryname
1836 LONG mode; open mode
1839 error
= open_(rambase
,
1840 (struct filehandle
**)&iofs
->IOFS
.io_Unit
,
1841 iofs
->io_Union
.io_OPEN
.io_Filename
,
1842 iofs
->io_Union
.io_OPEN
.io_FileMode
);
1847 open a file or create a new one
1848 Unit *current; current directory / new handle on return
1849 STRPTR name; file- or directoryname
1850 LONG mode; open mode
1851 LONG protect; protection flags if a new file is created
1854 error
= open_file(rambase
,
1855 (struct filehandle
**)&iofs
->IOFS
.io_Unit
,
1856 iofs
->io_Union
.io_OPEN_FILE
.io_Filename
,
1857 iofs
->io_Union
.io_OPEN_FILE
.io_FileMode
,
1858 iofs
->io_Union
.io_OPEN_FILE
.io_Protection
);
1863 read a number of bytes from a file
1864 Unit *current; filehandle
1866 LONG numbytes; number of bytes to read /
1867 number of bytes read on return,
1868 0 if there are no more bytes in the file
1870 error
= read(rambase
,
1871 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1872 iofs
->io_Union
.io_READ
.io_Buffer
,
1873 &iofs
->io_Union
.io_READ
.io_Length
);
1878 write a number of bytes to a file
1879 Unit *current; filehandle
1881 LONG numbytes; number of bytes to write /
1882 number of bytes written on return
1884 error
= write(rambase
,
1885 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1886 iofs
->io_Union
.io_WRITE
.io_Buffer
,
1887 &iofs
->io_Union
.io_WRITE
.io_Length
);
1892 set / read position in file
1893 Unit *current; filehandle
1895 LONG posl; relative position /
1896 old position on return
1897 LONG mode; one of OFFSET_BEGINNING, OFFSET_CURRENT,
1900 error
= seek(rambase
,
1901 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1902 &iofs
->io_Union
.io_SEEK
.io_Offset
,
1903 iofs
->io_Union
.io_SEEK
.io_SeekMode
);
1908 /* Get rid of a handle
1909 Unit *current; filehandle */
1911 struct filehandle
*handle
=
1912 (struct filehandle
*)iofs
->IOFS
.io_Unit
;
1914 Notify_fileChange(rambase
, NOTIFY_Close
,
1915 (struct fnode
*)handle
->node
);
1916 error
= free_lock(rambase
, handle
);
1922 Get information about the current object
1923 Unit *current; current object
1924 struct ExAllData *ead; buffer to be filled
1925 ULONG size; size of the buffer
1926 ULONG type; type of information to get
1927 iofs->io_DirPos; leave current position so
1928 ExNext() knows where to find
1931 error
= examine((struct fnode
*)((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
,
1932 iofs
->io_Union
.io_EXAMINE
.io_ead
,
1933 iofs
->io_Union
.io_EXAMINE
.io_Size
,
1934 iofs
->io_Union
.io_EXAMINE
.io_Mode
,
1935 &(iofs
->io_DirPos
));
1938 case FSA_EXAMINE_NEXT
:
1940 Get information about the next object
1941 Unit *current; current object
1942 struct FileInfoBlock *fib;
1944 error
= examine_next(rambase
,
1945 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1946 iofs
->io_Union
.io_EXAMINE_NEXT
.io_fib
);
1949 case FSA_EXAMINE_ALL
:
1951 Read the current directory
1952 Unit *current; current directory
1953 struct ExAllData *ead; buffer to be filled
1954 ULONG size; size of the buffer
1955 ULONG type; type of information to get
1957 error
= examine_all((struct filehandle
*)iofs
->IOFS
.io_Unit
,
1958 iofs
->io_Union
.io_EXAMINE_ALL
.io_ead
,
1959 iofs
->io_Union
.io_EXAMINE_ALL
.io_eac
,
1960 iofs
->io_Union
.io_EXAMINE_ALL
.io_Size
,
1961 iofs
->io_Union
.io_EXAMINE_ALL
.io_Mode
);
1964 case FSA_CREATE_DIR
:
1966 Build lock and open a new directory
1967 Unit *current; current directory
1968 STRPTR name; name of the dir to create
1969 LONG protect; Protection flags for the new dir
1972 // kprintf("Creating directory %s\n",
1973 // iofs->io_Union.io_CREATE_DIR.io_Filename);
1976 error
= create_dir(rambase
,
1977 (struct filehandle
**)&iofs
->IOFS
.io_Unit
,
1978 iofs
->io_Union
.io_CREATE_DIR
.io_Filename
,
1979 iofs
->io_Union
.io_CREATE_DIR
.io_Protection
);
1982 case FSA_DELETE_OBJECT
:
1984 Delete file or directory
1985 Unit *current; current directory
1986 STRPTR name; filename
1988 error
= delete_object(rambase
,
1989 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
1990 iofs
->io_Union
.io_DELETE_OBJECT
.io_Filename
);
1993 case FSA_SET_PROTECT
:
1996 Set protection bits for a certain file or directory.
1997 Unit *current; current directory
1998 STRPTR name; filename
1999 ULONG protect; new protection bits
2002 CONST_STRPTR name
= iofs
->io_Union
.io_SET_PROTECT
.io_Filename
;
2004 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
2005 error
= findname(rambase
, &name
, &dir
);
2009 dir
->protect
= iofs
->io_Union
.io_SET_PROTECT
.io_Protection
;
2018 Set owner and group of the file or directory
2019 Unit *current; current directory
2020 STRPTR name; filename
2025 CONST_STRPTR name
= iofs
->io_Union
.io_SET_OWNER
.io_Filename
;
2027 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
2028 error
= findname(rambase
, &name
, &dir
);
2040 Set creation date of the file
2041 Unit *current; current directory
2042 STRPTR name; filename
2045 ULONG ticks; timestamp
2048 CONST_STRPTR name
= iofs
->io_Union
.io_SET_DATE
.io_Filename
;
2050 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
2051 error
= findname(rambase
, &name
, &dir
);
2055 dir
->date
= iofs
->io_Union
.io_SET_DATE
.io_Date
;
2061 case FSA_SET_COMMENT
:
2064 Set a comment for the file or directory;
2065 Unit *current; current directory
2066 STRPTR name; filename
2067 STRPTR comment; NUL terminated C string or NULL.
2070 CONST_STRPTR name
= iofs
->io_Union
.io_SET_COMMENT
.io_Filename
;
2072 dir
= ((struct filehandle
*)iofs
->IOFS
.io_Unit
)->node
;
2073 error
= findname(rambase
, &name
, &dir
);
2077 if (iofs
->io_Union
.io_SET_COMMENT
.io_Comment
)
2079 STRPTR s
= Strdup(rambase
,
2080 iofs
->io_Union
.io_SET_COMMENT
.io_Comment
);
2083 Strfree(rambase
, dir
->comment
);
2088 error
= ERROR_NO_FREE_STORE
;
2093 Strfree(rambase
, dir
->comment
);
2094 dir
->comment
= NULL
;
2101 case FSA_SET_FILE_SIZE
:
2103 Set a new size for the file.
2104 Unit *file; filehandle
2106 LONG offl; offset to current position/
2108 LONG mode; relative to what (see Seek)
2110 error
= set_file_size(rambase
,
2111 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
2112 &iofs
->io_Union
.io_SET_FILE_SIZE
.io_Offset
,
2113 iofs
->io_Union
.io_SET_FILE_SIZE
.io_SeekMode
);
2116 case FSA_IS_FILESYSTEM
:
2117 iofs
->io_Union
.io_IS_FILESYSTEM
.io_IsFilesystem
= TRUE
;
2123 struct InfoData
*id
= iofs
->io_Union
.io_INFO
.io_Info
;
2125 id
->id_NumSoftErrors
= 0;
2126 id
->id_UnitNumber
= 0;
2127 id
->id_DiskState
= ID_VALIDATED
;
2128 id
->id_NumBlocks
= AvailMem(MEMF_TOTAL
| MEMF_PUBLIC
)/BLOCKSIZE
;
2129 id
->id_NumBlocksUsed
= id
->id_NumBlocks
- AvailMem(MEMF_PUBLIC
)/BLOCKSIZE
;
2130 id
->id_BytesPerBlock
= BLOCKSIZE
;
2131 id
->id_DiskType
= ID_DOS_DISK
;
2132 id
->id_VolumeNode
= NULL
; /* What is this? */
2133 id
->id_InUse
= (LONG
)TRUE
;
2141 case FSA_ADD_NOTIFY
:
2144 struct NotifyRequest
*nr
=
2145 iofs
->io_Union
.io_NOTIFY
.io_NotificationRequest
;
2146 struct filehandle
*fh
= (struct filehandle
*)iofs
->IOFS
.io_Unit
;
2148 D(kprintf("Adding notification for entity (nr = %s)\n",
2151 ok
= Notify_addNotification(rambase
, fh
->node
, nr
);
2155 error
= ERROR_NO_FREE_STORE
;
2158 D(kprintf("Notification now added!\n"));
2162 case FSA_REMOVE_NOTIFY
:
2164 struct NotifyRequest
*nr
=
2165 iofs
->io_Union
.io_NOTIFY
.io_NotificationRequest
;
2167 Notify_removeNotification(rambase
, nr
);
2172 error
= rename_object(rambase
,
2173 (struct filehandle
*)iofs
->IOFS
.io_Unit
,
2174 iofs
->io_Union
.io_RENAME
.io_Filename
,
2175 iofs
->io_Union
.io_RENAME
.io_NewName
);
2178 case FSA_IS_INTERACTIVE
:
2179 iofs
->io_Union
.io_IS_INTERACTIVE
.io_IsInteractive
= 0;
2183 error
= ERROR_NOT_IMPLEMENTED
;
2185 D(kprintf("ram_handler, unimplemented FSA: %ld\n", iofs
->IOFS
.io_Command
));
2189 Change or read the mode of a single filehandle
2190 Unit *current; filehandle to change
2191 ULONG newmode; new mode/old mode on return
2192 ULONG mask; bits affected
2195 Change or read the mode of the filesystem
2196 Unit *current; filesystem to change
2197 ULONG newmode; new mode/old mode on return
2198 ULONG mask; bits affected
2199 STRPTR passwd; password for MMF_LOCKED
2202 Create a hard link on a file, directory or soft link
2203 Unit *current; current directory
2204 STRPTR name; softlink name
2205 Unit *target; target handle
2208 Create a soft link to another object
2209 Unit *current; current directory
2210 STRPTR name; softlink name
2211 STRPTR target; target name
2230 iofs
->io_DosError
= error
;
2231 ReplyMsg(&iofs
->IOFS
.io_Message
);
2235 if (rambase
->iofs
!= NULL
)
2237 iofs
= rambase
->iofs
;
2239 if (iofs
->IOFS
.io_Message
.mn_Node
.ln_Type
== NT_MESSAGE
)
2241 abort_notify(rambase
, iofs
);
2242 iofs
->io_DosError
= ERROR_BREAK
;
2243 rambase
->iofs
= NULL
;
2244 ReplyMsg(&iofs
->IOFS
.io_Message
);
2248 rambase
->iofs
= NULL
;
2259 /***************************************************************************
2260 ****************************************************************************/
2262 /** Notification stuff **/
2265 * Immediate notification:
2267 * ACTION_RENAME_OBJECT
2268 * ACTION_RENAME_DISK
2270 * ACTION_DELETE_OBJECT
2274 * Session semantics notification:
2279 * ACTION_SET_FILE_SIZE
2282 * For ram-handler, the only FSA actions currently implemented/affected are
2283 * FSA_WRITE, FSA_CREATE_DIR, FSA_DELETE (and implicitly FSA_OPEN, FSA_CLOSE)
2288 BOOL
Notify_initialize(struct rambase
*rambase
)
2290 rambase
->notifyPort
= CreateMsgPort();
2292 if (rambase
->notifyPort
== NULL
)
2301 void Notify_fileChange(struct rambase
*rambase
, NType type
, struct fnode
*file
)
2309 D(bug("Setting write flag!\n"));
2310 file
->flags
|= FILEFLAGS_Changed
;
2314 /* Only notify in case the file was changed */
2315 if (file
->flags
& FILEFLAGS_Changed
)
2317 D(bug("Notification on close (file was changed).\n"));
2318 file
->flags
&= ~FILEFLAGS_Changed
;
2319 Notify_notifyTasks(rambase
, &file
->receivers
);
2326 struct List
*receivers
;
2328 fullName
= getName(rambase
, (struct dnode
*)file
);
2330 D(kprintf("Found full name: %s\n", fullName
));
2332 receivers
= HashTable_find(rambase
, rambase
->notifications
,
2335 if (receivers
!= NULL
)
2337 D(kprintf("Found notification for created file!\n"));
2339 while (!IsListEmpty(receivers
))
2341 AddHead((struct List
*)&file
->receivers
,
2342 RemHead(receivers
));
2346 HashTable_remove(rambase
, rambase
->notifications
, fullName
);
2348 D(bug("Notifying file receivers!\n"));
2349 Notify_notifyTasks(rambase
, &file
->receivers
);
2356 /* It's the same thing as for directories... */
2357 Notify_directoryChange(rambase
, NOTIFY_Delete
, (struct dnode
*)file
);
2367 void Notify_directoryChange(struct rambase
*rambase
, NType type
,
2376 fullName
= getName(rambase
, dir
);
2378 /* TODO: HashTable_apply(ht, fullName, dir); */
2387 struct List
*receivers
;
2389 fullName
= getName(rambase
, dir
);
2391 D(kprintf("Found full name: %s\n", fullName
));
2393 receivers
= HashTable_find(rambase
, rambase
->notifications
,
2396 if (receivers
!= NULL
)
2398 D(kprintf("Found notification for created directory!\n"));
2400 while (!IsListEmpty(receivers
))
2402 AddHead((struct List
*)&dir
->receivers
,
2403 RemHead(receivers
));
2407 HashTable_remove(rambase
, rambase
->notifications
, fullName
);
2412 D(kprintf("Notifying dir receivers!\n"));
2413 Notify_notifyTasks(rambase
, &dir
->receivers
);
2418 /* As we have deleted a file, we must move the requests for
2419 this file to the hash table */
2420 struct List
*receivers
= (struct List
*)&dir
->receivers
;
2422 Notify_notifyTasks(rambase
, &dir
->receivers
);
2424 /* Move the Notification request to the hash table as we're going
2425 to delete this directory */
2426 while (!IsListEmpty(receivers
))
2428 struct Receiver
*rr
= (struct Receiver
*)RemHead(receivers
);
2430 HashTable_insert(rambase
, rambase
->notifications
,
2431 rr
->nr
->nr_FullName
, rr
);
2442 // kprintf("Returning from Notify_dirChange()\n");
2446 /* TODO: Implement support for NRF_WAIT_REPLY */
2447 void Notify_notifyTasks(struct rambase
*rambase
, struct MinList
*notifications
)
2449 struct Receiver
*rr
;
2451 // kprintf("Inside notifytasks, not = %p\n", notifications);
2453 ForeachNode((struct List
*)notifications
, rr
)
2455 struct NotifyRequest
*nr
= rr
->nr
;
2457 if (nr
->nr_Flags
& NRF_SEND_MESSAGE
&&
2458 !(nr
->nr_Flags
& NRF_WAIT_REPLY
&& nr
->nr_Flags
& NRF_NOT_REPLIED
))
2460 struct NotifyMessage
*nm
= AllocVec(sizeof(struct NotifyMessage
),
2461 MEMF_PUBLIC
| MEMF_CLEAR
);
2468 nm
->nm_ExecMessage
.mn_ReplyPort
= rambase
->notifyPort
;
2469 nm
->nm_ExecMessage
.mn_Length
= sizeof(struct NotifyMessage
);
2471 nr
->nr_Flags
|= NRF_NOT_REPLIED
;
2473 PutMsg(nr
->nr_stuff
.nr_Msg
.nr_Port
, &nm
->nm_ExecMessage
);
2475 else if (nr
->nr_Flags
& NRF_SEND_SIGNAL
)
2477 Signal(nr
->nr_stuff
.nr_Signal
.nr_Task
,
2478 1 << nr
->nr_stuff
.nr_Signal
.nr_SignalNum
);
2483 /* also defined in rom/dos/filesystem_support.c */
2484 STRPTR
RamStripVolume(STRPTR name
)
2486 STRPTR path
= strchr(name
, ':');
2494 BOOL
Notify_addNotification(struct rambase
*rambase
, struct dnode
*dn
,
2495 struct NotifyRequest
*nr
)
2497 struct dnode
*dnTemp
= dn
;
2498 HashTable
*ht
= rambase
->notifications
;
2499 STRPTR name
= nr
->nr_FullName
;
2500 CONST_STRPTR tname
= RamStripVolume(name
);
2502 /* First: Check if the file is opened */
2503 D(bug("Checking existence of %s\n", tname
));
2505 if (findname(rambase
, &tname
, &dnTemp
) == 0)
2507 /* This file was already opened (or at least known by the file
2510 struct Receiver
*rr
= AllocVec(sizeof(struct Receiver
), MEMF_CLEAR
);
2519 if (nr
->nr_Flags
& NRF_NOTIFY_INITIAL
)
2521 struct MinList tempList
;
2523 /* Create a temporary list on the stack and add the receiver to
2524 it. Then forget about this and add the node to the receiver
2525 list (below this block). */
2526 NewList((struct List
*)&tempList
);
2527 AddHead((struct List
*)&tempList
, &rr
->node
);
2528 Notify_notifyTasks(rambase
, &tempList
);
2531 /* Add the receiver node to the file's/directory's list of receivers */
2532 AddTail((struct List
*)&dnTemp
->receivers
, &rr
->node
);
2534 D(bug("Notification added to node: %s\n", name
));
2540 /* This file is not opened */
2542 struct Receiver
*rr
= AllocVec(sizeof(struct Receiver
), MEMF_CLEAR
);
2551 HashTable_insert(rambase
, ht
, name
, rr
);
2558 void Notify_removeNotification(struct rambase
*rambase
,
2559 struct NotifyRequest
*nr
)
2561 struct dnode
*dn
= (struct dnode
*)rambase
->root
;
2562 struct Receiver
*rr
, *rrTemp
;
2563 STRPTR name
= nr
->nr_FullName
;
2564 CONST_STRPTR tname
= RamStripVolume(name
);
2565 struct List
*receivers
;
2566 BOOL fromTable
= FALSE
;
2568 if (findname(rambase
, &tname
, &dn
) == 0)
2570 receivers
= (struct List
*)&dn
->receivers
;
2574 /* This was a request for an entity that doesn't exist yet */
2575 receivers
= HashTable_find(rambase
, rambase
->notifications
, name
);
2577 if (receivers
== NULL
)
2579 D(bug("Ram: This should not happen! -- buggy application...\n"));
2586 ForeachNodeSafe(&receivers
, rr
, rrTemp
)
2590 Remove((struct Node
*)rr
);
2598 /* If we removed a request for a file that doesn't exist yet --
2599 if this was the only notification request for that file, remove
2600 also the hash entry. */
2601 if (IsListEmpty((struct List
*)receivers
))
2603 HashTable_remove(rambase
, rambase
->notifications
, name
);
2608 static STRPTR
getName(struct rambase
*rambase
, struct dnode
*dn
)
2610 struct dnode
*dnTemp
= dn
;
2614 CONST_STRPTR slash
= "/";
2615 CONST_STRPTR nextSlash
= slash
;
2618 /* First, calculate the size of the complete filename */
2619 length
= strlen(dn
->name
) + 2; /* Add trailing 0 byte and possible '/' */
2621 while (findname(rambase
, &slash
, &dnTemp
) == 0)
2624 length
+= 1 + strlen(dnTemp
->name
); /* Add '/' byte */
2627 /* The MEMF_CLEAR is necessary for the while loop below to work */
2628 fullName
= AllocVec(length
, MEMF_PUBLIC
| MEMF_CLEAR
);
2630 if (fullName
== NULL
)
2636 fullName
+= length
- 1;
2638 fullName
-= strlen(dn
->name
) + 1;
2639 strcpy(fullName
, dn
->name
);
2643 while (findname(rambase
, &slash
, &dnTemp
) != ERROR_OBJECT_NOT_FOUND
)
2646 partLen
= strlen(dnTemp
->name
);
2648 fullName
-= partLen
+ 1;
2649 strcpy(fullName
, dnTemp
->name
);
2651 if ((struct vnode
*)dnTemp
== dnTemp
->volume
)
2652 fullName
[partLen
] = ':'; /* Root of Ram Disk */
2654 fullName
[partLen
] = '/'; /* Replace 0 with '/' */
2660 ADD2INITLIB(GM_UNIQUENAME(Init
),0)
2661 ADD2OPENDEV(GM_UNIQUENAME(Open
),0)
2662 ADD2CLOSEDEV(GM_UNIQUENAME(Close
),0)
2663 ADD2EXPUNGELIB(GM_UNIQUENAME(Expunge
),0)