OSDN Git Service

OS X: correctly detect device size.
authorrelan <relan@users.noreply.github.com>
Wed, 12 Dec 2012 19:14:36 +0000 (19:14 +0000)
committerrelan <relan@users.noreply.github.com>
Mon, 24 Aug 2015 05:26:15 +0000 (08:26 +0300)
libexfat/exfat.h
libexfat/io.c
mkfs/main.c

index 03107d7..7eb1fa6 100644 (file)
@@ -136,6 +136,7 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode);
 int exfat_close(struct exfat_dev* dev);
 int exfat_fsync(struct exfat_dev* dev);
 enum exfat_mode exfat_get_mode(const struct exfat_dev* dev);
+off_t exfat_get_size(const struct exfat_dev* dev);
 off_t exfat_seek(struct exfat_dev* dev, off_t offset, int whence);
 ssize_t exfat_read(struct exfat_dev* dev, void* buffer, size_t size);
 ssize_t exfat_write(struct exfat_dev* dev, const void* buffer, size_t size);
index 0a04aa1..e9672fb 100644 (file)
@@ -26,6 +26,9 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <string.h>
+#ifdef __APPLE__
+#include <sys/disk.h>
+#endif
 #ifdef USE_UBLIO
 #include <sys/uio.h>
 #include <ublio.h>
@@ -39,6 +42,7 @@ struct exfat_dev
 {
        int fd;
        enum exfat_mode mode;
+       off_t size; /* in bytes */
 #ifdef USE_UBLIO
        off_t pos;
        ublio_filehandle_t ufh;
@@ -142,6 +146,42 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)
                return NULL;
        }
 
+#ifdef __APPLE__
+       if (S_ISBLK(stbuf.st_mode))
+       {
+               uint32_t block_size = 0;
+               uint64_t blocks = 0;
+
+               if (ioctl(dev->fd, DKIOCGETBLOCKSIZE, &block_size) != 0)
+               {
+                       close(dev->fd);
+                       free(dev);
+                       exfat_error("failed to get block size");
+                       return NULL;
+               }
+               if (ioctl(dev->fd, DKIOCGETBLOCKCOUNT, &blocks) != 0)
+               {
+                       close(dev->fd);
+                       free(dev);
+                       exfat_error("failed to get blocks count");
+                       return NULL;
+               }
+               dev->size = blocks * block_size;
+       }
+       else
+#endif
+       {
+               /* works for Linux, FreeBSD, Solaris */
+               dev->size = exfat_seek(dev, 0, SEEK_END);
+               if (dev->size <= 0)
+               {
+                       close(dev->fd);
+                       free(dev);
+                       exfat_error("failed to get device size");
+                       return NULL;
+               }
+       }
+
 #ifdef USE_UBLIO
        memset(&up, 0, sizeof(struct ublio_param));
        up.up_blocksize = 256 * 1024;
@@ -198,6 +238,11 @@ enum exfat_mode exfat_get_mode(const struct exfat_dev* dev)
        return dev->mode;
 }
 
+off_t exfat_get_size(const struct exfat_dev* dev)
+{
+       return dev->size;
+}
+
 off_t exfat_seek(struct exfat_dev* dev, off_t offset, int whence)
 {
 #ifdef USE_UBLIO
index b8ce63d..e842c71 100644 (file)
@@ -96,14 +96,6 @@ int get_cluster_size(void)
        return get_sector_size() << get_spc_bits();
 }
 
-static off_t setup_volume_size(struct exfat_dev* dev)
-{
-       off_t size = exfat_seek(dev, 0, SEEK_END);
-       if (size == (off_t) -1)
-               exfat_error("failed to get volume size");
-       return size;
-}
-
 static int setup_spc_bits(int sector_bits, int user_defined, off_t volume_size)
 {
        int i;
@@ -166,10 +158,7 @@ static int setup(struct exfat_dev* dev, int sector_bits, int spc_bits,
 {
        param.sector_bits = sector_bits;
        param.first_sector = first_sector;
-
-       param.volume_size = setup_volume_size(dev);
-       if (param.volume_size == (off_t) -1)
-               return 1;
+       param.volume_size = exfat_get_size(dev);
 
        param.spc_bits = setup_spc_bits(sector_bits, spc_bits, param.volume_size);
        if (param.spc_bits == -1)