Git Product home page Git Product logo

fs.smbfs's Introduction

fs.smbfs star me

Source PyPI Actions Codecov Codacy License Versions Format GitHub issues Downloads Changelog

Requirements

PyFilesystem2 PyPI fs Source fs License fs
six PyPI six Source six License six
PySMB PyPI pysmb Source pysmb License pysmb

Installation

Install directly from PyPI, using pip :

$ pip install fs.smbfs

Usage

Opener

Use fs.open_fs to open a filesystem with an SMB FS URL:

import fs
smb_fs = fs.open_fs('smb://username:password@SAMBAHOSTNAME:port/share')

The opener can use either an IPv4 address or a NetBIOS hostname, using the NetBIOS name service to find the other token. Otherwise, if NetBIOS is not available, a new SMB connection can be established by using the IPv4 address and giving the hostname with the hostname URL parameter.

The following parameters can be passed as URL parameters: timeout, name-port, direct-tcp, hostname, and domain.

Constructor

import fs.smbfs
smb_fs = fs.smbfs.SMBFS(
    host, username="guest", passwd="", timeout=15,
    port=139, name_port=137, direct_tcp=False, domain=""
)

with each argument explained below:

  • host: either the host name (not the FQDN) of the SMB server, its IP address, or both in a tuple. If either the IP address or the host name is not given, NETBIOS is queried to get the missing data.
  • user: the username to connect with, defaults to "guest" for anonymous connection.
  • passwd: an optional password to connect with, defaults to "" for anonymous connection.
  • timeout: the timeout, in seconds, for NetBIOS and TCP requests.
  • port: the port the SMB server is listening on.
  • name_port: the port the NetBIOS naming service is listening on.
  • direct_tcp: set to True if the server is accessible directly through TCP, leave as False for maximum compatibility.
  • domain: the network domain to connect with, i.e. the workgroup on Windows. Usually safe to leave as empty string, the default.

Once created, the SMBFS filesystem behaves like any other filesystem (see the Pyfilesystem2 documentation), except if it was open in the root directory of the server, in which case the root directory of the SMBFS instance will be read-only (since SMB clients cannot create new shares).

Feedback

Found a bug ? Have an enhancement request ? Head over to the GitHub issue tracker of the project if you need to report or ask something. If you are filling in on a bug, please include as much information as you can about the issue, and try to recreate the same bug in a simple, easily reproducible situation.

Credits

fs.smbfs is developed and maintained by:

The following people contributed to fs.sshfs:

This project obviously owes a lot to the PyFilesystem2 project and all its contributors.

See also

  • fs, the core Pyfilesystem2 library
  • fs.archive, enhanced archive filesystems for Pyfilesystem2
  • fs.sshfs, Pyfilesystem2 over SSH using paramiko

fs.smbfs's People

Contributors

althonos avatar dependabot-preview[bot] avatar frafra avatar josiahwitheford avatar mivade avatar telamonian avatar vegemash avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

fs.smbfs's Issues

fs.errors.CreateFailed: could not get an IP for name

Hi, I get following error while creating SMBFS object with host name:

  File "/home/kossak/Kossak/files_common/PythonProjects/testowy/testowy/test_pyfilesystem.py", line 43, in test_smb
    f = SMBFS(host=host, username=user, passwd=password)
  File "/home/kossak/.virtualenvs/testowy-jc7bDP4y/lib/python3.6/site-packages/fs/smbfs/smbfs.py", line 224, in __init__
    "could not get an IP for name: '{}'".format(host))
fs.errors.CreateFailed: could not get an IP for name: '<HOST>'

and with IP address:

  File "/home/kossak/Kossak/files_common/PythonProjects/testowy/testowy/test_pyfilesystem.py", line 44, in test_smb
    f = SMBFS(host=host, username=user, passwd=password)
  File "/home/kossak/.virtualenvs/testowy-jc7bDP4y/lib/python3.6/site-packages/fs/smbfs/smbfs.py", line 214, in __init__
    "could not get a name for IP: '{}'".format(host))
fs.errors.CreateFailed: could not get a name for IP: '<IP>'

I can connect to smb://<HOST>/ with my file manager without any errors. I can also ping it (by name and IP) and it responds properly. Any idea why it doesn't work with SMBFS? Thank you in advance.

I use:
Python: 3.6.2
fs.smbfs.__ version__: 0.3.3
os: Linux Mint

