def recv_file(i, o, e, progress, target_dir, command, preserve, times, check_hash): # TODO: add regex check on the command format # ignore the '\n' at the end mode, size, path = command[1:-1].split(" ", 2) size = int(size) mode = int(mode, 8) if os.path.isdir(target_dir): file_path = os.path.join(target_dir, path) else: file_path = target_dir seek = 0 if check_hash: # command: hash check if os.path.exists(file_path): file_size = os.stat(file_path).st_size hash_str = _calculate_hash(file_path, file_size) else: file_size = 0 hash_str = "0" * 40 i.write("H{0:40s} {1:d}\n".format(hash_str, file_size)) i.flush() ret = o.read(1) if ret != "\0": e.write(o.readline()) return error.E_UNK # wait for H command command = o.readline() if len(command) == 0 or command[0] != "H": i.write("\2") i.write(error.errstr(error.E_UNK)) i.flush() return error.E_UNK hash_str, seek = command[1:-1].split(" ", 1) seek = int(seek) if len(hash_str) != 40 or seek < 0: i.write("\2") i.write(error.errstr(error.E_FMT)) i.flush() return error.E_FMT i.write("\0") i.flush() _recv_file_data(o, progress, file_path, size, seek) os.chmod(file_path, mode) if preserve: os.utime(file_path, times) ret = o.read(1) if ret != "\0": i.write("\2") i.write(error.errstr(error.E_TFR)) i.flush() return error.E_TFR else: i.write("\0") i.flush() return error.E_OK
def recv(i, o, e, progress, dir_path, preserve, check_hash): try: if not os.path.exists(os.path.dirname(dir_path)): i.write("\2") i.write(error.errstr(error.E_MIS)) i.flush() return error.E_MIS else: i.write("\0") i.flush() while True: ret = recv_file_dir_or_end(i, o, e, progress, dir_path, preserve, check_hash) if ret == error.E_END: return error.E_OK if ret != error.E_OK: return ret except socket.error as socket_ex: # opposite side closed prematurely e.write(str(socket_ex) + "\n") ret = o.read(1) if len(ret) > 0 and ret != "\0": e.write(o.readline()) e.flush() return error.E_TFR except Exception as ex: i.write("\2") i.write(str(ex) + "\n") i.flush() return error.E_TFR
def recv_file_dir_or_end(i, o, e, progress, target_dir, preserve, check_hash): command = o.readline() if len(command) == 0: return error.E_END # end of transfer ? if command[0] == "E": i.write("\0") i.flush() return error.E_END # end of directory times = None if preserve: if command[0] == "T": times = command[1:-1].split(" ", 3) if len(times) != 4: i.write("\2") i.write(error.errstr(error.E_UNK)) i.flush() return error.E_UNK # ready tuple for utime (atime, mtime) times = (int(times[2]), int(times[0])) i.write("\0") i.flush() command = o.readline() if len(command) == 0: # should never happen i.write("\2") i.write(error.errstr(error.E_UNK)) i.flush() return error.E_UNK else: i.write("\2") i.write(error.errstr(error.E_UNK)) i.flush() return error.E_UNK ret = error.E_UNK if command[0] == "C": i.write("\0") i.flush() ret = recv_file(i, o, e, progress, target_dir, command, preserve, times, check_hash) elif command[0] == "D": i.write("\0") i.flush() ret = recv_dir(i, o, e, progress, target_dir, command, preserve, times, check_hash) else: i.write("\2") i.write(error.errstr(ret)) i.flush() return ret
def send_file(i, o, e, progress, file_path, preserve, check_hash): stat = os.stat(file_path) # command: touch if preserve: i.write("T{0:d} 0 {1:d} 0\n".format(stat.st_mtime, stat.st_atime)) i.flush() ret = o.read(1) if ret != "\0": e.write(o.readline()) return error.E_UNK mode = stat.st_mode & 0x1FF # command: sending file i.write("C{0:0=4o} {1:d} {2:s}\n".format(mode, stat.st_size, os.path.basename(file_path))) i.flush() ret = o.read(1) if ret != "\0": e.write(o.readline()) return error.E_UNK seek = 0 if check_hash: # wait for H command # format: H<hash> <size> command = o.readline() if len(command) == 0 or command[0] != "H": i.write("\2") i.write(error.errstr(error.E_UNK)) i.flush() return error.E_UNK hash_str, file_size = command[1:-1].split(" ", 1) file_size = int(file_size) if len(hash_str) != 40 or file_size < 0: i.write("\2") i.write(error.errstr(error.E_FMT)) i.flush() return error.E_FMT i.write("\0") i.flush() if file_size > 0 and file_size <= stat.st_size: # part of the file might already be at the destination # check if the parts are the same local_hash = _calculate_hash(file_path, file_size) if hash_str == local_hash: seek = file_size # command: hash ack # return 0 hash and seek value i.write("H{0:40s} {1:d}\n".format("0" * 40, seek)) i.flush() ret = o.read(1) if ret != "\0": e.write(o.readline()) return error.E_UNK _send_file_data(i, progress, file_path, stat.st_size, seek) # data transfer end i.write("\0") i.flush() ret = o.read(1) if ret != "\0": e.write(o.readline()) return error.E_TFR return error.E_OK