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