]>
Commit | Line | Data |
---|---|---|
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 | ||
44 | static 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 | */ | |
58 | errcode_t ext2fs_get_device_size(const char *file, int blocksize, | |
59 | blk_t *retblocks) | |
60 | { | |
61 | int fd; | |
62 | #ifdef BLKGETSIZE | |
63 | 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 | } |