miketeo / pysmb

pysmb is an experimental SMB/CIFS library written in Python. It implements the client-side SMB/CIFS protocol (SMB1 and SMB2) which allows your Python application to access and transfer files to/from SMB/CIFS shared folders like your Windows file sharing and Samba folders.
Other
338 stars 95 forks source link

Copy a file using pysmb from windows to linux #213

Closed prathishpkr closed 8 months ago

prathishpkr commented 1 year ago

Copy a file using smb from windows to remote linux and linux to remote windows, is that possible using retrieveFile() or storeFile().

import smbclient from smb.SMBConnection import SMBConnection

def Copy_data_linux_to_windows(source_file, destination_file, username, password, server_ip, share_name): try: conn = SMBConnection(username, password, '', '')

    conn = connect(server_ip, 445)

    #with smbclient.open_file(source_path, mode ="rb", username=username, password=password, remote_host=remote_host, port=port) as f:
    with open(source_file, "rb") as local_file:

            with conn.retrieveFile(share_name, destination_file, overwrite=True) as remote_file:

                 remote_file.write(local_file.read())

    print("File Copied successfully from Linux to Win")

except Exception as e:
    print("Error occurred while copying file from Linux to Windows: {e}")

finally:
     conn.close()            

if name == "main": source_file = "/tmp/Copy_dir/Python_Test.zip" destination_file = r"W:\Python_Test.zip"

destination_path ="C:\SMB\Python_Test.zip"

username = "uname"
password = ""paswrd
server_ip ="ipaddress"
share_name = "share_name"

print("Copying file from Linux to windows")
Copy_data_linux_to_windows(source_file, destination_file, server_ip, username, password, share_name)
miketeo commented 1 year ago

@prathishpkr Yes, pysmb can be used to copy file between Windows and Linux Samba service. However, there are issues with your code snippet. Please refer to https://pysmb.readthedocs.io/en/latest/api/smb_SMBConnection.html for an example on how the perform the copy operation.

prathishpkr commented 1 year ago

@miketeo, i have tried to upload the file from local to Samba server using storeFile method, there am getting the below issues

