OSDN Git Service

On Linux do BLKROGET ioctl to make sure the device is not read-only: after "blockdev...
authorresver <resver@60bc1c72-a15a-11de-b98f-4500b42dc123>
Tue, 4 Dec 2012 19:17:52 +0000 (19:17 +0000)
committerresver <resver@60bc1c72-a15a-11de-b98f-4500b42dc123>
Tue, 4 Dec 2012 19:17:52 +0000 (19:17 +0000)
git-svn-id: http://exfat.googlecode.com/svn/trunk@300 60bc1c72-a15a-11de-b98f-4500b42dc123

libexfat/io.c

index 755d0d6..e89349b 100644 (file)
@@ -23,6 +23,7 @@
 #include <sys/types.h>
 #include <sys/uio.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/uio.h>
 #include <sys/stat.h>
+#include <sys/mount.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <string.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <string.h>
@@ -45,6 +46,30 @@ struct exfat_dev
 #endif
 };
 
 #endif
 };
 
+static int open_ro(const char* spec)
+{
+       return open(spec, O_RDONLY);
+}
+
+static int open_rw(const char* spec)
+{
+       int fd = open(spec, O_RDWR);
+#ifdef __linux__
+       int ro = 0;
+
+       /*
+          This ioctl is needed because after "blockdev --setro" kernel still
+          allows to open the device in read-write mode but fails writes.
+       */
+       if (fd != -1 && ioctl(fd, BLKROGET, &ro) == 0 && ro)
+       {
+               close(fd);
+               return -1;
+       }
+#endif
+       return fd;
+}
+
 struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)
 {
        struct exfat_dev* dev;
 struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)
 {
        struct exfat_dev* dev;
@@ -63,7 +88,7 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)
        switch (mode)
        {
        case EXFAT_MODE_RO:
        switch (mode)
        {
        case EXFAT_MODE_RO:
-               dev->fd = open(spec, O_RDONLY);
+               dev->fd = open_ro(spec);
                if (dev->fd == -1)
                {
                        free(dev);
                if (dev->fd == -1)
                {
                        free(dev);
@@ -73,7 +98,7 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)
                dev->mode = EXFAT_MODE_RO;
                break;
        case EXFAT_MODE_RW:
                dev->mode = EXFAT_MODE_RO;
                break;
        case EXFAT_MODE_RW:
-               dev->fd = open(spec, O_RDWR);
+               dev->fd = open_rw(spec);
                if (dev->fd == -1)
                {
                        free(dev);
                if (dev->fd == -1)
                {
                        free(dev);
@@ -83,13 +108,13 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode)
                dev->mode = EXFAT_MODE_RW;
                break;
        case EXFAT_MODE_ANY:
                dev->mode = EXFAT_MODE_RW;
                break;
        case EXFAT_MODE_ANY:
-               dev->fd = open(spec, O_RDWR);
+               dev->fd = open_rw(spec);
                if (dev->fd != -1)
                {
                        dev->mode = EXFAT_MODE_RW;
                        break;
                }
                if (dev->fd != -1)
                {
                        dev->mode = EXFAT_MODE_RW;
                        break;
                }
-               dev->fd = open(spec, O_RDONLY);
+               dev->fd = open_ro(spec);
                if (dev->fd != -1)
                {
                        dev->mode = EXFAT_MODE_RO;
                if (dev->fd != -1)
                {
                        dev->mode = EXFAT_MODE_RO;