/* SPDX-License-Identifier: LGPL-3.0-or-later */
/*
* super.h - This file is part of libsquashfs
*
* Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef SQFS_SUPER_H
#define SQFS_SUPER_H
#include "sqfs/predef.h"
/**
* @file super.h
*
* @brief Contains on-disk data structures, identifiers and functions for the
* SquashFS super block.
*/
#define SQFS_MAGIC 0x73717368
#define SQFS_VERSION_MAJOR 4
#define SQFS_VERSION_MINOR 0
#define SQFS_DEVBLK_SIZE 4096
#define SQFS_DEFAULT_BLOCK_SIZE 131072
/**
* @struct sqfs_super_t
*
* @brief The SquashFS super block, located at the beginning of the file system
* to describe the layout of the filesystem.
*/
struct sqfs_super_t {
/**
* @brief Magic number. Must be set to SQFS_MAGIC.
*/
sqfs_u32 magic;
/**
* @brief Total number of inodes.
*/
sqfs_u32 inode_count;
/**
* @brief Last time the filesystem was modified.
*
* This field counts seconds (not counting leap seconds) since 00:00,
* Jan 1 1970 UTC. This field is unsigned, so it expires in the year
* 2106 (as opposed to 2038).
*/
sqfs_u32 modification_time;
/**
* @brief The data block size in bytes.
*
* Must be a power of 2, no less than 4k and not larger than 1M.
*/
sqfs_u32 block_size;
/**
* @brief The number of fragment blocks in the data area.
*/
sqfs_u32 fragment_entry_count;
/**
* @brief Identifies the compressor that has been used.
*
* Valid identifiers are in the @ref E_SQFS_COMPRESSOR enum.
*/
sqfs_u16 compression_id;
/**
* @brief The log2 of the block_size field for sanity checking
*
* Must be no less than 12 and not larger than 20.
*/
sqfs_u16 block_log;
/**
* @brief A combination of @ref E_SQFS_SUPER_FLAGS flags
*
* Most of the flags that can be set here are informative only.
*/
sqfs_u16 flags;
/**
* @brief The total number of unique user or group IDs.
*/
sqfs_u16 id_count;
/**
* @brief Must be @ref SQFS_VERSION_MAJOR
*/
sqfs_u16 version_major;
/**
* @brief Must be @ref SQFS_VERSION_MINOR
*/
sqfs_u16 version_minor;
/**
* @brief A reference to the root inode
*
* The bits 16 to 48 hold an offset that is added to inode_table_start
* to get the location of the meta data block containing the inode.
* The lower 16 bits hold a byte offset into the uncompressed block.
*/
sqfs_u64 root_inode_ref;
/**
* @brief Total size of the file system in bytes, not counting padding
*/
sqfs_u64 bytes_used;
/**
* @brief On-disk location of the ID table
*
* This value must point to a location after the directory table and
* (if present) after the export and fragment tables, but before the
* xattr table.
*/
sqfs_u64 id_table_start;
/**
* @brief On-disk location of the extended attribute table (if present)
*
* See @ref sqfs_xattr_reader_t for an overview on how SquashFS stores
* extended attributes on disk.
*
* This value must either point to a location after the ID table, or
* it must be set to 0xFFFFFFFF to indicate the table is not present.
*/
sqfs_u64 xattr_id_table_start;
/**
* @brief On-disk location of the first meta data block containing
* the inodes
*
* This value must point to a location before the directory table.
*/
sqfs_u64 inode_table_start;
/**
* @brief On-disk location of the first meta data block containing
* the directory entries
*
* This value must point to a location after the inode table but
* before the fragment, export, ID and xattr tables.
*/
sqfs_u64 directory_table_start;
/**
* @brief On-disk location of the fragment table (if present)
*
* This value must either point to a location after the directory
* table, but before the export, ID and xattr tables, or it must be
* set to 0xFFFFFFFF to indicate that the table is not present.
*/
sqfs_u64 fragment_table_start;
/**
* @brief On-disk location of the export table (if present)
*
* This value must either point to a location after directory table
* (and if present after the fragment table), but before the ID table,
* or it must be set to 0xFFFFFFFF to indicate that the table is not
* present.
*/
sqfs_u64 export_table_start;
};
/**
* @enum E_SQFS_COMPRESSOR
*
* @brief Set in @ref sqfs_super_t to identify the compresser used by the
* filesystem.
*
* Most of the flags that can be set are informative only.
*/
typedef enum {
SQFS_COMP_GZIP = 1,
SQFS_COMP_LZMA = 2,
SQFS_COMP_LZO = 3,
SQFS_COMP_XZ = 4,
SQFS_COMP_LZ4 = 5,
SQFS_COMP_ZSTD = 6,
SQFS_COMP_MIN = 1,
SQFS_COMP_MAX = 6,
} E_SQFS_COMPRESSOR;
/**
* @enum E_SQFS_SUPER_FLAGS
*
* @brief Flags that can be set in @ref sqfs_super flags field.
*/
typedef enum {
/**
* @brief Set to indicate that meta data blocks holding the inodes are
* stored uncompressed.
*/
SQFS_FLAG_UNCOMPRESSED_INODES = 0x0001,
/**
* @brief Set to indicate that all data blocks are stored uncompressed.
*/
SQFS_FLAG_UNCOMPRESSED_DATA = 0x0002,
/**
* @brief Set to indicate that all fragment blocks are stored
* uncompressed.
*/
SQFS_FLAG_UNCOMPRESSED_FRAGMENTS = 0x0008,
/**
* @brief Set to indicate that there are no fragment blocks.
*/
SQFS_FLAG_NO_FRAGMENTS = 0x0010,
/**
* @brief Set to indicate that fragments have been generated for all
* files that are not a multiple of the block size in size.
*/
SQFS_FLAG_ALWAYS_FRAGMENTS = 0x0020,
/**
* @brief Set to indicate that data blocks have not been deduplicated.
*/
SQFS_FLAG_DUPLICATES = 0x0040,
/**
* @brief Set to indicate that an NFS export table is present.
*/
SQFS_FLAG_EXPORTABLE = 0x0080,
/**
* @brief Set to indicate that meta data blocks holding extended
* attributes are stored uncompressed.
*/
SQFS_FLAG_UNCOMPRESSED_XATTRS = 0x0100,
/**
* @brief Set to indicate that the filesystem does not
* contain extended attributes.
*/
SQFS_FLAG_NO_XATTRS = 0x0200,
/**
* @brief Set to indicate that a single, uncompressed meta data block
* with compressor options follows the super block.
*/
SQFS_FLAG_COMPRESSOR_OPTIONS = 0x0400,
/**
* @brief Set to indicate that meta data blocks holding the IDs are
* stored uncompressed.
*/
SQFS_FLAG_UNCOMPRESSED_IDS = 0x0800,
} E_SQFS_SUPER_FLAGS;
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize the SquashFS super block.
*
* @memberof sqfs_super_t
*
* @param super A pointer to a super block structure.
* @param block_size The uncompressed size of the data blocks in bytes.
* @param mtime The modification time stamp to set.
* @param compressor The compressor ID to set.
*
* @return Zero on success, an @ref E_SQFS_ERROR value if one of the
* fields does not hold a valid value.
*/
SQFS_API int sqfs_super_init(sqfs_super_t *super, size_t block_size,
sqfs_u32 mtime,
E_SQFS_COMPRESSOR compressor);
/**
* @brief Encode and write a SquashFS super block to disk.
*
* @memberof sqfs_super_t
*
* @param super A pointer to the super block structure to write.
* @param file A file object through which to access the filesystem image.
*
* @return Zero on success, an @ref E_SQFS_ERROR value if one of the
* fields does not hold a valid value.
*/
SQFS_API int sqfs_super_write(const sqfs_super_t *super, sqfs_file_t *file);
/**
* @brief Read a SquashFS super block from disk, decode it and check the fields
*
* @memberof sqfs_super_t
*
* @param super A pointer to the super block structure to fill.
* @param file A file object through which to access the filesystem image.
*
* @return Zero on success, an @ref E_SQFS_ERROR value if one of the
* fields does not hold a valid value.
*/
SQFS_API int sqfs_super_read(sqfs_super_t *super, sqfs_file_t *file);
#ifdef __cplusplus
}
#endif
#endif /* SQFS_SUPER_H */