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