Question about working with vfs(mainly samba)
#1
Now that Python is unwrapped it has become difficult to work with vfs. I know that the xbmcvfs module is available, though quite limited and still being developed for Eden.

My script, cdART Manager, needs to create a directory( in the form 'Artist/extrafanart' ) but it fails since smb:// is a vfs. I though I had it taken care of by using xbmcvfs.copy() when I quickly glanced at the code and saw that it will create a directory if it was missing. When this didn't work, I looked a little closer at 'CFile::Cache' and saw that making of the directory only happens on a local path(URIUtils::IsHD(strDest) I believe checks to see if the path is on a Hard Drive - could be wrong)

So I have set out looking for other methods of creating a directory on a smb:// share(so far nothing works). I found threads dating back to 2006-07 when I think that python was not very well wrapped, which state using a module called 'dosamba.py' is used(posted by chunk_1970 on a now dead site is more than 4 years too much to ask.. Smile ) and have yet been able to find any source code that uses this module(I think I may have to look into pysamba next) I was wondering if any one has come up with a solution to use until xbmcvfs is more functional(I know XBMC is still going through code restructuring and features are added after the code is solid again, so I'm not asking for this from the Devs.)

Thanks
Reply
#2
Ok, I've found a Python work around... There is a module(free to use and distribute) that is a wrapper for 'smbclient' which is found in Linux, Mac OSX and even on the Apple TV2(notice I didn't say Windows - found that to be a fairly easy work around)

The module is called 'pysmbclient' available here -> https://bitbucket.org/nosklo/pysmbclient/wiki/Home

It provides access to samba shares with a similar API to the 'os' module.

Here is the following code that I used to make directories(recursive - started at a valid directory and moved forward.):

Code:
from smbclient import smblient

def smb_makedirs( path ):
    if exists( path ):
        return
    # setup for samba communication
    samba_list = path.split( "/" )
    #print samba_list
    if "@" in samba_list[ 2 ]:
        remote_name = samba_list[ 2 ].split( "@" )[1]
        samba_user = ( samba_list[ 2 ].split( "@" )[0] ).split( ":" )[0]
        samba_pass = ( samba_list[ 2 ].split( "@" )[0] ).split( ":" )[1]
    remote_share = samba_list[ 3 ]
    #print remote_share
    # default to guest if no user/pass is given
    if not samba_user:
        samba_user = None
        samba_pass = None
    #print samba_user
    #print samba_pass
    smb = smbclient.SambaClient( server=remote_name, share=remote_share,
                                username=samba_user, password=samba_pass )
    path2 = "smb://" + remote_name + "/" + "/".join( samba_list[3:] )
    tmppath = "/".join( samba_list[4:] )
    while(not ( exists( path2 ) or path2 == "smb:" ) ):
        #print path2
        try:
            smb.mkdir(tmppath.decode("utf-8"))
        except:
            tmppath = os.path.dirname( tmppath )
            # need to strip the same part from a true path for the exists option
            path2 = os.path.dirname( path2 )
    smb_makedirs(path)

def _makedirs( _path ):
    #print os.environ.get('OS')
    if _path.startswith( "smb://" ) and not os.environ.get( "OS", "win32" ) in ("win32", "Windows_NT"):
        smb_makedirs( _path )
        return True
    if ( _path.startswith( "smb://" ) and os.environ.get( "OS", "win32" ) in ("win32", "Windows_NT") ):
        if "@" in _path:
            t_path = "\\\\" + _path.split("@")[1]
            _path = t_path
        _path = _path.replace( "/", "\\" ).replace( "smb:", "" )
    # no need to create folders
    if ( os.path.isdir( _path ) ): return True
    # temp path
    tmppath = _path
    # loop thru and create each folder
    while ( not os.path.isdir( tmppath ) ):
        print tmppath
        try:
            os.mkdir( tmppath )
        except:
            tmppath = os.path.dirname( tmppath )
    # call function until path exists
    _makedirs( _path )

The smb_makedirs() is the proceedure that uses the smbclient wrapper to build the directories. The _makedirs() is called first, here it is determined what needs to be done. The first test is to see if the path starts with 'smb://' and that the system is not a Windows system. If it passes the test, it calls smb_makedirs(). If the path starts with 'smb://' and it is a Windows system(this still might need some work) the 'smb:' is removed and this seems to work on Windows systems. After that, it uses the standard os.mkdir() to make the directories. The standard os.mkdir() is also used when it happens to be a local path.

It might not be perfect, but so far seems to work every time....

At least it may work well as an intermidate work around until the xbmcvfs module has a mkdir() function...
Reply
#3
see this commit
Reply
#4
Ah, nice work-a-round, giftie. The fast fix and commit is, of course, always appreciated spiff. The only final addition (that's not minor at all) that I would like to see is actual file access through the vfs.
Image
Channel surfing for your video library
Development Blog Repository
Reply
#5
spiff Wrote:see this commit

LOL.. I knew this was going to happen... Thanks spiff for the commit, I knew you were working on it, didn't want to push... Smile
Reply
#6
That helps out so much spiff. Thank you... xbmcvfs.mkdir() works exactly like os.mkdir()

For those who are not 100% familar with os.mkdir(), it only will make a single directory at a time. So if you need a path made that has many directory levels, you can use the following code:

Code:
import os
import xbmcvfs

def _makedirs( _path ):
    success = False
    if ( xbmcvfs.exists( _path ) ): return True
    # temp path
    tmppath = _path
    # loop thru and create each folder
    while ( not exists( tmppath ) ):
        success = xbmcvfs.mkdir( tmppath )
        if not success:
            tmppath = os.path.dirname( tmppath )
     # call function until path exists
    _makedirs( _path )

os.path.dirname() works on anything that appears to be a proper path(urls even) it will just strip the path of the last directory.

And yes, this does exactly as the code I posted earlier(thanks to the addition of xbmcvfs.mkdir() ) thanks again spiff.
Reply

Logout Mark Read Team Forum Stats Members Help
Question about working with vfs(mainly samba)0