156 lines
4.1 KiB
C
Executable File
156 lines
4.1 KiB
C
Executable File
/*
|
|
* nilfs2.c - New Implementation of Log filesystem
|
|
*
|
|
* Written by Jiro SEKIBA <jir@unicus.jp>
|
|
*
|
|
* Copyright (C) 2011-2014, 2019-2023 Free Software Foundation, Inc.
|
|
*
|
|
* 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; 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 General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <parted/parted.h>
|
|
#include <parted/crc32.h>
|
|
#include <parted/endian.h>
|
|
|
|
/* Magic value for nilfs2 superblock. */
|
|
#define NILFS2_SUPER_MAGIC 0x3434
|
|
|
|
/* primariy superblock offset in 512bytes blocks. */
|
|
#define NILFS_SB_OFFSET 2
|
|
|
|
/* secondary superblock offset in 512byte blocks. */
|
|
#define NILFS_SB2_OFFSET(devsize) ((((devsize)>>3) - 1) << 3)
|
|
|
|
struct __attribute__ ((packed)) nilfs2_super_block {
|
|
uint32_t s_rev_level;
|
|
uint16_t s_minor_rev_level;
|
|
uint16_t s_magic;
|
|
uint16_t s_bytes;
|
|
uint16_t s_flags;
|
|
uint32_t s_crc_seed;
|
|
uint32_t s_sum;
|
|
uint32_t s_log_block_size;
|
|
uint64_t s_nsegments;
|
|
uint64_t s_dev_size;
|
|
uint64_t s_first_data_block;
|
|
uint32_t s_blocks_per_segment;
|
|
uint32_t s_r_segments_percentage;
|
|
uint64_t s_last_cno;
|
|
uint64_t s_last_pseg;
|
|
uint64_t s_last_seq;
|
|
uint64_t s_free_blocks_count;
|
|
uint64_t s_ctime;
|
|
uint64_t s_mtime;
|
|
uint64_t s_wtime;
|
|
uint16_t s_mnt_count;
|
|
uint16_t s_max_mnt_count;
|
|
uint16_t s_state;
|
|
uint16_t s_errors;
|
|
uint64_t s_lastcheck;
|
|
uint32_t s_checkinterval;
|
|
uint32_t s_creator_os;
|
|
uint16_t s_def_resuid;
|
|
uint16_t s_def_resgid;
|
|
uint32_t s_first_ino;
|
|
uint16_t s_inode_size;
|
|
uint16_t s_dat_entry_size;
|
|
uint16_t s_checkpoint_size;
|
|
uint16_t s_segment_usage_size;
|
|
uint8_t s_uuid[16];
|
|
char s_volume_name[80];
|
|
uint32_t s_c_interval;
|
|
uint32_t s_c_block_max;
|
|
uint32_t s_reserved[192];
|
|
};
|
|
|
|
static int
|
|
is_valid_nilfs_sb(struct nilfs2_super_block *sb)
|
|
{
|
|
static unsigned char sum[4];
|
|
const int sumoff = offsetof (struct nilfs2_super_block, s_sum);
|
|
size_t bytes;
|
|
uint32_t crc;
|
|
|
|
if (PED_LE16_TO_CPU(sb->s_magic) != NILFS2_SUPER_MAGIC)
|
|
return 0;
|
|
|
|
bytes = PED_LE16_TO_CPU(sb->s_bytes);
|
|
if (bytes > 1024 || bytes < sumoff - 4)
|
|
return 0;
|
|
|
|
crc = __efi_crc32(sb, sumoff, PED_LE32_TO_CPU(sb->s_crc_seed));
|
|
crc = __efi_crc32(sum, 4, crc);
|
|
crc = __efi_crc32((unsigned char *)sb + sumoff + 4,
|
|
bytes - sumoff - 4, crc);
|
|
|
|
return crc == PED_LE32_TO_CPU(sb->s_sum);
|
|
}
|
|
|
|
PedGeometry*
|
|
nilfs2_probe (PedGeometry* geom)
|
|
{
|
|
struct nilfs2_super_block *sb = NULL;
|
|
struct nilfs2_super_block *sb2 = NULL;
|
|
PedSector length = geom->length * (geom->dev->sector_size / 512);
|
|
|
|
PedSector sb2off = NILFS_SB2_OFFSET(length) / (geom->dev->sector_size / 512);
|
|
if (sb2off <= 2)
|
|
return NULL;
|
|
const int sectors = (4096 + geom->dev->sector_size - 1) /
|
|
geom->dev->sector_size;
|
|
uint8_t *buf = alloca (sectors * geom->dev->sector_size);
|
|
const int sectors2 = (1024 + geom->dev->sector_size -1 ) /
|
|
geom->dev->sector_size;
|
|
void *buff2 = alloca (sectors2 * geom->dev->sector_size);
|
|
|
|
if (ped_geometry_read(geom, buf, 0, sectors))
|
|
sb = (struct nilfs2_super_block*)(buf + 1024);
|
|
if (ped_geometry_read(geom, buff2, sb2off, sectors2))
|
|
sb2 = (struct nilfs2_super_block*)buff2;
|
|
|
|
if ((!sb || !is_valid_nilfs_sb(sb)) &&
|
|
(!sb2 || !is_valid_nilfs_sb(sb2)))
|
|
return NULL;
|
|
|
|
/* reserve 4k bytes for secondary superblock */
|
|
length = sb2off + ((4096 + geom->dev->sector_size - 1) /
|
|
geom->dev->sector_size);
|
|
|
|
return ped_geometry_new(geom->dev, geom->start, length);
|
|
}
|
|
|
|
static PedFileSystemOps nilfs2_ops = {
|
|
probe: nilfs2_probe,
|
|
};
|
|
|
|
static PedFileSystemType nilfs2_type = {
|
|
next: NULL,
|
|
ops: &nilfs2_ops,
|
|
name: "nilfs2",
|
|
};
|
|
|
|
void
|
|
ped_file_system_nilfs2_init ()
|
|
{
|
|
ped_file_system_type_register (&nilfs2_type);
|
|
}
|
|
|
|
void
|
|
ped_file_system_nilfs2_done ()
|
|
{
|
|
ped_file_system_type_unregister (&nilfs2_type);
|
|
}
|