2024-05-18 07:42:01 +03:00

379 lines
8.9 KiB
C

/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __FENNIX_API_FILESYSTEM_H__
#define __FENNIX_API_FILESYSTEM_H__
#ifdef __kernel__
#include <types.h>
#endif
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
/**
* File type mask for the upper 32 bits of mode_t.
*
* @note Maybe it will be used in the future.
*/
#define S_IFMT32 037777600000
/**
* File type mask.
*
* This mask is used to extract the file type
* from the mode field of a stat structure.
*
* Doing bitwise AND with this mask will return
* the file type.
* Example: st_mode & S_IFMT
*
* Doing bitwise negation and AND with this mask
* will return the permissions.
* Example: st_mode & ~S_IFMT
*/
#define S_IFMT 0170000
/* Whiteout */
#define S_IFWHT 0160000
/* Socket */
#define S_IFSOCK 0140000
/* Symbolic link */
#define S_IFLNK 0120000
/* Regular file */
#define S_IFREG 0100000
/* Block device */
#define S_IFBLK 0060000
/* Directory */
#define S_IFDIR 0040000
/* Character device */
#define S_IFCHR 0020000
/* FIFO */
#define S_IFIFO 0010000
#define S_ISUID 04000
#define S_ISGID 02000
#define S_ISVTX 01000
/** Owner: RWX */
#define S_IRWXU 0700
/** Owner: R */
#define S_IRUSR 0400
/** Owner: W */
#define S_IWUSR 0200
/** Owner: X */
#define S_IXUSR 0100
/** Group: RWX */
#define S_IRWXG 0070
/** Group: R */
#define S_IRGRP 0040
/** Group: W */
#define S_IWGRP 0020
/** Group: X */
#define S_IXGRP 0010
/** Other: RWX */
#define S_IRWXO 0007
/** Other: R */
#define S_IROTH 0004
/** Other: W */
#define S_IWOTH 0002
/** Other: X */
#define S_IXOTH 0001
#define O_RDONLY 00
#define O_WRONLY 01
#define O_RDWR 02
#define O_CREAT 0100
#define O_EXCL 0200
#define O_TRUNC 01000
#define O_APPEND 02000
#define O_NOFOLLOW 0400000
#define O_CLOEXEC 02000000
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
#define DT_UNKNOWN 0x0
#define DT_FIFO 0x1
#define DT_CHR 0x2
#define DT_DIR 0x4
#define DT_BLK 0x6
#define DT_REG 0x8
#define DT_LNK 0xA
#define DT_SOCK 0xC
#define DT_WHT 0xE
#define IFTODT(x) ((x) >> 12 & 0xF)
#define DTTOIF(x) ((x) << 12)
#define SYMLOOP_MAX 40
#ifndef __cplusplus
#define static_assert _Static_assert
#endif
#ifdef __LP64__
static_assert(sizeof(dev_t) == 8, "dev_t must be 64 bits");
static_assert(sizeof(ino_t) == 8, "ino_t must be 64 bits");
static_assert(sizeof(mode_t) == 4, "mode_t must be 32 bits");
static_assert(sizeof(nlink_t) == 4, "nlink_t must be 32 bits");
static_assert(sizeof(uid_t) == 4, "uid_t must be 32 bits");
static_assert(sizeof(gid_t) == 4, "gid_t must be 32 bits");
static_assert(sizeof(off_t) == 8, "off_t must be 64 bits");
static_assert(sizeof(time_t) == 8, "time_t must be 64 bits");
static_assert(sizeof(blksize_t) == 8, "blksize_t must be 64 bits");
static_assert(sizeof(blkcnt_t) == 8, "blkcnt_t must be 64 bits");
#else
static_assert(sizeof(dev_t) == 4, "dev_t must be 32 bits");
static_assert(sizeof(ino_t) == 4, "ino_t must be 32 bits");
static_assert(sizeof(mode_t) == 2, "mode_t must be 16 bits");
static_assert(sizeof(nlink_t) == 2, "nlink_t must be 16 bits");
static_assert(sizeof(uid_t) == 2, "uid_t must be 16 bits");
static_assert(sizeof(gid_t) == 2, "gid_t must be 16 bits");
static_assert(sizeof(off_t) == 4, "off_t must be 32 bits");
static_assert(sizeof(time_t) == 4, "time_t must be 32 bits");
static_assert(sizeof(blksize_t) == 4, "blksize_t must be 32 bits");
static_assert(sizeof(blkcnt_t) == 4, "blkcnt_t must be 32 bits");
#endif
#undef static_assert
struct kstat
{
/** Device ID of the file. */
dev_t Device;
/** Inode number. */
ino_t Index;
/** File type and mode. */
mode_t Mode;
/** Number of hard links. */
nlink_t HardLinks;
/** User ID of the file's owner. */
uid_t UserID;
/** Group ID of the file's owner. */
gid_t GroupID;
/** Device ID for special files. */
dev_t RawDevice;
/** Size of the file in bytes. */
off_t Size;
/** Time of last access. */
time_t AccessTime;
/** Time of last modification. */
time_t ModifyTime;
/** Time of last status change. */
time_t ChangeTime;
/** Optimal I/O block size. */
blksize_t BlockSize;
/** Number of blocks allocated. */
blkcnt_t Blocks;
/** Additional file attributes. */
mode_t Attribute;
#ifdef __cplusplus
dev_t MakeDevice(int Major, int Minor)
{
return ((Major & 0xFFF) << 8) |
(Minor & 0xFF);
}
int GetMajor()
{
return ((unsigned int)(Device) >> 8) & 0xFFF;
}
int GetMinor()
{
return Device & 0xFF;
}
void SetFileType(mode_t Type)
{
Mode = (Mode & ~S_IFMT) |
(Type & S_IFMT);
}
mode_t GetFileType() { return Mode & S_IFMT; }
void ClearFileType() { Mode = Mode & ~S_IFMT; }
bool IsType(mode_t Type) { return (Mode & S_IFMT) == Type; }
void SetPermissions(mode_t Permissions)
{
Mode = (Mode & S_IFMT) |
(Permissions & ~S_IFMT);
}
mode_t GetPermissions() { return Mode & ~S_IFMT; }
void ClearPermissions() { Mode = Mode & S_IFMT; }
#endif // __cplusplus
};
struct kdirent
{
ino_t d_ino;
off_t d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[];
};
struct InodeOperations
{
int (*Lookup)(struct Inode *Parent, const char *Name, struct Inode **Result);
int (*Create)(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result);
int (*Remove)(struct Inode *Parent, const char *Name);
int (*Rename)(struct Inode *Parent, const char *OldName, const char *NewName);
ssize_t (*Read)(struct Inode *Node, void *Buffer, size_t Size, off_t Offset);
ssize_t (*Write)(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset);
int (*Truncate)(struct Inode *Node, off_t Size);
int (*Open)(struct Inode *Node, int Flags, mode_t Mode);
int (*Close)(struct Inode *Node);
int (*Ioctl)(struct Inode *Node, unsigned long Request, void *Argp);
ssize_t (*ReadDir)(struct Inode *Node, struct kdirent *Buffer, size_t Size, off_t Offset, off_t Entries);
int (*MkDir)(struct Inode *Parent, const char *Name, mode_t Mode, struct Inode **Result);
int (*RmDir)(struct Inode *Parent, const char *Name);
int (*SymLink)(struct Inode *Parent, const char *Name, const char *Target, struct Inode **Result);
ssize_t (*ReadLink)(struct Inode *Node, char *Buffer, size_t Size);
off_t (*Seek)(struct Inode *Node, off_t Offset);
int (*Stat)(struct Inode *Node, struct kstat *Stat);
} __attribute__((packed));
#define I_FLAG_MOUNTPOINT 0x1
#define I_FLAG_CACHE_KEEP 0x2
struct Inode
{
dev_t Device, RawDevice;
ino_t Index;
mode_t Mode;
uint32_t Flags;
off_t Offset;
void *PrivateData;
#ifdef __cplusplus
/* ... */
void SetDevice(int Major, int Minor)
{
this->RawDevice = ((Major & 0xFFF) << 8) |
(Minor & 0xFF);
}
int GetMajor()
{
return ((unsigned int)(this->RawDevice) >> 8) & 0xFFF;
}
int GetMinor()
{
return this->RawDevice & 0xFF;
}
Inode()
{
Index = 0;
Mode = 0;
Device = 0;
RawDevice = 0;
Flags = 0;
PrivateData = nullptr;
}
~Inode() = default;
#else // __cplusplus
#define INODE_MAKEDEV(major, minor) \
((dev_t)(((major & 0xFFF) << 8) | \
(minor & 0xFF)))
#define INODE_MAJOR(rdev) \
((int)(((rdev) >> 8) & 0xFFF))
#define INODE_MINOR(rdev) \
((int)((rdev) & 0xFF))
#endif // __cplusplus
};
struct SuperBlockOperations
{
int (*AllocateInode)(struct FileSystemInfo *Info, struct Inode **Result);
int (*DeleteInode)(struct FileSystemInfo *Info, struct Inode *Node);
/**
* Synchronize the filesystem.
*
* Write all pending changes to the disk.
*
* @param Info Inode to synchronize. If NULL, synchronize all inodes.
*
* @return Zero on success, otherwise an error code.
*/
int (*Synchronize)(struct FileSystemInfo *Info, struct Inode *Node);
/**
* Destroy the filesystem.
*
* Unregister the filesystem and free all resources.
*
* @param Info Filesystem to destroy.
*
* @return Zero on success, otherwise an error code.
*/
int (*Destroy)(FileSystemInfo *Info);
} __attribute__((packed));
struct FileSystemInfo
{
const char *Name;
int Flags;
struct SuperBlockOperations SuperOps;
struct InodeOperations Ops;
void *PrivateData;
} __attribute__((packed));
dev_t RegisterFileSystem(FileSystemInfo *Info, struct Inode *Root);
int UnregisterFileSystem(dev_t Device);
#endif // !__FENNIX_API_FILESYSTEM_H__