smbclientng.core.LocalFileIO

  1#!/usr/bin/env python3
  2# -*- coding: utf-8 -*-
  3# File name          : LocalFileIO.py
  4# Author             : Podalirius (@podalirius_)
  5# Date created       : 23 may 2024
  6
  7
  8import os
  9import ntpath
 10from rich.progress import BarColumn, DownloadColumn, Progress, TextColumn, TimeRemainingColumn, TransferSpeedColumn
 11
 12
 13class LocalFileIO(object):
 14    """
 15    Class LocalFileIO is designed to handle local file input/output operations within the smbclient-ng tool.
 16    It provides functionalities to open, read, write, and manage progress of file operations based on the expected size of the file.
 17
 18    Attributes:
 19        mode (str): The mode in which the file should be opened (e.g., 'rb', 'wb').
 20        path (str): The path to the file that needs to be handled.
 21        expected_size (int, optional): The expected size of the file in bytes. This is used to display progress.
 22        debug (bool): Flag to enable debug mode which provides additional output during operations.
 23
 24    Methods:
 25        __init__(self, mode, path=None, expected_size=None, debug=False): Initializes the LocalFileIO instance.
 26        write(self, data): Writes data to the file and updates the progress bar if expected size is provided.
 27        read(self, size): Reads data from the file up to the specified size and updates the progress bar if expected size is provided.
 28    """
 29
 30    def __init__(self, mode, path=None, expected_size=None, keepRemotePath=False, logger=None):
 31        super(LocalFileIO, self).__init__()
 32        self.logger = logger
 33        self.mode = mode
 34        # Convert remote path format to local operating system path format 
 35        self.path = path.replace(ntpath.sep, os.path.sep)
 36        self.dir = None
 37        self.debug = False
 38        self.expected_size = expected_size
 39        self.keepRemotePath = keepRemotePath
 40
 41        # Write to local (read remote)
 42        if self.mode in ["wb"]:
 43            self.dir = '.' + os.path.sep
 44            if keepRemotePath:
 45                self.dir += os.path.dirname(self.path)
 46
 47            if not os.path.exists(self.dir):
 48                self.logger.debug("[debug] Creating local directory '%s'" % self.dir)
 49                os.makedirs(self.dir)
 50
 51            self.logger.debug("[debug] Openning local '%s' with mode '%s'" % (self.path, self.mode))
 52            
 53            try:
 54                self.fd = open(self.dir + os.path.sep + os.path.basename(self.path), self.mode)
 55            except PermissionError as err:
 56                self.fd = None
 57
 58        # Write to remote (read local)
 59        elif self.mode in ["rb"]:
 60            if ntpath.sep in self.path:
 61                self.dir = os.path.dirname(self.path)
 62
 63            self.logger.debug("[debug] Openning local '%s' with mode '%s'" % (self.path, self.mode))
 64            
 65            try:
 66                self.fd = open(self.path, self.mode)
 67            except PermissionError as err:
 68                self.fd = None
 69
 70            if self.fd is not None:
 71                if self.expected_size is None:
 72                    self.expected_size = os.path.getsize(filename=self.path)
 73
 74        # Create progress bar
 75        if self.expected_size is not None:
 76            self.__progress = Progress(
 77                TextColumn("[bold blue]{task.description}", justify="right"),
 78                BarColumn(bar_width=None),
 79                "[progress.percentage]{task.percentage:>3.1f}%",
 80                "•",
 81                DownloadColumn(),
 82                "•",
 83                TransferSpeedColumn(),
 84                "•",
 85                TimeRemainingColumn(),
 86            )
 87            self.__progress.start()
 88            self.__task = self.__progress.add_task(
 89                description="'%s'" % os.path.basename(self.path),
 90                start=True,
 91                total=self.expected_size,
 92                visible=True
 93            )
 94
 95    def write(self, data):
 96        """
 97        Writes data to the file.
 98
 99        This method writes the specified data to the file and updates the progress bar with the amount of data written if the expected size is set.
100
101        Args:
102            data (bytes): The data to be written to the file.
103
104        Returns:
105            int: The number of bytes written.
106        """
107
108        if self.fd is not None:
109            if self.expected_size is not None:
110                self.__progress.update(self.__task, advance=len(data))
111            return self.fd.write(data)
112        else:
113            return 0
114    
115    def read(self, size):
116        """
117        Reads a specified amount of data from the file.
118
119        This method reads data from the file based on the size specified. It also updates the progress bar with the amount of data read if the expected size is set.
120
121        Args:
122            size (int): The number of bytes to read from the file.
123
124        Returns:
125            bytes: The data read from the file.
126        """
127
128        if self.fd is not None:
129            read_data = self.fd.read(size)
130            if self.expected_size is not None:
131                self.__progress.update(self.__task, advance=len(read_data))
132            return read_data
133        else:
134            return b""
135
136    def close(self, remove=False):
137        """
138        Closes the file descriptor and optionally removes the file.
139
140        This method ensures that the file descriptor is properly closed and the file is removed if specified.
141        It also stops the progress bar if it was initiated and cleans up the object by deleting it.
142
143        Args:
144            remove (bool): If True, the file at the path will be removed after closing the file descriptor.
145        """
146
147        if self.fd is not None:
148            self.fd.close()
149
150        if remove:
151            try:
152                os.remove(path=self.path)
153            except (PermissionError, FileNotFoundError) as err:
154                pass
155
156        if self.expected_size is not None:
157            self.__progress.stop()
158        
159        del self
160
161    def set_error(self, message):
162        """
163        Sets an error message in the progress bar's description and modifies the progress bar to show only essential columns.
164
165        This method is used to communicate error states or important messages directly in the progress bar interface.
166        It updates the task description with the provided message and simplifies the progress bar to show only the text
167        and download columns, removing other elements like speed and time remaining which may not be relevant in an error state.
168
169        Args:
170            message (str): The error or status message to display in the progress bar.
171        """
172
173        self.__progress.tasks[0].description = message
174        self.__progress.columns = [
175            TextColumn("[bold blue]{task.description}", justify="right"),
176            BarColumn(bar_width=None),
177            "•",
178            DownloadColumn(),
179        ]
180        self.__progress.update(self.__task, advance=0)
class LocalFileIO:
 14class LocalFileIO(object):
 15    """
 16    Class LocalFileIO is designed to handle local file input/output operations within the smbclient-ng tool.
 17    It provides functionalities to open, read, write, and manage progress of file operations based on the expected size of the file.
 18
 19    Attributes:
 20        mode (str): The mode in which the file should be opened (e.g., 'rb', 'wb').
 21        path (str): The path to the file that needs to be handled.
 22        expected_size (int, optional): The expected size of the file in bytes. This is used to display progress.
 23        debug (bool): Flag to enable debug mode which provides additional output during operations.
 24
 25    Methods:
 26        __init__(self, mode, path=None, expected_size=None, debug=False): Initializes the LocalFileIO instance.
 27        write(self, data): Writes data to the file and updates the progress bar if expected size is provided.
 28        read(self, size): Reads data from the file up to the specified size and updates the progress bar if expected size is provided.
 29    """
 30
 31    def __init__(self, mode, path=None, expected_size=None, keepRemotePath=False, logger=None):
 32        super(LocalFileIO, self).__init__()
 33        self.logger = logger
 34        self.mode = mode
 35        # Convert remote path format to local operating system path format 
 36        self.path = path.replace(ntpath.sep, os.path.sep)
 37        self.dir = None
 38        self.debug = False
 39        self.expected_size = expected_size
 40        self.keepRemotePath = keepRemotePath
 41
 42        # Write to local (read remote)
 43        if self.mode in ["wb"]:
 44            self.dir = '.' + os.path.sep
 45            if keepRemotePath:
 46                self.dir += os.path.dirname(self.path)
 47
 48            if not os.path.exists(self.dir):
 49                self.logger.debug("[debug] Creating local directory '%s'" % self.dir)
 50                os.makedirs(self.dir)
 51
 52            self.logger.debug("[debug] Openning local '%s' with mode '%s'" % (self.path, self.mode))
 53            
 54            try:
 55                self.fd = open(self.dir + os.path.sep + os.path.basename(self.path), self.mode)
 56            except PermissionError as err:
 57                self.fd = None
 58
 59        # Write to remote (read local)
 60        elif self.mode in ["rb"]:
 61            if ntpath.sep in self.path:
 62                self.dir = os.path.dirname(self.path)
 63
 64            self.logger.debug("[debug] Openning local '%s' with mode '%s'" % (self.path, self.mode))
 65            
 66            try:
 67                self.fd = open(self.path, self.mode)
 68            except PermissionError as err:
 69                self.fd = None
 70
 71            if self.fd is not None:
 72                if self.expected_size is None:
 73                    self.expected_size = os.path.getsize(filename=self.path)
 74
 75        # Create progress bar
 76        if self.expected_size is not None:
 77            self.__progress = Progress(
 78                TextColumn("[bold blue]{task.description}", justify="right"),
 79                BarColumn(bar_width=None),
 80                "[progress.percentage]{task.percentage:>3.1f}%",
 81                "•",
 82                DownloadColumn(),
 83                "•",
 84                TransferSpeedColumn(),
 85                "•",
 86                TimeRemainingColumn(),
 87            )
 88            self.__progress.start()
 89            self.__task = self.__progress.add_task(
 90                description="'%s'" % os.path.basename(self.path),
 91                start=True,
 92                total=self.expected_size,
 93                visible=True
 94            )
 95
 96    def write(self, data):
 97        """
 98        Writes data to the file.
 99
100        This method writes the specified data to the file and updates the progress bar with the amount of data written if the expected size is set.
101
102        Args:
103            data (bytes): The data to be written to the file.
104
105        Returns:
106            int: The number of bytes written.
107        """
108
109        if self.fd is not None:
110            if self.expected_size is not None:
111                self.__progress.update(self.__task, advance=len(data))
112            return self.fd.write(data)
113        else:
114            return 0
115    
116    def read(self, size):
117        """
118        Reads a specified amount of data from the file.
119
120        This method reads data from the file based on the size specified. It also updates the progress bar with the amount of data read if the expected size is set.
121
122        Args:
123            size (int): The number of bytes to read from the file.
124
125        Returns:
126            bytes: The data read from the file.
127        """
128
129        if self.fd is not None:
130            read_data = self.fd.read(size)
131            if self.expected_size is not None:
132                self.__progress.update(self.__task, advance=len(read_data))
133            return read_data
134        else:
135            return b""
136
137    def close(self, remove=False):
138        """
139        Closes the file descriptor and optionally removes the file.
140
141        This method ensures that the file descriptor is properly closed and the file is removed if specified.
142        It also stops the progress bar if it was initiated and cleans up the object by deleting it.
143
144        Args:
145            remove (bool): If True, the file at the path will be removed after closing the file descriptor.
146        """
147
148        if self.fd is not None:
149            self.fd.close()
150
151        if remove:
152            try:
153                os.remove(path=self.path)
154            except (PermissionError, FileNotFoundError) as err:
155                pass
156
157        if self.expected_size is not None:
158            self.__progress.stop()
159        
160        del self
161
162    def set_error(self, message):
163        """
164        Sets an error message in the progress bar's description and modifies the progress bar to show only essential columns.
165
166        This method is used to communicate error states or important messages directly in the progress bar interface.
167        It updates the task description with the provided message and simplifies the progress bar to show only the text
168        and download columns, removing other elements like speed and time remaining which may not be relevant in an error state.
169
170        Args:
171            message (str): The error or status message to display in the progress bar.
172        """
173
174        self.__progress.tasks[0].description = message
175        self.__progress.columns = [
176            TextColumn("[bold blue]{task.description}", justify="right"),
177            BarColumn(bar_width=None),
178            "•",
179            DownloadColumn(),
180        ]
181        self.__progress.update(self.__task, advance=0)

