views:

286

answers:

2

How do I sort out (distinguish) an error derived from a "disk full condition" from "trying to write to a read-only file system"? I don't want to fill my HD to find out :) What I want is to know who to catch each exception, so my code can say something to the user when he is trying to write to a ReadOnly FS and another message if the user is trying to write a file in a disk that is full.

+2  A: 

On a read-only filesystem, the files themselves will be marked as read-only. Any attempt to open a read-only file for writing (O_WRONLY or O_RDWR) will fail. On UNIX-like systems, the errno EACCES will be set.

>>> file('/etc/resolv.conf', 'a')
Traceback (most recent call last):
  File "", line 1, in 
IOError: [Errno 13] Permission denied: '/etc/resolv.conf'

In contrast, attempts to write to a full file may result in ENOSPC. May is critical; the error may be delayed until fsync or close.

>>> file(/dev/full, 'a').write('\n')
close failed in file object destructor:
IOError: [Errno 28] No space left on device
ephemient
+6  A: 

Once you catch IOError, e.g. with an except IOError, e: clause in Python 2.*, you can examine e.errno to find out exactly what kind of I/O error it was (unfortunately in a way that's not necessarily fully portable among different operating systems).

See the errno module in Python standard library; opening a file for writing on a R/O filesystem (on a sensible OS) should produce errno.EPERM, errno.EACCES or better yet errno.EROFS ("read-only filesystem"); if the filesystem is R/W but there's no space left you should get errno.ENOSPC ("no space left on device"). But you will need to experiment on the OSes you care about (with a small USB key filling it up should be easy;-).

There's no way to use different except clauses depending on errno -- such clauses must be distinguished by the class of exceptions they catch, not by attributes of the exception instance -- so you'll need an if/else or other kind of dispatching within a single except IOError, e: clause.

Alex Martelli