Kerberos support.

I'm struggling to get kerberos authentication - working - is it supported at all?

direct_tcp=True tries to use NetBIOS

Setting direct_tcp=True should bypass NetBIOS, but NetBIOS is always used:

direct_tcp (int): set to True to attempt to connect directly to the
server using TCP instead of NetBIOS. **[default: False]**

fs.smbfs/fs/smbfs/smbfs.py

Lines 209 to 220 in 4625477

def __init__(self, host, username='guest', passwd='', timeout=15,
port=None, name_port=137, direct_tcp=False, domain=''): # noqa: D102
super(SMBFS, self).__init__()
try:
self._server_name, self._server_ip = utils.get_hostname_and_ip(
host, self.NETBIOS,
timeout=timeout,
name_port=name_port
)
except Exception:
raise errors.CreateFailed("could not get IP/host pair from '{}'".format(host))

smb.smb_structs.ProtocolError: Unknown status value (0xC0000001) in SMB_COM_SESSION_SETUP_ANDX (with extended security)

Here is the traceback

Traceback (most recent call last):
  File "C:/Users/adyah/Desktop/Codes/Projects/Server2Server/local2SMB.py", line 40, in <module>
    send_to_smb(host, username, password, src_fs, filename, remote_path)
  File "C:/Users/adyah/Desktop/Codes/Projects/Server2Server/local2SMB.py", line 21, in send_to_smb
    smb_fs = fs.smbfs.SMBFS(host)
  File "C:\Users\adyah\Desktop\Codes\Projects\Server2Server\venv\lib\site-packages\fs\smbfs\smbfs.py", line 230, in __init__
    self._smb.connect(self._server_ip, port, timeout=timeout)
  File "C:\Users\adyah\Desktop\Codes\Projects\Server2Server\venv\lib\site-packages\smb\SMBConnection.py", line 122, in connect
    self._pollForNetBIOSPacket(timeout)
  File "C:\Users\adyah\Desktop\Codes\Projects\Server2Server\venv\lib\site-packages\smb\SMBConnection.py", line 632, in _pollForNetBIOSPacket
    self.feedData(data)
  File "C:\Users\adyah\Desktop\Codes\Projects\Server2Server\venv\lib\site-packages\nmb\base.py", line 54, in feedData
    self._processNMBSessionPacket(self.data_nmb)
  File "C:\Users\adyah\Desktop\Codes\Projects\Server2Server\venv\lib\site-packages\nmb\base.py", line 75, in _processNMBSessionPacket
    self.onNMBSessionMessage(packet.flags, packet.data)
  File "C:\Users\adyah\Desktop\Codes\Projects\Server2Server\venv\lib\site-packages\smb\base.py", line 144, in onNMBSessionMessage
    if self._updateState(self.smb_message):
  File "C:\Users\adyah\Desktop\Codes\Projects\Server2Server\venv\lib\site-packages\smb\base.py", line 322, in _updateState_SMB2
    raise ProtocolError('Unknown status value (0x%08X) in SMB_COM_SESSION_SETUP_ANDX (with extended security)' % message.status,
smb.smb_structs.ProtocolError: Unknown status value (0xC0000001) in SMB_COM_SESSION_SETUP_ANDX (with extended security)
==================== SMB Message ====================
Command: 0x01 (SMB2_COM_SESSION_SETUP) 
Status: 0xC0000001 
Flags: 0x01 
PID: 0 
MID: 2 
TID: 0 
Data: 9 bytes 
b'090000000000000000' 
==================== SMB Data Packet (hex) ====================
b'fe534d4240000000010000c001000400010000000000000002000000000000000000000000000000b97d00000000f15100000000000000000000000000000000090000000000000000'

What does this mean?

smb port defaults to 139 in SMBFS constructor but defaults to 445 in opener

It looks like in the opener, the smb port defaults to 445:

smb_host, _, dir_path = parse_result.resource.partition('/')
smb_host, _, smb_port = smb_host.partition(':')
smb_port = int(smb_port) if smb_port.isdigit() else 445

However, in the SMBFS constructor the smb port definitely defaults to 139:

fs.smbfs/fs/smbfs/smbfs.py

Lines 204 to 205 in f9baeb4

def __init__(self, host, username='guest', passwd='', timeout=15,
port=139, name_port=137, direct_tcp=False): # noqa: D102

I initially didn't notice this issue when I was only working with shares exposed on Linux docker images (similar to the test case for this repo). However, now that I've started also working with local file servers on Windows this discrepancy has caused me no end of trouble.

Going by the pysmb docs, it seems like the most appropriate fix would be to use a default smb port of 139 everywhere.

Another option would be to simply delegate the choice of default port to pysmb

Critical error: version conflict in pysmb dependency when fs.smbfs entry_point is loaded

pysmb just did a new 1.2 release a few days ago. This breaks the fs.smbfs opener with a version conflict:

2020-05-19T15:21:54.9454056Z =================================== FAILURES ===================================
2020-05-19T15:21:54.9457168Z ________________ Test_FSManager_smb_docker_share.testWriteRead _________________
2020-05-19T15:21:54.9457788Z 
2020-05-19T15:21:54.9462901Z self = <fs-registry ['userdata', 'userconf', 'sitedata', 'siteconf', 'usercache', 'userlog', 'ftp', 'mem', 'file', 'osfs', 'tar', 'temp', 'zip', 'cifs', 'smb', 's3', 'minio']>
2020-05-19T15:21:54.9464547Z protocol = 'smb'
2020-05-19T15:21:54.9464922Z 
2020-05-19T15:21:54.9468130Z     def get_opener(self, protocol):
2020-05-19T15:21:54.9469069Z         # type: (Text) -> Opener
2020-05-19T15:21:54.9471024Z         """Get the opener class associated to a given protocol.
2020-05-19T15:21:54.9471317Z     
2020-05-19T15:21:54.9471502Z         Arguments:
2020-05-19T15:21:54.9485527Z             protocol (str): A filesystem protocol.
2020-05-19T15:21:54.9485974Z     
2020-05-19T15:21:54.9486207Z         Returns:
2020-05-19T15:21:54.9486494Z             Opener: an opener instance.
2020-05-19T15:21:54.9486890Z     
2020-05-19T15:21:54.9487070Z         Raises:
2020-05-19T15:21:54.9487506Z             ~fs.opener.errors.UnsupportedProtocol: If no opener
2020-05-19T15:21:54.9487984Z                 could be found for the given protocol.
2020-05-19T15:21:54.9488478Z             EntryPointLoadingError: If the returned entry point
2020-05-19T15:21:54.9488968Z                 is not an `Opener` subclass or could not be loaded
2020-05-19T15:21:54.9489722Z                 successfully.
2020-05-19T15:21:54.9490057Z     
2020-05-19T15:21:54.9490253Z         """
2020-05-19T15:21:54.9490599Z         protocol = protocol or self.default_opener
2020-05-19T15:21:54.9490962Z     
2020-05-19T15:21:54.9491199Z         if self.load_extern:
2020-05-19T15:21:54.9491450Z             entry_point = next(
2020-05-19T15:21:54.9492011Z                 pkg_resources.iter_entry_points("fs.opener", protocol), None
2020-05-19T15:21:54.9492411Z             )
2020-05-19T15:21:54.9505060Z         else:
2020-05-19T15:21:54.9505520Z             entry_point = None
2020-05-19T15:21:54.9505843Z     
2020-05-19T15:21:54.9506452Z         # If not entry point was loaded from the extensions, try looking
2020-05-19T15:21:54.9506924Z         # into the registered protocols
2020-05-19T15:21:54.9507394Z         if entry_point is None:
2020-05-19T15:21:54.9507840Z             if protocol in self._protocols:
2020-05-19T15:21:54.9508703Z                 opener_instance = self._protocols[protocol]
2020-05-19T15:21:54.9509137Z             else:
2020-05-19T15:21:54.9509499Z                 raise UnsupportedProtocol(
2020-05-19T15:21:54.9510341Z                     "protocol '{}' is not supported".format(protocol)
2020-05-19T15:21:54.9510829Z                 )
2020-05-19T15:21:54.9511171Z     
2020-05-19T15:21:54.9511483Z         # If an entry point was found in an extension, attempt to load it
2020-05-19T15:21:54.9511793Z         else:
2020-05-19T15:21:54.9512015Z             try:
2020-05-19T15:21:54.9512374Z >               opener = entry_point.load()
2020-05-19T15:21:54.9512690Z 
2020-05-19T15:21:54.9513362Z /opt/hostedtoolcache/Python/3.7.7/x64/lib/python3.7/site-packages/fs/opener/registry.py:134: 
2020-05-19T15:21:54.9513820Z _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
2020-05-19T15:21:54.9514093Z 
2020-05-19T15:21:54.9514796Z self = EntryPoint.parse('smb = fs.opener.smbfs:SMBOpener'), require = True
2020-05-19T15:21:54.9515287Z args = (), kwargs = {}
2020-05-19T15:21:54.9515583Z 
2020-05-19T15:21:54.9515881Z     def load(self, require=True, *args, **kwargs):
2020-05-19T15:21:54.9516152Z         """
2020-05-19T15:21:54.9516437Z         Require packages for this EntryPoint, then resolve it.
2020-05-19T15:21:54.9516695Z         """
2020-05-19T15:21:54.9517057Z         if not require or args or kwargs:
2020-05-19T15:21:54.9517522Z             warnings.warn(
2020-05-19T15:21:54.9517935Z                 "Parameters to load are deprecated.  Call .resolve and "
2020-05-19T15:21:54.9518478Z                 ".require separately.",
2020-05-19T15:21:54.9519005Z                 PkgResourcesDeprecationWarning,
2020-05-19T15:21:54.9519382Z                 stacklevel=2,
2020-05-19T15:21:54.9519722Z             )
2020-05-19T15:21:54.9520037Z         if require:
2020-05-19T15:21:54.9520394Z >           self.require(*args, **kwargs)
2020-05-19T15:21:54.9520699Z 
2020-05-19T15:21:54.9521361Z /opt/hostedtoolcache/Python/3.7.7/x64/lib/python3.7/site-packages/pkg_resources/__init__.py:2452: 
2020-05-19T15:21:54.9521835Z _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
2020-05-19T15:21:54.9522241Z 
2020-05-19T15:21:54.9522868Z self = EntryPoint.parse('smb = fs.opener.smbfs:SMBOpener'), env = None
2020-05-19T15:21:54.9523326Z installer = None
2020-05-19T15:21:54.9523598Z 
2020-05-19T15:21:54.9523883Z     def require(self, env=None, installer=None):
2020-05-19T15:21:54.9524220Z         if self.extras and not self.dist:
2020-05-19T15:21:54.9525036Z             raise UnknownExtra("Can't require() without a distribution", self)
2020-05-19T15:21:54.9525466Z     
2020-05-19T15:21:54.9525774Z         # Get the requirements for this entry point with all its extras and
2020-05-19T15:21:54.9541288Z         # then resolve them. We have to pass `extras` along when resolving so
2020-05-19T15:21:54.9541948Z         # that the working set knows what extras we want. Otherwise, for
2020-05-19T15:21:54.9542784Z         # dist-info distributions, the working set will assume that the
2020-05-19T15:21:54.9543393Z         # requirements for that extra are purely optional and skip over them.
2020-05-19T15:21:54.9543739Z         reqs = self.dist.requires(self.extras)
2020-05-19T15:21:54.9544102Z >       items = working_set.resolve(reqs, env, installer, extras=self.extras)
2020-05-19T15:21:54.9544343Z 
2020-05-19T15:21:54.9544973Z /opt/hostedtoolcache/Python/3.7.7/x64/lib/python3.7/site-packages/pkg_resources/__init__.py:2475: 
2020-05-19T15:21:54.9545434Z _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
2020-05-19T15:21:54.9545700Z 
2020-05-19T15:21:54.9545932Z self = <pkg_resources.WorkingSet object at 0x7f8d27f8b610>
2020-05-19T15:21:54.9546516Z requirements = [Requirement.parse('fs~=2.2'), Requirement.parse('six~=1.10')]
2020-05-19T15:21:54.9546926Z env = None, installer = None, replace_conflicting = False, extras = ()
2020-05-19T15:21:54.9547152Z 
2020-05-19T15:21:54.9547514Z     def resolve(self, requirements, env=None, installer=None,
2020-05-19T15:21:54.9547902Z                 replace_conflicting=False, extras=None):
2020-05-19T15:21:54.9584989Z         """List all distributions needed to (recursively) meet `requirements`
2020-05-19T15:21:54.9585255Z     
2020-05-19T15:21:54.9586013Z         `requirements` must be a sequence of ``Requirement`` objects.  `env`,
2020-05-19T15:21:54.9586336Z         if supplied, should be an ``Environment`` instance.  If
2020-05-19T15:21:54.9586643Z         not supplied, it defaults to all distributions available within any
2020-05-19T15:21:54.9586986Z         entry or distribution in the working set.  `installer`, if supplied,
2020-05-19T15:21:54.9587409Z         will be invoked with each requirement that cannot be met by an
2020-05-19T15:21:54.9588031Z         already-installed distribution; it should return a ``Distribution`` or
2020-05-19T15:21:54.9588404Z         ``None``.
2020-05-19T15:21:54.9588663Z     
2020-05-19T15:21:54.9588917Z         Unless `replace_conflicting=True`, raises a VersionConflict exception
2020-05-19T15:21:54.9589190Z         if
2020-05-19T15:21:54.9589440Z         any requirements are found on the path that have the correct name but
2020-05-19T15:21:54.9589797Z         the wrong version.  Otherwise, if an `installer` is supplied it will be
2020-05-19T15:21:54.9590173Z         invoked to obtain the correct version of the requirement and activate
2020-05-19T15:21:54.9590422Z         it.
2020-05-19T15:21:54.9590563Z     
2020-05-19T15:21:54.9590820Z         `extras` is a list of the extras to be used with these requirements.
2020-05-19T15:21:54.9591168Z         This is important because extra requirements may look like `my_req;
2020-05-19T15:21:54.9591515Z         extra = "my_extra"`, which would otherwise be interpreted as a purely
2020-05-19T15:21:54.9592114Z         optional requirement.  Instead, we want to be able to assert that these
2020-05-19T15:21:54.9592371Z         requirements are truly required.
2020-05-19T15:21:54.9592545Z         """
2020-05-19T15:21:54.9592688Z     
2020-05-19T15:21:54.9592832Z         # set up the stack
2020-05-19T15:21:54.9593230Z         requirements = list(requirements)[::-1]
2020-05-19T15:21:54.9593492Z         # set of processed requirements
2020-05-19T15:21:54.9593677Z         processed = {}
2020-05-19T15:21:54.9593967Z         # key -> dist
2020-05-19T15:21:54.9594124Z         best = {}
2020-05-19T15:21:54.9594301Z         to_activate = []
2020-05-19T15:21:54.9594439Z     
2020-05-19T15:21:54.9594590Z         req_extras = _ReqExtras()
2020-05-19T15:21:54.9627919Z     
2020-05-19T15:21:54.9628310Z         # Mapping of requirement to set of distributions that required it;
2020-05-19T15:21:54.9628722Z         # useful for reporting info about conflicts.
2020-05-19T15:21:54.9629107Z         required_by = collections.defaultdict(set)
2020-05-19T15:21:54.9629317Z     
2020-05-19T15:21:54.9629488Z         while requirements:
2020-05-19T15:21:54.9630112Z             # process dependencies breadth-first
2020-05-19T15:21:54.9634988Z             req = requirements.pop(0)
2020-05-19T15:21:54.9635435Z             if req in processed:
2020-05-19T15:21:54.9635807Z                 # Ignore cyclic or redundant dependencies
2020-05-19T15:21:54.9636173Z                 continue
2020-05-19T15:21:54.9636408Z     
2020-05-19T15:21:54.9636603Z             if not req_extras.markers_pass(req, extras):
2020-05-19T15:21:54.9636828Z                 continue
2020-05-19T15:21:54.9636979Z     
2020-05-19T15:21:54.9637128Z             dist = best.get(req.key)
2020-05-19T15:21:54.9637320Z             if dist is None:
2020-05-19T15:21:54.9637570Z                 # Find the best distribution and add it to the map
2020-05-19T15:21:54.9637815Z                 dist = self.by_key.get(req.key)
2020-05-19T15:21:54.9638110Z                 if dist is None or (dist not in req and replace_conflicting):
2020-05-19T15:21:54.9638519Z                     ws = self
2020-05-19T15:21:54.9638849Z                     if env is None:
2020-05-19T15:21:54.9639188Z                         if dist is None:
2020-05-19T15:21:54.9639608Z                             env = Environment(self.entries)
2020-05-19T15:21:54.9639863Z                         else:
2020-05-19T15:21:54.9640148Z                             # Use an empty environment and workingset to avoid
2020-05-19T15:21:54.9640503Z                             # any further conflicts with the conflicting
2020-05-19T15:21:54.9640786Z                             # distribution
2020-05-19T15:21:54.9641032Z                             env = Environment([])
2020-05-19T15:21:54.9641305Z                             ws = WorkingSet([])
2020-05-19T15:21:54.9641571Z                     dist = best[req.key] = env.best_match(
2020-05-19T15:21:54.9642056Z                         req, ws, installer,
2020-05-19T15:21:54.9642327Z                         replace_conflicting=replace_conflicting
2020-05-19T15:21:54.9642647Z                     )
2020-05-19T15:21:54.9642833Z                     if dist is None:
2020-05-19T15:21:54.9643093Z                         requirers = required_by.get(req, None)
2020-05-19T15:21:54.9643358Z                         raise DistributionNotFound(req, requirers)
2020-05-19T15:21:54.9643714Z                 to_activate.append(dist)
2020-05-19T15:21:54.9644062Z             if dist not in req:
2020-05-19T15:21:54.9644455Z                 # Oops, the "best" so far conflicts with a dependency
2020-05-19T15:21:54.9644742Z                 dependent_req = required_by[req]
2020-05-19T15:21:54.9645058Z >               raise VersionConflict(dist, req).with_context(dependent_req)
2020-05-19T15:21:54.9646012Z E               pkg_resources.VersionConflict: (pysmb 1.2.1 (/opt/hostedtoolcache/Python/3.7.7/x64/lib/python3.7/site-packages), Requirement.parse('pysmb!=1.1.26,~=1.1.22'))

The issue seems to be due to the fact that the version specs in setup.cfg are ignored by pip install, but are visible to the entry_point loading machinery in pkg_resources.

pysmb 1.2 seems to mostly be bugfixes (judging by the contents of the brief changelog), so the fix here is probably to a) upgrade the pysmb spec in setup.cfg to latest, b) switch over to a more permissive spec (eg ~=1.2) for pysmb to prevent these issues in the future

