getsize.c revision 343fa65e9fc67e55717d622ee1db6553dc2285b4
1/* 2 * getsize.c --- get the size of a partition. 3 * 4 * Copyright (C) 1995, 1995 Theodore Ts'o. 5 * 6 * %Begin-Header% 7 * This file may be redistributed under the terms of the GNU Public 8 * License. 9 * %End-Header% 10 */ 11 12#define _LARGEFILE_SOURCE 13#define _LARGEFILE64_SOURCE 14 15#include <stdio.h> 16#if HAVE_UNISTD_H 17#include <unistd.h> 18#endif 19#if HAVE_ERRNO_H 20#include <errno.h> 21#endif 22#include <fcntl.h> 23#ifdef HAVE_LINUX_FD_H 24#include <sys/ioctl.h> 25#include <linux/fd.h> 26#endif 27#ifdef HAVE_SYS_DISKLABEL_H 28#include <sys/ioctl.h> 29#include <sys/disklabel.h> 30#endif /* HAVE_SYS_DISKLABEL_H */ 31 32#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE) 33#define BLKGETSIZE _IO(0x12,96) /* return device size */ 34#endif 35#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE64) 36#define BLKGETSIZE64 _IO(0x12,109) /* return device size */ 37#endif 38 39#include "ext2_fs.h" 40#include "ext2fs.h" 41 42static int valid_offset (int fd, ext2_loff_t offset) 43{ 44 char ch; 45 46 if (ext2fs_llseek (fd, offset, 0) < 0) 47 return 0; 48 if (read (fd, &ch, 1) < 1) 49 return 0; 50 return 1; 51} 52 53/* 54 * Returns the number of blocks in a partition 55 */ 56errcode_t ext2fs_get_device_size(const char *file, int blocksize, 57 blk_t *retblocks) 58{ 59 int fd; 60#ifdef BLKGETSIZE64 61 unsigned long long size64; 62#endif 63#ifdef BLKGETSIZE 64 unsigned long size; 65#endif 66 ext2_loff_t high, low; 67#ifdef FDGETPRM 68 struct floppy_struct this_floppy; 69#endif 70#ifdef HAVE_SYS_DISKLABEL_H 71 int part; 72 struct disklabel lab; 73 struct partition *pp; 74 char ch; 75#endif /* HAVE_SYS_DISKLABEL_H */ 76 77#ifdef HAVE_OPEN64 78 fd = open64(file, O_RDONLY); 79#else 80 fd = open(file, O_RDONLY); 81#endif 82 if (fd < 0) 83 return errno; 84 85#ifdef BLKGETSIZE64 86 if (ioctl(fd, BLKGETSIZE64, &size64) >= 0) { 87 close(fd); 88 size64 = size64 / (blocksize / 512); 89 *retblocks = size64; 90 if (*retblocks != size64) { 91 return EFBIG; 92 } 93 return 0; 94 } 95#endif 96#ifdef BLKGETSIZE 97 if (ioctl(fd, BLKGETSIZE, &size) >= 0) { 98 close(fd); 99 *retblocks = size / (blocksize / 512); 100 return 0; 101 } 102#endif 103#ifdef FDGETPRM 104 if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) { 105 close(fd); 106 *retblocks = this_floppy.size / (blocksize / 512); 107 return 0; 108 } 109#endif 110#ifdef HAVE_SYS_DISKLABEL_H 111 part = strlen(file) - 1; 112 if (part >= 0) { 113 ch = file[part]; 114 if (isdigit(ch)) 115 part = 0; 116 else if (ch >= 'a' && ch <= 'h') 117 part = ch - 'a'; 118 else 119 part = -1; 120 } 121 if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) { 122 pp = &lab.d_partitions[part]; 123 if (pp->p_size) { 124 close(fd); 125 *retblocks = pp->p_size / (blocksize / 512); 126 return 0; 127 } 128 } 129#endif /* HAVE_SYS_DISKLABEL_H */ 130 131 /* 132 * OK, we couldn't figure it out by using a specialized ioctl, 133 * which is generally the best way. So do binary search to 134 * find the size of the partition. 135 */ 136 low = 0; 137 for (high = 1024; valid_offset (fd, high); high *= 2) 138 low = high; 139 while (low < high - 1) 140 { 141 const ext2_loff_t mid = (low + high) / 2; 142 143 if (valid_offset (fd, mid)) 144 low = mid; 145 else 146 high = mid; 147 } 148 valid_offset (fd, 0); 149 close(fd); 150 *retblocks = (low + 1) / blocksize; 151 return 0; 152} 153 154#ifdef DEBUG 155int main(int argc, char **argv) 156{ 157 blk_t blocks; 158 int retval; 159 160 if (argc < 2) { 161 fprintf(stderr, "Usage: %s device\n", argv[0]); 162 exit(1); 163 } 164 165 retval = ext2fs_get_device_size(argv[1], 1024, &blocks); 166 if (retval) { 167 com_err(argv[0], retval, 168 "while calling ext2fs_get_device_size"); 169 exit(1); 170 } 171 printf("Device %s has %d 1k blocks.\n", argv[1], blocks); 172 exit(0); 173} 174#endif 175