Whamcloud - gitweb
ChangeLog, ext2_err.et.in:
[tools/e2fsprogs.git] / lib / ext2fs / getsize.c
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 #include <stdio.h>
13 #if HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif
16 #if HAVE_ERRNO_H
17 #include <errno.h>
18 #endif
19 #include <fcntl.h>
20 #ifdef HAVE_LINUX_FS_H
21 #include <linux/fs.h>
22 #endif
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
40 static 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  */
54 errcode_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         fd = open(file, O_RDONLY);
73         if (fd < 0)
74                 return errno;
75
76 #ifdef BLKGETSIZE
77         if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
78                 close(fd);
79                 *retblocks = size / (blocksize / 512);
80                 return 0;
81         }
82 #endif
83 #ifdef FDGETPRM
84         if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) {
85                 close(fd);
86                 *retblocks = this_floppy.size / (blocksize / 512);
87                 return 0;
88         }
89 #endif
90 #ifdef HAVE_SYS_DISKLABEL_H
91         part = strlen(file) - 1;
92         if (part >= 0) {
93                 ch = file[part];
94                 if (isdigit(ch))
95                         part = 0;
96                 else if (ch >= 'a' && ch <= 'h')
97                         part = ch - 'a';
98                 else
99                         part = -1;
100         }
101         if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
102                 pp = &lab.d_partitions[part];
103                 if (pp->p_size) {
104                         close(fd);
105                         *retblocks = pp->p_size / (blocksize / 512);
106                         return 0;
107                 }
108         }
109 #endif /* HAVE_SYS_DISKLABEL_H */
110
111         /*
112          * OK, we couldn't figure it out by using a specialized ioctl,
113          * which is generally the best way.  So do binary search to
114          * find the size of the partition.
115          */
116         low = 0;
117         for (high = 1024; valid_offset (fd, high); high *= 2)
118                 low = high;
119         while (low < high - 1)
120         {
121                 const ext2_loff_t mid = (low + high) / 2;
122
123                 if (valid_offset (fd, mid))
124                         low = mid;
125                 else
126                         high = mid;
127         }
128         valid_offset (fd, 0);
129         close(fd);
130         *retblocks = (low + 1) / blocksize;
131         return 0;
132 }