diff options
Diffstat (limited to '')
-rw-r--r-- | libparted/fs/nilfs2/nilfs2.c | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/libparted/fs/nilfs2/nilfs2.c b/libparted/fs/nilfs2/nilfs2.c new file mode 100644 index 0000000..6204542 --- /dev/null +++ b/libparted/fs/nilfs2/nilfs2.c @@ -0,0 +1,155 @@ +/* + * 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); +} |