Add support for domain

There doesn't seem to be a way to send the domain through to be added to the SMBConnection arguments. It is sometimes required.

IPv6 support

NetBIOS names and IPv4 are supported at the moment, but no IPv6.

MissingInfoNamespace: namespace 'details' is required for this attribute

Cannot get file size:

    print(image.info.size)
  File "/home/frafra/.cache/pypoetry/virtualenvs/viltkamera-manager-QhDdi_a7-py3.8/lib/python3.8/site-packages/fs/info.py", line 370, in size
    self._require_namespace("details")
  File "/home/frafra/.cache/pypoetry/virtualenvs/viltkamera-manager-QhDdi_a7-py3.8/lib/python3.8/site-packages/fs/info.py", line 129, in _require_namespace
    raise MissingInfoNamespace(namespace)
fs.errors.MissingInfoNamespace: namespace 'details' is required for this attribute

fs.geturl() returns smb://username@host:None/path

I'd expect geturl() on a filesystem object to return either protocol://username:password@host[:port]/path or protocol://username@host[:port]/path, but geturl() in this case returns smb://username@host:None/path if no port was given explicitly, which seems to be wrong IMO.

_make_access_from_sd assumes that an "everyone" ACE exists, which sometimes isn't true on Windows

jupyter-fs is built on top of fs.smbfs, and I've been working to make it compatible with Windows. Right now I'm getting an error in my pytest CI on Windows durring SMBFS._make_access_from_sd:

