<commit_before>""" Filesystem to access SMB servers.
"""
import datetime
import random
import stat
import string
import threading

from functools import wraps

from smb.SMBConnection import SMBConnection
from smb.base import OperationFailure

from fs import _thread_synchronize_default
from fs import iotools
from fs.base import FS
from fs.errors import DestinationExistsError
from fs.errors import DirectoryNotEmptyError
from fs.errors import FSError
from fs.errors import OperationFailedError
from fs.errors import ParentDirectoryMissingError
from fs.errors import RemoveRootError
from fs.errors import ResourceInvalidError
from fs.errors import ResourceNotFoundError
from fs.filelike import SpooledTemporaryFile
from fs.filelike import StringIO
from fs.path import abspath
from fs.path import basename
from fs.path import dirname
from fs.path import normpath
from fs.path import pathjoin
from fs.path import recursepath
from fs.remote import RemoteFileBuffer


class DeletePendingError(OperationFailedError):
    default_message = "Unable to %(opname)s: delete pending"


def _conv_smb_errors(outer):
    """ Convert Samba errors (OperationFailure) into PyFilesystem errors. """
    def inner(*args, **kwargs):
        try:
            return outer(*args, **kwargs)
        except OperationFailure as e:
            # Cycle through each message and map the first one to PyFilesystem
            # that is not a successful status (0x00000000).
            path = args[1]
            for msg in e.smb_messages:
                # Protocol versions exposes the error values differently.
                if msg.protocol == 1:
                    msg_status = msg.status.internal_value
                else:
                    msg_status = msg.status

                if msg_status == 0x0:
                    continue
                elif msg_status == 0x103:
                    # Unknown error, but message says it is not found.
                    raise ResourceNotFoundError(path)
                elif msg_status == 0xc000000f:
                    raise ResourceNotFoundError(path)
                elif msg_status == 0xc0000033:
                    raise ResourceInvalidError(path)
                elif msg_status == 0xc0000034:
                    raise ResourceNotFoundError(path)
                elif msg_status == 0xc0000035:
                    raise DestinationExistsError(path)
                elif msg_status == 0xc000003a:
                    raise ResourceNotFoundError(path)
                elif msg_status == 0xc0000056:
                    raise DeletePendingError(path)
                elif msg_status == 0xc00000ba:
                    raise ResourceInvalidError(path)
                elif msg_status == 0xc00000d0:
                    raise ResourceInvalidError(path)
                elif msg_status == 0xc0000101:
                    raise DirectoryNotEmptyError(path)
                elif msg_status == 0xc0000103:
                    raise ResourceInvalidError(path)
                else:
                    raise Exception('Unhandled SMB error:  {0}'.format(
                        hex(msg_status)))
            raise
    return inner


def _determine_cause(outer):
    """ Determine specific path raising an exception for src/dst operations.

        The error raised by pysmb does not report which path is the cause.
    """
    def inner(*args, **kwargs):
        try:
            return outer(*args, **kwargs)
        except DestinationExistsError:
            raise DestinationExistsError(args[2])
        except ResourceNotFoundError:
            # Parent directory does not exist or is not a directory.
            src, dst = args[1:3]
            fs = args[0]
            for p in (src, dst):
                if not fs.exists(p):
                    root = dirname(p)
                    if not fs.isdir(root):
                        if fs.isfile(root):
                            raise ResourceInvalidError(p)
                        else:
                            raise ParentDirectoryMissingError(p)
                    else:
                        raise ResourceNotFoundError(p)
    return inner


def _absnorm_path(num_paths):
    """ Convert path (first) argument to absolute and normalize it.

        For example, pysmb has issues with ".", so "/" is needed.
    """
    def inner_1(func):
        @wraps(func)
        def inner_2(fs, *args, **kwargs):
            new_args = []
            for ndx, arg in enumerate(args):
                if ndx < num_paths:
                    arg = abspath(normpath(arg))
                new_args.append(arg)
            return func(fs, *new_args, **kwargs)
        return inner_2
    return inner_1


class SMBFS(FS):
    """ Filesystem stored on a SMB share.

        This wraps pysmb (https://pypi.python.org/pypi/pysmb) to access SMB
        shares.
    """
    _meta = {'thread_safe': True,
             'virtual': False,
             'read_only': False,
             'unicode_paths': True,
             'case_insensitive_paths': False,  # It depends upon the server.
             'network': True,
             'atomic.makedir': True,
             'atomic.removedir': False,
             'atomic.rename': True,
             'atomic.setcontents': False,
             'mime_type': 'virtual/filehub'}

    def __init__(self, username, password, server_name, server_IP, share,
                 port=139, client_name=None,
                 thread_synchronize=_thread_synchronize_default):
        self.username = username
        self.password = password
        self.server_name = server_name
        self.share = share
        self.server_IP = server_IP
        self.port = port
        self._tls = threading.local()

        # Automatically generate a client name if not provided.
        if client_name is None:
            self.client_name = 'fs{0}'.format(''.join(random.choice(
                string.uppercase + string.digits) for i in xrange(12)))
        else:
            self.client_name = client_name<commit_msg>Change mime type to virtual/smb.<commit_after>""" Filesystem to access SMB servers.
"""
import datetime
import random
import stat
import string
import threading