NFO:SMB.SMBConnection:Authentication with remote machine "IP address" for user "osboxes" will be using NTLM v2 authentication (with extended security) Traceback (most recent call last): File "w:/FIM_C_src/FIM-C-master/FIM-C-master/fim/Loc_SMB.py", line 50, in transfer_file() File "w:/FIM_C_src/FIM-C-master/FIM-C-master/fim/Loc_SMB.py", line 36, in transfer_file conn.connect(server_ip, 445) File "C:\Python38-32\lib\site-packages\smb\SMBConnection.py", line 129, in connect self._pollForNetBIOSPacket(timeout) File "C:\Python38-32\lib\site-packages\smb\SMBConnection.py", line 649, in _pollForNetBIOSPacket self.feedData(data) File "C:\Python38-32\lib\site-packages\nmb\base.py", line 54, in feedData self._processNMBSessionPacket(self.data_nmb) File "C:\Python38-32\lib\site-packages\nmb\base.py", line 75, in _processNMBSessionPacket self.onNMBSessionMessage(packet.flags, packet.data) File "C:\Python38-32\lib\site-packages\smb\base.py", line 128, in onNMBSessionMessage i = self.smb_message.decode(data) File "C:\Python38-32\lib\site-packages\smb\smb_structs.py", line 228, in decode self._decodePayload() File "C:\Python38-32\lib\site-packages\smb\smb_structs.py", line 255, in _decodePayload self.payload.decode(self) File "C:\Python38-32\lib\site-packages\smb\smb_structs.py", line 361, in decode raise ProtocolError('Server does not support any of the pysmb dialects. Please email pysmb to add in support for your OS',
smb.smb_structs.ProtocolError: Server does not support any of the pysmb dialects. Please email pysmb to add in support for your OS ==================== SMB Message ==================== Command: 0x72 (SMB_COM_NEGOTIATE) Status: NTSTATUS=0x00000000 Flags: 0x88 Flags2: 0xC003 PID: 26092 UID: 0 MID: 1 TID: 0 Security: 0x0000000000000000 Parameters: 2 bytes b'ffff' Data: 0 bytes b'' ==================== SMB Data Packet (hex) ==================== b'ff534d4272000000008803c00000000000000000000000000000ec650000010001ffff0000',

miketeo commented 1 year ago

@prathishpkr try to modify the smb.conf on the Samba service, and restart your Samba service.

client min protocol = SMB2
client max protocol = SMB3

More information at https://www.cyberciti.biz/faq/how-to-configure-samba-to-use-smbv2-and-disable-smbv1-on-linux-or-unix/

prathishpkr commented 1 year ago

@miketeo, could you please assist me for test file for this below code, do we want to define the function 2 times for connection for SMB2 and SMB, cause below code am not able to upload the files and also large amount of data will support to transfer storefile ?

class SMBNetworkShare(): SMBDetails(hardcoded) -> declared as Glo variable.

def __init__(self, smbServerAddress, smbport, conn, smbUser, smbPassword, smbShareName, smbClientName, smbDestFolder, smbSourceFolder, smbretSourceFolder, smbretDestFolder) -> None:
    self.smbServerAddress = smbServerAddress
    self.smbShareName = smbShareName
    self.smbClientName = smbClientName
    self.smbUser = smbUser
    self.smbport = smbport
    self.password = smbPassword
    self.conn = conn
    self.smbDestFolder = smbDestFolder
    self.smbSourceFolder = smbSourceFolder
    # self.smbretSourceFolder = smbretSourceFolder
    # self.smbretDestFolder = smbDestFolder
    # self.directory_was_online = True

# SMB Connect to Samba server

def __open_connection(self) -> None:
    logger = logging.getLogger("SMBNetworkShare")
    try:
        self.conn = SMBConnection(self.smbServerAddress, self.smbport, self.smbUser,
                                  self.smbPassword, self.smbClientName, use_ntlm_v2=True, is_direct_tcp=True)
        self.conn.connect(self.smbServerAddress, 445)
    except Exception as ex:
        logger.error('Failed to connect smb server "(' +
                     self.smbServerAddress + '":' + str(ex))

def local_dir_list(self, dir: str):  # Local dir
    list_dir = []
    try:
        # SMB_FILE_ATTRIBUTE_ARCHIVE | SMB_FILE_ATTRIBUTE_INCL_NORMAL)
        local_dir = os.listdir(dir)
        for file_list in local_dir:
            file_list.append(list_dir)
    except Exception as e:
        logging.error("Error occurred while listing files", str(e))

# -> None: #smb_shareName(target_dir)
def copy_to(self, SMBConnection, source_dir: str, target_dir: str, max_attempts=3):
    logger = logging.getLogger(SMBConnection)
    # self.conn.connect()

    try:
        source_file_size = os.path.getsize(self.smbSourceFolder)

        for attempt in range(1, max_attempts + 1):

            try:

                fileList = self.local_dir_list(source_dir)
                for filename in fileList:
                    logger.info("File Copying " + filename)
                # smbDestFolder, filename)
                destPath = os.path.join(
                    self.smbDestFolder, target_dir, filename)
                # (smbSourceFolder, filename)
                srcPath = os.path.join(source_dir, filename)

                with open(srcPath, 'rb') as f:
                    # (smbShareName, destPath, f)
                    self.conn.storeFile(
                        f, self.smbShareName, destPath, overwrite=True)
                    # ********for checking successfully******
                    logger.info(f"File Uploaded ")

                    destination_file_info = self.conn.query_info(
                        self.smbDestFolder)  # get_attributes(self.smbDestFolder)
                    destination_file_size = destination_file_info.standard_infromation.endoffile

                    if source_file_size != destination_file_size:
                        logger.warning(
                            f" File {attempt} + filename + Uploaded Successfully, but filesize does not match !!!")

                        if attempt < max_attempts:
                            logger.warning(
                                f"Retrying to upload again after sleep time")
                            time.sleep(5)  # wait for 5ms to retry!!!
                        else:
                            logger.info(
                                f"Filesize are same and uploaded successfully")
                    else:
                        # Successfully done
                        return True

            except Exception as ex:
                logger.warning(
                    f"Attempt {attempt} failed: + filename + :  + {str(ex)}")

                if attempt < max_attempts:
                    logger.warning(f"Retrying after sleep time")
                    time.sleep(5)  # wait for 5ms to retry!!!
                else:
                    logger.error(
                        f'Maximum attempts reached, Failed to upload')

    finally:
        self.conn.disconnect()
        if conn == True:
            conn.close()
miketeo commented 1 year ago

Can you correct the formatting for your code?

prathishpkr commented 1 year ago

@miketeo could you please check above format now, please check and let know.

miketeo commented 1 year ago
self.conn = SMBConnection(self.smbServerAddress, self.smbport, self.smbUser, self.smbPassword, self.smbClientName, use_ntlm_v2=True, is_direct_tcp=True)

The parameters to the SMBConnection are incorrect. The order should be userID, password, client_machine_name, server_name, use_ntlm_v2. The server_name must be the remote Samba name, e.g. MYSERVER, or SAMBA. You need to check your Samba configuration or try to use your Windows explorer to browse for the exact name.

It's probably safe to drop support SMB and focus on supporting SMB2 in your app. If your app fails to connect using port 445, try port 139. Sometimes, one of the ports is blocked by firewall.

prathishpkr commented 1 year ago

@miketeo Could you please assist me, have try to find the document of to get the list of files presents in subdirectory/subfolder and the filesize checked for destination location (remote location ), is that support os.walk() which is support for localfile to fetch the list of files details(it should retrieve the files of all file format, including subdirectory/subfolder inside files) and for filesize can we retrieve the information if use the below method

destination_file_info = self.conn.query_info(self.smbDestFolder) # get_attributes(self.smbDestFolder) destination_file_size = destination_file_info.standard_infromation.endoffile.

could you please share the documents, if we use above method.