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