Added some very pedantic warning flags
[tpg/acess2.git] / Kernel / drv / fifo.c
1 /* AcessOS
2  * FIFO Pipe Driver
3  */
4 #include <acess.h>
5 #include <modules.h>
6 #include <fs_devfs.h>
7 #include <semaphore.h>
8
9 // === CONSTANTS ===
10 #define DEFAULT_RING_SIZE       2048
11 #define PF_BLOCKING             1
12
13 // === TYPES ===
14 typedef struct sPipe {
15         struct sPipe    *Next;
16         char    *Name;
17         tVFS_Node       Node;
18         Uint    Flags;
19          int    ReadPos;
20          int    WritePos;
21          int    BufSize;
22         char    *Buffer;
23         tSemaphore      Semaphore;
24 } tPipe;
25
26 // === PROTOTYPES ===
27  int    FIFO_Install(char **Arguments);
28  int    FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data);
29 char    *FIFO_ReadDir(tVFS_Node *Node, int Id);
30 tVFS_Node       *FIFO_FindDir(tVFS_Node *Node, const char *Filename);
31  int    FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
32 void    FIFO_Close(tVFS_Node *Node);
33  int    FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
34 Uint64  FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
35 Uint64  FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
36 tPipe   *FIFO_Int_NewPipe(int Size, const char *Name);
37
38 // === GLOBALS ===
39 MODULE_DEFINE(0, 0x0032, FIFO, FIFO_Install, NULL, NULL);
40 tDevFS_Driver   gFIFO_DriverInfo = {
41         NULL, "fifo",
42         {
43         .Size = 1,
44         .NumACLs = 1,
45         .ACLs = &gVFS_ACL_EveryoneRW,
46         .Flags = VFS_FFLAG_DIRECTORY,
47         .ReadDir = FIFO_ReadDir,
48         .FindDir = FIFO_FindDir,
49         .MkNod = FIFO_MkNod,
50         .Relink = FIFO_Relink,
51         .IOCtl = FIFO_IOCtl
52         }
53 };
54 tVFS_Node       gFIFO_AnonNode = {
55         .NumACLs = 1,
56         .ACLs = &gVFS_ACL_EveryoneRW,
57         };
58 tPipe   *gFIFO_NamedPipes = NULL;
59
60 // === CODE ===
61 /**
62  * \fn int FIFO_Install(char **Options)
63  * \brief Installs the FIFO Driver
64  */
65 int FIFO_Install(char **Options)
66 {
67         DevFS_AddDevice( &gFIFO_DriverInfo );
68         return MODULE_ERR_OK;
69 }
70
71 /**
72  * \fn int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data)
73  */
74 int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data)
75 {
76         return 0;
77 }
78
79 /**
80  * \fn char *FIFO_ReadDir(tVFS_Node *Node, int Id)
81  * \brief Reads from the FIFO root
82  */
83 char *FIFO_ReadDir(tVFS_Node *Node, int Id)
84 {
85         tPipe   *tmp = gFIFO_NamedPipes;
86         
87         // Entry 0 is Anon Pipes
88         if(Id == 0)     return strdup("anon");
89         
90         // Find the id'th node
91         while(--Id && tmp)      tmp = tmp->Next;
92         // If node found, return it
93         if(tmp) return strdup(tmp->Name);
94         // else error return
95         return NULL;
96 }
97
98 /**
99  * \fn tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename)
100  * \brief Find a file in the FIFO root
101  * \note Creates an anon pipe if anon is requested
102  */
103 tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename)
104 {
105         tPipe   *tmp;
106         if(!Filename)   return NULL;
107         
108         // NULL String Check
109         if(Filename[0] == '\0') return NULL;
110         
111         // Anon Pipe
112         if(Filename[0] == 'a' && Filename[1] == 'n'
113         && Filename[2] == 'o' && Filename[3] == 'n'
114         && Filename[4] == '\0') {
115                 tmp = FIFO_Int_NewPipe(DEFAULT_RING_SIZE, "anon");
116                 return &tmp->Node;
117         }
118         
119         // Check Named List
120         tmp = gFIFO_NamedPipes;
121         while(tmp)
122         {
123                 if(strcmp(tmp->Name, Filename) == 0)
124                         return &tmp->Node;
125                 tmp = tmp->Next;
126         }
127         return NULL;
128 }
129
130 /**
131  * \fn int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
132  */
133 int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
134 {
135         return 0;
136 }
137
138 /**
139  * \fn void FIFO_Close(tVFS_Node *Node)
140  * \brief Close a FIFO end
141  */
142 void FIFO_Close(tVFS_Node *Node)
143 {
144         tPipe   *pipe;
145         if(!Node->ImplPtr)      return ;
146         
147         Node->ReferenceCount --;
148         if(Node->ReferenceCount)        return ;
149         
150         pipe = Node->ImplPtr;
151         
152         if(strcmp(pipe->Name, "anon") == 0) {
153                 free(Node->ImplPtr);
154                 return ;
155         }
156         
157         return ;
158 }
159
160 /**
161  * \fn int FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
162  * \brief Relink a file (Deletes named pipes)
163  */
164 int FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
165 {
166         tPipe   *pipe, *tmp;
167         
168         if(Node != &gFIFO_DriverInfo.RootNode)  return 0;
169         
170         // Can't relink anon
171         if(strcmp(OldName, "anon"))     return 0;
172         
173         // Find node
174         for(pipe = gFIFO_NamedPipes;
175                 pipe;
176                 pipe = pipe->Next)
177         {
178                 if(strcmp(pipe->Name, OldName) == 0)
179                         break;
180         }
181         if(!pipe)       return 0;
182         
183         // Relink a named pipe
184         if(NewName) {
185                 // Check new name
186                 for(tmp = gFIFO_NamedPipes;
187                         tmp;
188                         tmp = tmp->Next)
189                 {
190                         if(strcmp(tmp->Name, NewName) == 0)     return 0;
191                 }
192                 // Create new name
193                 free(pipe->Name);
194                 pipe->Name = malloc(strlen(NewName)+1);
195                 strcpy(pipe->Name, NewName);
196                 return 1;
197         }
198         
199         // Unlink the pipe
200         if(Node->ImplPtr) {
201                 free(Node->ImplPtr);
202                 return 1;
203         }
204         
205         return 0;
206 }
207
208 /**
209  * \fn Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
210  * \brief Read from a fifo pipe
211  */
212 Uint64 FIFO_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
213 {
214         tPipe   *pipe = Node->ImplPtr;
215         Uint    len;
216         Uint    remaining = Length;
217         
218         if(!pipe)       return 0;
219         
220         while(remaining)
221         {
222                 // Wait for buffer to fill
223                 if(pipe->Flags & PF_BLOCKING)
224                 {
225                         len = Semaphore_Wait( &pipe->Semaphore, remaining );
226                 }
227                 else
228                 {
229                         if(pipe->ReadPos == pipe->WritePos)
230                                 return 0;
231                         // Read buffer
232                         if(pipe->WritePos - pipe->ReadPos < remaining)
233                                 len = pipe->WritePos - pipe->ReadPos;
234                         else
235                                 len = remaining;
236                 }
237                 
238                 // Check if read overflows buffer
239                 if(len > pipe->BufSize - pipe->ReadPos)
240                 {
241                         int ofs = pipe->BufSize - pipe->ReadPos;
242                         memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], ofs);
243                         memcpy((Uint8*)Buffer + ofs, &pipe->Buffer, len-ofs);
244                 }
245                 else
246                 {
247                         memcpy(Buffer, &pipe->Buffer[pipe->ReadPos], len);
248                 }
249                 
250                 // Increment read position
251                 pipe->ReadPos += len;
252                 pipe->ReadPos %= pipe->BufSize;
253                 
254                 // Decrement Remaining Bytes
255                 remaining -= len;
256                 // Increment Buffer address
257                 Buffer = (Uint8*)Buffer + len;
258         }
259
260         return Length;
261
262 }
263
264 /**
265  * \fn Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
266  * \brief Write to a fifo pipe
267  */
268 Uint64 FIFO_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
269 {
270         tPipe   *pipe = Node->ImplPtr;
271         Uint    len;
272         Uint    remaining = Length;
273         
274         if(!pipe)       return 0;
275         
276         while(remaining)
277         {
278                 // Wait for buffer to empty
279                 if(pipe->Flags & PF_BLOCKING) {
280                         len = Semaphore_Signal( &pipe->Semaphore, remaining );
281                 }
282                 else
283                 {
284                         if(pipe->ReadPos == (pipe->WritePos+1)%pipe->BufSize)
285                                 return 0;
286                         // Write buffer
287                         if(pipe->ReadPos - pipe->WritePos < remaining)
288                                 len = pipe->ReadPos - pipe->WritePos;
289                         else
290                                 len = remaining;
291                 }
292                 
293                 // Check if write overflows buffer
294                 if(len > pipe->BufSize - pipe->WritePos)
295                 {
296                         int ofs = pipe->BufSize - pipe->WritePos;
297                         memcpy(&pipe->Buffer[pipe->WritePos], Buffer, ofs);
298                         memcpy(&pipe->Buffer, (Uint8*)Buffer + ofs, len-ofs);
299                 }
300                 else
301                 {
302                         memcpy(&pipe->Buffer[pipe->WritePos], Buffer, len);
303                 }
304                 
305                 // Increment read position
306                 pipe->WritePos += len;
307                 pipe->WritePos %= pipe->BufSize;
308                 
309                 // Decrement Remaining Bytes
310                 remaining -= len;
311                 // Increment Buffer address
312                 Buffer = (Uint8*)Buffer + len;
313         }
314
315         return Length;
316 }
317
318 // --- HELPERS ---
319 /**
320  * \fn tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
321  * \brief Create a new pipe
322  */
323 tPipe *FIFO_Int_NewPipe(int Size, const char *Name)
324 {
325         tPipe   *ret;
326          int    namelen = strlen(Name) + 1;
327          int    allocsize = sizeof(tPipe) + sizeof(tVFS_ACL) + Size + namelen;
328         
329         ret = malloc(allocsize);
330         if(!ret)        return NULL;
331         
332         // Clear Return
333         memset(ret, 0, allocsize);
334         ret->Flags = PF_BLOCKING;
335         
336         // Allocate Buffer
337         ret->BufSize = Size;
338         ret->Buffer = (void*)( (Uint)ret + sizeof(tPipe) + sizeof(tVFS_ACL) );
339         
340         // Set name (and FIFO name)
341         ret->Name = ret->Buffer + Size;
342         strcpy(ret->Name, Name);
343         // - Start empty, max of `Size`
344         Semaphore_Init( &ret->Semaphore, 0, Size, "FIFO", ret->Name );
345         
346         // Set Node
347         ret->Node.Size = 0;
348         ret->Node.ImplPtr = ret;
349         ret->Node.UID = Threads_GetUID();
350         ret->Node.GID = Threads_GetGID();
351         ret->Node.NumACLs = 1;
352         ret->Node.ACLs = (void*)( (Uint)ret + sizeof(tPipe) );
353                 ret->Node.ACLs->Group = 0;
354                 ret->Node.ACLs->ID = ret->Node.UID;
355                 ret->Node.ACLs->Inv = 0;
356                 ret->Node.ACLs->Perms = -1;
357         ret->Node.CTime
358                 = ret->Node.MTime
359                 = ret->Node.ATime = now();
360         ret->Node.Read = FIFO_Read;
361         ret->Node.Write = FIFO_Write;
362         ret->Node.Close = FIFO_Close;
363         
364         return ret;
365 }

UCC git Repository :: git.ucc.asn.au