Initial version

This commit is contained in:
2019-06-28 23:08:36 +02:00
commit 4d8973e20b
2426 changed files with 948029 additions and 0 deletions

View File

@ -0,0 +1,257 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program 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; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
*/
#ifndef REDCORE_H
#define REDCORE_H
#include <redstat.h>
#include <redvolume.h>
#include "rednodes.h"
#include "redcoremacs.h"
#include "redcorevol.h"
#define META_SIG_MASTER (0x5453414DU) /* 'MAST' */
#define META_SIG_METAROOT (0x4154454DU) /* 'META' */
#define META_SIG_IMAP (0x50414D49U) /* 'IMAP' */
#define META_SIG_INODE (0x444F4E49U) /* 'INOD' */
#define META_SIG_DINDIR (0x494C4244U) /* 'DBLI' */
#define META_SIG_INDIR (0x49444E49U) /* 'INDI' */
REDSTATUS RedIoRead(uint8_t bVolNum, uint32_t ulBlockStart, uint32_t ulBlockCount, void *pBuffer);
#if REDCONF_READ_ONLY == 0
REDSTATUS RedIoWrite(uint8_t bVolNum, uint32_t ulBlockStart, uint32_t ulBlockCount, const void *pBuffer);
REDSTATUS RedIoFlush(uint8_t bVolNum);
#endif
/** Indicates a block buffer is dirty (its contents are different than the
contents of the corresponding block on disk); or, when passed into
RedBufferGet(), indicates that the buffer should be marked dirty.
*/
#define BFLAG_DIRTY ((uint16_t) 0x0001U)
/** Tells RedBufferGet() that the buffer is for a newly allocated block, and its
contents should be zeroed instead of being read from disk. Always used in
combination with BFLAG_DIRTY.
*/
#define BFLAG_NEW ((uint16_t) 0x0002U)
/** Indicates that a block buffer is a master block (MASTERBLOCK) metadata node.
*/
#define BFLAG_META_MASTER ((uint16_t)(0x0004U | BFLAG_META))
/** Indicates that a block buffer is an imap (IMAPNODE) metadata node.
*/
#define BFLAG_META_IMAP ((uint16_t)(0x0008U | BFLAG_META))
/** Indicates that a block buffer is an inode (INODE) metadata node.
*/
#define BFLAG_META_INODE ((uint16_t)(0x0010U | BFLAG_META))
/** Indicates that a block buffer is an indirect (INDIR) metadata node.
*/
#define BFLAG_META_INDIR ((uint16_t)(0x0020U | BFLAG_META))
/** Indicates that a block buffer is a double indirect (DINDIR) metadata node.
*/
#define BFLAG_META_DINDIR ((uint16_t)(0x0040U | BFLAG_META))
/** Indicates that a block buffer is a metadata node. Callers of RedBufferGet()
should not use this flag; instead, use one of the BFLAG_META_* flags.
*/
#define BFLAG_META ((uint16_t) 0x8000U)
void RedBufferInit(void);
REDSTATUS RedBufferGet(uint32_t ulBlock, uint16_t uFlags, void **ppBuffer);
void RedBufferPut(const void *pBuffer);
#if REDCONF_READ_ONLY == 0
REDSTATUS RedBufferFlush(uint32_t ulBlockStart, uint32_t ulBlockCount);
void RedBufferDirty(const void *pBuffer);
void RedBufferBranch(const void *pBuffer, uint32_t ulBlockNew);
#if (REDCONF_API_POSIX == 1) || FORMAT_SUPPORTED
void RedBufferDiscard(const void *pBuffer);
#endif
#endif
REDSTATUS RedBufferDiscardRange(uint32_t ulBlockStart, uint32_t ulBlockCount);
/** @brief Allocation state of a block.
*/
typedef enum
{
ALLOCSTATE_FREE, /**< Free and may be allocated; writeable. */
ALLOCSTATE_USED, /**< In-use and transacted; not writeable. */
ALLOCSTATE_NEW, /**< In-use but not transacted; writeable. */
ALLOCSTATE_AFREE /**< Will become free after a transaction; not writeable. */
} ALLOCSTATE;
REDSTATUS RedImapBlockGet(uint8_t bMR, uint32_t ulBlock, bool *pfAllocated);
#if REDCONF_READ_ONLY == 0
REDSTATUS RedImapBlockSet(uint32_t ulBlock, bool fAllocated);
REDSTATUS RedImapAllocBlock(uint32_t *pulBlock);
#endif
REDSTATUS RedImapBlockState(uint32_t ulBlock, ALLOCSTATE *pState);
#if REDCONF_IMAP_INLINE == 1
REDSTATUS RedImapIBlockGet(uint8_t bMR, uint32_t ulBlock, bool *pfAllocated);
REDSTATUS RedImapIBlockSet(uint32_t ulBlock, bool fAllocated);
#endif
#if REDCONF_IMAP_EXTERNAL == 1
REDSTATUS RedImapEBlockGet(uint8_t bMR, uint32_t ulBlock, bool *pfAllocated);
REDSTATUS RedImapEBlockSet(uint32_t ulBlock, bool fAllocated);
uint32_t RedImapNodeBlock(uint8_t bMR, uint32_t ulImapNode);
#endif
/** @brief Cached inode structure.
*/
typedef struct
{
uint32_t ulInode; /**< The inode number of the cached inode. */
#if REDCONF_API_POSIX == 1
bool fDirectory; /**< True if the inode is a directory. */
#endif
#if REDCONF_READ_ONLY == 0
bool fBranched; /**< True if the inode is branched (writeable). */
bool fDirty; /**< True if the inode buffer is dirty. */
#endif
bool fCoordInited; /**< True after the first seek. */
INODE *pInodeBuf; /**< Pointer to the inode buffer. */
#if DINDIR_POINTERS > 0U
DINDIR *pDindir; /**< Pointer to the double indirect node buffer. */
#endif
#if REDCONF_DIRECT_POINTERS < INODE_ENTRIES
INDIR *pIndir; /**< Pointer to the indirect node buffer. */
#endif
uint8_t *pbData; /**< Pointer to the data block buffer. */
/* All the members below this point are part of the seek coordinates; see
RedInodeDataSeek().
*/
uint32_t ulLogicalBlock; /**< Logical block offset into the inode. */
#if DINDIR_POINTERS > 0U
uint32_t ulDindirBlock; /**< Physical block number of the double indirect node. */
#endif
#if REDCONF_DIRECT_POINTERS < INODE_ENTRIES
uint32_t ulIndirBlock; /**< Physical block number of the indirect node. */
#endif
uint32_t ulDataBlock; /**< Physical block number of the file data block. */
uint16_t uInodeEntry; /**< Which inode entry to traverse to reach ulLogicalBlock. */
#if DINDIR_POINTERS > 0U
uint16_t uDindirEntry; /**< Which double indirect entry to traverse to reach ulLogicalBlock. */
#endif
#if REDCONF_DIRECT_POINTERS < INODE_ENTRIES
uint16_t uIndirEntry; /**< Which indirect entry to traverse to reach ulLogicalBlock. */
#endif
} CINODE;
#define CINODE_IS_MOUNTED(pInode) (((pInode) != NULL) && INODE_IS_VALID((pInode)->ulInode) && ((pInode)->pInodeBuf != NULL))
#define CINODE_IS_DIRTY(pInode) (CINODE_IS_MOUNTED(pInode) && (pInode)->fDirty)
#define IPUT_UPDATE_ATIME (0x01U)
#define IPUT_UPDATE_MTIME (0x02U)
#define IPUT_UPDATE_CTIME (0x04U)
#define IPUT_UPDATE_MASK (IPUT_UPDATE_ATIME|IPUT_UPDATE_MTIME|IPUT_UPDATE_CTIME)
REDSTATUS RedInodeMount(CINODE *pInode, FTYPE type, bool fBranch);
#if REDCONF_READ_ONLY == 0
REDSTATUS RedInodeBranch(CINODE *pInode);
#endif
#if (REDCONF_READ_ONLY == 0) && ((REDCONF_API_POSIX == 1) || FORMAT_SUPPORTED)
REDSTATUS RedInodeCreate(CINODE *pInode, uint32_t ulPInode, uint16_t uMode);
#endif
#if DELETE_SUPPORTED
REDSTATUS RedInodeDelete(CINODE *pInode);
REDSTATUS RedInodeLinkDec(CINODE *pInode);
#endif
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX == 1)
REDSTATUS RedInodeFree(CINODE *pInode);
#endif
void RedInodePut(CINODE *pInode, uint8_t bTimeFields);
void RedInodePutCoord(CINODE *pInode);
#if DINDIR_POINTERS > 0U
void RedInodePutDindir(CINODE *pInode);
#endif
#if REDCONF_DIRECT_POINTERS < INODE_ENTRIES
void RedInodePutIndir(CINODE *pInode);
#endif
void RedInodePutData(CINODE *pInode);
#if ((REDCONF_READ_ONLY == 0) && ((REDCONF_API_POSIX == 1) || FORMAT_SUPPORTED)) || (REDCONF_CHECKER == 1)
REDSTATUS RedInodeIsFree(uint32_t ulInode, bool *pfFree);
#endif
REDSTATUS RedInodeBitGet(uint8_t bMR, uint32_t ulInode, uint8_t bWhich, bool *pfAllocated);
REDSTATUS RedInodeDataRead(CINODE *pInode, uint64_t ullStart, uint32_t *pulLen, void *pBuffer);
#if REDCONF_READ_ONLY == 0
REDSTATUS RedInodeDataWrite(CINODE *pInode, uint64_t ullStart, uint32_t *pulLen, const void *pBuffer);
#if DELETE_SUPPORTED || TRUNCATE_SUPPORTED
REDSTATUS RedInodeDataTruncate(CINODE *pInode, uint64_t ullSize);
#endif
#endif
REDSTATUS RedInodeDataSeekAndRead(CINODE *pInode, uint32_t ulBlock);
REDSTATUS RedInodeDataSeek(CINODE *pInode, uint32_t ulBlock);
#if REDCONF_API_POSIX == 1
#if REDCONF_READ_ONLY == 0
REDSTATUS RedDirEntryCreate(CINODE *pPInode, const char *pszName, uint32_t ulInode);
#endif
#if DELETE_SUPPORTED
REDSTATUS RedDirEntryDelete(CINODE *pPInode, uint32_t ulDeleteIdx);
#endif
REDSTATUS RedDirEntryLookup(CINODE *pPInode, const char *pszName, uint32_t *pulEntryIdx, uint32_t *pulInode);
#if (REDCONF_API_POSIX_READDIR == 1) || (REDCONF_CHECKER == 1)
REDSTATUS RedDirEntryRead(CINODE *pPInode, uint32_t *pulIdx, char *pszName, uint32_t *pulInode);
#endif
#if (REDCONF_READ_ONLY == 0) && (REDCONF_API_POSIX_RENAME == 1)
REDSTATUS RedDirEntryRename(CINODE *pSrcPInode, const char *pszSrcName, CINODE *pSrcInode, CINODE *pDstPInode, const char *pszDstName, CINODE *pDstInode);
#endif
#endif
REDSTATUS RedVolMount(void);
REDSTATUS RedVolMountMaster(void);
REDSTATUS RedVolMountMetaroot(void);
#if REDCONF_READ_ONLY == 0
REDSTATUS RedVolTransact(void);
#endif
void RedVolCriticalError(const char *pszFileName, uint32_t ulLineNum);
REDSTATUS RedVolSeqNumIncrement(void);
#if FORMAT_SUPPORTED
REDSTATUS RedVolFormat(void);
#endif
#endif