cls = <class 'fs.smbfs.smbfs.SMBFS'>, sd = <smb.security_descriptors.SecurityDescriptor object at 0x04DDD7F0>

    @classmethod
    def _make_access_from_sd(cls, sd):

    ...

>       other_ace = next(ace for ace in sd.dacl.aces
            if str(ace.sid).startswith(smb.security_descriptors.SID_EVERYONE))
E       StopIteration

I know the file that _make_access_from_sd is choking on, so I dug in and examined it more deeply using pysmb. The problem appears to be that the "everyone" SID does not correspond to any of the file's ACEs. In fact, of the ACEs that _make_access_from_sd checks for, in my particular case only the "owner" ACE exists:

In [10]: smb.security_descriptors.SID_EVERYONE
Out[10]: 'S-1-1-0'

In [11]: conn.getSecurity('test', 'foo.txt').owner
Out[11]: SID('S-1-5-21-3526669579-2242266465-3136906013-1006')

In [12]: conn.getSecurity('test', 'foo.txt').group
Out[12]: SID('S-1-5-21-3526669579-2242266465-3136906013-513')
In [8]: [a.sid for a in conn.getSecurity('test', 'foo.txt').dacl.aces]
Out[8]:
[SID('S-1-5-18'),
 SID('S-1-5-32-544'),
 SID('S-1-5-32-545'),
 SID('S-1-5-21-3526669579-2242266465-3136906013-1006')]

