您如何找到 Linux 驱动器上分区结束的位置?

How do you find where the end of a partition ends on a Linux drive?

在我的一个 类 中,我们的任务是在第一个超级块中查找并打印一些值,然后将这些值与所有其他超级块以 3、5 和 7 的幂进行比较,直到结束分区.

例如,您将 superblock0 与 superblock1、0 和 3、0 和 5、0 和 7、0 和 9 等进行比较。

我在超级块中输出值的代码有效,我有一个算法可以得到 3、5 和 7 的所有幂,但我不确定如何检测分区的末尾。

以及如何使用这些权力遍历所有超级块直到结束或中断情况是什么。

下面是我访问第一个超级块的代码。

int fd;
super_block_t s;

if((fd = open(DEVICE, O_RDONLY)) < 0){ //check if disk can be read
    perror(DEVICE);
    exit(1);
} 

//read superblock
lseek(fd, OFFSET, SEEK_SET);
read(fd, &s, sizeof(s));
close(fd);

您可以尝试在那里寻找并查看是否得到 EINVAL,或者您可以使用 BLKGETSIZE64 ioctl 来获取块设备的大小:

#include <linux/fs.h>
#include <stdint.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>

void main(int argc, char** argv) {
  int fd = open(argv[1], O_RDONLY);
  uint64_t size;
  ioctl(fd, BLKGETSIZE64, &size);
  printf("Size in bytes: %llu\n", size);
}

文件系统所在的块设备的大小与文件系统本身的大小不同。鉴于您的任务是对文件系统本身内的超级块进行操作,我假设您对后者更感兴趣。如果您对实际设备尺寸更感兴趣,那么@that-other-guy 的回答是正确的。

假设您正在为文件系统使用 ext4,并且根据信息 here,文件系统的完整大小将是总块数乘以块大小。在超级块的结构中,相关的字段是:

s_blocks_count_lo 很简单,但是 s_log_block_size 需要一些处理,因为存储的值意味着:

Block size is 2 ^ (10 + s_log_block_size).

将所有这些放在一起,您可以执行以下操作:

uintmax_t get_filesystem_size(const char *device) {
  int fd; 
  
  if((fd = open(device, O_RDONLY)) < 0) {
    perror(device);
    exit(1);
  }   

  if (lseek(fd, 1024, SEEK_SET) < 0) {
    perror("lseek");
    exit(1);
  }

  uint8_t block0[1024];
  if (read(fd, &block0, 1024) < 0) {
    perror("read");
    exit(1);
  }

  if (s_magic(block0) != 0xef53) {
    fprintf(stderr, "bad magic\n");
    exit(1);
  }

  close(fd);

  return s_blocks_count_lo(block0) * s_block_size(block0);
}

使用以下 ext4 超级块特定的辅助函数:

uint16_t s_magic(const uint8_t *buffer) {
  return le16(buffer + 0x38);
}

uint32_t s_blocks_count_lo(const uint8_t *buffer) {
  return le32(buffer + 0x4);
}

uintmax_t s_block_size(const uint8_t *buffer) {
  return 1 << (10 + le32(buffer + 0x18));
}

和以下通用字节序辅助函数:

uint16_t le16(const uint8_t *buffer) {
  int result = 0;
  for (int i = 1; i >= 0; i--) {
    result *= 256;
    result += buffer[i];
  }
  return result;
}

uint32_t le32(const uint8_t *buffer) {
  int result = 0;
  for (int i = 3; i >= 0; i--) {
    result *= 256;
    result += buffer[i];
  }
  return result;
}