/* * nilfs2.c - New Implementation of Log filesystem * * Written by Jiro SEKIBA * * Copyright (C) 2011-2014, 2019-2022 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 . */ #include #include #include #include /* 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); }