Skip to content

Commit 1cce0d0

Browse files
author
Pan
committed
Updated sftp file handle implementation. Added sftp file read test.
1 parent 33e5089 commit 1cce0d0

File tree

3 files changed

+54
-21
lines changed

3 files changed

+54
-21
lines changed

ssh/sftp_handles.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ cimport c_sftp
2323
cdef class SFTPFile:
2424
cdef c_sftp.sftp_file _file
2525
cdef SFTP sftp
26+
cdef bint closed
2627

2728
@staticmethod
2829
cdef SFTPFile from_ptr(c_sftp.sftp_file _file, SFTP sftp)

ssh/sftp_handles.pyx

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,24 @@
1414
# License along with this library; if not, write to the Free Software
1515
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-130
1616

17+
from libc.stdlib cimport malloc, free
18+
1719
from sftp_attributes cimport SFTPAttributes
1820

1921
from .exceptions import SFTPHandleError
2022

21-
from c_ssh cimport uint32_t, uint64_t
23+
from c_ssh cimport uint32_t, uint64_t, ssh_get_error
2224
cimport c_sftp
2325

2426

2527
cdef class SFTPFile:
2628

2729
def __cinit__(self, SFTP sftp):
2830
self.sftp = sftp
31+
self.closed = False
32+
33+
def __dealloc__(self):
34+
pass
2935

3036
@staticmethod
3137
cdef SFTPFile from_ptr(c_sftp.sftp_file _file, SFTP sftp):
@@ -44,28 +50,59 @@ cdef class SFTPFile:
4450

4551
def __next__(self):
4652
size, data = self.read()
47-
while size > 0:
48-
return size
53+
if size > 0:
54+
return size, data
4955
raise StopIteration
5056

5157
@property
5258
def sftp_session(self):
5359
return self.sftp
5460

5561
def fstat(self):
56-
pass
62+
cdef SFTPAttributes _attrs
63+
cdef c_sftp.sftp_attributes c_attrs
64+
with nogil:
65+
c_attrs = c_sftp.sftp_fstat(self._file)
66+
if c_attrs is NULL:
67+
raise SFTPHandleError(ssh_get_error(self.sftp.session._session))
68+
_attrs = SFTPAttributes.from_ptr(c_attrs, self.sftp)
69+
return _attrs
5770

5871
def close(self):
59-
pass
72+
cdef int rc
73+
if self.closed:
74+
return 0
75+
with nogil:
76+
rc = c_sftp.sftp_close(self._file)
77+
if rc < 0:
78+
raise SFTPHandleError(ssh_get_error(self.sftp.session._session))
79+
self.closed = True
80+
return rc
6081

6182
def set_nonblocking(self):
62-
pass
83+
with nogil:
84+
c_sftp.sftp_file_set_nonblocking(self._file)
6385

6486
def set_blocking(self):
65-
pass
87+
with nogil:
88+
c_sftp.sftp_file_set_blocking(self._file)
6689

6790
def read(self, size_t count=1024000):
68-
pass
91+
cdef ssize_t size
92+
cdef bytes buf = b''
93+
cdef char *c_buf
94+
with nogil:
95+
c_buf = <char *>malloc(sizeof(char) * count)
96+
if c_buf is NULL:
97+
with gil:
98+
raise MemoryError
99+
size = c_sftp.sftp_read(self._file, c_buf, count)
100+
try:
101+
if size > 0:
102+
buf = c_buf[:size]
103+
finally:
104+
free(c_buf)
105+
return size, buf
69106

70107
def async_read_begin(self, uint32_t length=1024000):
71108
pass

tests/test_sftp.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def test_sftp_readdir(self):
7070
self.assertEqual(attrs.name, b'.')
7171
self.assertTrue(len(attrs.longname) > 1)
7272

73-
def test_sftp_file(self):
73+
def test_sftp_file_read(self):
7474
self._auth()
7575
sftp = self.session.sftp_new()
7676
sftp.init()
@@ -83,17 +83,12 @@ def test_sftp_file(self):
8383
with open(remote_filename, 'wb') as test_fh:
8484
test_fh.write(test_file_data)
8585
try:
86-
remote_fh = sftp.open(remote_filename, os.O_RDONLY, 0)
87-
self.assertIsInstance(remote_fh, SFTPFile)
86+
with sftp.open(remote_filename, os.O_RDONLY, 0) as remote_fh:
87+
self.assertIsInstance(remote_fh, SFTPFile)
88+
remote_data = b""
89+
for rc, data in remote_fh:
90+
remote_data += data
91+
self.assertEqual(remote_fh.close(), 0)
92+
self.assertEqual(remote_data, test_file_data)
8893
finally:
8994
os.unlink(remote_filename)
90-
# with sftp.open(remote_filename, 0, 0) as remote_fh:
91-
# try:
92-
# self.assertTrue(remote_fh is not None)
93-
# remote_data = b""
94-
# for rc, data in remote_fh:
95-
# remote_data += data
96-
# self.assertEqual(remote_fh.close(), 0)
97-
# self.assertEqual(remote_data, test_file_data)
98-
# finally:
99-
# os.unlink(remote_filename)

0 commit comments

Comments
 (0)