busybox/e2fsprogs/old_e2fsprogs/ext2fs/getsize.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * getsize.c --- get the size of a partition.
   4 *
   5 * Copyright (C) 1995, 1995 Theodore Ts'o.
   6 * Copyright (C) 2003 VMware, Inc.
   7 *
   8 * Windows version of ext2fs_get_device_size by Chris Li, VMware.
   9 *
  10 * %Begin-Header%
  11 * This file may be redistributed under the terms of the GNU Public
  12 * License.
  13 * %End-Header%
  14 */
  15
  16#include <stdio.h>
  17#if HAVE_UNISTD_H
  18#include <unistd.h>
  19#endif
  20#if HAVE_ERRNO_H
  21#include <errno.h>
  22#endif
  23#include <fcntl.h>
  24#ifdef HAVE_SYS_IOCTL_H
  25#include <sys/ioctl.h>
  26#endif
  27#ifdef HAVE_LINUX_FD_H
  28#include <linux/fd.h>
  29#endif
  30#ifdef HAVE_SYS_DISKLABEL_H
  31#include <sys/disklabel.h>
  32#endif
  33#ifdef HAVE_SYS_DISK_H
  34#ifdef HAVE_SYS_QUEUE_H
  35#include <sys/queue.h> /* for LIST_HEAD */
  36#endif
  37#include <sys/disk.h>
  38#endif
  39#ifdef __linux__
  40#include <sys/utsname.h>
  41#endif
  42
  43#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
  44#define BLKGETSIZE _IO(0x12,96) /* return device size */
  45#endif
  46
  47#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64)
  48#define BLKGETSIZE64 _IOR(0x12,114,size_t)      /* return device size in bytes (u64 *arg) */
  49#endif
  50
  51#ifdef APPLE_DARWIN
  52#define BLKGETSIZE DKIOCGETBLOCKCOUNT32
  53#endif /* APPLE_DARWIN */
  54
  55#include "ext2_fs.h"
  56#include "ext2fs.h"
  57
  58#if defined(__CYGWIN__) || defined(WIN32)
  59#include <windows.h>
  60#include <winioctl.h>
  61
  62#if (_WIN32_WINNT >= 0x0500)
  63#define HAVE_GET_FILE_SIZE_EX 1
  64#endif
  65
  66errcode_t ext2fs_get_device_size(const char *file, int blocksize,
  67                                 blk_t *retblocks)
  68{
  69        HANDLE dev;
  70        PARTITION_INFORMATION pi;
  71        DISK_GEOMETRY gi;
  72        DWORD retbytes;
  73#ifdef HAVE_GET_FILE_SIZE_EX
  74        LARGE_INTEGER filesize;
  75#else
  76        DWORD filesize;
  77#endif /* HAVE_GET_FILE_SIZE_EX */
  78
  79        dev = CreateFile(file, GENERIC_READ,
  80                         FILE_SHARE_READ | FILE_SHARE_WRITE ,
  81                         NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  82
  83        if (dev == INVALID_HANDLE_VALUE)
  84                return EBADF;
  85        if (DeviceIoControl(dev, IOCTL_DISK_GET_PARTITION_INFO,
  86                            &pi, sizeof(PARTITION_INFORMATION),
  87                            &pi, sizeof(PARTITION_INFORMATION),
  88                            &retbytes, NULL)) {
  89
  90                *retblocks = pi.PartitionLength.QuadPart / blocksize;
  91
  92        } else if (DeviceIoControl(dev, IOCTL_DISK_GET_DRIVE_GEOMETRY,
  93                                &gi, sizeof(DISK_GEOMETRY),
  94                                &gi, sizeof(DISK_GEOMETRY),
  95                                &retbytes, NULL)) {
  96
  97                *retblocks = gi.BytesPerSector *
  98                             gi.SectorsPerTrack *
  99                             gi.TracksPerCylinder *
 100                             gi.Cylinders.QuadPart / blocksize;
 101
 102#ifdef HAVE_GET_FILE_SIZE_EX
 103        } else if (GetFileSizeEx(dev, &filesize)) {
 104                *retblocks = filesize.QuadPart / blocksize;
 105        }
 106#else
 107        } else {
 108                filesize = GetFileSize(dev, NULL);
 109                if (INVALID_FILE_SIZE != filesize) {
 110                        *retblocks = filesize / blocksize;
 111                }
 112        }
 113#endif /* HAVE_GET_FILE_SIZE_EX */
 114
 115        CloseHandle(dev);
 116        return 0;
 117}
 118
 119#else
 120
 121static int valid_offset (int fd, ext2_loff_t offset)
 122{
 123        char ch;
 124
 125        if (ext2fs_llseek (fd, offset, 0) < 0)
 126                return 0;
 127        if (read (fd, &ch, 1) < 1)
 128                return 0;
 129        return 1;
 130}
 131
 132/*
 133 * Returns the number of blocks in a partition
 134 */
 135errcode_t ext2fs_get_device_size(const char *file, int blocksize,
 136                                 blk_t *retblocks)
 137{
 138        int     fd;
 139        int valid_blkgetsize64 = 1;
 140#ifdef __linux__
 141        struct          utsname ut;
 142#endif
 143        unsigned long long size64;
 144        unsigned long   size;
 145        ext2_loff_t high, low;
 146#ifdef FDGETPRM
 147        struct floppy_struct this_floppy;
 148#endif
 149#ifdef HAVE_SYS_DISKLABEL_H
 150        int part;
 151        struct disklabel lab;
 152        struct partition *pp;
 153        char ch;
 154#endif /* HAVE_SYS_DISKLABEL_H */
 155
 156#ifdef CONFIG_LFS
 157        fd = open64(file, O_RDONLY);
 158#else
 159        fd = open(file, O_RDONLY);
 160#endif
 161        if (fd < 0)
 162                return errno;
 163
 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))
 168                        return EFBIG;
 169                close(fd);
 170                *retblocks = size64 / (blocksize / 512);
 171                return 0;
 172        }
 173#endif
 174
 175#ifdef BLKGETSIZE64
 176#ifdef __linux__
 177        if ((uname(&ut) == 0) &&
 178            ((ut.release[0] == '2') && (ut.release[1] == '.') &&
 179             (ut.release[2] < '6') && (ut.release[3] == '.')))
 180                valid_blkgetsize64 = 0;
 181#endif
 182        if (valid_blkgetsize64 &&
 183            ioctl(fd, BLKGETSIZE64, &size64) >= 0) {
 184                if ((sizeof(*retblocks) < sizeof(unsigned long long))
 185                    && ((size64 / blocksize) > 0xFFFFFFFF))
 186                        return EFBIG;
 187                close(fd);
 188                *retblocks = size64 / blocksize;
 189                return 0;
 190        }
 191#endif
 192
 193#ifdef BLKGETSIZE
 194        if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
 195                close(fd);
 196                *retblocks = size / (blocksize / 512);
 197                return 0;
 198        }
 199#endif
 200
 201#ifdef FDGETPRM
 202        if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) {
 203                close(fd);
 204                *retblocks = this_floppy.size / (blocksize / 512);
 205                return 0;
 206        }
 207#endif
 208
 209#ifdef HAVE_SYS_DISKLABEL_H
 210#if defined(DIOCGMEDIASIZE)
 211        {
 212            off_t ms;
 213            u_int bs;
 214            if (ioctl(fd, DIOCGMEDIASIZE, &ms) >= 0) {
 215                *retblocks = ms / blocksize;
 216                return 0;
 217            }
 218        }
 219#elif defined(DIOCGDINFO)
 220        /* old disklabel interface */
 221        part = strlen(file) - 1;
 222        if (part >= 0) {
 223                ch = file[part];
 224                if (isdigit(ch))
 225                        part = 0;
 226                else if (ch >= 'a' && ch <= 'h')
 227                        part = ch - 'a';
 228                else
 229                        part = -1;
 230        }
 231        if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
 232                pp = &lab.d_partitions[part];
 233                if (pp->p_size) {
 234                        close(fd);
 235                        *retblocks = pp->p_size / (blocksize / 512);
 236                        return 0;
 237                }
 238        }
 239#endif /* defined(DIOCG*) */
 240#endif /* HAVE_SYS_DISKLABEL_H */
 241
 242        /*
 243         * OK, we couldn't figure it out by using a specialized ioctl,
 244         * which is generally the best way.  So do binary search to
 245         * find the size of the partition.
 246         */
 247        low = 0;
 248        for (high = 1024; valid_offset (fd, high); high *= 2)
 249                low = high;
 250        while (low < high - 1)
 251        {
 252                const ext2_loff_t mid = (low + high) / 2;
 253
 254                if (valid_offset (fd, mid))
 255                        low = mid;
 256                else
 257                        high = mid;
 258        }
 259        valid_offset (fd, 0);
 260        close(fd);
 261        size64 = low + 1;
 262        if ((sizeof(*retblocks) < sizeof(unsigned long long))
 263            && ((size64 / blocksize) > 0xFFFFFFFF))
 264                return EFBIG;
 265        *retblocks = size64 / blocksize;
 266        return 0;
 267}
 268
 269#endif /* WIN32 */
 270
 271#ifdef DEBUG
 272int main(int argc, char **argv)
 273{
 274        blk_t   blocks;
 275        int     retval;
 276
 277        if (argc < 2) {
 278                fprintf(stderr, "Usage: %s device\n", argv[0]);
 279                exit(1);
 280        }
 281
 282        retval = ext2fs_get_device_size(argv[1], 1024, &blocks);
 283        if (retval) {
 284                com_err(argv[0], retval,
 285                        "while calling ext2fs_get_device_size");
 286                exit(1);
 287        }
 288        printf("Device %s has %d 1k blocks.\n", argv[1], blocks);
 289        exit(0);
 290}
 291#endif
 292