Class LocalFileIO is designed to handle local file input/output operations within the smbclient-ng tool. It provides functionalities to open, read, write, and manage progress of file operations based on the expected size of the file.

Attributes: mode (str): The mode in which the file should be opened (e.g., 'rb', 'wb'). path (str): The path to the file that needs to be handled. expected_size (int, optional): The expected size of the file in bytes. This is used to display progress. debug (bool): Flag to enable debug mode which provides additional output during operations.

Methods: __init__(self, mode, path=None, expected_size=None, debug=False): Initializes the LocalFileIO instance. write(self, data): Writes data to the file and updates the progress bar if expected size is provided. read(self, size): Reads data from the file up to the specified size and updates the progress bar if expected size is provided.

LocalFileIO( mode, path=None, expected_size=None, keepRemotePath=False, logger=None)
31    def __init__(self, mode, path=None, expected_size=None, keepRemotePath=False, logger=None):
32        super(LocalFileIO, self).__init__()
33        self.logger = logger
34        self.mode = mode
35        # Convert remote path format to local operating system path format 
36        self.path = path.replace(ntpath.sep, os.path.sep)
37        self.dir = None
38        self.debug = False
39        self.expected_size = expected_size
40        self.keepRemotePath = keepRemotePath
41
42        # Write to local (read remote)
43        if self.mode in ["wb"]:
44            self.dir = '.' + os.path.sep
45            if keepRemotePath:
46                self.dir += os.path.dirname(self.path)
47
48            if not os.path.exists(self.dir):
49                self.logger.debug("[debug] Creating local directory '%s'" % self.dir)
50                os.makedirs(self.dir)
51
52            self.logger.debug("[debug] Openning local '%s' with mode '%s'" % (self.path, self.mode))
53            
54            try:
55                self.fd = open(self.dir + os.path.sep + os.path.basename(self.path), self.mode)
56            except PermissionError as err:
57                self.fd = None
58
59        # Write to remote (read local)
60        elif self.mode in ["rb"]:
61            if ntpath.sep in self.path:
62                self.dir = os.path.dirname(self.path)
63
64            self.logger.debug("[debug] Openning local '%s' with mode '%s'" % (self.path, self.mode))
65            
66            try:
67                self.fd = open(self.path, self.mode)
68            except PermissionError as err:
69                self.fd = None
70
71            if self.fd is not None:
72                if self.expected_size is None:
73                    self.expected_size = os.path.getsize(filename=self.path)
74
75        # Create progress bar
76        if self.expected_size is not None:
77            self.__progress = Progress(
78                TextColumn("[bold blue]{task.description}", justify="right"),
79                BarColumn(bar_width=None),
80                "[progress.percentage]{task.percentage:>3.1f}%",
81                "•",
82                DownloadColumn(),
83                "•",
84                TransferSpeedColumn(),
85                "•",
86                TimeRemainingColumn(),
87            )
88            self.__progress.start()
89            self.__task = self.__progress.add_task(
90                description="'%s'" % os.path.basename(self.path),
91                start=True,
92                total=self.expected_size,
93                visible=True
94            )
logger
mode
path
dir
debug
expected_size
keepRemotePath
def write(self, data):
 96    def write(self, data):
 97        """
 98        Writes data to the file.
 99
100        This method writes the specified data to the file and updates the progress bar with the amount of data written if the expected size is set.
101
102        Args:
103            data (bytes): The data to be written to the file.
104
105        Returns:
106            int: The number of bytes written.
107        """
108
109        if self.fd is not None:
110            if self.expected_size is not None:
111                self.__progress.update(self.__task, advance=len(data))
112            return self.fd.write(data)
113        else:
114            return 0