from functools import wraps

from smb.SMBConnection import SMBConnection
from smb.base import OperationFailure

from fs import _thread_synchronize_default
from fs import iotools
from fs.base import FS
from fs.errors import DestinationExistsError
from fs.errors import DirectoryNotEmptyError
from fs.errors import FSError
from fs.errors import OperationFailedError
from fs.errors import ParentDirectoryMissingError
from fs.errors import RemoveRootError
from fs.errors import ResourceInvalidError
from fs.errors import ResourceNotFoundError
from fs.filelike import SpooledTemporaryFile
from fs.filelike import StringIO
from fs.path import abspath
from fs.path import basename
from fs.path import dirname
from fs.path import normpath
from fs.path import pathjoin
from fs.path import recursepath
from fs.remote import RemoteFileBuffer


class DeletePendingError(OperationFailedError):
    default_message = "Unable to %(opname)s: delete pending"


def _conv_smb_errors(outer):
    """ Convert Samba errors (OperationFailure) into PyFilesystem errors. """
    def inner(*args, **kwargs):
        try:
            return outer(*args, **kwargs)
        except OperationFailure as e:
            # Cycle through each message and map the first one to PyFilesystem
            # that is not a successful status (0x00000000).
            path = args[1]
            for msg in e.smb_messages:
                # Protocol versions exposes the error values differently.
                if msg.protocol == 1:
                    msg_status = msg.status.internal_value
                else:
                    msg_status = msg.status

                if msg_status == 0x0:
                    continue
                elif msg_status == 0x103:
                    # Unknown error, but message says it is not found.
                    raise ResourceNotFoundError(path)
                elif msg_status == 0xc000000f:
                    raise ResourceNotFoundError(path)
                elif msg_status == 0xc0000033:
                    raise ResourceInvalidError(path)
                elif msg_status == 0xc0000034:
                    raise ResourceNotFoundError(path)
                elif msg_status == 0xc0000035:
                    raise DestinationExistsError(path)
                elif msg_status == 0xc000003a:
                    raise ResourceNotFoundError(path)
                elif msg_status == 0xc0000056:
                    raise DeletePendingError(path)
                elif msg_status == 0xc00000ba:
                    raise ResourceInvalidError(path)
                elif msg_status == 0xc00000d0:
                    raise ResourceInvalidError(path)
                elif msg_status == 0xc0000101:
                    raise DirectoryNotEmptyError(path)
                elif msg_status == 0xc0000103:
                    raise ResourceInvalidError(path)
                else:
                    raise Exception('Unhandled SMB error:  {0}'.format(
                        hex(msg_status)))
            raise
    return inner


def _determine_cause(outer):
    """ Determine specific path raising an exception for src/dst operations.

        The error raised by pysmb does not report which path is the cause.
    """
    def inner(*args, **kwargs):
        try:
            return outer(*args, **kwargs)
        except DestinationExistsError:
            raise DestinationExistsError(args[2])
        except ResourceNotFoundError:
            # Parent directory does not exist or is not a directory.
            src, dst = args[1:3]
            fs = args[0]
            for p in (src, dst):
                if not fs.exists(p):
                    root = dirname(p)
                    if not fs.isdir(root):
                        if fs.isfile(root):
                            raise ResourceInvalidError(p)
                        else:
                            raise ParentDirectoryMissingError(p)
                    else:
                        raise ResourceNotFoundError(p)
    return inner


def _absnorm_path(num_paths):
    """ Convert path (first) argument to absolute and normalize it.

        For example, pysmb has issues with ".", so "/" is needed.
    """
    def inner_1(func):
        @wraps(func)
        def inner_2(fs, *args, **kwargs):
            new_args = []
            for ndx, arg in enumerate(args):
                if ndx < num_paths:
                    arg = abspath(normpath(arg))
                new_args.append(arg)
            return func(fs, *new_args, **kwargs)
        return inner_2
    return inner_1


class SMBFS(FS):
    """ Filesystem stored on a SMB share.

        This wraps pysmb (https://pypi.python.org/pypi/pysmb) to access SMB
        shares.
    """
    _meta = {'thread_safe': True,
             'virtual': False,
             'read_only': False,
             'unicode_paths': True,
             'case_insensitive_paths': False,  # It depends upon the server.
             'network': True,
             'atomic.makedir': True,
             'atomic.removedir': False,
             'atomic.rename': True,
             'atomic.setcontents': False,
             'mime_type': 'virtual/smb'}

    def __init__(self, username, password, server_name, server_IP, share,
                 port=139, client_name=None,
                 thread_synchronize=_thread_synchronize_default):
        self.username = username
        self.password = password
        self.server_name = server_name
        self.share = share
        self.server_IP = server_IP
        self.port = port
        self._tls = threading.local()

        # Automatically generate a client name if not provided.
        if client_name is None:
            self.client_name = 'fs{0}'.format(''.join(random.choice(
                string.uppercase + string.digits) for i in xrange(12)))
        else:
            self.client_name = client_name
{'fraction_non_alphanumeric': 0.07080528546497133, 'fraction_numerical': 0.017784426161389512, 'mean_word_length': 1.86865315852205, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1729934', 'n_tokens_mistral': 3269, 'n_tokens_neox': 2982, 'n_words': 939}