1 /* vi: set sw=4 ts=4: */
3 * getsize.c --- get the size of a partition.
5 * Copyright (C) 1995, 1995 Theodore Ts'o.
6 * Copyright (C) 2003 VMware, Inc.
8 * Windows version of ext2fs_get_device_size by Chris Li, VMware.
11 * This file may be redistributed under the terms of the GNU Public
24 #ifdef HAVE_SYS_IOCTL_H
25 #include <sys/ioctl.h>
27 #ifdef HAVE_LINUX_FD_H
30 #ifdef HAVE_SYS_DISKLABEL_H
31 #include <sys/disklabel.h>
33 #ifdef HAVE_SYS_DISK_H
34 #ifdef HAVE_SYS_QUEUE_H
35 #include <sys/queue.h> /* for LIST_HEAD */
40 #include <sys/utsname.h>
43 #if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
44 #define BLKGETSIZE _IO(0x12,96) /* return device size */
47 #if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64)
48 #define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */
52 #define BLKGETSIZE DKIOCGETBLOCKCOUNT32
53 #endif /* APPLE_DARWIN */
58 #if defined(__CYGWIN__) || defined(WIN32)
62 #if (_WIN32_WINNT >= 0x0500)
63 #define HAVE_GET_FILE_SIZE_EX 1
66 errcode_t
ext2fs_get_device_size(const char *file
, int blocksize
,
70 PARTITION_INFORMATION pi
;
73 #ifdef HAVE_GET_FILE_SIZE_EX
74 LARGE_INTEGER filesize
;
77 #endif /* HAVE_GET_FILE_SIZE_EX */
79 dev
= CreateFile(file
, GENERIC_READ
,
80 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
81 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
83 if (dev
== INVALID_HANDLE_VALUE
)
85 if (DeviceIoControl(dev
, IOCTL_DISK_GET_PARTITION_INFO
,
86 &pi
, sizeof(PARTITION_INFORMATION
),
87 &pi
, sizeof(PARTITION_INFORMATION
),
90 *retblocks
= pi
.PartitionLength
.QuadPart
/ blocksize
;
92 } else if (DeviceIoControl(dev
, IOCTL_DISK_GET_DRIVE_GEOMETRY
,
93 &gi
, sizeof(DISK_GEOMETRY
),
94 &gi
, sizeof(DISK_GEOMETRY
),
97 *retblocks
= gi
.BytesPerSector
*
99 gi
.TracksPerCylinder
*
100 gi
.Cylinders
.QuadPart
/ blocksize
;
102 #ifdef HAVE_GET_FILE_SIZE_EX
103 } else if (GetFileSizeEx(dev
, &filesize
)) {
104 *retblocks
= filesize
.QuadPart
/ blocksize
;
108 filesize
= GetFileSize(dev
, NULL
);
109 if (INVALID_FILE_SIZE
!= filesize
) {
110 *retblocks
= filesize
/ blocksize
;
113 #endif /* HAVE_GET_FILE_SIZE_EX */
121 static int valid_offset (int fd
, ext2_loff_t offset
)
125 if (ext2fs_llseek (fd
, offset
, 0) < 0)
127 if (read (fd
, &ch
, 1) < 1)
133 * Returns the number of blocks in a partition
135 errcode_t
ext2fs_get_device_size(const char *file
, int blocksize
,
139 int valid_blkgetsize64
= 1;
143 unsigned long long size64
;
145 ext2_loff_t high
, low
;
147 struct floppy_struct this_floppy
;
149 #ifdef HAVE_SYS_DISKLABEL_H
151 struct disklabel lab
;
152 struct partition
*pp
;
154 #endif /* HAVE_SYS_DISKLABEL_H */
157 fd
= open64(file
, O_RDONLY
);
159 fd
= open(file
, O_RDONLY
);
164 #ifdef DKIOCGETBLOCKCOUNT /* For Apple Darwin */
165 if (ioctl(fd
, DKIOCGETBLOCKCOUNT
, &size64
) >= 0) {
166 if ((sizeof(*retblocks
) < sizeof(unsigned long long))
167 && ((size64
/ (blocksize
/ 512)) > 0xFFFFFFFF))
170 *retblocks
= size64
/ (blocksize
/ 512);
178 if ((ut
.release
[0] == '2') && (ut
.release
[1] == '.') &&
179 (ut
.release
[2] < '6') && (ut
.release
[3] == '.'))
180 valid_blkgetsize64
= 0;
182 if (valid_blkgetsize64
&&
183 ioctl(fd
, BLKGETSIZE64
, &size64
) >= 0) {
184 if ((sizeof(*retblocks
) < sizeof(unsigned long long))
185 && ((size64
/ blocksize
) > 0xFFFFFFFF))
188 *retblocks
= size64
/ blocksize
;
194 if (ioctl(fd
, BLKGETSIZE
, &size
) >= 0) {
196 *retblocks
= size
/ (blocksize
/ 512);
202 if (ioctl(fd
, FDGETPRM
, &this_floppy
) >= 0) {
204 *retblocks
= this_floppy
.size
/ (blocksize
/ 512);
209 #ifdef HAVE_SYS_DISKLABEL_H
210 #if defined(DIOCGMEDIASIZE)
214 if (ioctl(fd
, DIOCGMEDIASIZE
, &ms
) >= 0) {
216 *retblocks
= ms
/ blocksize
;
220 #elif defined(DIOCGDINFO)
221 /* old disklabel interface */
222 part
= strlen(file
) - 1;
227 else if (ch
>= 'a' && ch
<= 'h')
232 if (part
>= 0 && (ioctl(fd
, DIOCGDINFO
, (char *)&lab
) >= 0)) {
233 pp
= &lab
.d_partitions
[part
];
236 *retblocks
= pp
->p_size
/ (blocksize
/ 512);
240 #endif /* defined(DIOCG*) */
241 #endif /* HAVE_SYS_DISKLABEL_H */
244 * OK, we couldn't figure it out by using a specialized ioctl,
245 * which is generally the best way. So do binary search to
246 * find the size of the partition.
249 for (high
= 1024; valid_offset (fd
, high
); high
*= 2)
251 while (low
< high
- 1)
253 const ext2_loff_t mid
= (low
+ high
) / 2;
255 if (valid_offset (fd
, mid
))
260 valid_offset (fd
, 0);
263 if ((sizeof(*retblocks
) < sizeof(unsigned long long))
264 && ((size64
/ blocksize
) > 0xFFFFFFFF))
266 *retblocks
= size64
/ blocksize
;
273 int main(int argc
, char **argv
)
279 fprintf(stderr
, "Usage: %s device\n", argv
[0]);
283 retval
= ext2fs_get_device_size(argv
[1], 1024, &blocks
);
285 com_err(argv
[0], retval
,
286 "while calling ext2fs_get_device_size");
289 printf("Device %s has %d 1k blocks.\n", argv
[1], blocks
);