[Mono-dev] DriveInfo implementation

Javier Martín lordhabbit at gmail.com
Fri Dec 21 08:33:30 EST 2007

Quoting the Bicentennial Man, "one is glad to be of service" ^^

However, there are some chilling news: in these last weeks, I've been
gathering information on the DriveInfo spec and MS's implementation,
comparing them to what we have in Mono. The results are not exactly

MS's implementation seems to save just the path entered when creating
the instance. Only in the constructor is the path checked against the
mounted volume list and rejected if there is no such volume. However,
after that all properties are dynamic: if the volume is unmounted all
throw an IOEx, all save DriveType which returns NotRootDirectory
(whatever, I don't remember the enum tags right now). Also, if the
path passed to the constructor points to a directory within a volume,
it can be either a mount point (NTFS junction), a symlink (NTFS
reparse point) or just a standard directory. I still have to check the
two first, but in the latter, MS's implementation gets you the drive
information for the correspondant volume.

The current Mono implementation does nothing of this. First, most of
these properties have only stub implementations, which rely on arcane
methods (parsing /proc/mounts in Linux is just an example). Also, the
drive type and format are determined at construction time, so if a
volume is unmounted the DriveInfo instance would show inconsistent
behaviour (the currently static properties would keep referring to the
unmounted drive, while the dynamic ones would either raise exceptions
or return values for another volume).

In Windows, these properties don't pose a programming challenge -
there are easy-fitting Win32 API calls for most of them, and in fact
I've already got a preliminary implementation of (g) DriveFormat and
(g/s) Label. I'm currently working on (g) DriveType, which is crucial
for sane behaviour of the whole class.

In Linux, however (or other unices), things don't look so up. The
current approach of parsing /proc/mounts is a bit of a hack: works,
and provides information about all mounted volumes whatever its
options (real mount, bind, loopdev), but if the class properties
become dynamic, we could find DriveInfo parsing /proc/mounts once per
call. Besides, FUSE devices (NTFS volumes mainly, though also many
other FSs and pseudo-FSs) are reported as "fuse" or "fuseblk". I once
heard of a submitted kernel patch to make them be reported as
"fuse.sshfs" or "fuseblk.ntfs-3g", but either it's going to be
included in 2.6.24 or it's "lost in translation". Finally, this way
fits only Linux, but (I think) neither the BSDs nor commercial Unices.
We probably want a portable implementation rather than 5 different
ones. Even if there _are_ so many different versions of this
platform-dependent code, my opinion is that they should be "hidden" in
io_layer, not in mscorlib.

I thought of using the getmntent function family, together with the
already used statvfs, but I don't think they provide enough
information. I also dipped a toe in the HALd world (over DBUS). The
information it provides is very good and complete, and could be even
be ported to other Unices apart from Linux, but it only works with
physical devices: loopdevs and bindings are not reported through it,
which is bad, because some users depend on loopmounted volumes (WUBI,
cryptoloop, etc).

I admit I'm completely lost on this *nix issue, as this area is not
exactly standardised, even on Linux. Also, if I make any further
changes to the Windows version, it'll behave quite differently in
Linux (dynamic vs. saved properties mainly), which I think is not
exactly optimal. Any ideas?


2007/12/20, Miguel de Icaza <miguel at novell.com>:
> Hey Javier,
>     Excellent work!   I know that it has been a long process from the
> original simple contribution, but am looking forward to it ;-)
> Miguel.
> On Thu, 2007-12-06 at 14:33 +0100, Javier Martín wrote:
> > Status update: I'm currently at step 4, i.e. the Windows version has
> > been implemented and everything seems fine, sane and consistent. I had
> > to implement the WindowsGetDrives method too in order to make the
> > class even usable, but it's a bit of a stub based on
> > Environment.GetLogicalDrives and does not detect the filesystem type -
> > that should be trivial with the Win32 GetVolumeInformation call, but
> > it's secondary and for later: I don't want to add two new internal
> > calls on a single patch.
> >
> > I'm now going for lauch. If noone reports breakage in a few hours,
> > I'll start with the POSIX port, probably adding two files "volume.h"
> > and "volume.c" to io-layer, since I don't think the new functions fit
> > anywhere else.
> >
> > I have done my best to create solid, consistent code and to avoid
> > corrupting the namespace, but if anything can be improved, I'm
> > positively waiting for feedback. All my code was compiled with MSVC
> > 8.0 (a gcc cygwin build proved frustratingly impossible because of a
> > Makefile error), so, even if I tried avoiding compiler dialectisms, I
> > could have introduced some.
> >
> > This patch has two diff files: icalls.diff (to be applied at
> > /mono/metadata) and DriveInfo.diff (at mcs/class/corlib/System.IO).
> > Also, I noticed an small typo at the declaration of the Exp function
> > in mcs/class/corlib/System.PAL/IOperatingSystem.cs (dobule instead of
> > double) which prevented corlib from compiling at first.
> >
> > Habbit
> >
> > 2007/12/5, Javier Martín <lordhabbit at gmail.com>:
> > > Ok, this last nut of wisdom from Robert has really fueled me up. It's
> > > quite nice to be back from class and find such good news lying on my
> > > mailbox. So, I'm starting with the Windows version first. Since this
> > > will be the first time I delve into the depths of the runtime's
> > > support code, I've written a small checklist with what I'll do where
> > > so that any accidental receiver of this list can spot the probable
> > > mistakes that my usually astounding lack of judgment is certain to
> > > cause x_x
> > >
> > > --ON WINDOWS--
> > > 1.- DriveInfo.cs - create a "external" method with the appropiate
> > > MethodImplAttribute flagging it as an internal call.
> > > 2.- icall-def.h - define the new internal call, possibly MONOIO_34,
> > > and route it to a new function
> > > 3.- icall.c - implement the said function, calling only ANSI C and
> > > Win32 APIs. Be careful not to dereference NULLs, corrupt memory, etc,
> > > since mommy GC & daddy runtime are not here to help
> > > 4.- build and check everything is sane. Compare to M$'s results
> > > --ON LINUX--
> > > 5.- some file in io-layer, possibly io.c - implement POSIX-based
> > > substitutes to the missing Win32 functions/structs/etc I've used
> > > 6.- $thatLastFile.h - expose the Win32 prototypes I've used
> > > 7.- build and check everything is sane. Compare to both mono-win and
> > > MS-win results
> > > --HAPPY ENDING--
> > >
> > > Seems easy at first, but I suppose it's neither a piece-of-cake nor an
> > > impossible mission. Well, tomorrow is a holiday here in Spain, so I
> > > can hack the whole day.
> > >
> > > Habbit
> > >

More information about the Mono-devel-list mailing list