View File

@ -0,0 +1,92 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program 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; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
*/
#ifndef REDCOREMACS_H
#define REDCOREMACS_H
#define BLOCK_NUM_MASTER (0UL) /* Block number of the master block. */
#define BLOCK_NUM_FIRST_METAROOT (1UL) /* Block number of the first metaroot. */
#define BLOCK_SPARSE (0U)
#define DINDIR_POINTERS ((INODE_ENTRIES - REDCONF_DIRECT_POINTERS) - REDCONF_INDIRECT_POINTERS)
#define DINDIR_DATA_BLOCKS (INDIR_ENTRIES * INDIR_ENTRIES)
#define INODE_INDIR_BLOCKS (REDCONF_INDIRECT_POINTERS * INDIR_ENTRIES)
#define INODE_DINDIR_BLOCKS (DINDIR_POINTERS * DINDIR_DATA_BLOCKS)
#define INODE_DATA_BLOCKS (REDCONF_DIRECT_POINTERS + INODE_INDIR_BLOCKS + INODE_DINDIR_BLOCKS)
#define INODE_SIZE_MAX (UINT64_SUFFIX(1) * REDCONF_BLOCK_SIZE * INODE_DATA_BLOCKS)
/* First inode number that can be allocated.
*/
#if REDCONF_API_POSIX == 1
#define INODE_FIRST_FREE (INODE_FIRST_VALID + 1U)
#else
#define INODE_FIRST_FREE (INODE_FIRST_VALID)
#endif
/** @brief Determine if an inode number is valid.
*/
#define INODE_IS_VALID(INODENUM) (((INODENUM) >= INODE_FIRST_VALID) && ((INODENUM) < (INODE_FIRST_VALID + gpRedVolConf->ulInodeCount)))
/* The number of blocks reserved to allow a truncate or delete operation to
complete when the disk is otherwise full.
The more expensive of the two operations is delete, which has to actually
write to a file data block to remove the directory entry.
*/
#if REDCONF_READ_ONLY == 1
#define RESERVED_BLOCKS 0U
#elif (REDCONF_API_POSIX == 1) && ((REDCONF_API_POSIX_UNLINK == 1) || (REDCONF_API_POSIX_RMDIR == 1))
#if DINDIR_POINTERS > 0U
#define RESERVED_BLOCKS 3U
#elif REDCONF_INDIRECT_POINTERS > 0U
#define RESERVED_BLOCKS 2U
#else
#define RESERVED_BLOCKS 1U
#endif
#elif ((REDCONF_API_POSIX == 1) && (REDCONF_API_POSIX_FTRUNCATE == 1)) || ((REDCONF_API_FSE == 1) && (REDCONF_API_FSE_TRUNCATE == 1))
#if DINDIR_POINTERS > 0U
#define RESERVED_BLOCKS 2U
#elif REDCONF_INDIRECT_POINTERS > 0U
#define RESERVED_BLOCKS 1U
#else
#define RESERVED_BLOCKS 0U
#endif
#else
#define RESERVED_BLOCKS 0U
#endif
#define CRITICAL_ASSERT(EXP) ((EXP) ? (void)0 : CRITICAL_ERROR())
#define CRITICAL_ERROR() RedVolCriticalError(__FILE__, __LINE__)
#endif

