3 * - By John Hodge (thePowersGang)
6 * - VFS IO Handling (Read/Write)
8 * TODO: VFS-level caching to support non-blocking IO?
18 * \fn Uint64 VFS_Read(int FD, Uint64 Length, void *Buffer)
19 * \brief Read data from a node (file)
21 size_t VFS_Read(int FD, size_t Length, void *Buffer)
26 h = VFS_GetHandle(FD);
28 LOG("FD%i is a bad Handle", FD);
32 if( !(h->Mode & VFS_OPENFLAG_READ) ) {
33 LOG("FD%i not open for reading", FD);
36 if( (h->Node->Flags & VFS_FFLAG_DIRECTORY) ) {
37 LOG("FD%i is a directory", FD);
41 if(!h->Node->Type || !h->Node->Type->Read) {
42 LOG("FD%i has no read method", FD);
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,
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;
64 * \fn Uint64 VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer)
65 * \brief Read data from a given offset (atomic)
67 size_t VFS_ReadAt(int FD, Uint64 Offset, size_t Length, void *Buffer)
72 h = VFS_GetHandle(FD);
75 if( !(h->Mode & VFS_OPENFLAG_READ) ) return -1;
76 if( h->Node->Flags & VFS_FFLAG_DIRECTORY ) return -1;
78 if( !h->Node->Type || !h->Node->Type->Read) {
79 Warning("VFS_ReadAt - Node %p, does not have a read method", h->Node);
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,
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;
98 * \fn Uint64 VFS_Write(int FD, Uint64 Length, const void *Buffer)
99 * \brief Read data from a node (file)
101 size_t VFS_Write(int FD, size_t Length, const void *Buffer)
103 tVFS_Handle *h = VFS_GetHandle(FD);
105 LOG("FD%i is not open", FD);
110 size_t ret = VFS_WriteAt(FD, h->Position, Length, Buffer);
111 if(ret == (size_t)-1) return -1;
113 if( !(h->Node->Type->Flags & VFS_NODETYPEFLAG_STREAM) )
119 * \fn Uint64 VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, const void *Buffer)
120 * \brief Write data to a file at a given offset
122 size_t VFS_WriteAt(int FD, Uint64 Offset, size_t Length, const void *Buffer)
124 LOG("FD=%i,Offset=%lli,Length=%i,Buffer=%p",
125 FD, Offset, Length, Buffer);
126 tVFS_Handle *h = VFS_GetHandle(FD);
129 if( !(h->Mode & VFS_OPENFLAG_WRITE) ) {
130 LOG("FD%i not opened for writing", FD);
134 if( h->Node->Flags & VFS_FFLAG_DIRECTORY ) {
135 LOG("FD%i is a directory", FD);
140 const tVFS_NodeType* nodetype = h->Node->Type;
141 if(!nodetype || !nodetype->Write) {
142 LOG("FD%i has no write method", FD);
147 if( !MM_GetPhysAddr(nodetype->Write) ) {
148 Log_Error("VFS", "Node type %p(%s) write method is junk %p",
149 nodetype, nodetype->TypeName, nodetype->Write);
155 if( h->Node->Size != (Uint64)-1 && Offset > h->Node->Size ) {
156 Log_Notice("VFS", "Write starting past EOF of FD%x (%lli > %lli)",
157 FD, Offset, h->Node->Size);
161 if( Offset + Length > h->Node->Size )
164 if( !nodetype->Truncate )
166 LOG("No .Truncate method, emiting write past EOF");
168 else if( nodetype->Flags & VFS_NODETYPEFLAG_NOAUTOEXPAND )
170 LOG("NOAUTOEXPAND set, truncating length from %i to %i",
171 Length, h->Node->Size - Offset);
172 Length = h->Node->Size - Offset;
174 else if( nodetype->Truncate(h->Node, Offset + Length) != Offset + Length )
176 // oh... fail? Truncate to current size
177 LOG(".Truncate failed, truncating length from %i to %i",
178 Length, h->Node->Size - Offset);
179 Length = h->Node->Size - Offset;
183 // Expansion, node size should now fit
184 LOG("Expanded file");
190 flags |= (h->Mode & VFS_OPENFLAG_NONBLOCK) ? VFS_IOFLAG_NOBLOCK : 0;
192 // Dispatch the read!
193 size_t ret = nodetype->Write(h->Node, Offset, Length, Buffer, flags);
194 if(ret == (size_t)-1) return -1;
195 if(ret != Length) LOG("%i/%i written", ret, Length);
201 * \fn Uint64 VFS_Tell(int FD)
202 * \brief Returns the current file position
204 Uint64 VFS_Tell(int FD)
208 h = VFS_GetHandle(FD);
215 * \fn int VFS_Seek(int FD, Sint64 Offset, int Whence)
216 * \brief Seek to a new location
217 * \param FD File descriptor
218 * \param Offset Where to go
219 * \param Whence From where
221 int VFS_Seek(int FD, Sint64 Offset, int Whence)
223 tVFS_Handle *h = VFS_GetHandle(FD);
226 if( (h->Node->Type->Flags & VFS_NODETYPEFLAG_STREAM) ) {
227 LOG("Seeking in stream");
231 // Set relative to current position
233 LOG("(FD%x)->Position += %lli", FD, Offset);
234 h->Position += Offset;
238 // Set relative to end of file
240 if( h->Node->Size == (Uint64)-1 ) return -1;
242 LOG("(FD%x)->Position = %llx - %llx", FD, h->Node->Size, Offset);
243 h->Position = h->Node->Size - Offset;
247 // Set relative to start of file
248 LOG("(FD%x)->Position = %llx", FD, Offset);
249 h->Position = Offset;
254 * Truncate/Expand a file's allocation
256 off_t VFS_Truncate(int FD, off_t Size)
258 tVFS_Handle *h = VFS_GetHandle(FD);
264 if( !h->Node->Type->Truncate)
266 Log_Notice("VFS", "Nodetype '%s' doesn't have a Truncate method", h->Node->Type->TypeName);
271 return h->Node->Type->Truncate(h->Node, Size);
275 * \fn int VFS_IOCtl(int FD, int ID, void *Buffer)
276 * \brief Call an IO Control on a file
278 int VFS_IOCtl(int FD, int ID, void *Buffer)
280 tVFS_Handle *h = VFS_GetHandle(FD);
282 LOG("FD%i is invalid", FD);
287 if(!h->Node->Type || !h->Node->Type->IOCtl) {
288 LOG("FD%i does not have an IOCtl method");
292 return h->Node->Type->IOCtl(h->Node, ID, Buffer);
296 * \fn int VFS_FInfo(int FD, tFInfo *Dest, int MaxACLs)
297 * \brief Retrieve file information
298 * \return Number of ACLs stored
300 int VFS_FInfo(int FD, tFInfo *Dest, int MaxACLs)
305 h = VFS_GetHandle(FD);
309 Dest->mount = h->Mount->Identifier;
312 Dest->inode = h->Node->Inode;
313 Dest->uid = h->Node->UID;
314 Dest->gid = h->Node->GID;
315 Dest->size = h->Node->Size;
316 Dest->atime = h->Node->ATime;
317 Dest->ctime = h->Node->MTime;
318 Dest->mtime = h->Node->CTime;
319 Dest->numacls = h->Node->NumACLs;
322 if(h->Node->Flags & VFS_FFLAG_DIRECTORY) Dest->flags |= 0x10;
323 if(h->Node->Flags & VFS_FFLAG_SYMLINK) Dest->flags |= 0x20;
325 max = (MaxACLs < h->Node->NumACLs) ? MaxACLs : h->Node->NumACLs;
326 memcpy(&Dest->acls, h->Node->ACLs, max*sizeof(tVFS_ACL));