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