Is comma actually an invalid SMB path character?

Hi,

I've posted the details in the PyFilesystem2 issue here:
PyFilesystem/pyfilesystem2#494

But now realise that this is probably best asked in this project.

It boils down to the question: are commas actually invalid SMB path characters? They seem to work fine for me, yet are included in fs.smbfs.SMBFS._meta['invalid_path_chars'].

Is this a bug?

Cheers,
Sam.

get_hostname_and_ip erroneous example in docstring

def get_hostname_and_ip(host, netbios, timeout=15, name_port=137):
"""Get the IP and hostnames from the given token.
Example:
>>> from fs.smbfs.utils import get_hostname_and_ip as ghip
>>> from nmb.NetBIOS import NetBIOS
>>> nb = NetBIOS()
>>> ghip("SAMBAALPINE")

Last line should be: ghip("SAMBAALPINE", nb) . Following example calls to ghip have the same problem (second mandatory argument nb is missing).

how to open and read a file?

smb = fs.smbfs.SMBFS(host='x.x.x.x', username='xxx', passwd='xxx', port=139)`
fnexps=["*.txt"]`
for root, dirs, files in smb.walk('test',filter=fnexps):`
    for file in files:`
        print(file.name)

how to open file xx.txt?

Connect to Microsoft Azure File Service

Hi,
I am failing to connect to Microsoft Azure file service.
It works perfectly from the command line on the same machine (linux VM in Azure):
sudo mount -t cifs //<storageaccount>.file.core.windows.net/<sharename> <localmountdir> -o vers=3.0,credentials=<credentialfile>,dir_mode=0777,file_mode=0777,serverino
(copied from the Azure connection instructions)

I tried to connect with the IP adress, which I got from nslookup, as I don't know the hostname for a netbios lookup. I disabled netbios lookup with direct_tcp=True:
smb_fs = fs.smbfs.SMBFS(<IPaddress>, username, passwd, port=445, direct_tcp=True)

However, I receive the error smb.smb_structs.ProtocolError: Not a SMB_COM_NEGOTIATE reply.
When I enable netbios lookup with direct_tcp=False, I fails after hitting the timeout. As far as I know, netbios is not available in azure virtual networks.

Does anyone have a solution on how to connect to Azure File Service?

Connection to server is not closed

It is necessary to add the following method to class SMBFS:

def __del__(self):
    if self._smb:
        self._smb.close()

Otherwise, the connection to the server is left opened until the server itself closes it by idle timeout (by default it is 15 minutes on Windows).
The Windows File Server rejects new connections if there are many idle connections with the following error:

smb.smb_structs.ProtocolError: Unknown status value (0xC00000D0) in SMB_COM_SESSION_SETUP_ANDX (with extended security)

support case insensitive for entire smbfs

The server, file, and folder names are all case sensitive. Only some methods have a case insensitive option (like glob).
Ideally, the whole thing would behave transparently unless an ambiguous name is detected. This matters to me because I'm using windows, so the names I'm starting with are case-sensitive. I will need to create a work-around if I choose to use this package.

[ and ] should be valid path characters

fs.smbfs considers [ and ] invalid path characters, but I have several files with those characters on my SMB share; experimentally removing [] from the list of invalid chars in smbfs.py, I found those files download completely fine..

Extremely low apparent performance

Wondering if any light could be shed on why I'm seeing extremally slow performance using the smb_fs on a Windows 11 system.

I haven't done exhaustive profiling, but reading a small text file from an smb share on an ubuntu server on my local network takes around 3.6 seconds using smb_fs.readtext(), where reading the exact same file from the exact same smb server using a drive letter mount on my windows machine using OSFS.readtext() takes around .008 seconds.

I'm not sure how much caching the windows smb mount system is doing (that was my first thought), but a 450x difference is very noticeable (which is why I perfed it in the first place) and if this delay stays consistent across the board, makes this pretty unusable for my purposes (which is unfortunate because it would be really cool to enable access to these files without having to configure the network drive letter mapping first).

Is this something I'm potentially doing when constructing the object, or something inherent to the way SMB is being utilized? It doesn't seem to be an overhead in the fs library itself as the osfs object shows no such performance drop.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.