View File

@ -0,0 +1,95 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program 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; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
*/
#ifndef REDCOREVOL_H
#define REDCOREVOL_H
/** @brief Per-volume run-time data specific to the core.
*/
typedef struct
{
/** Whether this volume uses the inline imap (true) or external imap
(false). Computed at initialization time based on the block count.
*/
bool fImapInline;
#if REDCONF_IMAP_EXTERNAL == 1
/** First block number of the on-disk imap. Valid only when fImapInline
is false.
*/
uint32_t ulImapStartBN;
/** The number of double-allocated imap nodes that make up the imap.
*/
uint32_t ulImapNodeCount;
#endif
/** Block number where the inode table starts.
*/
uint32_t ulInodeTableStartBN;
/** First block number that can be allocated.
*/
uint32_t ulFirstAllocableBN;
/** The two metaroot structures, committed and working state.
*/
METAROOT aMR[2U];
/** The index of the current metaroot; must be 0 or 1.
*/
uint8_t bCurMR;
/** Whether the volume has been branched or not.
*/
bool fBranched;
/** The number of blocks which will become free after the next transaction.
*/
uint32_t ulAlmostFreeBlocks;
#if RESERVED_BLOCKS > 0U
/** Whether to use the blocks reserved for operations that create free
space.
*/
bool fUseReservedBlocks;
#endif
} COREVOLUME;
/* Pointer to the core volume currently being accessed; populated during
RedCoreVolSetCurrent().
*/
extern COREVOLUME * CONST_IF_ONE_VOLUME gpRedCoreVol;
/* Pointer to the metaroot currently being accessed; populated during
RedCoreVolSetCurrent() and RedCoreVolTransact().
*/
extern METAROOT *gpRedMR;
#endif

