~davide-cst00/uftp/0.2

« back to all changes in this revision

Viewing changes to paramiko/file.py

  • Committer: Davide Costa
  • Date: 2018-09-14 12:21:37 UTC
  • Revision ID: davide.cst00@gmail.com-20180914122137-j0ycqb4tk9z2r1k5
Xenial release 0.2.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2003-2007  Robey Pointer <robeypointer@gmail.com>
 
2
#
 
3
# This file is part of paramiko.
 
4
#
 
5
# Paramiko is free software; you can redistribute it and/or modify it under the
 
6
# terms of the GNU Lesser General Public License as published by the Free
 
7
# Software Foundation; either version 2.1 of the License, or (at your option)
 
8
# any later version.
 
9
#
 
10
# Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY
 
11
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 
12
# A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
 
13
# details.
 
14
#
 
15
# You should have received a copy of the GNU Lesser General Public License
 
16
# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
 
17
# 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 
18
from paramiko.common import (
 
19
    linefeed_byte_value, crlf, cr_byte, linefeed_byte, cr_byte_value,
 
20
)
 
21
from paramiko.py3compat import BytesIO, PY2, u, bytes_types, text_type
 
22
 
 
23
from paramiko.util import ClosingContextManager
 
24
 
 
25
 
 
26
class BufferedFile (ClosingContextManager):
 
27
    """
 
28
    Reusable base class to implement Python-style file buffering around a
 
29
    simpler stream.
 
30
    """
 
31
 
 
32
    _DEFAULT_BUFSIZE = 8192
 
33
 
 
34
    SEEK_SET = 0
 
35
    SEEK_CUR = 1
 
36
    SEEK_END = 2
 
37
 
 
38
    FLAG_READ = 0x1
 
39
    FLAG_WRITE = 0x2
 
40
    FLAG_APPEND = 0x4
 
41
    FLAG_BINARY = 0x10
 
42
    FLAG_BUFFERED = 0x20
 
43
    FLAG_LINE_BUFFERED = 0x40
 
44
    FLAG_UNIVERSAL_NEWLINE = 0x80
 
45
 
 
46
    def __init__(self):
 
47
        self.newlines = None
 
48
        self._flags = 0
 
49
        self._bufsize = self._DEFAULT_BUFSIZE
 
50
        self._wbuffer = BytesIO()
 
51
        self._rbuffer = bytes()
 
52
        self._at_trailing_cr = False
 
53
        self._closed = False
 
54
        # pos - position within the file, according to the user
 
55
        # realpos - position according the OS
 
56
        # (these may be different because we buffer for line reading)
 
57
        self._pos = self._realpos = 0
 
58
        # size only matters for seekable files
 
59
        self._size = 0
 
60
 
 
61
    def __del__(self):
 
62
        self.close()
 
63
 
 
64
    def __iter__(self):
 
65
        """
 
66
        Returns an iterator that can be used to iterate over the lines in this
 
67
        file.  This iterator happens to return the file itself, since a file is
 
68
        its own iterator.
 
69
 
 
70
        :raises: ``ValueError`` -- if the file is closed.
 
71
        """
 
72
        if self._closed:
 
73
            raise ValueError('I/O operation on closed file')
 
74
        return self
 
75
 
 
76
    def close(self):
 
77
        """
 
78
        Close the file.  Future read and write operations will fail.
 
79
        """
 
80
        self.flush()
 
81
        self._closed = True
 
82
 
 
83
    def flush(self):
 
84
        """
 
85
        Write out any data in the write buffer.  This may do nothing if write
 
86
        buffering is not turned on.
 
87
        """
 
88
        self._write_all(self._wbuffer.getvalue())
 
89
        self._wbuffer = BytesIO()
 
90
        return
 
91
 
 
92
    if PY2:
 
93
        def next(self):
 
94
            """
 
95
            Returns the next line from the input, or raises
 
96
            ``StopIteration`` when EOF is hit.  Unlike Python file
 
97
            objects, it's okay to mix calls to `next` and `readline`.
 
98
 
 
99
            :raises: ``StopIteration`` -- when the end of the file is reached.
 
100
 
 
101
            :returns: a line (`str`) read from the file.
 
102
            """
 
103
            line = self.readline()
 
104
            if not line:
 
105
                raise StopIteration
 
106
            return line
 
107
    else:
 
108
        def __next__(self):
 
