Virtual Box Disk Image Wrapper for sfdisk

The following script allows viewing properties of VirtualBox disks to mount them directly. Simple (and incomplete) syscalls interposition for accessing fixed-size Sun xVM VirtualBox Virtual Disk Images (.vdi files), especially using sfdisk.

Compile:

gcc -fPIC -c               -o vdiwrap.o  vdiwrap.c &&
gcc -nostdlib -shared -ldl -o vdiwrap.so vdiwrap.o

Use:

LD_PRELOAD="./vdiwrap.so" sfdisk -qluS image.vdi

/*
 * Copyright (C) 2009  Przemyslaw Pawelczyk <przemoc@gmail.com>
 * GNU General Public License v2, v3
 */

#define _GNU_SOURCE
#define _LARGEFILE64_SOURCE

#include <dlfcn.h>
#include <stdarg.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define LOAD(name) orig_##name = dlsym(RTLD_NEXT, #name)
#if __LP64__
# define N(name) name
# define O(name) orig_##name
# define OFF_T off_t
# define STAT  stat
#else
# define N(name) name ## 64
# define O(name) orig_##name ## 64
# define OFF_T off64_t
# define STAT  stat64
#endif

#define OPEN_SIGNATURE   const char *__file, int __oflag, ...
#define LSEEK_SIGNATURE  int __fd, OFF_T __offset, int __whence
#define FXSTAT_SIGNATURE int __ver, int __fd, struct STAT *__stat_buf


static int vdi_fd = -1;
static int vdi_type = 0;
static int vdi_offset = 0;

static int   (*O(open))(OPEN_SIGNATURE);
static OFF_T (*O(lseek))(LSEEK_SIGNATURE);
static int   (*O(__fxstat))(FXSTAT_SIGNATURE);

/* Functions' prototypes */

int   N(open)(OPEN_SIGNATURE);
OFF_T N(lseek)(LSEEK_SIGNATURE);
int   N(__fxstat)(FXSTAT_SIGNATURE);

/* Initialization */

void _init()
{
  LOAD(open);
  LOAD(lseek);
  LOAD(__fxstat);
}

/* Functions' bodies */

int N(open)(OPEN_SIGNATURE)
{
  int result;
  int namelen;
  unsigned mode;
  va_list ap;

  if (__oflag & O_CREAT) {
    va_start(ap, __oflag);
    mode = va_arg(ap, unsigned);
    result = O(open)(__file, __oflag, mode);
    va_end(ap);
    return result;
  }

  result = O(open)(__file, __oflag);

  if (result > 0 && (namelen = strlen(__file)) && !strncasecmp(&__file[namelen - 4], ".vdi", 4)) {
    O(lseek)(result, 76, SEEK_SET);
    read(result, &vdi_type, 4);
    if (vdi_type == 2) {
      O(lseek)(result, 344, SEEK_SET);
      read(result, &vdi_offset, 4);
      O(lseek)(result, vdi_offset, SEEK_SET);
      vdi_fd = result;
      dprintf(STDERR_FILENO, "--- VDI data offset == %d bytes ---\n", vdi_offset);
    } else
      vdi_fd = -1;
  }

  return result;
}


OFF_T N(lseek)(LSEEK_SIGNATURE)
{
  OFF_T result;

  if (__fd == vdi_fd && __whence == SEEK_SET)
    __offset += vdi_offset;

  result = O(lseek)(__fd, __offset, __whence);

  if (__fd == vdi_fd && result > 0)
    result -= vdi_offset;

  return result;
}

int N(__fxstat)(FXSTAT_SIGNATURE)
{
  int result = O(__fxstat)(__ver, __fd, __stat_buf);

  if (__fd == vdi_fd && result == 0)
    __stat_buf->st_size -= vdi_offset;

  return result;
}

@Tools