Kernel/arch - Fix common division macro to handle numerators around datatype max
[tpg/acess2.git] / KernelLand / Kernel / vfs / io.c
1 /*
2  * Acess2 Kernel
3  * - By John Hodge (thePowersGang)
4  *
5  * vfs/io.c
6  * - VFS IO Handling (Read/Write)
7  *
8  * TODO: VFS-level caching to support non-blocking IO?
9  */
10 #define DEBUG   0
11 #include <acess.h>
12 #include <vfs.h>
13 #include <vfs_ext.h>
14 #include <vfs_int.h>
15
16 // === CODE ===
17 /**
18  * \fn Uint64 VFS_Read(int FD, Uint64 Length, void *Buffer)
19  * \brief Read data from a node (file)
20  */
21 size_t VFS_Read(int FD, size_t Length, void *Buffer)
22 {
23         tVFS_Handle     *h;
24         size_t  ret;
25         
26         h = VFS_GetHandle(FD);
27         if(!h) {
28                 LOG("FD%i is a bad Handle", FD);
29                 return -1;
30         }
31         
32         if( !(h->Mode & VFS_OPENFLAG_READ) ) {
33                 LOG("FD%i not open for reading", FD);
34                 return -1;
35         }
36         if( (h->Node->Flags & VFS_FFLAG_DIRECTORY) ) {
37                 LOG("FD%i is a directory", FD);
38                 return -1;
39         }
40
41         if(!h->Node->Type || !h->Node->Type->Read) {
42                 LOG("FD%i has no read method", FD);
43                 return -1;
44         }
45
46         if( !MM_GetPhysAddr(h->Node->Type->Read) ) {
47                 Log_Error("VFS", "Node type %p(%s) read method is junk %p",
48                         h->Node->Type, h->Node, h->Node->Type->TypeName,
49                         h->Node->Type->Read);
50                 return -1;
51         }
52         
53         Uint    flags = 0;
54         flags |= (h->Mode & VFS_OPENFLAG_NONBLOCK) ? VFS_IOFLAG_NOBLOCK : 0;
55         ret = h->Node->Type->Read(h->Node, h->Position, Length, Buffer, flags);
56         if(ret != Length)       LOG("%i/%i read", ret, Length);
57         if(ret == (size_t)-1)   return -1;
58         
59         h->Position += ret;
60         return ret;
61 }
62
63 /**
64  * \fn Uint64 VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer)
65  * \brief Read data from a given offset (atomic)
66  */
67 size_t VFS_ReadAt(int FD, Uint64 Offset, size_t Length, void *Buffer)
68 {
69         tVFS_Handle     *h;
70         size_t  ret;
71         
72         h = VFS_GetHandle(FD);
73         if(!h)  return -1;
74         
75         if( !(h->Mode & VFS_OPENFLAG_READ) )    return -1;
76         if( h->Node->Flags & VFS_FFLAG_DIRECTORY )      return -1;
77
78         if( !h->Node->Type || !h->Node->Type->Read) {
79                 Warning("VFS_ReadAt - Node %p, does not have a read method", h->Node);
80                 return 0;
81         }
82
83         if( !MM_GetPhysAddr(h->Node->Type->Read) ) {
84                 Log_Error("VFS", "Node type %p(%s) read method is junk %p",
85                         h->Node->Type, h->Node->Type->TypeName,
86                         h->Node->Type->Read);
87         }
88         
89         Uint    flags = 0;
90         flags |= (h->Mode & VFS_OPENFLAG_NONBLOCK) ? VFS_IOFLAG_NOBLOCK : 0;
91         ret = h->Node->Type->Read(h->Node, Offset, Length, Buffer, flags);
92         if(ret != Length)       LOG("%i/%i read", ret, Length);
93         if(ret == (size_t)-1)   return -1;
94         return ret;
95 }
96
97 /**
98  * \fn Uint64 VFS_Write(int FD, Uint64 Length, const void *Buffer)
99  * \brief Read data from a node (file)
100  */
101 size_t VFS_Write(int FD, size_t Length, const void *Buffer)
102 {
103         tVFS_Handle     *h;
104         size_t  ret;
105         
106         h = VFS_GetHandle(FD);
107         if(!h) {
108                 LOG("FD%i is not open", FD);
109                 errno = EBADF;
110                 return -1;
111         }
112         
113         if( !(h->Mode & VFS_OPENFLAG_WRITE) ) {
114                 LOG("FD%i not opened for writing", FD);
115                 errno = EBADF;
116                 return -1;
117         }
118         if( h->Node->Flags & VFS_FFLAG_DIRECTORY ) {
119                 LOG("FD%i is a directory", FD);
120                 errno = EISDIR;
121                 return -1;
122         }
123
124         if( !h->Node->Type || !h->Node->Type->Write ) {
125                 LOG("FD%i has no write method", FD);
126                 errno = EINTERNAL;
127                 return 0;
128         }
129
130         if( !MM_GetPhysAddr(h->Node->Type->Write) ) {
131                 Log_Error("VFS", "Node type %p(%s) write method is junk %p",
132                         h->Node->Type, h->Node->Type->TypeName,
133                         h->Node->Type->Write);
134                 errno = EINTERNAL;
135                 return -1;
136         }
137         
138         Uint flags = 0;
139         flags |= (h->Mode & VFS_OPENFLAG_NONBLOCK) ? VFS_IOFLAG_NOBLOCK : 0;
140         ret = h->Node->Type->Write(h->Node, h->Position, Length, Buffer, flags);
141         if(ret != Length)       LOG("%i/%i written", ret, Length);
142         if(ret == (size_t)-1)   return -1;
143
144         h->Position += ret;
145         return ret;
146 }
147
148 /**
149  * \fn Uint64 VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, const void *Buffer)
150  * \brief Write data to a file at a given offset
151  */
152 size_t VFS_WriteAt(int FD, Uint64 Offset, size_t Length, const void *Buffer)
153 {
154         tVFS_Handle     *h;
155         size_t  ret;
156         
157         h = VFS_GetHandle(FD);
158         if(!h)  return -1;
159         
160         if( !(h->Mode & VFS_OPENFLAG_WRITE) )   return -1;
161         if( h->Node->Flags & VFS_FFLAG_DIRECTORY )      return -1;
162
163         if(!h->Node->Type || !h->Node->Type->Write)     return 0;
164
165         if( !MM_GetPhysAddr(h->Node->Type->Write) ) {
166                 Log_Error("VFS", "Node type %p(%s) write method is junk %p",
167                         h->Node->Type, h->Node->Type->TypeName,
168                         h->Node->Type->Write);
169                 return -1;
170         }
171         Uint flags = 0;
172         flags |= (h->Mode & VFS_OPENFLAG_NONBLOCK) ? VFS_IOFLAG_NOBLOCK : 0;
173         ret = h->Node->Type->Write(h->Node, Offset, Length, Buffer, flags);
174         if(ret == (size_t)-1)   return -1;
175         return ret;
176 }
177
178 /**
179  * \fn Uint64 VFS_Tell(int FD)
180  * \brief Returns the current file position
181  */
182 Uint64 VFS_Tell(int FD)
183 {
184         tVFS_Handle     *h;
185         
186         h = VFS_GetHandle(FD);
187         if(!h)  return -1;
188         
189         return h->Position;
190 }
191
192 /**
193  * \fn int VFS_Seek(int FD, Sint64 Offset, int Whence)
194  * \brief Seek to a new location
195  * \param FD    File descriptor
196  * \param Offset        Where to go
197  * \param Whence        From where
198  */
199 int VFS_Seek(int FD, Sint64 Offset, int Whence)
200 {
201         tVFS_Handle     *h;
202         
203         h = VFS_GetHandle(FD);
204         if(!h)  return -1;
205         
206         // Set relative to current position
207         if(Whence == 0) {
208                 LOG("(FD%x)->Position += %lli", FD, Offset);
209                 h->Position += Offset;
210                 return 0;
211         }
212         
213         // Set relative to end of file
214         if(Whence < 0) {
215                 if( h->Node->Size == (Uint64)-1 )       return -1;
216
217                 LOG("(FD%x)->Position = %llx - %llx", FD, h->Node->Size, Offset);
218                 h->Position = h->Node->Size - Offset;
219                 return 0;
220         }
221         
222         // Set relative to start of file
223         LOG("(FD%x)->Position = %llx", FD, Offset);
224         h->Position = Offset;
225         return 0;
226 }
227
228 /**
229  * \fn int VFS_IOCtl(int FD, int ID, void *Buffer)
230  * \brief Call an IO Control on a file
231  */
232 int VFS_IOCtl(int FD, int ID, void *Buffer)
233 {
234         tVFS_Handle     *h;
235         
236         h = VFS_GetHandle(FD);
237         if(!h) {
238                 LOG("FD%i is invalid", FD);
239                 errno = EINVAL;
240                 return -1;
241         }
242
243         if(!h->Node->Type || !h->Node->Type->IOCtl) {
244                 LOG("FD%i does not have an IOCtl method");
245                 errno = EINVAL;
246                 return -1;
247         }
248         return h->Node->Type->IOCtl(h->Node, ID, Buffer);
249 }
250
251 /**
252  * \fn int VFS_FInfo(int FD, tFInfo *Dest, int MaxACLs)
253  * \brief Retrieve file information
254  * \return Number of ACLs stored
255  */
256 int VFS_FInfo(int FD, tFInfo *Dest, int MaxACLs)
257 {
258         tVFS_Handle     *h;
259          int    max;
260         
261         h = VFS_GetHandle(FD);
262         if(!h)  return -1;
263
264         if( h->Mount )
265                 Dest->mount = h->Mount->Identifier;
266         else
267                 Dest->mount = 0;
268         Dest->inode = h->Node->Inode;   
269         Dest->uid = h->Node->UID;
270         Dest->gid = h->Node->GID;
271         Dest->size = h->Node->Size;
272         Dest->atime = h->Node->ATime;
273         Dest->ctime = h->Node->MTime;
274         Dest->mtime = h->Node->CTime;
275         Dest->numacls = h->Node->NumACLs;
276         
277         Dest->flags = 0;
278         if(h->Node->Flags & VFS_FFLAG_DIRECTORY)        Dest->flags |= 0x10;
279         if(h->Node->Flags & VFS_FFLAG_SYMLINK)  Dest->flags |= 0x20;
280         
281         max = (MaxACLs < h->Node->NumACLs) ? MaxACLs : h->Node->NumACLs;
282         memcpy(&Dest->acls, h->Node->ACLs, max*sizeof(tVFS_ACL));
283         
284         return max;
285 }
286
287 // === EXPORTS ===
288 EXPORT(VFS_Read);
289 EXPORT(VFS_Write);
290 EXPORT(VFS_ReadAt);
291 EXPORT(VFS_WriteAt);
292 EXPORT(VFS_IOCtl);
293 EXPORT(VFS_Seek);
294 EXPORT(VFS_Tell);

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