Writes data to the file.

This method writes the specified data to the file and updates the progress bar with the amount of data written if the expected size is set.

Args: data (bytes): The data to be written to the file.

Returns: int: The number of bytes written.

def read(self, size):
116    def read(self, size):
117        """
118        Reads a specified amount of data from the file.
119
120        This method reads data from the file based on the size specified. It also updates the progress bar with the amount of data read if the expected size is set.
121
122        Args:
123            size (int): The number of bytes to read from the file.
124
125        Returns:
126            bytes: The data read from the file.
127        """
128
129        if self.fd is not None:
130            read_data = self.fd.read(size)
131            if self.expected_size is not None:
132                self.__progress.update(self.__task, advance=len(read_data))
133            return read_data
134        else:
135            return b""

Reads a specified amount of data from the file.

This method reads data from the file based on the size specified. It also updates the progress bar with the amount of data read if the expected size is set.

Args: size (int): The number of bytes to read from the file.

Returns: bytes: The data read from the file.

def close(self, remove=False):
137    def close(self, remove=False):
138        """
139        Closes the file descriptor and optionally removes the file.
140
141        This method ensures that the file descriptor is properly closed and the file is removed if specified.
142        It also stops the progress bar if it was initiated and cleans up the object by deleting it.
143
144        Args:
145            remove (bool): If True, the file at the path will be removed after closing the file descriptor.
146        """
147
148        if self.fd is not None:
149            self.fd.close()
150
151        if remove:
152            try:
153                os.remove(path=self.path)
154            except (PermissionError, FileNotFoundError) as err:
155                pass
156
157        if self.expected_size is not None:
158            self.__progress.stop()
159        
160        del self

