* %End-Header%
*/
-#ifndef __LINUX__
+#ifndef __linux__
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <errno.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern char *optarg;
+extern int optind;
+#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/vfs.h>
#define FIBMAP _IO(0x00,1) /* bmap access */
#define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */
+#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */
+#define EXT3_IOC_GETFLAGS _IOR('f', 1, long)
+
+static unsigned int div_ceil(unsigned int a, unsigned int b)
+{
+ if (!a)
+ return 0;
+ return ((a - 1) / b) + 1;
+}
+
static unsigned long get_bmap(int fd, unsigned long block)
{
int ret;
- unsigned long b;
+ unsigned int b;
b = block;
- ret = ioctl(fd, FIBMAP, &b);
+ ret = ioctl(fd, FIBMAP, &b); /* FIBMAP takes a pointer to an integer */
if (ret < 0) {
if (errno == EPERM) {
fprintf(stderr, "No permission to use FIBMAP ioctl; must have root privileges\n");
#define EXT2_DIRECT 12
-void frag_report(const char *filename)
+static void frag_report(const char *filename)
{
struct statfs fsinfo;
+#ifdef HAVE_FSTAT64
struct stat64 fileinfo;
- long i, fd, bs, block, last_block, numblocks;
+#else
+ struct stat fileinfo;
+#endif
+ int bs;
+ long fd;
+ unsigned long block, last_block = 0, numblocks, i;
long bpib; /* Blocks per indirect block */
long cylgroups;
int discont = 0, expected;
int is_ext2 = 0;
+ unsigned int flags;
if (statfs(filename, &fsinfo) < 0) {
perror("statfs");
return;
}
+#ifdef HAVE_FSTAT64
if (stat64(filename, &fileinfo) < 0) {
+#else
+ if (stat(filename, &fileinfo) < 0) {
+#endif
perror("stat");
return;
}
(fsinfo.f_type == 0xef53))
is_ext2++;
if (verbose) {
- printf("Filesystem type is: %x\n", fsinfo.f_type);
+ printf("Filesystem type is: %lx\n",
+ (unsigned long) fsinfo.f_type);
}
- cylgroups = (fsinfo.f_blocks + fsinfo.f_bsize*8-1) / fsinfo.f_bsize*8;
+ cylgroups = div_ceil(fsinfo.f_blocks, fsinfo.f_bsize*8);
if (verbose) {
printf("Filesystem cylinder groups is approximately %ld\n",
cylgroups);
}
- fd = open(filename, O_RDONLY | O_LARGEFILE);
+#ifdef HAVE_OPEN64
+ fd = open64(filename, O_RDONLY);
+#else
+ fd = open(filename, O_RDONLY);
+#endif
if (fd < 0) {
perror("open");
return;
}
- if (ioctl(fd, FIGETBSZ, &bs) < 0) {
+ if (ioctl(fd, FIGETBSZ, &bs) < 0) { /* FIGETBSZ takes an int */
perror("FIGETBSZ");
+ close(fd);
return;
}
+ if (ioctl(fd, EXT3_IOC_GETFLAGS, &flags) < 0)
+ flags = 0;
+ if (flags & EXT4_EXTENTS_FL) {
+ printf("File is stored in extents format\n");
+ is_ext2 = 0;
+ }
if (verbose)
- printf("Blocksize of file %s is %ld\n", filename, bs);
+ printf("Blocksize of file %s is %d\n", filename, bs);
bpib = bs / 4;
numblocks = (fileinfo.st_size + (bs-1)) / bs;
- if (verbose)
+ if (verbose) {
printf("File size of %s is %lld (%ld blocks)\n", filename,
(long long) fileinfo.st_size, numblocks);
+ printf("First block: %lu\nLast block: %lu\n",
+ get_bmap(fd, 0), get_bmap(fd, numblocks - 1));
+ }
for (i=0; i < numblocks; i++) {
- if (is_ext2) {
+ if (is_ext2 && last_block) {
if (((i-EXT2_DIRECT) % bpib) == 0)
last_block++;
if (((i-EXT2_DIRECT-bpib) % (bpib*bpib)) == 0)
last_block++;
}
block = get_bmap(fd, i);
- if (i && (block != last_block +1) ) {
+ if (block == 0)
+ continue;
+ if (last_block && (block != last_block +1) ) {
if (verbose)
- printf("Discontinuity: Block %ld is at %ld (was %ld)\n",
+ printf("Discontinuity: Block %ld is at %lu (was %lu)\n",
i, block, last_block);
discont++;
}
- if (block)
- last_block = block;
+ last_block = block;
}
if (discont==0)
printf("%s: 1 extent found", filename);
(expected>1) ? "s" : "");
else
fputc('\n', stdout);
-
+ close(fd);
}
-void usage(const char *progname)
+static void usage(const char *progname)
{
fprintf(stderr, "Usage: %s [-v] file ...\n", progname);
exit(1);