/* -------------------------------------------------------------------------- *
 *
 *   Copyright 2011 Shao Miller - All Rights Reserved
 *
 *   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, Inc., 53 Temple Place Ste 330,
 *   Boston MA 02111-1307, USA; either version 2 of the License, or
 *   (at your option) any later version; incorporated herein by reference.
 *
 * ------------------------------------------------------------------------- */

/****
 * ntfstest.c
 *
 * (C) Shao Miller, 2011
 *
 * Tests ntfssect.c functions
 *
 * With special thanks to Mark Roddy for his article:
 *   http://www.wd-3.com/archive/luserland.htm
 */
#include <windows.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "ntfssect.h"

/*** Object types */

/*** Function declarations */
static void show_usage(void);
static void show_last_err(void);
static void show_err(DWORD);

/*** Struct/union definitions */

/*** Function definitions */

/** Program entry-point */
int main(int argc, char ** argv) {
    int rc;
    DWORD err;
    S_NTFSSECT_VOLINFO vol_info;
    HANDLE file;
    LARGE_INTEGER vcn, lba;
    S_NTFSSECT_EXTENT extent;
    LONGLONG len;
    BOOL ok;

    if (argc != 2) {
        rc = EXIT_FAILURE;
        show_usage();
        goto err_args;
      }

    /* Get volume info */
    err = NtfsSectGetVolumeInfoFromFileName(argv[1], &vol_info);
    if (err != ERROR_SUCCESS) {
        show_err(err);
        goto err_vol_info;
      }
    printf(
        "Volume has %d bytes per sector, %d sectors per cluster\n",
        vol_info.BytesPerSector,
        vol_info.SectorsPerCluster
      );

    /* Open the file for reading */
    file = CreateFile(
        argv[1],
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        0,
        NULL
      );
    if (file == INVALID_HANDLE_VALUE) {
        rc = EXIT_FAILURE;
        show_last_err();
        goto err_file;
      }

    /* For each extent */
    for (
        vcn.QuadPart = 0;
        NtfsSectGetFileVcnExtent(file, &vcn, &extent) == ERROR_SUCCESS;
        vcn = extent.NextVcn
      ) {
        len = extent.NextVcn.QuadPart - extent.FirstVcn.QuadPart;
        printf("Extent @ VCN #%lld,", extent.FirstVcn.QuadPart);
        printf(" %lld clusters long:\n", len);
        printf("  VCN #%lld -", extent.FirstVcn.QuadPart);
        printf(" #%lld\n", extent.FirstVcn.QuadPart + len - 1);
        printf("  LCN #%lld -", extent.FirstLcn.QuadPart);
        printf(" #%lld\n", extent.FirstLcn.QuadPart + len - 1);
        err = NtfsSectLcnToLba(
            &vol_info,
            &extent.FirstLcn,
            &lba
          );
        if (err == ERROR_SUCCESS) {
            printf("  LBA #%lld -", lba.QuadPart);
            printf(
                " #%lld\n",
                lba.QuadPart + len * vol_info.SectorsPerCluster
              );
          }
        continue;
      }

    rc = EXIT_SUCCESS;

    CloseHandle(file);
    err_file:

    CloseHandle(vol_info.Handle);
    err_vol_info:

    err_args:

    return rc;
  }

/** Display usage */
static void show_usage(void) {
    static const char usage_text[] = "\
  File sector info . . . . . . . . . . . . . . . . . . . . Shao Miller, 2011\n\
\n\
  Usage: NTFSTEST.EXE <filename>\n\
\n\
  Attempts to dump cluster and sector info for <filename>.\n";

    printf(usage_text);
    return;
  }

static void show_last_err(void) {
    show_err(GetLastError());
    return;
  }

/** Display an error */
static void show_err(DWORD err_code) {
    void * buf;

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        NULL,
        err_code,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &buf,
        0,
        NULL
      );
    fprintf(stderr, "Error: %s\n", buf);
    LocalFree(buf);
    return;
  }