private void SendError(SCPChannelStream stream, string message) { message = "Poderosa: " + message.Replace('\n', ' '); byte[] messageBytes = _encoding.GetBytes(message); byte[] data = new byte[messageBytes.Length + 2]; data[0] = 1; Buffer.BlockCopy(messageBytes, 0, data, 1, messageBytes.Length); data[messageBytes.Length + 1] = LF; stream.Write(data); }
private bool CreateDirectory(SCPChannelStream stream, string directoryPath, SCPModTime modTime, Cancellation cancellation, SCPFileTransferProgressDelegate progressDelegate) { if (cancellation != null && cancellation.IsRequested) { return(false); // cancel } string directoryName = Path.GetFileName(directoryPath); if (progressDelegate != null) { progressDelegate(directoryPath, directoryName, SCPFileTransferStatus.CreateDirectory, 0, 0); } if (!Directory.Exists(directoryPath)) // skip if already exists { try { Directory.CreateDirectory(directoryPath); } catch (Exception e) { SendError(stream, "failed to create a directory"); throw new SCPClientException("Failed to create a directory: " + directoryPath, e); } } if (modTime != null) { try { Directory.SetLastWriteTimeUtc(directoryPath, modTime.MTime); Directory.SetLastAccessTimeUtc(directoryPath, modTime.ATime); } catch (Exception e) { SendError(stream, "failed to modify time of a directory"); throw new SCPClientException("Failed to modify time of a directory: " + directoryPath, e); } } stream.Write(ZERO); if (progressDelegate != null) { progressDelegate(directoryPath, directoryName, SCPFileTransferStatus.DirectoryCreated, 0, 0); } return(true); }
private void SendModTime(SCPChannelStream stream, DateTime mtime, DateTime atime) { DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0); long mtimeSec = (mtime.Ticks - epoch.Ticks) / 10000000L; long mtimeUSec = ((mtime.Ticks - epoch.Ticks) % 10000000L) / 10L; long atimeSec = (atime.Ticks - epoch.Ticks) / 10000000L; long atimeUSec = ((atime.Ticks - epoch.Ticks) % 10000000L) / 10L; string line = new StringBuilder() .Append('T') .Append(mtimeSec.ToString(NumberFormatInfo.InvariantInfo)) .Append(' ') .Append(mtimeUSec.ToString(NumberFormatInfo.InvariantInfo)) .Append(' ') .Append(atimeSec.ToString(NumberFormatInfo.InvariantInfo)) .Append(' ') .Append(atimeUSec.ToString(NumberFormatInfo.InvariantInfo)) .Append('\n') .ToString(); stream.Write(_encoding.GetBytes(line)); CheckResponse(stream); }
private bool CreateFile(SCPChannelStream stream, string filePath, SCPEntry entry, SCPModTime modTime, Cancellation cancellation, SCPFileTransferProgressDelegate progressDelegate) { string fileName = Path.GetFileName(filePath); ulong transmitted = 0; if (progressDelegate != null) { progressDelegate(filePath, fileName, SCPFileTransferStatus.Open, (ulong)entry.FileSize, transmitted); } FileStream fileStream; try { fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Read); } catch (Exception e) { SendError(stream, "failed to create a file"); throw new SCPClientException("Failed to create a file: " + filePath, e); } stream.Write(ZERO); using (fileStream) { byte[] buff = new byte[FILE_TRANSFER_BLOCK_SIZE]; long remain = entry.FileSize; try { while (remain > 0) { if (cancellation != null && cancellation.IsRequested) { if (progressDelegate != null) { progressDelegate(filePath, fileName, SCPFileTransferStatus.CompletedAbort, (ulong)entry.FileSize, transmitted); } return(false); // cancel } int maxLength = (int)Math.Min((long)buff.Length, remain); int readLength = stream.Read(buff, maxLength, _protocolTimeout); fileStream.Write(buff, 0, readLength); remain -= readLength; transmitted += (ulong)readLength; if (progressDelegate != null) { progressDelegate(filePath, fileName, SCPFileTransferStatus.Transmitting, (ulong)entry.FileSize, transmitted); } } } catch (Exception e) { SendError(stream, "failed to write to a file"); throw new SCPClientException("Failed to write to a file: " + filePath, e); } } if (modTime != null) { try { File.SetLastWriteTimeUtc(filePath, modTime.MTime); File.SetLastAccessTimeUtc(filePath, modTime.ATime); } catch (Exception e) { SendError(stream, "failed to modify time of a file"); throw new SCPClientException("Failed to modify time of a file: " + filePath, e); } } CheckResponse(stream); stream.Write(ZERO); if (progressDelegate != null) { progressDelegate(filePath, fileName, SCPFileTransferStatus.CompletedSuccess, (ulong)entry.FileSize, transmitted); } return(true); }
/// <summary> /// Download files or directories. /// </summary> /// <remarks> /// <para>Unfortunately, Granados sends a command line in the ASCII encoding. /// So the "remotePath" must be an ASCII text.</para> /// </remarks> /// <param name="remotePath">Remote path (Unix path)</param> /// <param name="localPath">Local path (Windows' path)</param> /// <param name="recursive">Specifies recursive mode</param> /// <param name="preserveTime">Specifies to preserve time of the directory or file.</param> /// <param name="cancellation">An object to request the cancellation. Set null if the cancellation is not needed.</param> /// <param name="progressDelegate">Delegate to notify progress. Set null if notification is not needed.</param> public void Download(string remotePath, string localPath, bool recursive, bool preserveTime, Cancellation cancellation, SCPFileTransferProgressDelegate progressDelegate) { if (!IsAscii(remotePath)) { throw new SCPClientException("Remote path must consist of ASCII characters."); } string absLocalPath = Path.GetFullPath(localPath); string command = "scp -f "; if (recursive) { command += "-r "; } if (preserveTime) { command += "-p "; } command += EscapeUnixPath(remotePath); string localBasePath = null; // local directory to store SCPModTime modTime = null; Stack <string> localBasePathStack = new Stack <string>(); using (SCPChannelStream stream = new SCPChannelStream()) { stream.Open(_connection, command, _protocolTimeout); stream.Write(ZERO); while (true) { byte[] lineBytes = stream.ReadUntil(LF, _protocolTimeout); if (lineBytes[0] == 1 || lineBytes[0] == 2) { // Warning or Error string message = _encoding.GetString(lineBytes, 1, lineBytes.Length - 2); throw new SCPClientException(message); } if (lineBytes[0] == 0x43 /*'C'*/ || lineBytes[0] == 0x44 /*'D'*/) { SCPEntry entry; try { entry = ParseEntry(lineBytes); } catch (Exception e) { SendError(stream, e.Message); throw; } if (entry.IsDirectory) { string directoryPath = DeterminePathToCreate(localBasePath, absLocalPath, entry); bool continued = CreateDirectory(stream, directoryPath, modTime, cancellation, progressDelegate); if (!continued) { break; } modTime = null; localBasePathStack.Push(localBasePath); localBasePath = directoryPath; } else { string filePath = DeterminePathToCreate(localBasePath, absLocalPath, entry); bool continued = CreateFile(stream, filePath, entry, modTime, cancellation, progressDelegate); if (!continued) { break; } modTime = null; if (!recursive) { break; } } } else if (lineBytes[0] == 0x54 /*'T'*/) { if (preserveTime) { try { modTime = ParseModTime(lineBytes); } catch (Exception e) { SendError(stream, e.Message); throw; } } stream.Write(ZERO); } else if (lineBytes[0] == 0x45 /*'E'*/) { if (localBasePathStack.Count > 0) { localBasePath = localBasePathStack.Pop(); if (localBasePath == null) { break; } } stream.Write(ZERO); } else { SendError(stream, "Invalid control"); throw new SCPClientException("Invalid control"); } } } }
private bool UploadDirectory(string fullPath, SCPChannelStream stream, bool preserveTime, Cancellation cancellation, SCPFileTransferProgressDelegate progressDelegate) { Debug.Assert(fullPath != null); if (cancellation != null && cancellation.IsRequested) { return(false); // cancel } string directoryName = Path.GetFileName(fullPath); if (directoryName != null) // not a root directory { if (progressDelegate != null) { progressDelegate(fullPath, directoryName, SCPFileTransferStatus.CreateDirectory, 0, 0); } if (preserveTime) { SendModTime( stream, Directory.GetLastWriteTimeUtc(fullPath), Directory.GetLastAccessTimeUtc(fullPath) ); } string line = new StringBuilder() .Append('D') .Append(GetPermissionsText(true)) .Append(" 0 ") .Append(directoryName) .Append('\n') .ToString(); stream.Write(_encoding.GetBytes(line)); CheckResponse(stream); if (progressDelegate != null) { progressDelegate(fullPath, directoryName, SCPFileTransferStatus.DirectoryCreated, 0, 0); } } foreach (String fullSubDirPath in Directory.GetDirectories(fullPath)) { bool continued = UploadDirectory(fullSubDirPath, stream, preserveTime, cancellation, progressDelegate); if (!continued) { return(false); // cancel } } foreach (String fullFilePath in Directory.GetFiles(fullPath)) { bool continued = UploadFile(fullFilePath, stream, preserveTime, cancellation, progressDelegate); if (!continued) { return(false); // cancel } } if (directoryName != null) // not a root directory { string line = "E\n"; stream.Write(_encoding.GetBytes(line)); CheckResponse(stream); } return(true); // continue }
private bool UploadFile(string fullPath, SCPChannelStream stream, bool preserveTime, Cancellation cancellation, SCPFileTransferProgressDelegate progressDelegate) { Debug.Assert(fullPath != null); string fileName = Path.GetFileName(fullPath); FileInfo fileInfo = new FileInfo(fullPath); long fileSize = fileInfo.Length; ulong transmitted = 0; if (progressDelegate != null) { progressDelegate(fullPath, fileName, SCPFileTransferStatus.Open, (ulong)fileSize, transmitted); } if (preserveTime) { SendModTime( stream, File.GetLastWriteTimeUtc(fullPath), File.GetLastAccessTimeUtc(fullPath) ); } using (FileStream fileStream = new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { string line = new StringBuilder() .Append('C') .Append(GetPermissionsText(false)) .Append(' ') .Append(fileSize.ToString(NumberFormatInfo.InvariantInfo)) .Append(' ') .Append(fileName) .Append('\n') .ToString(); stream.Write(_encoding.GetBytes(line)); CheckResponse(stream); byte[] buff = new byte[stream.GetPreferredDatagramSize()]; long remain = fileSize; while (remain > 0) { if (cancellation != null && cancellation.IsRequested) { if (progressDelegate != null) { progressDelegate(fullPath, fileName, SCPFileTransferStatus.CompletedAbort, (ulong)fileSize, transmitted); } return(false); // cancel } int readLength = fileStream.Read(buff, 0, buff.Length); if (readLength <= 0) { break; } if (readLength > remain) { readLength = (int)remain; } stream.Write(buff, readLength); remain -= readLength; transmitted += (ulong)readLength; if (progressDelegate != null) { progressDelegate(fullPath, fileName, SCPFileTransferStatus.Transmitting, (ulong)fileSize, transmitted); } } stream.Write(ZERO); CheckResponse(stream); } if (progressDelegate != null) { progressDelegate(fullPath, fileName, SCPFileTransferStatus.CompletedSuccess, (ulong)fileSize, transmitted); } return(true); }
private bool UploadDirectory(string fullPath, SCPChannelStream stream, bool preserveTime, Cancellation cancellation, SCPFileTransferProgressDelegate progressDelegate) { Debug.Assert(fullPath != null); if (cancellation != null && cancellation.IsRequested) { return false; // cancel } string directoryName = Path.GetFileName(fullPath); if (directoryName != null) { // not a root directory if (progressDelegate != null) progressDelegate(fullPath, directoryName, SCPFileTransferStatus.CreateDirectory, 0, 0); if (preserveTime) { SendModTime( stream, Directory.GetLastWriteTimeUtc(fullPath), Directory.GetLastAccessTimeUtc(fullPath) ); } string line = new StringBuilder() .Append('D') .Append(GetPermissionsText(true)) .Append(" 0 ") .Append(directoryName) .Append('\n') .ToString(); stream.Write(_encoding.GetBytes(line)); CheckResponse(stream); if (progressDelegate != null) progressDelegate(fullPath, directoryName, SCPFileTransferStatus.DirectoryCreated, 0, 0); } foreach (String fullSubDirPath in Directory.GetDirectories(fullPath)) { bool continued = UploadDirectory(fullSubDirPath, stream, preserveTime, cancellation, progressDelegate); if (!continued) return false; // cancel } foreach (String fullFilePath in Directory.GetFiles(fullPath)) { bool continued = UploadFile(fullFilePath, stream, preserveTime, cancellation, progressDelegate); if (!continued) return false; // cancel } if (directoryName != null) { // not a root directory string line = "E\n"; stream.Write(_encoding.GetBytes(line)); CheckResponse(stream); } return true; // continue }
private bool UploadFile(string fullPath, SCPChannelStream stream, bool preserveTime, Cancellation cancellation, SCPFileTransferProgressDelegate progressDelegate) { Debug.Assert(fullPath != null); string fileName = Path.GetFileName(fullPath); FileInfo fileInfo = new FileInfo(fullPath); long fileSize = fileInfo.Length; ulong transmitted = 0; if (progressDelegate != null) progressDelegate(fullPath, fileName, SCPFileTransferStatus.Open, (ulong)fileSize, transmitted); if (preserveTime) { SendModTime( stream, File.GetLastWriteTimeUtc(fullPath), File.GetLastAccessTimeUtc(fullPath) ); } using (FileStream fileStream = new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { string line = new StringBuilder() .Append('C') .Append(GetPermissionsText(false)) .Append(' ') .Append(fileSize.ToString(NumberFormatInfo.InvariantInfo)) .Append(' ') .Append(fileName) .Append('\n') .ToString(); stream.Write(_encoding.GetBytes(line)); CheckResponse(stream); byte[] buff = new byte[stream.GetPreferredDatagramSize()]; long remain = fileSize; while (remain > 0) { if (cancellation != null && cancellation.IsRequested) { if (progressDelegate != null) progressDelegate(fullPath, fileName, SCPFileTransferStatus.CompletedAbort, (ulong)fileSize, transmitted); return false; // cancel } int readLength = fileStream.Read(buff, 0, buff.Length); if (readLength <= 0) break; if (readLength > remain) readLength = (int)remain; stream.Write(buff, readLength); remain -= readLength; transmitted += (ulong)readLength; if (progressDelegate != null) progressDelegate(fullPath, fileName, SCPFileTransferStatus.Transmitting, (ulong)fileSize, transmitted); } stream.Write(ZERO); CheckResponse(stream); } if (progressDelegate != null) progressDelegate(fullPath, fileName, SCPFileTransferStatus.CompletedSuccess, (ulong)fileSize, transmitted); return true; }
private bool CreateFile(SCPChannelStream stream, string filePath, SCPEntry entry, SCPModTime modTime, Cancellation cancellation, SCPFileTransferProgressDelegate progressDelegate) { string fileName = Path.GetFileName(filePath); ulong transmitted = 0; if (progressDelegate != null) progressDelegate(filePath, fileName, SCPFileTransferStatus.Open, (ulong)entry.FileSize, transmitted); FileStream fileStream; try { fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Read); } catch (Exception e) { SendError(stream, "failed to create a file"); throw new SCPClientException("Failed to create a file: " + filePath, e); } stream.Write(ZERO); using (fileStream) { byte[] buff = new byte[FILE_TRANSFER_BLOCK_SIZE]; long remain = entry.FileSize; try { while (remain > 0) { if (cancellation != null && cancellation.IsRequested) { if (progressDelegate != null) progressDelegate(filePath, fileName, SCPFileTransferStatus.CompletedAbort, (ulong)entry.FileSize, transmitted); return false; // cancel } int maxLength = (int)Math.Min((long)buff.Length, remain); int readLength = stream.Read(buff, maxLength, _protocolTimeout); fileStream.Write(buff, 0, readLength); remain -= readLength; transmitted += (ulong)readLength; if (progressDelegate != null) progressDelegate(filePath, fileName, SCPFileTransferStatus.Transmitting, (ulong)entry.FileSize, transmitted); } } catch (Exception e) { SendError(stream, "failed to write to a file"); throw new SCPClientException("Failed to write to a file: " + filePath, e); } } if (modTime != null) { try { File.SetLastWriteTimeUtc(filePath, modTime.MTime); File.SetLastAccessTimeUtc(filePath, modTime.ATime); } catch (Exception e) { SendError(stream, "failed to modify time of a file"); throw new SCPClientException("Failed to modify time of a file: " + filePath, e); } } CheckResponse(stream); stream.Write(ZERO); if (progressDelegate != null) progressDelegate(filePath, fileName, SCPFileTransferStatus.CompletedSuccess, (ulong)entry.FileSize, transmitted); return true; }
private bool CreateDirectory(SCPChannelStream stream, string directoryPath, SCPModTime modTime, Cancellation cancellation, SCPFileTransferProgressDelegate progressDelegate) { if (cancellation != null && cancellation.IsRequested) { return false; // cancel } string directoryName = Path.GetFileName(directoryPath); if (progressDelegate != null) progressDelegate(directoryPath, directoryName, SCPFileTransferStatus.CreateDirectory, 0, 0); if (!Directory.Exists(directoryPath)) { // skip if already exists try { Directory.CreateDirectory(directoryPath); } catch (Exception e) { SendError(stream, "failed to create a directory"); throw new SCPClientException("Failed to create a directory: " + directoryPath, e); } } if (modTime != null) { try { Directory.SetLastWriteTimeUtc(directoryPath, modTime.MTime); Directory.SetLastAccessTimeUtc(directoryPath, modTime.ATime); } catch (Exception e) { SendError(stream, "failed to modify time of a directory"); throw new SCPClientException("Failed to modify time of a directory: " + directoryPath, e); } } stream.Write(ZERO); if (progressDelegate != null) progressDelegate(directoryPath, directoryName, SCPFileTransferStatus.DirectoryCreated, 0, 0); return true; }
/// <summary> /// Download files or directories. /// </summary> /// <remarks> /// <para>Unfortunately, Granados sends a command line in the ASCII encoding. /// So the "remotePath" must be an ASCII text.</para> /// </remarks> /// <param name="remotePath">Remote path (Unix path)</param> /// <param name="localPath">Local path (Windows' path)</param> /// <param name="recursive">Specifies recursive mode</param> /// <param name="preserveTime">Specifies to preserve time of the directory or file.</param> /// <param name="cancellation">An object to request the cancellation. Set null if the cancellation is not needed.</param> /// <param name="progressDelegate">Delegate to notify progress. Set null if notification is not needed.</param> public void Download(string remotePath, string localPath, bool recursive, bool preserveTime, Cancellation cancellation, SCPFileTransferProgressDelegate progressDelegate) { if (!IsAscii(remotePath)) throw new SCPClientException("Remote path must consist of ASCII characters."); string absLocalPath = Path.GetFullPath(localPath); string command = "scp -f "; if (recursive) command += "-r "; if (preserveTime) command += "-p "; command += EscapeUnixPath(remotePath); string localBasePath = null; // local directory to store SCPModTime modTime = null; Stack<string> localBasePathStack = new Stack<string>(); using (SCPChannelStream stream = new SCPChannelStream()) { stream.Open(_connection, command, _protocolTimeout); stream.Write(ZERO); while (true) { byte[] lineBytes = stream.ReadUntil(LF, _protocolTimeout); if (lineBytes[0] == 1 || lineBytes[0] == 2) { // Warning or Error string message = _encoding.GetString(lineBytes, 1, lineBytes.Length - 2); throw new SCPClientException(message); } if (lineBytes[0] == 0x43 /*'C'*/ || lineBytes[0] == 0x44 /*'D'*/) { SCPEntry entry; try { entry = ParseEntry(lineBytes); } catch (Exception e) { SendError(stream, e.Message); throw; } if (entry.IsDirectory) { string directoryPath = DeterminePathToCreate(localBasePath, absLocalPath, entry); bool continued = CreateDirectory(stream, directoryPath, modTime, cancellation, progressDelegate); if (!continued) break; modTime = null; localBasePathStack.Push(localBasePath); localBasePath = directoryPath; } else { string filePath = DeterminePathToCreate(localBasePath, absLocalPath, entry); bool continued = CreateFile(stream, filePath, entry, modTime, cancellation, progressDelegate); if (!continued) break; modTime = null; if (!recursive) break; } } else if (lineBytes[0] == 0x54 /*'T'*/) { if (preserveTime) { try { modTime = ParseModTime(lineBytes); } catch (Exception e) { SendError(stream, e.Message); throw; } } stream.Write(ZERO); } else if (lineBytes[0] == 0x45 /*'E'*/) { if (localBasePathStack.Count > 0) { localBasePath = localBasePathStack.Pop(); if (localBasePath == null) break; } stream.Write(ZERO); } else { SendError(stream, "Invalid control"); throw new SCPClientException("Invalid control"); } } } }