~ubuntu-branches/ubuntu/trusty/util-linux/trusty-proposed

« back to all changes in this revision

Viewing changes to lib/blkdev.c

  • Committer: Bazaar Package Importer
  • Author(s): LaMont Jones
  • Date: 2011-05-11 08:38:31 UTC
  • mfrom: (1.3.10 upstream)
  • mto: (1.6.3 upstream) (4.5.5 sid)
  • mto: This revision was merged to the branch mainline in revision 82.
  • Revision ID: james.westby@ubuntu.com-20110511083831-tty7wnezw55fmrn4
ImportĀ upstreamĀ versionĀ 2.19.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
 
2
2
#include <sys/types.h>
 
3
#include <sys/stat.h>
3
4
#include <sys/ioctl.h>
4
5
#include <unistd.h>
 
6
#include <stdint.h>
 
7
 
 
8
#ifdef HAVE_LINUX_FD_H
 
9
#include <linux/fd.h>
 
10
#endif
 
11
 
 
12
#ifdef HAVE_SYS_DISKLABEL_H
 
13
#include <sys/disklabel.h>
 
14
#endif
 
15
 
 
16
#ifdef HAVE_SYS_DISK_H
 
17
#ifdef HAVE_SYS_QUEUE_H
 
18
#include <sys/queue.h> /* for LIST_HEAD */
 
19
#endif
 
20
#include <sys/disk.h>
 
21
#endif
5
22
 
6
23
#include "blkdev.h"
7
24
#include "linux_version.h"
19
36
 
20
37
off_t
21
38
blkdev_find_size (int fd) {
22
 
        off_t high, low;
23
 
 
24
 
        low = 0;
25
 
        for (high = 1; high > 0 && blkdev_valid_offset (fd, high); high *= 2)
 
39
        uintmax_t high, low = 0;
 
40
 
 
41
        for (high = 1024; blkdev_valid_offset (fd, high); ) {
 
42
                if (high == UINTMAX_MAX)
 
43
                        return -1;
 
44
 
26
45
                low = high;
 
46
 
 
47
                if (high >= UINTMAX_MAX/2)
 
48
                        high = UINTMAX_MAX;
 
49
                else
 
50
                        high *= 2;
 
51
        }
 
52
 
27
53
        while (low < high - 1)
28
54
        {
29
 
                const off_t mid = (low + high) / 2;
 
55
                uintmax_t mid = (low + high) / 2;
30
56
 
31
57
                if (blkdev_valid_offset (fd, mid))
32
58
                        low = mid;
41
67
int
42
68
blkdev_get_size(int fd, unsigned long long *bytes)
43
69
{
44
 
        /* TODO: use stat as well */
 
70
#ifdef DKIOCGETBLOCKCOUNT
 
71
        /* Apple Darwin */
 
72
        if (ioctl(fd, DKIOCGETBLOCKCOUNT, bytes) >= 0) {
 
73
                *bytes <<= 9;
 
74
                return 0;
 
75
        }
 
76
#endif
45
77
 
46
78
#ifdef BLKGETSIZE64
 
79
        {
47
80
#ifdef __linux__
48
 
        int ver = get_linux_version();
49
 
        /* kernels 2.4.15-2.4.17, had a broken BLKGETSIZE64 */
50
 
        if (ver >= KERNEL_VERSION (2,6,0) ||
51
 
           (ver >= KERNEL_VERSION (2,4,18) && ver < KERNEL_VERSION (2,5,0)))
 
81
                int ver = get_linux_version();
 
82
 
 
83
                /* kernels 2.4.15-2.4.17, had a broken BLKGETSIZE64 */
 
84
                if (ver >= KERNEL_VERSION (2,6,0) ||
 
85
                   (ver >= KERNEL_VERSION (2,4,18) && ver < KERNEL_VERSION (2,5,0)))
52
86
#endif
53
 
                if (ioctl(fd, BLKGETSIZE64, bytes) >= 0)
54
 
                        return 0;
 
87
                        if (ioctl(fd, BLKGETSIZE64, bytes) >= 0)
 
88
                                return 0;
 
89
        }
55
90
#endif /* BLKGETSIZE64 */
56
91
 
57
92
#ifdef BLKGETSIZE
64
99
                }
65
100
        }
66
101
 
67
 
        return -1;
68
102
#endif /* BLKGETSIZE */
69
103
 
 
104
#ifdef DIOCGMEDIASIZE
 
105
        /* FreeBSD */
 
106
        if (ioctl(fd, DIOCGMEDIASIZE, bytes) >= 0)
 
107
                return 0;
 
108
#endif
 
109
 
 
110
#ifdef FDGETPRM
 
111
        {
 
112
                struct floppy_struct this_floppy;
 
113
 
 
114
                if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) {
 
115
                        *bytes = this_floppy.size << 9;
 
116
                        return 0;
 
117
                }
 
118
        }
 
119
#endif /* FDGETPRM */
 
120
 
 
121
#ifdef HAVE_SYS_DISKLABEL_H
 
122
        {
 
123
                /*
 
124
                 * This code works for FreeBSD 4.11 i386, except for the full device
 
125
                 * (such as /dev/ad0). It doesn't work properly for newer FreeBSD
 
126
                 * though. FreeBSD >= 5.0 should be covered by the DIOCGMEDIASIZE
 
127
                 * above however.
 
128
                 *
 
129
                 * Note that FreeBSD >= 4.0 has disk devices as unbuffered (raw,
 
130
                 * character) devices, so we need to check for S_ISCHR, too.
 
131
                 */
 
132
                int part = -1;
 
133
                struct disklabel lab;
 
134
                struct partition *pp;
 
135
                char ch;
 
136
                struct stat st;
 
137
 
 
138
                if ((fstat(fd, &st) >= 0) &&
 
139
                    (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)))
 
140
                        part = st.st_rdev & 7;
 
141
 
 
142
                if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
 
143
                        pp = &lab.d_partitions[part];
 
144
                        if (pp->p_size) {
 
145
                                 *bytes = pp->p_size << 9;
 
146
                                 return 0;
 
147
                        }
 
148
                }
 
149
        }
 
150
#endif /* HAVE_SYS_DISKLABEL_H */
 
151
 
 
152
        {
 
153
                struct stat st;
 
154
 
 
155
                if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
 
156
                        *bytes = st.st_size;
 
157
                        return 0;
 
158
                }
 
159
                if (!S_ISBLK(st.st_mode))
 
160
                        return -1;
 
161
        }
 
162
 
70
163
        *bytes = blkdev_find_size(fd);
71
164
        return 0;
72
165
}