View File

@ -0,0 +1,195 @@
/* ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
Copyright (c) 2014-2015 Datalight, Inc.
All Rights Reserved Worldwide.
This program 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; use version 2 of the License.
This program is distributed in the hope that it will be useful,
but "AS-IS," 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Businesses and individuals that for commercial or other reasons cannot
comply with the terms of the GPLv2 license may obtain a commercial license
before incorporating Reliance Edge into proprietary software for
distribution in any form. Visit http://www.datalight.com/reliance-edge for
more information.
*/
/** @file
*/
#ifndef REDNODES_H
#define REDNODES_H
#define NODEHEADER_SIZE (16U)
#define NODEHEADER_OFFSET_SIG (0U)
#define NODEHEADER_OFFSET_CRC (4U)
#define NODEHEADER_OFFSET_SEQ (8U)
/** @brief Common header for all metadata nodes.
*/
typedef struct
{
uint32_t ulSignature; /**< Value which uniquely identifies the metadata node type. */
uint32_t ulCRC; /**< CRC-32 checksum of the node contents, starting after the CRC. */
uint64_t ullSequence; /**< Current sequence number at the time the node was written to disk. */
} NODEHEADER;
/** Flag set in the master block when REDCONF_API_POSIX == 1. */
#define MBFLAG_API_POSIX (0x01U)
/** Flag set in the master block when REDCONF_INODE_TIMESTAMPS == 1. */
#define MBFLAG_INODE_TIMESTAMPS (0x02U)
/** Flag set in the master block when REDCONF_INODE_BLOCKS == 1. */
#define MBFLAG_INODE_BLOCKS (0x04U)
/** Flag set in the master block when (REDCONF_API_POSIX == 1) && (REDCONF_API_POSIX_LINK == 1). */
#define MBFLAG_INODE_NLINK (0x08U)
/** @brief Node which identifies the volume and stores static volume information.
*/
typedef struct
{
NODEHEADER hdr; /**< Common node header. */
uint32_t ulVersion; /**< On-disk layout version number. */
char acBuildNum[8U]; /**< Build number of the product (not null terminated). */
uint32_t ulFormatTime; /**< Date and time the volume was formatted. */
uint32_t ulInodeCount; /**< Compile-time configured number of inodes. */
uint32_t ulBlockCount; /**< Compile-time configured number of logical blocks. */
uint16_t uMaxNameLen; /**< Compile-time configured maximum file name length. */
uint16_t uDirectPointers; /**< Compile-time configured number of direct pointers per inode. */
uint16_t uIndirectPointers; /**< Compile-time configured number of indirect pointers per inode. */
uint8_t bBlockSizeP2; /**< Compile-time configured block size, expressed as a power of two. */
uint8_t bFlags; /**< Compile-time booleans which affect on-disk structures. */
} MASTERBLOCK;
#if REDCONF_API_POSIX == 1
#define METAROOT_HEADER_SIZE (NODEHEADER_SIZE + 16U) /* Size in bytes of the metaroot header fields. */
#else
#define METAROOT_HEADER_SIZE (NODEHEADER_SIZE + 12U) /* Size in bytes of the metaroot header fields. */
#endif
#define METAROOT_ENTRY_BYTES (REDCONF_BLOCK_SIZE - METAROOT_HEADER_SIZE) /* Number of bytes remaining in the metaroot block for entries. */
#define METAROOT_ENTRIES (METAROOT_ENTRY_BYTES * 8U)
/** @brief Metadata root node; each volume has two.
*/
typedef struct
{
NODEHEADER hdr; /**< Common node header. */
uint32_t ulSectorCRC; /**< CRC-32 checksum of the first sector. */
uint32_t ulFreeBlocks; /**< Number of allocable blocks that are free. */
#if REDCONF_API_POSIX == 1
uint32_t ulFreeInodes; /**< Number of inode slots that are free. */
#endif
uint32_t ulAllocNextBlock; /**< Forward allocation pointer. */
/** Imap bitmap. With inline imaps, this is the imap bitmap that indicates
which inode blocks are used and which allocable blocks are used.
Otherwise, this bitmap toggles nodes in the external imap between one
of two possible block locations.
*/
uint8_t abEntries[METAROOT_ENTRY_BYTES];
} METAROOT;
#if REDCONF_IMAP_EXTERNAL == 1
#define IMAPNODE_HEADER_SIZE (NODEHEADER_SIZE) /* Size in bytes of the imap node header fields. */
#define IMAPNODE_ENTRY_BYTES (REDCONF_BLOCK_SIZE - IMAPNODE_HEADER_SIZE) /* Number of bytes remaining in the imap node for entries. */
#define IMAPNODE_ENTRIES (IMAPNODE_ENTRY_BYTES * 8U)
/** @brief One node of the external imap.
*/
typedef struct
{
NODEHEADER hdr; /**< Common node header. */
/** Bitmap which indicates which inode blocks are used and which allocable
blocks are used.
*/
uint8_t abEntries[IMAPNODE_ENTRY_BYTES];
} IMAPNODE;
#endif
#define INODE_HEADER_SIZE (NODEHEADER_SIZE + 8U + ((REDCONF_INODE_BLOCKS == 1) ? 4U : 0U) + \
((REDCONF_INODE_TIMESTAMPS == 1) ? 12U : 0U) + 4U + ((REDCONF_API_POSIX == 1) ? 4U : 0U))
#define INODE_ENTRIES ((REDCONF_BLOCK_SIZE - INODE_HEADER_SIZE) / 4U)
#if (REDCONF_DIRECT_POINTERS < 0) || (REDCONF_DIRECT_POINTERS > (INODE_ENTRIES - REDCONF_INDIRECT_POINTERS))
#error "Configuration error: invalid value of REDCONF_DIRECT_POINTERS"
#endif
#if (REDCONF_INDIRECT_POINTERS < 0) || (REDCONF_INDIRECT_POINTERS > (INODE_ENTRIES - REDCONF_DIRECT_POINTERS))
#error "Configuration error: invalid value of REDCONF_INDIRECT_POINTERS"
#endif
/** @brief Stores metadata for a file or directory.
*/
typedef struct
{
NODEHEADER hdr; /**< Common node header. */
uint64_t ullSize; /**< Size of the inode, in bytes. */
#if REDCONF_INODE_BLOCKS == 1
uint32_t ulBlocks; /**< Total number file data blocks allocated to the inode. */
#endif
#if REDCONF_INODE_TIMESTAMPS == 1
uint32_t ulATime; /**< Time of last access (seconds since January 1, 1970). */
uint32_t ulMTime; /**< Time of last modification (seconds since January 1, 1970). */
uint32_t ulCTime; /**< Time of last status change (seconds since January 1, 1970). */
#endif
uint16_t uMode; /**< Inode type (file or directory) and permissions (reserved). */
#if (REDCONF_API_POSIX == 1) && (REDCONF_API_POSIX_LINK == 1)
uint16_t uNLink; /**< Link count, number of names pointing to the inode. */
#else
uint8_t abPadding[2]; /**< Padding to 32-bit align the next member. */
#endif
#if REDCONF_API_POSIX == 1
uint32_t ulPInode; /**< Parent inode number. Only guaranteed to be accurate for directories. */
#endif
/** Block numbers for lower levels of the file metadata structure. Some
fraction of these entries are for direct pointers (file data block
numbers), some for indirect pointers, some for double-indirect
pointers; the number allocated to each is static but user-configurable.
For all types, an array slot is zero if the range is sparse or beyond
the end of file.
*/
uint32_t aulEntries[INODE_ENTRIES];
} INODE;
#define INDIR_HEADER_SIZE (NODEHEADER_SIZE + 4U)
#define INDIR_ENTRIES ((REDCONF_BLOCK_SIZE - INDIR_HEADER_SIZE) / 4U)
/** @brief Node for storing block pointers.
*/
typedef struct
{
NODEHEADER hdr; /**< Common node header. */
uint32_t ulInode; /**< Inode which owns this indirect or double indirect. */
/** For indirect nodes, stores block numbers of file data. For double
indirect nodes, stores block numbers of indirect nodes. An array
slot is zero if the corresponding block or indirect range is beyond
the end of file or entirely sparse.
*/
uint32_t aulEntries[INDIR_ENTRIES];
} INDIR, DINDIR;
#endif