Skip to content

Commit

Permalink
dumpexfat: add option to show file fragments.
Browse files Browse the repository at this point in the history
Add an option to show a list of fragments that a given file is composed
of. This is useful for if you want to have low-level access to a file
without going through the file system layers.
  • Loading branch information
dsd authored and relan committed Dec 5, 2016
1 parent e10d9d0 commit 1b38628
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 2 deletions.
9 changes: 9 additions & 0 deletions dump/dumpexfat.8
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
.B \-u
]
[
.B \-f
.I file
]
[
.B \-V
]
.I device
Expand All @@ -33,6 +37,11 @@ systems.
Dump ranges of used sectors starting from 0 and separated with spaces. May be
useful for backup tools.
.TP
.B \-f file
Print out a list of fragments that compose the given file. Each fragment is
printed on its own line, as the start offset (in bytes) into the file system,
and the length (in bytes).
.TP
.BI \-V
Print version and copyright.

Expand Down
68 changes: 66 additions & 2 deletions dump/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,66 @@ static int dump_full(const char* spec, bool used_sectors)
return 0;
}

static int dump_file_fragments(const char* spec, const char* path)
{
struct exfat ef;
struct exfat_node* node;
cluster_t cluster;
cluster_t next_cluster;
cluster_t fragment_start_cluster;
off_t remainder;
off_t fragment_size = 0;
int rc = 0;

if (exfat_mount(&ef, spec, "ro") != 0)
return 1;

rc = exfat_lookup(&ef, &node, path);
if (rc != 0)
{
exfat_unmount(&ef);
exfat_error("'%s': %s", path, strerror(-rc));
return 1;
}

cluster = fragment_start_cluster = node->start_cluster;
remainder = node->size;
while (remainder > 0)
{
off_t lsize;

if (CLUSTER_INVALID(cluster))
{
exfat_error("'%s' has invalid cluster %#x", path, cluster);
rc = 1;
break;
}

lsize = MIN(CLUSTER_SIZE(*ef.sb), remainder);
fragment_size += lsize;
remainder -= lsize;

next_cluster = exfat_next_cluster(&ef, node, cluster);
if (next_cluster != cluster + 1 || remainder == 0)
{
/* next cluster is not contiguous or this is EOF */
printf("%"PRIu64" %"PRIu64"\n",
exfat_c2o(&ef, fragment_start_cluster), fragment_size);
/* start a new fragment */
fragment_start_cluster = next_cluster;
fragment_size = 0;
}
cluster = next_cluster;
}

exfat_put_node(&ef, node);
exfat_unmount(&ef);
return rc;
}

static void usage(const char* prog)
{
fprintf(stderr, "Usage: %s [-s] [-u] [-V] <device>\n", prog);
fprintf(stderr, "Usage: %s [-s] [-u] [-f file] [-V] <device>\n", prog);
exit(1);
}

Expand All @@ -152,10 +209,11 @@ int main(int argc, char* argv[])
const char* spec = NULL;
bool sb_only = false;
bool used_sectors = false;
const char* file_path = NULL;

printf("dumpexfat %s\n", VERSION);

while ((opt = getopt(argc, argv, "suV")) != -1)
while ((opt = getopt(argc, argv, "suf:V")) != -1)
{
switch (opt)
{
Expand All @@ -165,6 +223,9 @@ int main(int argc, char* argv[])
case 'u':
used_sectors = true;
break;
case 'f':
file_path = optarg;
break;
case 'V':
puts("Copyright (C) 2011-2016 Andrew Nayenko");
return 0;
Expand All @@ -176,6 +237,9 @@ int main(int argc, char* argv[])
usage(argv[0]);
spec = argv[optind];

if (file_path)
return dump_file_fragments(spec, file_path);

if (sb_only)
return dump_sb(spec);

Expand Down

0 comments on commit 1b38628

Please sign in to comment.