filefrag.c revision 3d16b3f4bbb4c1f43a442e303658a7a50320c40a
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * filefrag.c -- report if a particular file is fragmented 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright 2003 by Theodore Ts'o. 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * %Begin-Header% 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This file may be redistributed under the terms of the GNU Public 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * License. 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * %End-Header% 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef __linux__ 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h> 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <stdlib.h> 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int main(void) { 17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch fputs("This program is only supported on Linux!\n", stderr); 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit(EXIT_FAILURE); 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define _LARGEFILE64_SOURCE 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h> 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h> 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h> 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h> 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <time.h> 28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <fcntl.h> 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h> 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_GETOPT_H 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <getopt.h> 327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#else 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern char *optarg; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern int optind; 351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#endif 361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include <sys/types.h> 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/stat.h> 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/vfs.h> 391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include <sys/ioctl.h> 401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include <linux/fd.h> 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int verbose = 0; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 44c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#define FIBMAP _IO(0x00,1) /* bmap access */ 45e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */ 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define EXT3_EXTENTS_FL 0x00080000 /* Inode uses extents */ 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define EXT3_IOC_GETFLAGS _IOR('f', 1, long) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static unsigned long get_bmap(int fd, unsigned long block) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int ret; 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) unsigned long b; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) b = block; 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ret = ioctl(fd, FIBMAP, &b); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ret < 0) { 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (errno == EPERM) { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fprintf(stderr, "No permission to use FIBMAP ioctl; must have root privileges\n"); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit(1); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) perror("FIBMAP"); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return b; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define EXT2_DIRECT 12 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void frag_report(const char *filename) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct statfs fsinfo; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) struct stat64 fileinfo; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) long i, fd, bs, block, last_block = 0, numblocks; 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) long bpib; /* Blocks per indirect block */ 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) long cylgroups; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int discont = 0, expected; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int is_ext2 = 0; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int flags; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (statfs(filename, &fsinfo) < 0) { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) perror("statfs"); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (stat64(filename, &fileinfo) < 0) { 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) perror("stat"); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!S_ISREG(fileinfo.st_mode)) { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("%s: Not a regular file\n", filename); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((fsinfo.f_type == 0xef51) || (fsinfo.f_type == 0xef52) || 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (fsinfo.f_type == 0xef53)) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_ext2++; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (verbose) { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("Filesystem type is: %x\n", fsinfo.f_type); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cylgroups = (fsinfo.f_blocks + fsinfo.f_bsize*8-1) / fsinfo.f_bsize*8; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (verbose) { 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("Filesystem cylinder groups is approximately %ld\n", 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cylgroups); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fd = open(filename, O_RDONLY | O_LARGEFILE); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (fd < 0) { 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) perror("open"); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ioctl(fd, FIGETBSZ, &bs) < 0) { 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) perror("FIGETBSZ"); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) close(fd); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ioctl(fd, EXT3_IOC_GETFLAGS, &flags) < 0) { 114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) perror("EXT3_IOC_GETFLAGS"); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) close(fd); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flags & EXT3_EXTENTS_FL) { 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("File is stored in extents format\n"); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_ext2 = 0; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (verbose) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("Blocksize of file %s is %ld\n", filename, bs); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bpib = bs / 4; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) numblocks = (fileinfo.st_size + (bs-1)) / bs; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (verbose) { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("File size of %s is %lld (%ld blocks)\n", filename, 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (long long) fileinfo.st_size, numblocks); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("First block: %ld\nLast block: %ld\n", 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) get_bmap(fd, 0), get_bmap(fd, numblocks - 1)); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i=0; i < numblocks; i++) { 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_ext2) { 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (((i-EXT2_DIRECT) % bpib) == 0) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_block++; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (((i-EXT2_DIRECT-bpib) % (bpib*bpib)) == 0) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_block++; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (((i-EXT2_DIRECT-bpib-bpib*bpib) % (bpib*bpib*bpib)) == 0) 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_block++; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) block = get_bmap(fd, i); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (block == 0) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (last_block && (block != last_block +1) ) { 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (verbose) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("Discontinuity: Block %ld is at %ld (was %ld)\n", 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i, block, last_block); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) discont++; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_block = block; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (discont==0) 153e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch printf("%s: 1 extent found", filename); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) printf("%s: %d extents found", filename, discont+1); 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) expected = (numblocks/((bs*8)-(fsinfo.f_files/8/cylgroups)-3))+1; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_ext2 && expected != discont+1) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf(", perfection would be %d extent%s\n", expected, 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (expected>1) ? "s" : ""); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fputc('\n', stdout); 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) close(fd); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void usage(const char *progname) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fprintf(stderr, "Usage: %s [-v] file ...\n", progname); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit(1); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int main(int argc, char**argv) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char **cpp; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int c; 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while ((c = getopt(argc, argv, "v")) != EOF) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (c) { 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case 'v': 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) verbose++; 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usage(argv[0]); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (optind == argc) 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usage(argv[0]); 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (cpp=argv+optind; *cpp; cpp++) { 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (verbose) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) printf("Checking %s\n", *cpp); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frag_report(*cpp); 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)