00001 ## 00002 # 00003 # SSH support for win32 development to spoof accessing server based Linux resources. 00004 # 00005 00006 __copyright__ = """\ 00007 (c). Copyright 1990-2008, Vyper Logix Corp., All Rights Reserved. 00008 00009 Published under Creative Commons License 00010 (http://creativecommons.org/licenses/by-nc/3.0/) 00011 restricted to non-commercial educational use only., 00012 00013 See also: http://www.VyperLogix.com and http://www.pypi.info for details. 00014 00015 THE AUTHOR VYPER LOGIX CORP DISCLAIMS ALL WARRANTIES WITH REGARD TO 00016 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 00017 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, 00018 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING 00019 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 00020 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 00021 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE ! 00022 00023 USE AT YOUR OWN RISK. 00024 """ 00025 00026 import os 00027 import sys 00028 import traceback 00029 00030 from vyperlogix.classes.CooperativeClass import Cooperative 00031 from vyperlogix.misc import ObjectTypeName 00032 from vyperlogix.misc.ObjectTypeName import __typeName as ObjectTypeName__typeName 00033 from vyperlogix.misc import _utils 00034 from vyperlogix import misc 00035 00036 try: 00037 import paramiko 00038 except ImportError, details: 00039 print 'WARNING due to "%s".' % str(details) 00040 00041 try: 00042 from cStringIO import StringIO 00043 except ImportError: 00044 from StringIO import StringIO 00045 00046 from vyperlogix.hash import lists 00047 00048 def calcXferRate(xfer_rate): 00049 xfer_factor = 1 00050 xfer_rate_calc = xfer_rate/1024 00051 xfer_rate_fmt = '%s KB/sec' % ('%-4.2f' % xfer_rate_calc).strip() 00052 if (xfer_rate_calc > 1024): 00053 xfer_factor = 1024 00054 xfer_rate_calc = xfer_rate/(1024*xfer_factor) 00055 xfer_rate_fmt = '%s MB/sec' % ('%-4.2f' % xfer_rate_calc).strip() 00056 return lists.HashedLists2({'xfer_rate':xfer_rate,'xfer_factor':xfer_factor,'xfer_rate_fmt':xfer_rate_fmt}) 00057 00058 def giveXferStatus(iBytes,iTotal,xfer_rate,secs): 00059 if (iTotal > 0) and (xfer_rate > 0): 00060 xfer_rate_calc = calcXferRate(xfer_rate) 00061 print '(%2.2f%%) %s %s of %s in %4.2f seconds.' % ((float(iBytes)/float(iTotal))*100.0,xfer_rate_calc['xfer_rate_fmt'],iBytes,iTotal,((iTotal-iBytes)/(xfer_rate*xfer_rate_calc['xfer_factor']))) 00062 00063 class SSHConnection(Cooperative): 00064 def __init__(self,hostname='',port=22,username='',password='',isLazy=False): 00065 self.__lastError__ = StringIO() 00066 self.__hostname__ = hostname 00067 self.__port__ = port 00068 self.__username__ = username 00069 self.__password__ = password 00070 self.__transport__ = None 00071 self.__sftp__ = None 00072 self.__sep__ = '/' 00073 if (not isLazy): 00074 self.ssh_connect_client() 00075 pass 00076 00077 def __repr__(self): 00078 c = ObjectTypeName__typeName(self) 00079 return '%s(hostname="%s",port=%s,username="%s",password="...")' % (c,self.hostname,self.port,self.username) 00080 00081 def __str__(self): 00082 return '%s@%s:%s' % (self.username,self.hostname,self.port) 00083 00084 def sep(): 00085 doc = "seperator for host file names" 00086 def fget(self): 00087 return self.__sep__ 00088 return locals() 00089 sep = property(**sep()) 00090 00091 def transport(): 00092 doc = "transport" 00093 def fget(self): 00094 return self.__transport__ 00095 return locals() 00096 transport = property(**transport()) 00097 00098 def sftp(): 00099 doc = "sftp" 00100 def fget(self): 00101 if (self.__sftp__ is None): 00102 self.ssh_connect_client() 00103 return self.__sftp__ 00104 return locals() 00105 sftp = property(**sftp()) 00106 00107 def hostname(): 00108 doc = "hostname" 00109 def fget(self): 00110 return self.__hostname__ 00111 def fset(self, hostname): 00112 self.__hostname__ = hostname 00113 return locals() 00114 hostname = property(**hostname()) 00115 00116 def port(): 00117 doc = "port" 00118 def fget(self): 00119 return self.__port__ 00120 def fset(self, port): 00121 self.__port__ = port 00122 return locals() 00123 port = property(**port()) 00124 00125 def username(): 00126 doc = "username" 00127 def fget(self): 00128 return self.__username__ 00129 def fset(self, username): 00130 self.__username__ = username 00131 return locals() 00132 username = property(**username()) 00133 00134 def password(): 00135 doc = "password" 00136 def fget(self): 00137 return self.__password__ 00138 def fset(self, password): 00139 self.__password__ = password 00140 return locals() 00141 password = property(**password()) 00142 00143 def lastError(): 00144 doc = "lastError message - use getvalue() to retrieve the message" 00145 def fget(self): 00146 return self.__lastError__ 00147 return locals() 00148 lastError = property(**lastError()) 00149 00150 def lastErrorMessage(): 00151 doc = "lastError message" 00152 def fget(self): 00153 return self.__lastError__.getvalue() 00154 return locals() 00155 lastErrorMessage = property(**lastErrorMessage()) 00156 00157 ## 00158 # Make an SSH connection with the server to mimic certain functions only for win32 platform to facilitate development. 00159 # 00160 def ssh_connect_transport(self): 00161 # get host key, if we know one 00162 hostkeytype = None 00163 hostkey = None 00164 try: 00165 host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/.ssh/known_hosts')) 00166 except IOError: 00167 try: 00168 host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/ssh/known_hosts')) 00169 except IOError: 00170 exc_info = sys.exc_info() 00171 info_string = '\n'.join(traceback.format_exception(*exc_info)) 00172 print >>self.lastError, '\n%s :: Cannot open host keys file, Reason: %s' % (ObjectTypeName.objectSignature(self),info_string) 00173 host_keys = {} 00174 if host_keys.has_key(self.hostname): 00175 hostkeytype = host_keys[self.hostname].keys()[0] 00176 hostkey = host_keys[self.hostname][hostkeytype] 00177 else: 00178 print "%s :: Host key not found. Please create key manually using: ssh %s" % (misc.funcName(),self.hostname) 00179 # now, connect and use paramiko Transport to negotiate SSH2 across the connection 00180 try: 00181 t = paramiko.Transport((self.hostname, self.port)) 00182 t.connect(username=self.username, password=self.password, hostkey=hostkey) 00183 except Exception, e: 00184 exc_info = sys.exc_info() 00185 info_string = '\n'.join(traceback.format_exception(*exc_info)) 00186 print >>self.lastError, '\n%s :: Cannot open connection to %s:%s using username of "%s", Reason: %s' % (ObjectTypeName.objectSignature(self),self.hostname,self.port,self.username,info_string) 00187 return None 00188 return t 00189 00190 ## 00191 # connect and use paramiko Transport to negotiate SSH2 across the connection 00192 # 00193 def ssh_connect_client(self): 00194 self.__sftp__ = None 00195 if (self.transport is None): 00196 self.__transport__ = self.ssh_connect_transport() 00197 if (self.__transport__ is not None): 00198 try: 00199 self.__sftp__ = paramiko.SFTPClient.from_transport(self.transport) 00200 except Exception, e: 00201 exc_info = sys.exc_info() 00202 info_string = '\n'.join(traceback.format_exception(*exc_info)) 00203 print >>self.lastError, '\n%s :: Cannot open client connection to %s:%s using username of "%s", Reason: %s' % (ObjectTypeName.objectSignature(self),self.hostname,self.port,self.username,info_string) 00204 try: 00205 if (self.sftp is not None): 00206 ssh_close() 00207 except: 00208 pass 00209 return None 00210 else: 00211 return None 00212 00213 return self.sftp 00214 00215 ## 00216 # Close the previously opened client connection as obtained by ssh_connect_client() 00217 def ssh_close(self): 00218 try: 00219 self.sftp.close() 00220 self.__sftp__ = None 00221 except: 00222 pass 00223 try: 00224 self.transport.close() 00225 self.__transport__ = None 00226 except: 00227 pass 00228 return 00229 00230 ## 00231 # Perform directoy list against an SSH accessible server. 00232 # 00233 def __ssh_listdir(self,dir_path): 00234 if ((dir_path == None) or (dir_path == '')): 00235 dir_path = '.' 00236 try: 00237 dirlist = self.sftp.listdir(dir_path) 00238 except: 00239 return None 00240 return dirlist 00241 00242 ## 00243 # 00244 # Return a list containing the names of the entries in the given path. The list is in arbitrary order. It does not include the special entries '.' and '..' even if they are present in the folder. This method is meant to mirror os.listdir as closely as possible. For a list of full SFTPAttributes objects, see listdir_attr. 00245 # 00246 # Parameters: 00247 # * path (str) - path to list (defaults to '.') 00248 # 00249 # Returns: list of str 00250 # list of filenames 00251 # 00252 def listdir(self,pathName): 00253 return self.__ssh_listdir(pathName) 00254 00255 ## 00256 # 00257 # Return the normalized path (on the server) of a given path. This can be used to quickly resolve symbolic links or determine what the server is considering to be the "current folder" (by passing '.' as path). 00258 # 00259 # Parameters: 00260 # * path (str) - path to be normalized 00261 # 00262 # Returns: str 00263 # normalized form of the given path 00264 # 00265 # Raises: 00266 # * IOError - if the path can't be resolved on the server 00267 # 00268 def normalize(self,dir_path): 00269 if ((dir_path == None) or (dir_path == '')): 00270 dir_path = '.' 00271 try: 00272 return self.sftp.normalize(dir_path) 00273 except: 00274 return None 00275 return None 00276 00277 ## 00278 # 00279 # Change the "current directory" of this SFTP session. Since SFTP doesn't really have the concept of a current working directory, this is emulated by paramiko. Once you use this method to set a working directory, all operations on this SFTPClient object will be relative to that path. 00280 # 00281 # Parameters: 00282 # * path (str) - new current working directory 00283 # 00284 # Raises: 00285 # * IOError - if the requested path doesn't exist on the server 00286 # 00287 def chdir(self,dir_path): 00288 try: 00289 return self.sftp.chdir(dir_path) 00290 except: 00291 return None 00292 return None 00293 00294 ## 00295 # 00296 # Change the mode (permissions) of a file. The permissions are unix-style and identical to those used by python's os.chmod function. 00297 # 00298 # Parameters: 00299 # * path (str) - path of the file to change the permissions of 00300 # * mode (int) - new permissions 00301 # 00302 def chmod(self,path,mode): 00303 try: 00304 return self.sftp.chmod(path,mode) 00305 except: 00306 return None 00307 return None 00308 00309 ## 00310 # 00311 # Change the owner (uid) and group (gid) of a file. As with python's os.chown function, you must pass both arguments, so if you only want to change one, use stat first to retrieve the current owner and group. 00312 # 00313 # Parameters: 00314 # * path (str) - path of the file to change the owner and group of 00315 # * uid (int) - new owner's uid 00316 # * gid (int) - new group id 00317 # 00318 def chown(self,path,uid,gid): 00319 try: 00320 return self.sftp.chown(path,uid,gid) 00321 except: 00322 return None 00323 return None 00324 00325 ## 00326 # 00327 # Close the SFTP session and its underlying channel. 00328 # 00329 def close(self): 00330 return self.ssh_close() 00331 00332 ## 00333 # 00334 # Return the underlying Channel object for this SFTP session. This might be useful for doing things like setting a timeout on the channel. 00335 # 00336 # Returns: Channel 00337 # the SSH channel 00338 # 00339 def get_channel(self): 00340 try: 00341 return self.sftp.get_channel() 00342 except: 00343 return None 00344 return None 00345 00346 ## 00347 # 00348 # Return the "current working directory" for this SFTP session, as emulated by paramiko. If no directory has been set with chdir, this method will return None. 00349 # 00350 # Returns: str 00351 # the current working directory on the server, or None 00352 # 00353 def getcwd(self): 00354 try: 00355 f = self.sftp.getcwd() 00356 return f if (f is not None) else self.home() 00357 except: 00358 return None 00359 return None 00360 00361 ## 00362 # 00363 # Return a list containing SFTPAttributes objects corresponding to files in the given path. The list is in arbitrary order. It does not include the special entries '.' and '..' even if they are present in the folder. 00364 # 00365 # The returned SFTPAttributes objects will each have an additional field: longname, which may contain a formatted string of the file's attributes, in unix format. The content of this string will probably depend on the SFTP server implementation. 00366 # 00367 # Parameters: 00368 # * path (str) - path to list (defaults to '.') 00369 # 00370 # Returns: list of SFTPAttributes 00371 # list of attributes 00372 # 00373 def listdir_attr(self,dir_path): 00374 try: 00375 return self.sftp.listdir_attr(dir_path) 00376 except: 00377 return None 00378 return None 00379 00380 ## 00381 # 00382 # Retrieve information about a file on the remote system. The return value is an object whose attributes correspond to the attributes of python's stat structure as returned by os.stat, except that it contains fewer fields. An SFTP server may return as much or as little info as it wants, so the results may vary from server to server. 00383 # 00384 # Unlike a python stat object, the result may not be accessed as a tuple. This is mostly due to the author's slack factor. 00385 # 00386 # The fields supported are: st_mode, st_size, st_uid, st_gid, st_atime, and st_mtime. 00387 # 00388 # Parameters: 00389 # 00390 # * path (str) - the filename to stat 00391 # 00392 # Returns: SFTPAttributes 00393 # an object containing attributes about the given file 00394 # 00395 def stat(self,dir_path): 00396 try: 00397 return self.sftp.stat(dir_path) 00398 except: 00399 return None 00400 return None 00401 00402 ## 00403 # 00404 # Retrieve information about a file on the remote system, without following symbolic links (shortcuts). This otherwise behaves exactly the same as stat. 00405 # 00406 # Parameters: 00407 # * path (str) - the filename to stat 00408 # 00409 # Returns: SFTPAttributes 00410 # an object containing attributes about the given file 00411 # 00412 def lstat(self,dir_path): 00413 try: 00414 return self.sftp.lstat(dir_path) 00415 except: 00416 return None 00417 return None 00418 00419 ## 00420 # 00421 # Create a folder (directory) named path with numeric mode mode. The default mode is 0777 (octal). On some systems, mode is ignored. Where it is used, the current umask value is first masked out. 00422 # 00423 # Parameters: 00424 # * path (str) - name of the folder to create 00425 # * mode (int) - permissions (posix-style) for the newly-created folder 00426 # 00427 def mkdir(self,dir_path,file_mode=0777): 00428 try: 00429 return self.sftp.mkdir(dir_path,file_mode) 00430 except: 00431 return None 00432 return None 00433 00434 ## 00435 # 00436 # Open a file on the remote server. The arguments are the same as for python's built-in file (aka open). A file-like object is returned, which closely mimics the behavior of a normal python file object. 00437 # 00438 # The mode indicates how the file is to be opened: 'r' for reading, 'w' for writing (truncating an existing file), 'a' for appending, 'r+' for reading/writing, 'w+' for reading/writing (truncating an existing file), 'a+' for reading/appending. The python 'b' flag is ignored, since SSH treats all files as binary. The 'U' flag is supported in a compatible way. 00439 # 00440 # Since 1.5.2, an 'x' flag indicates that the operation should only succeed if the file was created and did not previously exist. This has no direct mapping to python's file flags, but is commonly known as the O_EXCL flag in posix. 00441 # 00442 # The file will be buffered in standard python style by default, but can be altered with the bufsize parameter. 0 turns off buffering, 1 uses line buffering, and any number greater than 1 (>1) uses that specific buffer size. 00443 # 00444 # Parameters: 00445 # * filename (str) - name of the file to open 00446 # * mode (str) - mode (python-style) to open in 00447 # * bufsize (int) - desired buffering (-1 = default buffer size) 00448 # 00449 # Returns: SFTPFile 00450 # a file object representing the open file 00451 # 00452 # Raises: 00453 # * IOError - if the file could not be opened. 00454 # 00455 def file(self,filename,mode='r',bufsize=-1): 00456 try: 00457 return self.sftp.file(filename,mode,bufsize) 00458 except: 00459 return None 00460 return None 00461 00462 ## 00463 # 00464 # Open a file on the remote server. The arguments are the same as for python's built-in file (aka open). A file-like object is returned, which closely mimics the behavior of a normal python file object. 00465 # 00466 # The mode indicates how the file is to be opened: 'r' for reading, 'w' for writing (truncating an existing file), 'a' for appending, 'r+' for reading/writing, 'w+' for reading/writing (truncating an existing file), 'a+' for reading/appending. The python 'b' flag is ignored, since SSH treats all files as binary. The 'U' flag is supported in a compatible way. 00467 # 00468 # Since 1.5.2, an 'x' flag indicates that the operation should only succeed if the file was created and did not previously exist. This has no direct mapping to python's file flags, but is commonly known as the O_EXCL flag in posix. 00469 # 00470 # The file will be buffered in standard python style by default, but can be altered with the bufsize parameter. 0 turns off buffering, 1 uses line buffering, and any number greater than 1 (>1) uses that specific buffer size. 00471 # 00472 # Parameters: 00473 # * filename (str) - name of the file to open 00474 # * mode (str) - mode (python-style) to open in 00475 # * bufsize (int) - desired buffering (-1 = default buffer size) 00476 # 00477 # Returns: SFTPFile 00478 # a file object representing the open file 00479 # 00480 # Raises: 00481 # * IOError - if the file could not be opened. 00482 # 00483 def open(self,filename,mode='r',bufsize=-1): 00484 try: 00485 return self.sftp.open(filename,mode,bufsize) 00486 except: 00487 return None 00488 return None 00489 00490 ## 00491 # 00492 # Copy a remote file (remotepath) from the SFTP server to the local host as localpath. Any exception raised by operations will be passed through. This method is primarily provided as a convenience. 00493 # 00494 # Parameters: 00495 # * remotepath (str) - the remote file to copy 00496 # * localpath (str) - the destination path on the local host 00497 # * callback (function(int, int)) - optional callback function that accepts the bytes transferred so far and the total bytes to be transferred (since 1.7.4) 00498 # 00499 def get(self,remotepath,localpath,callback=None): 00500 try: 00501 return self.sftp.get(remotepath,localpath,callback=None) 00502 except: 00503 return None 00504 return None 00505 00506 ## 00507 # 00508 # Copy a local file (localpath) to the SFTP server as remotepath. Any exception raised by operations will be passed through. This method is primarily provided as a convenience. 00509 # 00510 # The SFTP operations use pipelining for speed. 00511 # 00512 # Parameters: 00513 # * localpath (str) - the local file to copy 00514 # * remotepath (str) - the destination path on the SFTP server 00515 # * callback (function(int iBytes, int iTotal, float xfer_rate, int elapsed_secs)) - optional callback function that accepts the bytes transferred so far and the total bytes to be transferred (since 1.7.4) 00516 # 00517 # Returns: SFTPAttributes 00518 # an object containing attributes about the given file (since 1.7.4) 00519 # 00520 def put(self,localpath,remotepath,callback=None): 00521 import time 00522 from vyperlogix.misc import _utils 00523 00524 _begin_ts = time.time() 00525 _callback_ = None 00526 def _callback(iBytes,iTotal): 00527 if (callable(_callback_)): 00528 et = time.time() - _begin_ts 00529 if (et == 0): 00530 et = 0.00000000001 00531 xfer = iBytes / et 00532 try: 00533 _callback_(iBytes,iTotal,xfer,et) 00534 except Exception, details: 00535 print >>sys.stderr, '%s' % str(details) 00536 00537 try: 00538 if (not callable(callback)): 00539 callback = None 00540 else: 00541 try: 00542 callback(0,0,0,0) 00543 except Exception, details: 00544 print >>sys.stderr, '%s :: Cannot use the callback because it has the following problem: "%s".' % (ObjectTypeName.objectSignature(self),str(details)) 00545 callback = None 00546 if (callback is not None): 00547 _callback_ = callback 00548 result = self.sftp.put(localpath,remotepath,_callback) 00549 _end_ts = time.time() 00550 _iTotal = result.st_size 00551 xfer = _iTotal / (_end_ts - _begin_ts) 00552 return [result,xfer] 00553 except: 00554 exc_info = sys.exc_info() 00555 info_string = _utils.asMessage('\n'.join(traceback.format_exception(*exc_info))) 00556 print >>sys.stderr, info_string 00557 return None 00558 return None 00559 00560 ## 00561 # 00562 # Return the target of a symbolic link (shortcut). You can use symlink to create these. The result may be either an absolute or relative pathname. 00563 # 00564 # Parameters: 00565 # * path (str) - path of the symbolic link file 00566 # 00567 # Returns: str 00568 # target path 00569 # 00570 def readlink(self,dir_path): 00571 try: 00572 return self.sftp.readlink(dir_path) 00573 except: 00574 return None 00575 return None 00576 00577 ## 00578 # 00579 # Remove the file at the given path. This only works on files; for removing folders (directories), use rmdir. 00580 # 00581 # Parameters: 00582 # * path (str) - path (absolute or relative) of the file to remove 00583 # 00584 # Raises: 00585 # * IOError - if the path refers to a folder (directory) 00586 # 00587 def remove(self,dir_path): 00588 try: 00589 return self.sftp.remove(dir_path) 00590 except: 00591 return None 00592 return None 00593 00594 ## 00595 # 00596 # Rename a file or folder from oldpath to newpath. 00597 # 00598 # Parameters: 00599 # * oldpath (str) - existing name of the file or folder 00600 # * newpath (str) - new name for the file or folder 00601 # 00602 # Raises: 00603 # * IOError - if newpath is a folder, or something else goes wrong 00604 # 00605 def rename(self,old_name,new_name): 00606 try: 00607 return self.sftp.rename(old_name,new_name) 00608 except: 00609 return None 00610 return None 00611 00612 ## 00613 # 00614 # Remove the folder named path. 00615 # 00616 # Parameters: 00617 # * path (str) - name of the folder to remove 00618 # 00619 def rmdir(self,fname): 00620 try: 00621 return self.sftp.rmdir(fname) 00622 except: 00623 return None 00624 return None 00625 00626 ## 00627 # 00628 # Create a symbolic link (shortcut) of the source path at destination. 00629 # 00630 # Parameters: 00631 # * source (str) - path of the original file 00632 # * dest (str) - path of the newly created symlink 00633 # 00634 def symlink(self,source,dest): 00635 try: 00636 return self.sftp.symlink(source,dest) 00637 except: 00638 return None 00639 return None 00640 00641 ## 00642 # 00643 # Change the size of the file specified by path. This usually extends or shrinks the size of the file, just like the truncate() method on python file objects. 00644 # 00645 # Parameters: 00646 # * path (str) - path of the file to modify 00647 # * size (int or long) - the new size of the file 00648 # 00649 def truncate(self,fname,fsize): 00650 try: 00651 return self.sftp.truncate(fname,fsize) 00652 except: 00653 return None 00654 return None 00655 00656 ## 00657 # 00658 # Remove the file at the given path. This only works on files; for removing folders (directories), use rmdir. 00659 # 00660 # Parameters: 00661 # * path (str) - path (absolute or relative) of the file to remove 00662 # 00663 # Raises: 00664 # * IOError - if the path refers to a folder (directory) 00665 # 00666 def unlink(self,fname): 00667 try: 00668 return self.sftp.unlink(fname) 00669 except: 00670 return None 00671 return None 00672 00673 ## 00674 # 00675 # Set the access and modified times of the file specified by path. If times is None, then the file's access and modified times are set to the current time. Otherwise, times must be a 2-tuple of numbers, of the form (atime, mtime), which is used to set the access and modified times, respectively. This bizarre API is mimicked from python for the sake of consistency -- I apologize. 00676 # 00677 # Parameters: 00678 # * path (str) - path of the file to modify 00679 # * times (tuple(int)) - None or a tuple of (access time, modified time) in standard internet epoch time (seconds since 01 January 1970 GMT) 00680 # 00681 def utime(self,fname,times): 00682 try: 00683 return self.sftp.utime(fname,times) 00684 except: 00685 return None 00686 return None 00687 00688 ## 00689 # home folder for current user 00690 def home(self): 00691 f = self.normalize(self.getcwd()) 00692 toks = f.split(self.sep) 00693 t = toks[0:3] 00694 return self.sep.join(t) 00695 00696 ## 00697 # Test whether a remote path is a directory 00698 def isdir(self, pathName): 00699 import stat 00700 try: 00701 st = self.stat(pathName) 00702 return False if (st == None) else stat.S_ISDIR(st.st_mode) 00703 except os.error: 00704 return False 00705 return False 00706 00707 ## 00708 # Test whether a path is a symbolic link 00709 def islink(self, pathName): 00710 import stat 00711 try: 00712 st = self.lstat(pathName) 00713 except (os.error, AttributeError): 00714 return False 00715 return stat.S_ISLNK(st.st_mode) 00716 00717 ## 00718 # Remote Directory tree generator. 00719 # 00720 # For each directory in the remote directory tree rooted at top (including top 00721 # itself, but excluding '.' and '..'), yields a 3-tuple 00722 # 00723 # dirpath, dirnames, filenames 00724 # 00725 # dirpath is a string, the path to the directory. dirnames is a list of 00726 # the names of the subdirectories in dirpath (excluding '.' and '..'). 00727 # filenames is a list of the names of the non-directory files in dirpath. 00728 # Note that the names in the lists are just names, with no path components. 00729 # To get a full path (which begins with top) to a file or directory in 00730 # dirpath, do os.path.join(dirpath, name). 00731 # 00732 # If optional arg 'topdown' is true or not specified, the triple for a 00733 # directory is generated before the triples for any of its subdirectories 00734 # (directories are generated top down). If topdown is false, the triple 00735 # for a directory is generated after the triples for all of its 00736 # subdirectories (directories are generated bottom up). 00737 # 00738 # When topdown is true, the caller can modify the dirnames list in-place 00739 # (e.g., via del or slice assignment), and walk will only recurse into the 00740 # subdirectories whose names remain in dirnames; this can be used to prune 00741 # the search, or to impose a specific order of visiting. Modifying 00742 # dirnames when topdown is false is ineffective, since the directories in 00743 # dirnames have already been generated by the time dirnames itself is 00744 # generated. 00745 # 00746 # By default errors from the os.listdir() call are ignored. If 00747 # optional arg 'onerror' is specified, it should be a function; it 00748 # will be called with one argument, an os.error instance. It can 00749 # report the error to continue with the walk, or raise the exception 00750 # to abort the walk. Note that the filename is available as the 00751 # filename attribute of the exception object. 00752 # 00753 # Caution: if you pass a relative pathname for top, don't change the 00754 # current working directory between resumptions of walk. walk never 00755 # changes the current directory, and assumes that the client doesn't 00756 # either. 00757 # 00758 # Example: 00759 # 00760 # from os.path import join, getsize 00761 # for root, dirs, files in walk('python/Lib/email'): 00762 # print root, "consumes", 00763 # print sum([getsize(join(root, name)) for name in files]), 00764 # print "bytes in", len(files), "non-directory files" 00765 # if 'CVS' in dirs: 00766 # dirs.remove('CVS') # don't visit CVS directories 00767 # 00768 def walk(self, top, topdown=True, onerror=None): 00769 00770 from posixpath import join 00771 00772 # We may not have read permission for top, in which case we can't 00773 # get a list of the files the directory contains. os.path.walk 00774 # always suppressed the exception then, rather than blow up for a 00775 # minor reason when (say) a thousand readable directories are still 00776 # left to visit. That logic is copied here. 00777 try: 00778 # Note that listdir and error are globals in this module due 00779 # to earlier import-*. 00780 names = self.listdir(top) 00781 except error, err: 00782 if (callable(onerror)): 00783 try: 00784 onerror(err) 00785 except: 00786 pass 00787 return 00788 00789 dirs, nondirs = [], [] 00790 if (names is not None): 00791 for name in names: 00792 if self.isdir(join(top, name)): 00793 dirs.append(name) 00794 else: 00795 nondirs.append(name) 00796 00797 if topdown: 00798 yield top, dirs, nondirs 00799 for name in dirs: 00800 path = join(top, name) 00801 if not self.islink(path): 00802 for x in self.walk(path, topdown, onerror): 00803 yield x 00804 if not topdown: 00805 yield top, dirs, nondirs 00806 else: 00807 print '(%s) :: Possibly no files found at "%s".' % (ObjectTypeName.objectSignature(self),top) 00808 00809 ## 00810 # Search for a folder of a specific name 00811 def searchForFolderNamed(self,fname,top='/'): 00812 for root, dirs, files in self.walk(top, topdown=True): 00813 if (fname in dirs): 00814 return self.sep.join([root,fname]) 00815 return '' 00816 00817 ## 00818 # Perform os.path.exists(). 00819 # 00820 def exists(self,pathName): 00821 return self.stat(pathName) != None 00822 00823 ## 00824 # Chmod the tree at path (Chmod recursively on a whole subtree) 00825 def chmod_tree(self, path, mode, mask): 00826 import stat 00827 def visit(arg, dirname, names): 00828 mode, mask = arg 00829 for name in names: 00830 fullname = self.sep.join([dirname, name]) 00831 if not self.islink(fullname): 00832 new_mode = (self.stat(fullname)[stat.ST_MODE] & ~mask) | mode 00833 self.chmod(fullname, new_mode) 00834 self.walk(path, visit, (mode, mask)) 00835 00836 def fileSize(self,fname): 00837 if (self.exists(fname)): 00838 st = self.stat(fname) 00839 return st.st_size 00840 return -1 00841 00842 ## 00843 # Recursively delete a directory tree. 00844 # 00845 # If ignore_errors is set, errors are ignored; otherwise, if onerror 00846 # is set, it is called to handle the error with arguments (func, 00847 # path, exc_info) where func is os.listdir, os.remove, or os.rmdir; 00848 # path is the argument to that function that caused it to fail; and 00849 # exc_info is a tuple returned by sys.exc_info(). If ignore_errors 00850 # is false and onerror is None, an exception is raised. 00851 # 00852 # 00853 def rmtree(self, path, ignore_errors=False, onerror=None): 00854 import sys, stat 00855 if ignore_errors: 00856 def onerror(*args): 00857 pass 00858 elif onerror is None: 00859 def onerror(*args): 00860 raise 00861 names = [] 00862 try: 00863 names = self.listdir(path) 00864 except os.error, err: 00865 onerror(self.listdir, path, sys.exc_info()) 00866 for name in names: 00867 fullname = self.sep.join([path, name]) 00868 try: 00869 mode = self.lstat(fullname).st_mode 00870 except os.error: 00871 mode = 0 00872 if stat.S_ISDIR(mode): 00873 self.rmtree(fullname, ignore_errors, onerror) 00874 else: 00875 try: 00876 self.remove(fullname) 00877 except os.error, err: 00878 onerror(self.remove, fullname, sys.exc_info()) 00879 try: 00880 self.rmdir(path) 00881 except os.error: 00882 onerror(self.rmdir, path, sys.exc_info()) 00883 00884 ## 00885 # Remove the tree at DIRNAME (For clearing away read-only directories) 00886 def safe_rmtree(dirname, retry=0): 00887 import os, sys, time 00888 def rmtree(dirname): 00889 self.chmod_tree(dirname, 0666, 0666) 00890 self.rmtree(dirname) 00891 00892 if not self.exists(dirname): 00893 return 00894 00895 if retry: 00896 for delay in (0.5, 1, 2, 4): 00897 try: 00898 self.rmtree(dirname) 00899 break 00900 except: 00901 time.sleep(delay) 00902 else: 00903 self.rmtree(dirname) 00904 else: 00905 self.rmtree(dirname) 00906 00907 def sftp_to_host(hostname,username,password,source,dest,isSilent=False): 00908 try: 00909 ssh = SSHConnection(hostname=hostname,username=username,password=password) 00910 except: 00911 exc_info = sys.exc_info() 00912 info_string = _utils.asMessage('\n'.join(traceback.format_exception(*exc_info))) 00913 print >>sys.stderr, info_string 00914 if (not isSilent): 00915 print 'ssh.transport = %s' % (ssh.transport) 00916 if (ssh.transport): 00917 results = [0,-1] 00918 try: 00919 if (not isSilent): 00920 print 'ssh.isdir(%s)=%s' % (dest,ssh.isdir(dest)) 00921 if (ssh.isdir(dest)): 00922 dest = ssh.sep.join([dest,os.path.basename(source)]) 00923 if (not isSilent): 00924 print 'dest=%s' % (dest) 00925 print 'ssh.exists(%s)=%s' % (dest,ssh.exists(dest)) 00926 if (ssh.exists(dest)): 00927 if (not isSilent): 00928 print 'ssh.remove(%s)' % (dest) 00929 ssh.remove(dest) 00930 if (not isSilent): 00931 print 'SFTP "%s" to host as "%s".' % (source,dest) 00932 results = ssh.put(source, dest, callback=giveXferStatus if (not isSilent) else None) 00933 except: 00934 exc_info = sys.exc_info() 00935 info_string = _utils.asMessage('\n'.join(traceback.format_exception(*exc_info))) 00936 print >>sys.stderr, info_string 00937 finally: 00938 xfer_rate_calc = lists.HashedLists2() if (results is None) else calcXferRate(results[-1]) 00939 if (not isSilent): 00940 print 'SFTP Done, %s, Closing Connection.' % (xfer_rate_calc['xfer_rate_fmt']) 00941 ssh.close() 00942 else: 00943 print >>sys.stderr, 'Unable to get a connection with the server using "%s".' % ('%s,%s,%s' % (hostname,username,password)) 00944 00945 if __name__ == "__main__": 00946 import sys 00947 print >>sys.stdout, __copyright__ 00948 print >>sys.stderr, __copyright__ 00949 00950
© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved; If you reference this document or any part of this document you must use the citation verbatim (including the link) "© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved."
Notice: This source code contained in this document is NOT open source and is NOT being distributed as open source.
122,241 lines of code and growing...