#!/usr/bin/env python # -*- mode: python; tab-width: 4 -*- # $Id: smbcp,v 1.8 2002/08/03 05:45:32 miketeo Exp $ # # Copyright (C) 2001 Michael Teo # smbcp - file transfer program between local machine and remote SMB machines # # This software is provided 'as-is', without any express or implied warranty. # In no event will the author be held liable for any damages arising from the # use of this software. # # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # # 3. This notice cannot be removed or altered from any source distribution. # import os, os.path, sys, stat, string, re, getopt, getpass import smb, nmb VERSION = '0.1.4' USER_HOST_PATH_PATTERN = re.compile('(\w+)@([\w\.]+):/*([^/]+)(/.*)') HOST_PATH_PATTERN = re.compile(r"([\w\.]+):/*([^/]+)(/*.*)") def parse_path(path): m = USER_HOST_PATH_PATTERN.match(path) if m: return m.groups() m = HOST_PATH_PATTERN.match(path) if m: return '', m.group(1), m.group(2), m.group(3) return None def print_usage_screen(): print 'Usage: smbcp [options] src ... [@]:/share/path' print ' smbcp [options] [@]:/share/path dest' print print 'Options:' print ' -n show what would have been transferred without doing it' print ' -r recurse into directories' print ' -B broadcast addr the address to use for broadcasts' print ' -I remote IP addr connect to this IP address for remote host' print ' --version show version and exit' print def remote2local_copy(src, src_service, src_path, dest_path, is_dest_dir, password): global recursive, dry_run try: info = src.list_path(src_service, src_path, password = password) is_src_dir = info[0].is_directory() except smb.SessionError, ex: print ex[0], ':', smb.strerror(ex[1], ex[2])[1] return if is_src_dir: if not is_dest_dir: print 'Warning: Destination is not directory' return if recursive: if not dry_run: try: os.mkdir(os.path.join(dest_path, os.path.basename(src_path))) except: pass for f in src.list_path(src_service, src_path + '/*', password = password): name = f.get_longname() if name == '.' or name == '..': continue if f.is_directory(): remote2local_copy(src, src_service, src_path + '/' + name, os.path.join(dest_path, os.path.basename(src_path)), is_dest_dir, password) else: print src_path + '/' + name, print '=>', os.path.join(dest_path, os.path.basename(src_path), name) if not dry_run: fh = open(os.path.join(dest_path, os.path.basename(src_path), name), 'wb') try: src.retr_file(src_service, src_path + '/' + name, fh.write, password = password) finally: fh.close() else: print 'Warning: source is a directory but -r is not set.' else: if is_dest_dir: print src_path, '=>', os.path.join(dest_path, os.path.basename(src_path)) else: print src_path, '=>', dest_path if not dry_run: if is_dest_dir: fh = open(os.path.join(dest_path, os.path.basename(src_path)), 'wb') else: fh = open(dest_path, 'wb') try: src.retr_file(src_service, src_path, fh.write, password = password) finally: fh.close() def local2remote_copy(remote, dest_service, dest_path, src_path, is_dest_dir, password): global recursive, dry_run if os.path.isdir(src_path): if not is_dest_dir: print 'Warning: Destination is not directory' return if recursive: for f in os.listdir(src_path): if f != '.' and f != '..': try: remote.mkdir(dest_service, dest_path + '/' + os.path.basename(src_path), password) except smb.SessionError: pass local2remote_copy(remote, dest_service, dest_path + '/' + os.path.basename(src_path), os.path.join(src_path, f), is_dest_dir, password) else: print 'Warning:', src_path, 'is a directory but -r is not set.' else: print src_path, '=>', if is_dest_dir: print dest_path + '/' + os.path.basename(src_path) else: print dest_path if not os.path.exists(src_path): print 'Warning:', src_path, 'does not exist' elif not dry_run: fh = open(src_path, 'rb') try: if is_dest_dir: remote.stor_file(dest_service, dest_path + '/' + os.path.basename(src_path), fh.read, password = password) else: remote.stor_file(dest_service, dest_path, fh.read, password = password) finally: fh.close() recursive = 0 dry_run = 0 def main(): global recursive, dry_run remote_ip_addr = None netbios = nmb.NetBIOS() try: optlist, args = getopt.getopt(sys.argv[1:], 'rnB:I:', [ 'version' ]) for k, v in optlist: if k == '-r': recursive = 1 elif k == '-n': dry_run = 1 elif k == '-B': netbios.set_broadcastaddr(v) elif k == '-I': remote_ip_addr = v elif k == '--version': print 'smbcp version', VERSION, '(smb:', smb.CVS_REVISION, 'and nmb:', nmb.CVS_REVISION, ')' return except getopt.error: print_usage_screen() return if len(args) < 2: print_usage_screen() return dest = args[-1] sources = args[:-1] dest_info = parse_path(dest) if dest_info: user, dest_name, dest_service, dest_path = dest_info if not remote_ip_addr: try: addrs = netbios.gethostbyname(dest_name) if not addrs: print 'Warning: No such host,', dest_name return except nmb.NetBIOSTimeout: print 'Warning: Cannot resolve', dest_name return except nmb.NetBIOSError, ex: print 'Warning: Error resolving', dest_name print ex[0], ':', nmb.strerror(ex[1], ex[2])[1] return print 'Connecting to remote,', dest_name, 'using', addrs[0].get_ip() remote = smb.SMB(dest_name, addrs[0].get_ip()) else: print 'Connecting to remote,', dest_name, 'using', remote_ip_addr remote = smb.SMB(dest_name, remote_ip_addr) if remote.is_login_required(): if not user: user = getpass.getuser() password = getpass.getpass('Password for ' + user + '@' + dest_name + ': ') remote.login(user, password) password = None else: password = getpass.getpass('Password for ' + dest_service + ': ') is_dest_dir = 0 try: remote.check_dir(dest_service, dest_path, password) is_dest_dir = 1 except smb.SessionError: pass if len(sources) > 1 and not is_dest_dir: print 'Warning: Destination not directory' return if dest_path and dest_path[-1] == '/': dest_path = dest_path[:-1] for source in sources: if parse_path(source): print 'Warning: You have specified a remote=>remote copy. We can only do local=>remote or remote=>local copy.' else: source = os.path.normpath(source) local2remote_copy(remote, dest_service, dest_path, source, is_dest_dir, password) else: is_dest_dir = os.path.isdir(dest) if len(sources) > 1 and not is_dest_dir: print 'Warning: Destination not directory' return passwords = { } for source in sources: src_info = parse_path(source) if not src_info: print 'Warning: You have specified a local=>local copy. We can only do local=>remote or remote=>local copy.' user, src_name, src_service, src_path = src_info if not remote_ip_addr: try: addrs = netbios.gethostbyname(src_name) if not addrs: print 'Warning: No such host,', dest_name return except nmb.NetBIOSTimeout: print 'Warning: Cannot resolve', src_name return except nmb.NetBIOSError, ex: print 'Warning: Error resolving', src_name print ex[0], ':', nmb.strerror(ex[1], ex[2])[1] return print 'Connecting to remote,', src_name, 'using', addrs[0].get_ip() src = smb.SMB(src_name, addrs[0].get_ip()) else: print 'Connecting to remote,', src_name, 'using', remote_ip_addr src = smb.SMB(src_name, remote_ip_addr) if src.is_login_required(): if not user: user = getpass.getuser() if passwords.has_key(( user, src_name )): password = passwords[( user, src_name )] else: password = getpass.getpass('Password for ' + user + '@' + src_name + ': ') passwords[( user, src_name )] = password src.login(user, password) password = None else: password = getpass.getpass('Password for ' + src_service + ': ') if src_path and src_path[-1] == '/': src_path = src_path[:-1] remote2local_copy(src, src_service, src_path, dest, is_dest_dir, password) if __name__ == '__main__': try: main() except nmb.NetBIOSError, ex: _, err_msg = nmb.strerror(ex[1], ex[2]) print ex[0], ':', err_msg except smb.SessionError, ex: _, err_msg = smb.strerror(ex[1], ex[2]) print ex[0], ':', err_msg except KeyboardInterrupt: pass