10

I have remote server with some files.

smb://ftpsrv/public/

I can be authorized there as an anonymous user. In java I could simply write this code:

SmbFile root = new SmbFile(SMB_ROOT);

And get the ability to work with files inside (it is all I need, one row!), but I can't find how to manage with this task in Python 3, there are a lot of resources, but I think they are not relevant to me, because they are frequently tailored for Python 2, and old other approaches. Is there some simple way, similar to Java code above? Or can somebody provide a real working solution if, for example, I want to access file fgg.txt in smb://ftpsrv/public/ folder. Is there really a handy lib to tackle this problem?

For example on site:

import tempfile
from smb.SMBConnection import SMBConnection

# There will be some mechanism to capture userID, password, client_machine_name, server_name and server_ip
# client_machine_name can be an arbitary ASCII string
# server_name should match the remote machine name, or else the connection will be rejected
conn = SMBConnection(userID, password, client_machine_name, server_name, use_ntlm_v2 = True)
assert conn.connect(server_ip, 139)

file_obj = tempfile.NamedTemporaryFile()
file_attributes, filesize = conn.retrieveFile('smbtest', '/rfc1001.txt', file_obj)

# Retrieved file contents are inside file_obj
# Do what you need with the file_obj and then close it
# Note that the file obj is positioned at the end-of-file,
# so you might need to perform a file_obj.seek() if you need
# to read from the beginning
file_obj.close()

Do I seriously need to provide all of these details: conn = SMBConnection(userID, password, client_machine_name, server_name, use_ntlm_v2 = True)?

Philip Kearns
  • 355
  • 4
  • 13
Alex
  • 2,343
  • 3
  • 16
  • 35
  • Looking around on the pysmb website I found this page, is this what you need? http://pysmb.readthedocs.io/en/latest/api/smb_SMBHandler.html – Rick Rongen Mar 26 '18 at 14:39
  • thank you for your support, but it is not helpful. I have some problems with installation of urllib2 – Alex Mar 26 '18 at 14:42

2 Answers2

13

A simple example of opening a file using urllib and pysmb in Python 3

import urllib
from smb.SMBHandler import SMBHandler
opener = urllib.request.build_opener(SMBHandler)
fh = opener.open('smb://host/share/file.txt')
data = fh.read()
fh.close()

I haven't got an anonymous SMB share ready to test it with, but this code should work.
urllib2 is the python 2 package, in python 3 it was renamed to just urllib and some stuff got moved around.

Rick Rongen
  • 559
  • 3
  • 9
  • I have an exception `self.sock.sendto(data, ( ip, port )) socket.gaierror: [Errno -2] Name or service not known` – Alex Mar 27 '18 at 08:09
  • That seems like you mistyped your hostname. Make sure it is int he correct format. [username:password@]hostname[:port] where everything between [ ] is optional – Rick Rongen Mar 27 '18 at 08:55
  • `smb://ftpsrv/public/` I have a such path and my code is `opener.open('smb://ftpsrv/public/fgg.txt')` – Alex Mar 27 '18 at 10:08
  • Can you try to use `ping ftpsrv` on the system you are running your script on? It seems like it can't find that hostname. – Rick Rongen Mar 27 '18 at 10:14
  • you are right, but I can see directory with such path and name in nautilus `smb://ftpsrv/public/fgg.txt`. What is going on? – Alex Mar 27 '18 at 14:06
  • I think this is because SMB likes to work with NetBIOS names (the hostname you can set in Windows). Linux by default doesn't use NetBIOS names. Nautulis knows how to handle these names when using the smb protocol. You could try to add .local to the name, otherwise you probably need to use the host file or the actual ip. – Rick Rongen Mar 27 '18 at 14:21
  • Thanks a lot Rick! By this command I've got ip `nmblookup ftpsrv` and then `opener.open('smb://12*.**.**.***/public/fgg.txt')` has opened my file successfully! – Alex Mar 27 '18 at 14:34
  • Unfortunately, pysmb is very slow when it comes to big files :( Moreover, `SMBHandler` "opens" a file by downloading it entirely... – George Sovetov Apr 24 '19 at 16:23
  • @GeorgeSovetov You could use `retrieveFileFromOffset` to partially retrieve the file. See the documentation of `SMBConnection` for more info on this. – Rick Rongen Apr 25 '19 at 18:06
  • @RickRongen Actually I'm using `pysmb` extensively and make use of this function. Regarding downloading the whole file, the best recipe I came up with is to download it in parallel from 10-20 threads using `retrieveFileFromOffset`. – George Sovetov Apr 25 '19 at 18:17
  • 2
    I got this error, both for ip and hostname. `urllib.error.URLError: ` – TangHongWan Jan 27 '20 at 08:18
  • I get the same result as @PageNotFound. Hostname and IP both return this error. (Tried from MacOS and a Linux container). – George Mar 25 '20 at 04:42
  • What is smb? How to install it? – Sören May 10 '20 at 23:30
3

I think you were asking for Linux, but for completeness I'll share how it works on Windows.

On Windows, it seems that Samba access is supported out of the box with Python's standard library functions:

import glob, os

with open(r'\\USER1-PC\Users\Public\test.txt', 'w') as f:
    f.write('hello')    # write a file on a distant Samba share

for f in glob.glob(r'\\USER1-PC\Users\**\*', recursive=True):
    print(f)   # glob works too
    if os.path.isfile(f):
        print(os.path.getmtime(f))  # we can get filesystem information
Basj
  • 29,668
  • 65
  • 241
  • 451