You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

543 lines
19 KiB

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

Powered by TurnKey Linux.