Closes the file descriptor and optionally removes the file.

This method ensures that the file descriptor is properly closed and the file is removed if specified. It also stops the progress bar if it was initiated and cleans up the object by deleting it.

Args: remove (bool): If True, the file at the path will be removed after closing the file descriptor.

def set_error(self, message):
162    def set_error(self, message):
163        """
164        Sets an error message in the progress bar's description and modifies the progress bar to show only essential columns.
165
166        This method is used to communicate error states or important messages directly in the progress bar interface.
167        It updates the task description with the provided message and simplifies the progress bar to show only the text
168        and download columns, removing other elements like speed and time remaining which may not be relevant in an error state.
169
170        Args:
171            message (str): The error or status message to display in the progress bar.
172        """
173
174        self.__progress.tasks[0].description = message
175        self.__progress.columns = [
176            TextColumn("[bold blue]{task.description}", justify="right"),
177            BarColumn(bar_width=None),
178            "•",
179            DownloadColumn(),
180        ]
181        self.__progress.update(self.__task, advance=0)

Sets an error message in the progress bar's description and modifies the progress bar to show only essential columns.

This method is used to communicate error states or important messages directly in the progress bar interface. It updates the task description with the provided message and simplifies the progress bar to show only the text and download columns, removing other elements like speed and time remaining which may not be relevant in an error state.

Args: message (str): The error or status message to display in the progress bar.