109
            """
 
110
            Returns the next line from the input, or raises ``StopIteration``
 
111
            when EOF is hit.  Unlike python file objects, it's okay to mix
 
112
            calls to `.next` and `.readline`.
 
113
 
 
114
            :raises: ``StopIteration`` -- when the end of the file is reached.
 
115
 
 
116
            :returns: a line (`str`) read from the file.
 
117
            """
 
118
            line = self.readline()
 
119
            if not line:
 
120
                raise StopIteration
 
121
            return line
 
122
 
 
123
    def readable(self):
 
124
        """
 
125
        Check if the file can be read from.
 
126
 
 
127
        :returns:
 
128
            `True` if the file can be read from. If `False`, `read` will raise
 
129
            an exception.
 
130
        """
 
131
        return (self._flags & self.FLAG_READ) == self.FLAG_READ
 
132
 
 
133
    def writable(self):
 
134
        """
 
135
        Check if the file can be written to.
 
136
 
 
137
        :returns:
 
138
            `True` if the file can be written to. If `False`, `write` will
 
139
            raise an exception.
 
140
        """
 
141
        return (self._flags & self.FLAG_WRITE) == self.FLAG_WRITE
 
142
 
 
143
    def seekable(self):
 
144
        """
 
145
        Check if the file supports random access.
 
146
 
 
147
        :returns:
 
148
            `True` if the file supports random access. If `False`, `seek` will
 
149
            raise an exception.
 
150
        """
 
151
        return False
 
152
 
 
153
    def readinto(self, buff):
 
154
        """
 
155
        Read up to ``len(buff)`` bytes into ``bytearray`` *buff* and return the
 
156
        number of bytes read.
 
157
 
 
158
        :returns:
 
159
            The number of bytes read.
 
160
        """
 
161
        data = self.read(len(buff))
 
162
        buff[:len(data)] = data
 
163
        return len(data)
 
164
 
 
165
    def read(self, size=None):
 
166
        """
 
167
        Read at most ``size`` bytes from the file (less if we hit the end of
 
168
        the file first).  If the ``size`` argument is negative or omitted,
 
169
        read all the remaining data in the file.
 
170
 
 
171
        .. note::
 
172
            ``'b'`` mode flag is ignored (``self.FLAG_BINARY`` in
 
173
            ``self._flags``), because SSH treats all files as binary, since we
 
174
            have no idea what encoding the file is in, or even if the file is
 
175
            text data.
 
176
 
 
177
        :param int size: maximum number of bytes to read
 
178
        :returns:
 
179
            data read from the file (as bytes), or an empty string if EOF was
 
180
            encountered immediately
 
181
        """
 
182
        if self._closed:
 
183
            raise IOError('File is closed')
 
184
        if not (self._flags & self.FLAG_READ):
 
185
            raise IOError('File is not open for reading')
 
186
        if (size is None) or (size < 0):
 
187
            # go for broke
 
188
            result = self._rbuffer
 
189
            self._rbuffer = bytes()
 
190
            self._pos += len(result)
 
191
            while True:
 
192
                try:
 
193
                    new_data = self._read(self._DEFAULT_BUFSIZE)
 
194
                except EOFError:
 
195
                    new_data = None
 
196
                if (new_data is None) or (len(new_data) == 0):
 
197
                    break
 
198
                result += new_data
 
199
                self._realpos += len(new_data)
 
200
                self._pos += len(new_data)
 
201
            return result
 
202
        if size <= len(self._rbuffer):
 
203
            result = self._rbuffer[:size]
 
204
            self._rbuffer = self._rbuffer[size:]
 
205
            self._pos += len(result)
 
206
            return result
 
207
        while len(self._rbuffer) < size:
 
208
            read_size = size - len(self._rbuffer)
 
209
            if self._flags & self.FLAG_BUFFERED:
 
210
                read_size = max(self._bufsize, read_size)
 
211
            try:
 
212
                new_data = self._read(read_size)
 
213
            except EOFError:
 
214
                new_data = None
 
215
            if (new_data is None) or (len(new_data) == 0):
 
216
                break
 
217
            self._rbuffer += new_data
 
218
            self._realpos += len(new_data)
 
219
        result = self._rbuffer[:size]
 
220
        self._rbuffer = self._rbuffer[size:]
 
221
        self._pos += len(result)
 
222
        return result
 
223
 
 
224
    def readline(self, size=None):
 
