chrrrisw / kmel_db

A parser and generator for Kenwood Music Editor Light databases
Apache License 2.0
6 stars 1 forks source link

os.fwalk is not available on Mac OSX, consider falling back to os.walk #12

Open arthurjy opened 7 years ago

arthurjy commented 7 years ago

On Mac OSX with Python 3.5.2, script fails with error:

Traceback (most recent call last):
  File "DapGen.py", line 411, in <module>
    sys.exit(main())
  File "DapGen.py", line 368, in main
    ml = MediaLocation(inpath)
  File "DapGen.py", line 92, in __init__
    for root, dirs, files, rootfd in os.fwalk(self.topdir):
AttributeError: module 'os' has no attribute 'fwalk'

For some reason os.fwalk is not available. Not 100% why, core os.py seems to not define it because this is not true: if {open, stat} <= supports_dir_fd and {listdir, stat} <= supports_fd:

For kmel_db, consider falling back to using os.walk instead and removing use of directory file descriptor in such instances.

chrrrisw commented 7 years ago

Thanks again @arthurjy, will fall back to os.walk as suggested, might have to get you to test as I don't have a Mac. Regards, Chris.

arthurjy commented 7 years ago

My worry here is how you find out the FAT shortnames for files and folders without the file descriptors. As the rootfd is required for your call to:-

result = fcntl.ioctl( rootfd, vfat_ioctl.VFAT_IOCTL_READDIR_BOTH, self._buffer)

I presume accurate dos shortnames are fairly critical to the Kenwood DB?

chrrrisw commented 7 years ago

I've had a look at the code in os.py. We should just be able to open the directory as read-only to get a file descriptor. My concern is that the call to fcntl will not have an equivalent on Mac. The database stores both full and FAT filenames, I've not tried to create one without the FAT filenames to see what will happen. My guess is that the radio itself uses the FAT names, but this is not proven.

arthurjy commented 7 years ago

Tried that:

        if "fwalk" in dir(os) :
            for root, dirs, files, rootfd in os.fwalk(self.topdir):
                self.get_directory_entries(root, rootfd, files)
        else:
            for root, dirs, files in os.walk(self.topdir):
                rootfd = os.open(root, os.O_RDONLY);
                self.get_directory_entries(root, rootfd, files)           

But later fcntl.ioctl throws up this error:-

OSError: [Errno 25] Inappropriate ioctl for device

Sorry, my Python isn't great, so wasn't sure if I'm doing something daft here.

chrrrisw commented 7 years ago

That looks like a good start. You could also use:

        if hasattr(os, "fwalk") :
            for root, dirs, files, rootfd in os.fwalk(self.topdir):
                self.get_directory_entries(root, rootfd, files)
        else:
            for root, dirs, files in os.walk(self.topdir):
                rootfd = os.open(root, os.O_RDONLY);
                self.get_directory_entries(root, rootfd, files)           

And we should close the file descriptor after use.

The ioctl error is what I'm afraid of.

There is a Makefile in the kmeldb subdirectory that generates a new vfat_ioctl.py file for your system.

Try running 'make' in that directory (assuming you have a C compiler and make) and see if the vfat_ioctl.py file changes. If you post the output from 'git diff' for that file here, we can attempt to accommodate Macs without the generator.

chrrrisw commented 7 years ago

I've just had a quick look at generate_ioctl.c in the kmeldb subdirectory, and I've got an include that might break on Mac OSX (since it has a BSD heritage).

#include <linux/msdos_fs.h>

You might need to find an equivalent. I'll see what I can find on the topic.