Commit 22d0e4b6 authored by 广宏伟's avatar 广宏伟

Merged in dev (pull request #108)

Dev
parents 6d1c50e1 cbf8e8d0
...@@ -11,15 +11,14 @@ from coco.httpd.ws import ProxyNamespace, ElfinderNamespace ...@@ -11,15 +11,14 @@ from coco.httpd.ws import ProxyNamespace, ElfinderNamespace
logger = get_logger(__file__) logger = get_logger(__file__)
app = Flask(__name__, template_folder='templates', app = Flask(__name__, template_folder='templates',
static_folder='static', static_folder='static')
static_url_path='/coco/static')
app.config.update(config) app.config.update(config)
socket_io = SocketIO() socket_io = SocketIO()
socket_io.on_namespace(ProxyNamespace('/ssh')) socket_io.on_namespace(ProxyNamespace('/ssh'))
socket_io.on_namespace(ElfinderNamespace('/elfinder')) socket_io.on_namespace(ElfinderNamespace('/elfinder'))
# init_kwargs = {'async_mode': 'threading'} # init_kwargs = {'async_mode': 'threading'}
init_kwargs = {'async_mode': 'eventlet',} init_kwargs = {'async_mode': 'eventlet'}
socket_io.init_app(app, **init_kwargs), socket_io.init_app(app, **init_kwargs),
socket_io.on_error_default(lambda x: logger.exception(x)) socket_io.on_error_default(lambda x: logger.exception(x))
......
...@@ -23,8 +23,7 @@ class ElFinderConnector: ...@@ -23,8 +23,7 @@ class ElFinderConnector:
'mkfile': ('__mkfile', {'target': True, 'name': True}), 'mkfile': ('__mkfile', {'target': True, 'name': True}),
'rename': ('__rename', {'target': True, 'name': True}), 'rename': ('__rename', {'target': True, 'name': True}),
'ls': ('__list', {'target': True}), 'ls': ('__list', {'target': True}),
'paste': ('__paste', {'targets[]': True, 'src': True, 'paste': ('__paste', {'targets[]': True, 'dst': True, 'cut': True}),
'dst': True, 'cut': True}),
'rm': ('__remove', {'targets[]': True}), 'rm': ('__remove', {'targets[]': True}),
'upload': ('__upload', {'target': True}), 'upload': ('__upload', {'target': True}),
'size': ('__size', {'targets[0]': True}), 'size': ('__size', {'targets[0]': True}),
...@@ -256,14 +255,10 @@ class ElFinderConnector: ...@@ -256,14 +255,10 @@ class ElFinderConnector:
def __paste(self): def __paste(self):
targets = self.data['targets[]'] targets = self.data['targets[]']
source = self.data['src']
dest = self.data['dst'] dest = self.data['dst']
cut = (self.data['cut'] == '1') cut = self.data['cut'] == '1'
source_volume = self.get_volume(source)
dest_volume = self.get_volume(dest) dest_volume = self.get_volume(dest)
if source_volume != dest_volume: self.response.update(dest_volume.paste(targets, dest, cut))
raise Exception('Moving between volumes is not supported.')
self.response.update(dest_volume.paste(targets, source, dest, cut))
def __remove(self): def __remove(self):
targets = self.data['targets[]'] targets = self.data['targets[]']
......
...@@ -186,7 +186,7 @@ class BaseVolume: ...@@ -186,7 +186,7 @@ class BaseVolume:
""" """
raise NotImplementedError raise NotImplementedError
def paste(self, targets, source, dest, cut): def paste(self, targets, dest, cut):
""" Moves/copies target files/directories from source to dest. """ Moves/copies target files/directories from source to dest.
If a file with the same name already exists in the dest directory If a file with the same name already exists in the dest directory
...@@ -194,7 +194,6 @@ class BaseVolume: ...@@ -194,7 +194,6 @@ class BaseVolume:
before sending the request). before sending the request).
:param targets: A list of hashes of files/dirs to move/copy. :param targets: A list of hashes of files/dirs to move/copy.
:param source: The current parent of the targets.
:param dest: The new parent of the targets. :param dest: The new parent of the targets.
:param cut: Boolean. If true, move the targets. If false, copy the :param cut: Boolean. If true, move the targets. If false, copy the
targets. targets.
......
...@@ -146,7 +146,9 @@ class SFTPVolume(BaseVolume): ...@@ -146,7 +146,9 @@ class SFTPVolume(BaseVolume):
def mkfile(self, name, parent): def mkfile(self, name, parent):
""" Creates a new file. """ """ Creates a new file. """
parent_path = self._path(parent) parent_path = self._path(parent)
remote_path = self._remote_path(parent_path) path = self._join(parent_path, name)
remote_path = self._remote_path(path)
with self.sftp.open(remote_path, mode='w'): with self.sftp.open(remote_path, mode='w'):
pass pass
return self._info(parent_path) return self._info(parent_path)
...@@ -163,9 +165,42 @@ class SFTPVolume(BaseVolume): ...@@ -163,9 +165,42 @@ class SFTPVolume(BaseVolume):
'removed': [target] 'removed': [target]
} }
def paste(self, targets, source, dest, cut): def is_exist(self, path):
remote_path = self._remote_path(path)
try:
data = self.sftp.lstat(remote_path)
print(data)
exist = True
except FileNotFoundError:
exist = False
return exist
def paste(self, targets, dest, cut):
""" Moves/copies target files/directories from source to dest. """ """ Moves/copies target files/directories from source to dest. """
return {"error": "Not support paste"} print("Paste {} {} {}".format(targets, dest, cut))
dest_parent_path = self._path(dest)
added = []
removed = []
for target in targets:
src_path = self._path(target)
dest_path = self._join(dest_parent_path, self._base_name(src_path))
print("Paste {} to => {}".format(src_path, dest_parent_path))
if self.is_exist(dest_path):
print("Exist {}".format(dest_path))
continue
src_remote_path = self._remote_path(src_path)
dest_remote_path = self._remote_path(dest_path)
try:
f = self.sftp.open(src_remote_path, mode='r')
attr = self.sftp.putfo(f, dest_remote_path)
if cut:
removed.append(self.remove(target))
added.append(self._info(dest_path, attr))
finally:
f.close()
return {"added": added, "removed": removed}
def remove(self, target): def remove(self, target):
""" Delete a File or Directory object. """ """ Delete a File or Directory object. """
...@@ -201,7 +236,6 @@ class SFTPVolume(BaseVolume): ...@@ -201,7 +236,6 @@ class SFTPVolume(BaseVolume):
def upload_as_chunk(self, files, chunk_name, parent): def upload_as_chunk(self, files, chunk_name, parent):
added = [] added = []
print("Upload chunk: {}".format(chunk_name))
parent_path = self._path(parent) parent_path = self._path(parent)
item = files.get('upload[]') item = files.get('upload[]')
__tmp = chunk_name.split('.') __tmp = chunk_name.split('.')
......
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
<body style="margin: 0"> <body style="margin: 0">
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery-2.1.1.js') }}"></script> <script type="text/javascript" src="{{ url_for('static', filename='js/jquery-2.1.1.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery-ui-1.10.4.min.js') }}"></script> <script type="text/javascript" src="{{ url_for('static', filename='js/jquery-ui-1.10.4.min.js') }}"></script>
<link rel="stylesheet" type="text/css" media="screen" href="{{ url_for('static', filename='elfinder/css/elfinder.min.css') }}">
<link rel="stylesheet" type="text/css" media="screen" href="{{ url_for('static', filename='elfinder/css/theme-gray.css') }}">
<script type="text/javascript" src="{{ url_for('static', filename='elfinder/elfinder.full.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='elfinder/i18n/elfinder.pl.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/socket.io.js') }}"></script> <script type="text/javascript" src="{{ url_for('static', filename='js/socket.io.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='plugins/elfinder/elfinder.full.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='plugins/elfinder/i18n/elfinder.pl.js') }}"></script>
<link rel="stylesheet" type="text/css" media="screen" href="{{ url_for('static', filename='plugins/elfinder/css/elfinder.min.css') }}">
<link rel="stylesheet" type="text/css" media="screen" href="{{ url_for('static', filename='plugins/elfinder/css/theme-gray.css') }}">
<script type="text/javascript" charset="utf-8"> <script type="text/javascript" charset="utf-8">
var socket = io.connect('/elfinder'); var socket = io.connect('/elfinder');
socket.on('connect', function () { socket.on('connect', function () {
...@@ -42,10 +42,10 @@ ...@@ -42,10 +42,10 @@
], ],
cwd: [ cwd: [
'reload', 'back', '|', 'mkdir', 'mkfile', '|', 'reload', 'back', '|', 'mkdir', 'mkfile', '|',
'upload' 'upload', 'paste'
], ],
files: [ files: [
'rm', 'rename', 'download' 'rm', 'rename', 'download', 'copy', 'cut', 'paste'
] ]
}, },
rememberLastDir: false, rememberLastDir: false,
...@@ -80,7 +80,7 @@ ...@@ -80,7 +80,7 @@
} }
if (lng !== 'en') { if (lng !== 'en') {
$.ajax({ $.ajax({
url : "{{ url_for('static', filename='elfinder/i18n/') }}"+'/elfinder.'+lng+'.js', url : "{{ url_for('static', filename='plugins/elfinder/i18n/') }}"+'/elfinder.'+lng+'.js',
cache : true, cache : true,
dataType : 'script' dataType : 'script'
}) })
...@@ -101,8 +101,6 @@ ...@@ -101,8 +101,6 @@
if (!$('#elfinder').hasClass('elfinder-fullscreen')) { if (!$('#elfinder').hasClass('elfinder-fullscreen')) {
resizeTimer = setTimeout(function () { resizeTimer = setTimeout(function () {
var h, w; var h, w;
var isTrue = window == parent;
console.log("Window == parent" + isTrue);
if (window != parent) { if (window != parent) {
h = parseInt(parent.$('.window.active').height()); h = parseInt(parent.$('.window.active').height());
w = parseInt(parent.$('.window.active').width()); w = parseInt(parent.$('.window.active').width());
...@@ -112,7 +110,6 @@ ...@@ -112,7 +110,6 @@
} }
var ori_h = parseInt($('#elfinder').height()); var ori_h = parseInt($('#elfinder').height());
var ori_w = parseInt($('#elfinder').width()); var ori_w = parseInt($('#elfinder').width());
console.log("Height: " + h + " Wid: " + w);
if (h !== ori_h || w != ori_w){ if (h !== ori_h || w != ori_w){
elf.resize(w, h); elf.resize(w, h);
} }
......
import os import os
import tempfile
import paramiko import paramiko
import time import time
from datetime import datetime from datetime import datetime
from functools import wraps
import traceback
from paramiko.sftp import SFTP_PERMISSION_DENIED, SFTP_NO_SUCH_FILE, \
SFTP_FAILURE, SFTP_EOF, SFTP_CONNECTION_LOST
from coco.utils import get_logger
from .config import config from .config import config
from .ctx import app_service from .ctx import app_service
from .connection import SSHConnection from .connection import SSHConnection
CURRENT_DIR = os.path.dirname(__file__)
logger = get_logger(__file__)
def convert_error(func):
@wraps(func)
def wrapper(*args, **kwargs):
error = None
try:
response = func(*args, **kwargs)
except FileNotFoundError as e:
error = e
response = SFTP_NO_SUCH_FILE
except PermissionError as e:
error = e
response = SFTP_PERMISSION_DENIED
except OSError as e:
error = e
response = SFTP_CONNECTION_LOST
except EOFError as e:
error = e
response = SFTP_EOF
# except Exception as e:
# error = e
# response = SFTP_FAILURE
finally:
if isinstance(error, Exception):
logger.error(error)
return response
return wrapper
class SFTPServer(paramiko.SFTPServerInterface): class SFTPServer(paramiko.SFTPServerInterface):
root = '/tmp' root = 'home' # Home or /tmp or other path, must exist on all server
def __init__(self, server, **kwargs): def __init__(self, server, **kwargs):
"""
:param server: SSH Interface instance
:param kwargs:
hosts = {
"hostname[.org]": {
"asset": asset_instance,
"system_users": {
system_user_name: system_user_instance,
}
}
"""
super().__init__(server, **kwargs) super().__init__(server, **kwargs)
self.server = server self.server = server
self._sftp = {} self._sftp = {}
self.hosts = self.get_perm_hosts() self.hosts = self.get_permed_hosts()
def get_permed_hosts(self):
hosts = {}
assets = app_service.get_user_assets(
self.server.connection.user
)
for asset in assets:
value = {}
key = asset.hostname
if asset.org_id:
key = "{}.{}".format(asset.hostname, asset.org_name)
value['asset'] = asset
value['system_users'] = {su.name: su
for su in asset.system_users_granted
if su.protocol == "ssh" and su.login_mode == 'auto'
}
hosts[key] = value
return hosts
def session_ended(self): def session_ended(self):
super().session_ended() super().session_ended()
for _, v in self._sftp.items(): for _, v in self._sftp.items():
sftp = v['sftp'] sftp = v['client']
sock = v.get('sock') proxy = v.get('proxy')
chan = sftp.get_channel() chan = sftp.get_channel()
trans = chan.get_transport() trans = chan.get_transport()
sftp.close() sftp.close()
...@@ -31,82 +99,89 @@ class SFTPServer(paramiko.SFTPServerInterface): ...@@ -31,82 +99,89 @@ class SFTPServer(paramiko.SFTPServerInterface):
if not active_channels: if not active_channels:
print("CLose transport") print("CLose transport")
trans.close() trans.close()
if sock: if proxy:
sock.close() proxy.close()
sock.transport.close() proxy.transport.close()
self._sftp = {} self._sftp = {}
def get_host_sftp(self, host, su): def get_host_sftp(self, host, su):
asset = self.hosts.get(host) asset = self.hosts.get(host)['asset']
system_user = None system_user = self.get_host_system_users(host, only_name=False).get(su)
for s in self.get_asset_system_users(host):
if s.name == su:
system_user = s
break
if not asset or not system_user: if not asset or not system_user:
raise OSError("No asset or system user explicit") raise PermissionError("No asset or system user explicit")
if host not in self._sftp: cache_key = '{}@{}'.format(su, host)
if cache_key not in self._sftp:
ssh = SSHConnection() ssh = SSHConnection()
sftp, sock, msg = ssh.get_sftp(asset, system_user) __sftp, proxy, msg = ssh.get_sftp(asset, system_user)
if sftp: if __sftp:
self._sftp[host] = {'sftp': sftp, 'sock': sock} sftp = {
'client': __sftp, 'proxy': proxy,
'home': __sftp.normalize('')
}
self._sftp[cache_key] = sftp
return sftp return sftp
else: else:
raise OSError("Can not connect asset sftp server: {}".format(msg)) raise OSError("Can not connect asset sftp server: {}".format(msg))
else: else:
return self._sftp[host]['sftp'] return self._sftp[cache_key]
def get_perm_hosts(self): def host_has_unique_su(self, host):
hosts = {} host_sus = self.get_host_system_users(host, only_name=True)
assets = app_service.get_user_assets( logger.debug("Host system users: {}".format(host_sus))
self.server.connection.user unique = False
) su = ''
for asset in assets: if len(host_sus) == 1:
key = asset.hostname unique = True
if asset.org_id: su = host_sus[0]
key = "{}.{}".format(asset.hostname, asset.org_name) return unique, su
hosts[key] = asset
return hosts
def parse_path(self, path): def parse_path(self, path):
data = path.lstrip('/').split('/') data = path.lstrip('/').split('/')
su = rpath = '' request = {"host": "", "su": "", "dpath": "", "su_unique": False}
if len(data) == 1:
host = data[0] if len(data) == 1 and not data[0]:
elif len(data) == 2: return request
host, su = data
rpath = self.root host, *path = data
request["host"] = host
unique, su = self.host_has_unique_su(host)
if unique:
request['su'] = su
request['su_unique'] = True
else: else:
host, su, *rpath = data request['su'] = path.pop() if path else ''
rpath = os.path.join(self.root, '/'.join(rpath)) request['dpath'] = '/'.join(path)
return host, su, rpath return request
def get_sftp_rpath(self, path): def get_sftp_client_rpath(self, request):
host, su, rpath = self.parse_path(path) if isinstance(request, str):
sftp = self.get_host_sftp(host, su) if host and su else None request = self.parse_path(request)
return sftp, rpath host, su, dpath = request['host'], request['su'], request['dpath']
if host and su:
def get_asset_system_users(self, host): sftp = self.get_host_sftp(host, su)
asset = self.hosts.get(host) if self.root.lower() in ['~', 'home']:
if not asset: root = sftp['home']
return [] else:
return [ root = self.root
su for su in asset.system_users_granted rpath = os.path.join(root, dpath.lstrip('/'))
if su.protocol == "ssh" and su.login_mode != 'auto' return sftp['client'], rpath
] else:
raise FileNotFoundError()
def su_in_asset(self, su, host):
system_users = self.get_asset_system_users(host) def is_su_in_asset(self, su, host):
if su in [s.name for s in system_users]: system_users = self.get_host_system_users(host, only_name=True)
if su in system_users:
return True return True
else: else:
return False return False
def create_ftp_log(self, path, operate, is_success=True, filename=None): def create_ftp_log(self, path, operate, is_success=True, filename=None):
host, su, rpath = self.parse_path(path) request = self.parse_path(path)
asset = self.hosts.get(host) host, su = request['host'], request['su']
c, rpath = self.get_sftp_client_rpath(request)
asset = self.hosts.get(host)['asset']
date_start = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S") + " +0000", date_start = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S") + " +0000",
data = { data = {
"user": self.server.connection.user.username, "user": self.server.connection.user.username,
...@@ -128,67 +203,64 @@ class SFTPServer(paramiko.SFTPServerInterface): ...@@ -128,67 +203,64 @@ class SFTPServer(paramiko.SFTPServerInterface):
continue continue
@staticmethod @staticmethod
def stat_host_dir(): def stat_fake_dir():
tmp = tempfile.TemporaryDirectory() s = os.stat(CURRENT_DIR)
attr = paramiko.SFTPAttributes.from_stat(os.stat(tmp.name)) attr = paramiko.SFTPAttributes.from_stat(s)
tmp.cleanup()
return attr return attr
def get_host_system_users(self, host, only_name=False):
system_users = self.hosts.get(host, {}).get('system_users', {})
if only_name:
system_users = list(system_users.keys())
return system_users
@convert_error
def list_folder(self, path): def list_folder(self, path):
output = [] output = []
host, su, rpath = self.parse_path(path) request = self.parse_path(path)
if not host: logger.debug("List folder: {} => {}".format(path, request))
if not request['host']: # It's root
for hostname in self.hosts: for hostname in self.hosts:
attr = self.stat_host_dir() attr = self.stat_fake_dir()
attr.filename = hostname attr.filename = hostname
output.append(attr) output.append(attr)
elif not su: elif not request['su']:
for su in self.get_asset_system_users(host): for su in self.get_host_system_users(request['host']):
attr = self.stat_host_dir() attr = self.stat_fake_dir()
attr.filename = su.name attr.filename = su
output.append(attr) output.append(attr)
else: else:
sftp, rpath = self.get_sftp_rpath(path) client, rpath = self.get_sftp_client_rpath(request)
file_list = sftp.listdir(rpath) output = client.listdir_attr(rpath)
for filename in file_list:
attr = sftp.stat(os.path.join(rpath, filename))
attr.filename = filename
output.append(attr)
return output return output
@convert_error
def stat(self, path): def stat(self, path):
host, su, rpath = self.parse_path(path) request = self.parse_path(path)
host, su, dpath, unique = request['host'], request['su'], \
request['dpath'], request['su_unique']
logger.debug("Stat path: {} => {}".format(path, request))
if not host or not su:
stat = self.stat_fake_dir()
stat.filename = host or su or '/'
return stat
e = OSError("Not that dir")
if host and host not in self.hosts: if host and host not in self.hosts:
return paramiko.SFTPServer.convert_errno(e.errno) raise PermissionError("Permission deny")
if su and not self.su_in_asset(su, host): if su and not self.is_su_in_asset(su, host):
return paramiko.SFTPServer.convert_errno(e.errno) raise PermissionError("Permission deny")
if not rpath or rpath == "/":
attr = self.stat_host_dir()
attr.filename = su or host
return attr
else:
sftp = self.get_host_sftp(host, su)
try:
stat = sftp.stat(rpath)
return stat
except FileNotFoundError as e:
return paramiko.SFTPServer.convert_errno(e.errno)
def lstat(self, path): client, rpath = self.get_sftp_client_rpath(request)
host, su, rpath = self.parse_path(path) logger.debug("Stat path2: {} => {}".format(client, rpath))
stat = client.stat(rpath)
return stat
if not host or not su or not rpath or rpath == "/": @convert_error
attr = self.stat_host_dir() def lstat(self, path):
attr.filename = su or host return self.stat(path)
else:
sftp = self.get_host_sftp(host, su)
attr = sftp.stat(rpath)
attr.filename = os.path.basename(path)
return attr
@convert_error
def open(self, path, flags, attr=None): def open(self, path, flags, attr=None):
binary_flag = getattr(os, 'O_BINARY', 0) binary_flag = getattr(os, 'O_BINARY', 0)
flags |= binary_flag flags |= binary_flag
...@@ -207,110 +279,80 @@ class SFTPServer(paramiko.SFTPServerInterface): ...@@ -207,110 +279,80 @@ class SFTPServer(paramiko.SFTPServerInterface):
else: else:
mode = 'rb' mode = 'rb'
sftp, rpath = self.get_sftp_rpath(path)
if 'r' in mode: if 'r' in mode:
operate = "Download" operate = "Download"
elif 'a' in mode:
operate = "Append"
else: else:
operate = "Upload" operate = "Upload"
result = None try:
if sftp is not None: client, rpath = self.get_sftp_client_rpath(path)
try: f = client.open(rpath, mode, bufsize=4096)
f = sftp.open(rpath, mode, bufsize=4096) obj = paramiko.SFTPHandle(flags)
obj = paramiko.SFTPHandle(flags) obj.filename = rpath
obj.filename = rpath obj.readfile = f
obj.readfile = f obj.writefile = f
obj.writefile = f result = obj
result = obj success = True
success = True return result
except OSError: finally:
pass self.create_ftp_log(path, operate, success)
self.create_ftp_log(path, operate, success)
return result @convert_error
def remove(self, path): def remove(self, path):
sftp, rpath = self.get_sftp_rpath(path) client, rpath = self.get_sftp_client_rpath(path)
success = False success = False
if sftp is not None: try:
try: client.remove(rpath)
sftp.remove(rpath) success = True
except OSError as e: return paramiko.SFTP_OK
result = paramiko.SFTPServer.convert_errno(e.errno) finally:
else: self.create_ftp_log(path, "Delete", success)
result = paramiko.SFTP_OK
success = True
else:
result = paramiko.SFTP_FAILURE
self.create_ftp_log(path, "Delete", success)
return result
@convert_error
def rename(self, src, dest): def rename(self, src, dest):
host1, su1, rsrc = self.parse_path(src) client, rsrc = self.get_sftp_client_rpath(src)
host2, su2, rdest = self.parse_path(dest) client2, rdest = self.get_sftp_client_rpath(dest)
success = False success = False
filename = "{}=>{}".format(rsrc, rdest)
if host1 == host2 and su1 == su2 and host1: try:
sftp = self.get_host_sftp(host1, su1) if client == client2:
try: client.rename(rsrc, rdest)
sftp.rename(rsrc, rdest)
success = True success = True
except OSError as e: return paramiko.SFTP_OK
result = paramiko.SFTPServer.convert_errno(e.errno)
else: else:
result = paramiko.SFTP_OK raise FileNotFoundError("Can't rename {} => {}".format(src, dest))
else: finally:
result = paramiko.SFTP_FAILURE self.create_ftp_log(src, "Rename", success, filename=filename)
filename = "{}=>{}".format(rsrc, rdest)
self.create_ftp_log(src, "Rename", success, filename=filename)
return result
@convert_error
def mkdir(self, path, attr=0o755): def mkdir(self, path, attr=0o755):
sftp, rpath = self.get_sftp_rpath(path) client, rpath = self.get_sftp_client_rpath(path)
success = False success = False
if sftp is not None and rpath != '/': try:
try: if rpath == '/':
sftp.mkdir(rpath) raise PermissionError("Create '/', are you sure?")
success = True client.mkdir(rpath)
except OSError as e: success = True
result = paramiko.SFTPServer.convert_errno(e.errno) return paramiko.SFTP_OK
else: finally:
result = paramiko.SFTP_OK self.create_ftp_log(path, "Mkdir", success)
else:
result = paramiko.SFTP_FAILURE
self.create_ftp_log(path, "Mkdir", success, filename=rpath)
return result
@convert_error
def rmdir(self, path): def rmdir(self, path):
sftp, rpath = self.get_sftp_rpath(path) client, rpath = self.get_sftp_client_rpath(path)
success = False success = False
if sftp is not None: try:
try: client.rmdir(rpath)
sftp.rmdir(rpath) success = True
success = True return paramiko.SFTP_OK
except OSError as e: finally:
result = paramiko.SFTPServer.convert_errno(e.errno) self.create_ftp_log(path, "Rmdir", success)
else:
result = paramiko.SFTP_OK
else:
result = paramiko.SFTP_FAILURE
self.create_ftp_log(path, "Rmdir", success)
return result
# def chattr(self, path, attr):
# sftp, rpath = self.get_sftp_rpath(path)
# if sftp is not None:
# if attr._flags & attr.FLAG_PERMISSIONS:
# sftp.chmod(rpath, attr.st_mode)
# if attr._flags & attr.FLAG_UIDGID:
# sftp.chown(rpath, attr.st_uid, attr.st_gid)
# if attr._flags & attr.FLAG_AMTIME:
# sftp.utime(rpath, (attr.st_atime, attr.st_mtime))
# if attr._flags & attr.FLAG_SIZE:
# sftp.truncate(rpath, attr.st_size)
# return paramiko.SFTP_OK
class FakeServer: class FakeServer:
...@@ -352,22 +394,26 @@ class InternalSFTPClient(SFTPServer): ...@@ -352,22 +394,26 @@ class InternalSFTPClient(SFTPServer):
return self.list_folder(path) return self.list_folder(path)
def open(self, path, mode, **kwargs): def open(self, path, mode, **kwargs):
sftp, rpath = self.get_sftp_rpath(path) client, rpath = self.get_sftp_client_rpath(path)
if 'r' in mode: if 'r' in mode:
operate = "Download" operate = "Download"
else: else:
operate = "Upload" operate = "Upload"
success = False success = False
if sftp is not None: try:
try: f = client.open(rpath, mode, bufsize=4096)
f = sftp.open(rpath, mode, bufsize=4096) success = True
except OSError:
raise OSError("Open file {} failed".format(rpath))
finally:
print("Open success")
self.create_ftp_log(path, operate, success)
return f return f
finally:
self.create_ftp_log(path, operate, success)
def stat(self, path):
attr = super().stat.__wrapped__(self, path)
return attr
def lstat(self, path):
attr = super().lstat.__wrapped__(self, path)
return attr
def get_channel(self): def get_channel(self):
return FakeChannel.new() return FakeChannel.new()
...@@ -375,6 +421,9 @@ class InternalSFTPClient(SFTPServer): ...@@ -375,6 +421,9 @@ class InternalSFTPClient(SFTPServer):
def unlink(self, path): def unlink(self, path):
return self.remove(path) return self.remove(path)
def putfo(self, f, path, callback=None, confirm=True):
client, rpath = self.get_sftp_client_rpath(path)
return client.putfo(f, rpath, callback=callback, confirm=confirm)
def close(self): def close(self):
print("End ")
return self.session_ended() return self.session_ended()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment