Search code examples
pythonfuse

How to properly write readdir in Fuse python?


I want to learn how to write filesystems in Fuse. My idea is to write a filesystem that communicates with pinboard.in (a bookmark service). I have problem with readdir. As far as I understand (which is not very much since this is new stuff for me) readdir is the function that returns what files and folders are in the filesystem.

I have the following code:

def readdir ( self, path, flags ):
    print '*** readdir', path, flags
    if path == '/':
        # Path is root meaning we need to list tags and untagged bookmarks
        tags_json=urllib2.urlopen('https://api.pinboard.in/v1/tags/get?format=json&auth_token='+self.apitoken).read()
        tags = json.loads(tags_json)
        ret = map(lambda k: fuse.Direntry(name=k, type=stat.S_IFDIR), tags.keys())
        print ret
        return ret
    else:
        pass

When running this in Fuse with debug flags I get something like

    *** getattr /
    unique: 2, success, outsize: 120
    unique: 3, opcode: OPENDIR (27), nodeid: 1, insize: 48, pid: 6441
    unique: 3, success, outsize: 32
    unique: 4, opcode: READDIR (28), nodeid: 1, insize: 80, pid: 6441
    readdir[0] from 0
    *** readdir / 0
    [<fuse.Direntry object at 0xb65b8f70>, <fuse.Direntry object at 0xb65b8f90>,........,<fuse.Direntry > object at 0xb65e1670>]
    unique: 4, success, outsize: 16
    unique: 5, opcode: RELEASEDIR (29), nodeid: 1, insize: 64, pid: 0
    unique: 5, success, outsize: 16

but the file system is empty. I tried a little bit of everything but I think that I don't understand the flow of a filesystem. My real questions are, what do I return so ls shows files/directories? Where should I be reading about this?

In case you need more code you can go to my bitbucket and read everything: https://bitbucket.org/aquaplanet/pinboard.in-fuse/commits/38212eb035d3aba163bab9ed5a6b9284ce1dc93c

Thanks very much for your time reading my question, I am looking forward for any answers!

Solution

Thanks to @aleatha who told me that I wrote correct but there is a kind of type error in tags.keys(), that normal strings works, I quickly found that tags.keys() was unicode. Despite having sv_SE.UTF-8 in both LANG and LC_CTYPE (working on a raspberry pi) it wants 8 bit strings. This works much better:

def readdir ( self, path, flags ):
    print '*** readdir', path, flags
    if path == '/':
        # Path is root meaning we need to list tags and untagged bookmarks
        tags_json=urllib2.urlopen('https://api.pinboard.in/v1/tags/get?format=json&auth_token='+self.apitoken).read()
        tags = json.loads(tags_json)
        ret = map(lambda k: fuse.Direntry(name=k.encode('iso-8859-1','replace'), type=stat.S_IFDIR), tags.keys())
        return ret
    else:
        pass

Solution

  • You look like you're on the right path... You need to return a series of Direntry objects.

    If I replace your API call with a simple array of strings, like so:

    tags = ["a", "b", "c"]  
    ret = map(lambda k: fuse.Direntry(name = k, type = stat.S_IFDIR), tags)
    return ret
    

    Then it works fine. So my surmise is that there's something wrong with tags.keys(). I'd start by inspecting the individual Direntry objects and seeing if they look right.