225
        """
 
226
        Read one entire line from the file.  A trailing newline character is
 
227
        kept in the string (but may be absent when a file ends with an
 
228
        incomplete line).  If the size argument is present and non-negative, it
 
229
        is a maximum byte count (including the trailing newline) and an
 
230
        incomplete line may be returned.  An empty string is returned only when
 
231
        EOF is encountered immediately.
 
232
 
 
233
        .. note::
 
234
            Unlike stdio's ``fgets``, the returned string contains null
 
235
            characters (``'\\0'``) if they occurred in the input.
 
236
 
 
237
        :param int size: maximum length of returned string.
 
238
        :returns:
 
239
            next line of the file, or an empty string if the end of the
 
240
            file has been reached.
 
241
 
 
242
            If the file was opened in binary (``'b'``) mode: bytes are returned
 
243
            Else: the encoding of the file is assumed to be UTF-8 and character
 
244
            strings (`str`) are returned
 
245
        """
 
246
        # it's almost silly how complex this function is.
 
247
        if self._closed:
 
248
            raise IOError('File is closed')
 
249
        if not (self._flags & self.FLAG_READ):
 
250
            raise IOError('File not open for reading')
 
251
        line = self._rbuffer
 
252
        truncated = False
 
253
        while True:
 
254
            if (
 
255
                self._at_trailing_cr and
 
256
                self._flags & self.FLAG_UNIVERSAL_NEWLINE and
 
257
                len(line) > 0
 
258
            ):
 
259
                # edge case: the newline may be '\r\n' and we may have read
 
260
                # only the first '\r' last time.
 
261
                if line[0] == linefeed_byte_value:
 
262
                    line = line[1:]
 
263
                    self._record_newline(crlf)
 
264
                else:
 
265
                    self._record_newline(cr_byte)
 
266
                self._at_trailing_cr = False
 
267
            # check size before looking for a linefeed, in case we already have
 
268
            # enough.
 
269
            if (size is not None) and (size >= 0):
 
270
                if len(line) >= size:
 
271
                    # truncate line
 
272
                    self._rbuffer = line[size:]
 
273
                    line = line[:size]
 
274
                    truncated = True
 
275
                    break
 
276
                n = size - len(line)
 
277
            else:
 
278
                n = self._bufsize
 
279
            if (
 
280
                linefeed_byte in line or
 
281
                (
 
282
                    self._flags & self.FLAG_UNIVERSAL_NEWLINE and
 
283
                    cr_byte in line
 
284
                )
 
285
            ):
 
286
                break
 
287
            try:
 
288
                new_data = self._read(n)
 
289
            except EOFError:
 
290
                new_data = None
 
291
            if (new_data is None) or (len(new_data) == 0):
 
292
                self._rbuffer = bytes()
 
293
                self._pos += len(line)
 
294
                return line if self._flags & self.FLAG_BINARY else u(line)
 
295
            line += new_data
 
296
            self._realpos += len(new_data)
 
297
        # find the newline
 
298
        pos = line.find(linefeed_byte)
 
299
        if self._flags & self.FLAG_UNIVERSAL_NEWLINE:
 
300
            rpos = line.find(cr_byte)
 
301
            if (rpos >= 0) and (rpos < pos or pos < 0):
 
302
                pos = rpos
 
303
        if pos == -1:
 
304
            # we couldn't find a newline in the truncated string, return it
 
305
            self._pos += len(line)
 
306
            return line if self._flags & self.FLAG_BINARY else u(line)
 
307
        xpos = pos + 1
 
308
        if (
 
309
            line[pos] == cr_byte_value and
 
310
            xpos < len(line) and
 
311
            line[xpos] == linefeed_byte_value
 
312
        ):
 
313
            xpos += 1
 
314
        # if the string was truncated, _rbuffer needs to have the string after
 
315
        # the newline character plus the truncated part of the line we stored
 
316
        # earlier in _rbuffer
 
317
        if truncated:
 
318
            self._rbuffer = line[xpos:] + self._rbuffer
 
319
        else:
 
320
            self._rbuffer = line[xpos:]
 
321
 
 
322
        lf = line[pos:xpos]
 
323
        line = line[:pos] + linefeed_byte
 
324
        if (len(self._rbuffer) == 0) and (lf == cr_byte):
 
325
            # we could read the line up to a '\r' and there could still be a
 
326
            # '\n' following that we read next time.  note that and eat it.
 
327
            self._at_trailing_cr = True
 
328
        else:
 
329
            self._record_newline(lf)
 
330
        self._pos += len(line)
 
331
        return line if self._flags & self.FLAG_BINARY else u(line)
 
