Home > Back-end >  Reading data from the end of disk in C
Reading data from the end of disk in C

Time:07-06

I try to use crypto key for decrypting disk in Ubuntu 16 and I want read it from the end of disk just as raw data without creating any file for security reason, i.e. like dd does in way

sudo dd if=some_disk bs=1 skip=end_of_disk - keysize count=keysize

So, I wrote a test program

#include <fcntl.h>
#include <linux/fs.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

unsigned long long disksize(char *drivename)
{
  int fd;
  unsigned long long numblocks=0;

  fd = open(drivename, O_RDONLY);
  ioctl(fd, BLKGETSIZE64, &numblocks);
  close(fd);
  return numblocks;
}

int main(int argc, char **argv)
{
  int fd;
  FILE *device;
  int keySize = 2048;
  int count;
  unsigned char *block;
  unsigned long long endOfDisk=disksize(argv[1]);
  unsigned long long startFrom = endOfDisk - keySize;
  block = calloc(keySize, sizeof(char));
//  fd=open(argv[1], O_RDWR | O_DIRECT);
  device = fopen(argv[1], "r");
  long res = fseek(device, startFrom, SEEK_SET);
  perror("\nSeeking error:");
  fread(block, 1, keySize, device);
  fclose(device);
  printf("\nDevice Size: %lld\n", endOfDisk);
  printf("\nReading data starting from: %lld\n", startFrom);
  for(count = 0; count < keySize; count  ){
      printf("%c", block[count]); 
  }
  free(block);
}

It works good on small disks, say, on boot partition or USB stick with capacity of 1Gb, but when I try to get key from, say, 4Gb USB stick, I can't: program prints something beyond key area on disk and perror shows "Invalid argument" as result of fseek. It looks like fseek can't set pointer right and I don't understand why:

fdisk -l some_disk

shows exactly the same disk size as endOfDisk from given program.

P.S. As someone can see from a couple of rudiments, I tried lseek too with exactly the same result printing exactly the same info instead of stored on disk key.

CodePudding user response:

ioctl(fd, BLKGETSIZE64, &numblocks) return size in 512-byte blocks, fseek() expect offset in bytes. BTW, you can set pointer relative to the end of disk without knowing it's size:

fseek(device, -keySize, SEEK_END);
  • Related