getsize.c revision 954a683dd0353d280d56b3d70b5e8f24e88b3d2f
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 36#if EXT2_FLAT_INCLUDES 37#include "ext2_fs.h" 38#else 39#include <linux/ext2_fs.h> 40#endif 41 42#include "ext2fs.h" 43 44static int valid_offset (int fd, ext2_loff_t offset) 45{ 46 char ch; 47 48 if (ext2fs_llseek (fd, offset, 0) < 0) 49 return 0; 50 if (read (fd, &ch, 1) < 1) 51 return 0; 52 return 1; 53} 54 55/* 56 * Returns the number of blocks in a partition 57 */ 58errcode_t ext2fs_get_device_size(const char *file, int blocksize, 59 blk_t *retblocks) 60{ 61 int fd; 62#ifdef BLKGETSIZE 63 unsigned long size; 64#endif 65 ext2_loff_t high, low; 66#ifdef FDGETPRM 67 struct floppy_struct this_floppy; 68#endif 69#ifdef HAVE_SYS_DISKLABEL_H 70 int part; 71 struct disklabel lab; 72 struct partition *pp; 73 char ch; 74#endif /* HAVE_SYS_DISKLABEL_H */ 75 76#ifdef HAVE_OPEN64 77 fd = open64(file, O_RDONLY); 78#else 79 fd = open(file, O_RDONLY); 80#endif 81 if (fd < 0) 82 return errno; 83 84#ifdef BLKGETSIZE 85 if (ioctl(fd, BLKGETSIZE, &size) >= 0) { 86 close(fd); 87 *retblocks = size / (blocksize / 512); 88 return 0; 89 } 90#endif 91#ifdef FDGETPRM 92 if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) { 93 close(fd); 94 *retblocks = this_floppy.size / (blocksize / 512); 95 return 0; 96 } 97#endif 98#ifdef HAVE_SYS_DISKLABEL_H 99 part = strlen(file) - 1; 100 if (part >= 0) { 101 ch = file[part]; 102 if (isdigit(ch)) 103 part = 0; 104 else if (ch >= 'a' && ch <= 'h') 105 part = ch - 'a'; 106 else 107 part = -1; 108 } 109 if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) { 110 pp = &lab.d_partitions[part]; 111 if (pp->p_size) { 112 close(fd); 113 *retblocks = pp->p_size / (blocksize / 512); 114 return 0; 115 } 116 } 117#endif /* HAVE_SYS_DISKLABEL_H */ 118 119 /* 120 * OK, we couldn't figure it out by using a specialized ioctl, 121 * which is generally the best way. So do binary search to 122 * find the size of the partition. 123 */ 124 low = 0; 125 for (high = 1024; valid_offset (fd, high); high *= 2) 126 low = high; 127 while (low < high - 1) 128 { 129 const ext2_loff_t mid = (low + high) / 2; 130 131 if (valid_offset (fd, mid)) 132 low = mid; 133 else 134 high = mid; 135 } 136 valid_offset (fd, 0); 137 close(fd); 138 *retblocks = (low + 1) / blocksize; 139 return 0; 140} 141 142#ifdef DEBUG 143int main(int argc, char **argv) 144{ 145 blk_t blocks; 146 int retval; 147 148 if (argc < 2) { 149 fprintf(stderr, "Usage: %s device\n", argv[0]); 150 exit(1); 151 } 152 153 retval = ext2fs_get_device_size(argv[1], 1024, &blocks); 154 if (retval) { 155 com_err(argv[0], retval, 156 "while calling ext2fs_get_device_size"); 157 exit(1); 158 } 159 printf("Device %s has %d 1k blocks.\n", argv[1], blocks); 160 exit(0); 161} 162#endif 163