332
 
 
333
    def readlines(self, sizehint=None):
 
334
        """
 
335
        Read all remaining lines using `readline` and return them as a list.
 
336
        If the optional ``sizehint`` argument is present, instead of reading up
 
337
        to EOF, whole lines totalling approximately sizehint bytes (possibly
 
338
        after rounding up to an internal buffer size) are read.
 
339
 
 
340
        :param int sizehint: desired maximum number of bytes to read.
 
341
        :returns: list of lines read from the file.
 
342
        """
 
343
        lines = []
 
344
        byte_count = 0
 
345
        while True:
 
346
            line = self.readline()
 
347
            if len(line) == 0:
 
348
                break
 
349
            lines.append(line)
 
350
            byte_count += len(line)
 
351
            if (sizehint is not None) and (byte_count >= sizehint):
 
352
                break
 
353
        return lines
 
354
 
 
355
    def seek(self, offset, whence=0):
 
356
        """
 
357
        Set the file's current position, like stdio's ``fseek``.  Not all file
 
358
        objects support seeking.
 
359
 
 
360
        .. note::
 
361
            If a file is opened in append mode (``'a'`` or ``'a+'``), any seek
 
362
            operations will be undone at the next write (as the file position
 
363
            will move back to the end of the file).
 
364
 
 
365
        :param int offset:
 
366
            position to move to within the file, relative to ``whence``.
 
367
        :param int whence:
 
368
            type of movement: 0 = absolute; 1 = relative to the current
 
369
            position; 2 = relative to the end of the file.
 
370
 
 
371
        :raises: ``IOError`` -- if the file doesn't support random access.
 
372
        """
 
373
        raise IOError('File does not support seeking.')
 
374
 
 
375
    def tell(self):
 
376
        """
 
377
        Return the file's current position.  This may not be accurate or
 
378
        useful if the underlying file doesn't support random access, or was
 
379
        opened in append mode.
 
380
 
 
381
        :returns: file position (`number <int>` of bytes).
 
382
        """
 
383
        return self._pos
 
384
 
 
385
    def write(self, data):
 
386
        """
 
387
        Write data to the file.  If write buffering is on (``bufsize`` was
 
388
        specified and non-zero), some or all of the data may not actually be
 
389
        written yet.  (Use `flush` or `close` to force buffered data to be
 
390
        written out.)
 
391
 
 
392
        :param data: ``str``/``bytes`` data to write
 
393
        """
 
394
        if isinstance(data, text_type):
 
395
            # Accept text and encode as utf-8 for compatibility only.
 
396
            data = data.encode('utf-8')
 
397
        if self._closed:
 
398
            raise IOError('File is closed')
 
399
        if not (self._flags & self.FLAG_WRITE):
 
400
            raise IOError('File not open for writing')
 
401
        if not (self._flags & self.FLAG_BUFFERED):
 
402
            self._write_all(data)
 
403
            return
 
404
        self._wbuffer.write(data)
 
405
        if self._flags & self.FLAG_LINE_BUFFERED:
 
406
            # only scan the new data for linefeed, to avoid wasting time.
 
407
            last_newline_pos = data.rfind(linefeed_byte)
 
408
            if last_newline_pos >= 0:
 
409
                wbuf = self._wbuffer.getvalue()
 
410
                last_newline_pos += len(wbuf) - len(data)
 
411
                self._write_all(wbuf[:last_newline_pos + 1])
 
412
                self._wbuffer = BytesIO()
 
413
                self._wbuffer.write(wbuf[last_newline_pos + 1:])
 
414
            return
 
415
        # even if we're line buffering, if the buffer has grown past the
 
416
        # buffer size, force a flush.
 
417
        if self._wbuffer.tell() >= self._bufsize:
 
418
            self.flush()
 
419
        return
 
420
 
 
421
    def writelines(self, sequence):
 
422
        """
 
423
        Write a sequence of strings to the file.  The sequence can be any
 
424
        iterable object producing strings, typically a list of strings.  (The
 
425
        name is intended to match `readlines`; `writelines` does not add line
 
426
        separators.)
 
427
 
 
428
        :param sequence: an iterable sequence of strings.
 
429
        """
 
430
        for line in sequence:
 
431
            self.write(line)
 
432
        return
 
433
 
 
434
    def xreadlines(self):
 
435
        """
 
436
        Identical to ``iter(f)``.  This is a deprecated file interface that
 
437
        predates Python iterator support.
 
438
        """
 
439
        return self
 
