Search code examples
pythonrecursionsambapysmb

How to rename nested directories and files recursively using pysmb in python?


Recently, I had to rename all space characters used in the directory and file names in a Samba tree. Before that, I used os.walk to traverse the directory tree of regular files in python, but I wanted to rename them in-place.

To connect to my Samba server and rename a single file, I used this snippet:

from smb import SMBConnection

conn = SMBConnection.SMBConnection(userID, password, client_machine_name, server_name, is_direct_tcp=True, domain='workgroup')
assert conn.connect('1.2.3.4')

shares = conn.listShares()
    for share in shares:
        if share.name == 'share':
            conn.rename('share', 'path/old_name', 'path/new_name')

My problem is when I rename parent directories to new names, I can't access their children anymore. How can I rename old directories and files recursively using pysmb?


Solution

  • Finally I find a sample code as follow in pysmb here as os.walk:

    def smb_walk(conn, shareddevice, top='/'):
        dirs, nondirs = [], []
        if not isinstance(conn, SMBConnection.SMBConnection):
            raise TypeError("SMBConnection required")
        names = conn.listPath(shareddevice, top)
        for name in names:
            if name.isDirectory:
                if name.filename not in [u'.', u'..']:
                    dirs.append(name.filename)
            else:
                nondirs.append(name.filename)
        yield top, dirs, nondirs
        for name in dirs:
            new_path = os.path.join(top, name)
            for x in smb_walk(conn, shareddevice, new_path):
                yield x
    

    Then I rename directories and files recursively from the innermost directory (because the files path name before them name renaming sholdn't changed):

    ans = smb_walk(conn, 'share', top=source_path)
    smb_l = list(ans)
    for s_i in smb_l[::-1]:
        for s_j in s_i[2][::-1]:
            if s_j:
                #rename file name
                conn.rename('share', f'{s_i[0]}/{s_j}', f'{s_i[0]}/{encode_n(s_j)}')
        for s_j in s_i[1][::-1]:
            if s_j:
                #rename directory name
                conn.rename('share', f'{s_i[0]}/{s_j}', f'{s_i[0]}/{encode_n(s_j)}')