440
 
 
441
    @property
 
442
    def closed(self):
 
443
        return self._closed
 
444
 
 
445
    # ...overrides...
 
446
 
 
447
    def _read(self, size):
 
448
        """
 
449
        (subclass override)
 
450
        Read data from the stream.  Return ``None`` or raise ``EOFError`` to
 
451
        indicate EOF.
 
452
        """
 
453
        raise EOFError()
 
454
 
 
455
    def _write(self, data):
 
456
        """
 
457
        (subclass override)
 
458
        Write data into the stream.
 
459
        """
 
460
        raise IOError('write not implemented')
 
461
 
 
462
    def _get_size(self):
 
463
        """
 
464
        (subclass override)
 
465
        Return the size of the file.  This is called from within `_set_mode`
 
466
        if the file is opened in append mode, so the file position can be
 
467
        tracked and `seek` and `tell` will work correctly.  If the file is
 
468
        a stream that can't be randomly accessed, you don't need to override
 
469
        this method,
 
470
        """
 
471
        return 0
 
472
 
 
473
    # ...internals...
 
474
 
 
475
    def _set_mode(self, mode='r', bufsize=-1):
 
476
        """
 
477
        Subclasses call this method to initialize the BufferedFile.
 
478
        """
 
479
        # set bufsize in any event, because it's used for readline().
 
480
        self._bufsize = self._DEFAULT_BUFSIZE
 
481
        if bufsize < 0:
 
482
            # do no buffering by default, because otherwise writes will get
 
483
            # buffered in a way that will probably confuse people.
 
484
            bufsize = 0
 
485
        if bufsize == 1:
 
486
            # apparently, line buffering only affects writes.  reads are only
 
487
            # buffered if you call readline (directly or indirectly: iterating
 
488
            # over a file will indirectly call readline).
 
489
            self._flags |= self.FLAG_BUFFERED | self.FLAG_LINE_BUFFERED
 
490
        elif bufsize > 1:
 
491
            self._bufsize = bufsize
 
492
            self._flags |= self.FLAG_BUFFERED
 
493
            self._flags &= ~self.FLAG_LINE_BUFFERED
 
494
        elif bufsize == 0:
 
495
            # unbuffered
 
496
            self._flags &= ~(self.FLAG_BUFFERED | self.FLAG_LINE_BUFFERED)
 
497
 
 
498
        if ('r' in mode) or ('+' in mode):
 
499
            self._flags |= self.FLAG_READ
 
500
        if ('w' in mode) or ('+' in mode):
 
501
            self._flags |= self.FLAG_WRITE
 
502
        if 'a' in mode:
 
503
            self._flags |= self.FLAG_WRITE | self.FLAG_APPEND
 
504
            self._size = self._get_size()
 
505
            self._pos = self._realpos = self._size
 
506
        if 'b' in mode:
 
507
            self._flags |= self.FLAG_BINARY
 
508
        if 'U' in mode:
 
509
            self._flags |= self.FLAG_UNIVERSAL_NEWLINE
 
510
            # built-in file objects have this attribute to store which kinds of
 
511
            # line terminations they've seen:
 
512
            # <http://www.python.org/doc/current/lib/built-in-funcs.html>
 
513
            self.newlines = None
 
514
 
 
515
    def _write_all(self, data):
 
516
        # the underlying stream may be something that does partial writes (like
 
517
        # a socket).
 
518
        while len(data) > 0:
 
519
            count = self._write(data)
 
520
            data = data[count:]
 
521
            if self._flags & self.FLAG_APPEND:
 
522
                self._size += count
 
523
                self._pos = self._realpos = self._size
 
524
            else:
 
525
                self._pos += count
 
526
                self._realpos += count
 
527
        return None
 
528
 
 
529
    def _record_newline(self, newline):
 
530
        # silliness about tracking what kinds of newlines we've seen.
 
531
        # i don't understand why it can be None, a string, or a tuple, instead
 
532
        # of just always being a tuple, but we'll emulate that behavior anyway.
 
533
        if not (self._flags & self.FLAG_UNIVERSAL_NEWLINE):
 
534
            return
 
535
        if self.newlines is None:
 
536
            self.newlines = newline
 
537
        elif (
 
538
            self.newlines != newline and
 
539
            isinstance(self.newlines, bytes_types)
 
540
        ):
 
541
            self.newlines = (self.newlines, newline)
 
542
        elif newline not in self.newlines:
 
543
            self.newlines += (newline,)