I want to upload and store some of my backups to another server via an FTP account.
This account has only read permissions (no write permissions), to prevent attackers from deleting my backups.
So I started to code the solution with full permissions (aka read + write). This how my code looks: (this code is currently working)
string file = #"C:\1.html";
FtpWebRequest ftpClient = (FtpWebRequest)FtpWebRequest.Create(new Uri(ConfigurationManager.AppSettings["FTPUrl"]) + #"/" + Path.GetFileNameWithoutExtension(file));
ftpClient.Credentials = new System.Net.NetworkCredential(ConfigurationManager.AppSettings["FtpUserName"], ConfigurationManager.AppSettings["FtpPassword"]);
ftpClient.Method = WebRequestMethods.Ftp.UploadFile;
ftpClient.UseBinary = true;
ftpClient.KeepAlive = true;
FileInfo fi = new FileInfo(file);
ftpClient.ContentLength = fi.Length;
byte[] buffer = new byte[4097];
int bytes = 0;
int total_bytes = (int)fi.Length;
System.IO.FileStream fs = fi.OpenRead();
System.IO.Stream rs = ftpClient.GetRequestStream();
while (total_bytes > 0)
{
bytes = fs.Read(buffer, 0, buffer.Length);
rs.Write(buffer, 0, bytes);
total_bytes = total_bytes - bytes;
}
fs.Close();
rs.Close();
But, when I remove the read permissions, it no longer works.
The problematic code line is:
System.IO.Stream rs = ftpClient.GetRequestStream();
And the error is:
An unhandled exception of type 'System.Net.WebException' occurred in
System.dll
Additional information: The remote server returned an error: (550)
File unavailable (e.g., file not found, no access).
Theoretically, it seems okay to upload a file without read permissions (also works with FileZilla). Practically, it's not working for me. Can someone give me a solution for this case?
Related
I have an FTP domain that I must to upload file txt to its FTP server the FTP domain looks like ftpes://domain.com, I never see the ftpes before, but when I upload by FileZilla it works success upload, but if I using my this code
FtpWebRequest ftpClient = (FtpWebRequest)FtpWebRequest.Create(FTPdestination+ i + ".txt");
ftpClient.Credentials = new System.Net.NetworkCredential(user, pass);
ftpClient.Method = System.Net.WebRequestMethods.Ftp.UploadFile;
ftpClient.UseBinary = true;
ftpClient.EnableSsl = true;
ftpClient.KeepAlive = true;
System.IO.FileInfo fi = new System.IO.FileInfo(server+dtm+"_"+i+".txt");
ftpClient.ContentLength = fi.Length;
byte[] buffer = new byte[4097];
int bytes = 0;
int total_bytes = (int)fi.Length;
System.IO.FileStream fs = fi.OpenRead();
System.IO.Stream rs = ftpClient.GetRequestStream();
while (total_bytes > 0)
{
bytes = fs.Read(buffer, 0, buffer.Length);
rs.Write(buffer, 0, bytes);
total_bytes = total_bytes - bytes;
}
fs.Close();
rs.Close();
FtpWebResponse uploadResponse = (FtpWebResponse)ftpClient.GetResponse();
uploadResponse.Close();
The error message is
URI prefix not recognized
Please help me to solve my case.
ftpes:// is not a standard protocol prefix. But it is recognized by some FTP clients to mean "Explicit FTP over TLS/SSL".
With FtpWebRequest you specify that by using standard ftp:// protocol prefix and setting EnableSsl = true (what you do already).
See also Does .NET FtpWebRequest Support both Implicit (FTPS) and explicit (FTPES)?
I need to move files from one ftp to another (currently using ftpwebrequest) both requiring authentication and have different settings (timeout, ascii, active etc). Is downloading files from one to a local server and then uploading to the other significant slower than just copying the files (if that exists even, how would you do it, renameto?). It feels like it should be faster but I'm not sure, I have no understanding of file copying or downloading.
they are all .txt or .csv and mostly around 3-10 mb each so quite a bit of data
You can copy a file from FTP-Server A to FTP-Server B using FXP. Both servers and the client have to support that feature.
Some time we need to download, upload file from FTP server. Here is some good example for FTP operation in C#.
You can use this. It will help you to make a C# program to full fill your requirements.
File Download from FTP Server
public void DownloadFile(stringHostURL, string UserName, string Password, stringSourceDirectory, string FileName, string LocalDirectory)
{
if(!File.Exists(LocalDirectory + FileName))
{
try
{
FtpWebRequestrequestFileDownload = (FtpWebRequest)WebRequest.Create(HostURL + “/” + SourceDirectory + “/” + FileName);
requestFileDownload.Credentials = new NetworkCredential(UserName, Password);
requestFileDownload.Method = WebRequestMethods.Ftp.DownloadFile;
FtpWebResponseresponseFileDownload = (FtpWebResponse)requestFileDownload.GetResponse();
StreamresponseStream = responseFileDownload.GetResponseStream();
FileStreamwriteStream = new FileStream(LocalDirectory + FileName, FileMode.Create);
intLength = 2048;
Byte[] buffer = new Byte[Length];
intbytesRead = responseStream.Read(buffer, 0, Length);
while(bytesRead > 0)
{
writeStream.Write(buffer, 0, bytesRead);
bytesRead = responseStream.Read(buffer, 0, Length);
}
responseStream.Close();
writeStream.Close();
requestFileDownload = null;
responseFileDownload = null;
}
catch(Exception ex)
{
throwex;
}
}
}
Some Good Examples
Hope it will help you.
I need to upload some DATA inside and FTP server.
Following stackoverflow posts on how to upload a FILE inside and FTP everything works.
Now i am trying to improve my upload.
Instead collecting the DATA, writing them to a FILE and then upload the file inside the FTP i want to collect the DATA and upload them without creating a local file.
To achieve this i do the following:
string uri = "ftp://" + ftpServerIp + "/" + fileToUpload.Name;
System.Net.FtpWebRequest reqFTP;
// Create FtpWebRequest object from the Uri provided
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + ftpServerIp + "/" + fileToUpload.Name));
// Provide the WebPermission Credintials
reqFTP.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
// By default KeepAlive is true, where the control connection is not closed after a command is executed.
reqFTP.KeepAlive = false;
// Specify the command to be executed.
reqFTP.Method = WebRequestMethods.Ftp.UploadFile;
// Specify the data transfer type.
reqFTP.UseBinary = true;
byte[] messageContent = Encoding.ASCII.GetBytes(message);
// Notify the server about the size of the uploaded file
reqFTP.ContentLength = messageContent.Length;
int buffLength = 2048;
// Stream to which the file to be upload is written
Stream strm = reqFTP.GetRequestStream();
// Write Content from the file stream to the FTP Upload Stream
int total_bytes = (int)messageContent.Length;
while (total_bytes > 0)
{
strm.Write(messageContent, 0, buffLength);
total_bytes = total_bytes - buffLength;
}
strm.Close();
Now what happen is the following:
i see the client connecting to the server
the file is created
no data are transferred
at some point the thread is terminated the connection is closed
if i inspect the uploaded file is empty.
the DATA i want to to transfer is a STRING TYPE, that is why i do byte[] messageContent = Encoding.ASCII.GetBytes(message);
what am i doing wrong?
moreover: if i encode date with ASCII.GetBytes, on the remote server will i have a TEXT file or a file with some Bytes?
thank you for any suggestion
One issue that I see with the code is that you are writing the same bytes to the server on each iteration:
while (total_bytes > 0)
{
strm.Write(messageContent, 0, buffLength);
total_bytes = total_bytes - buffLength;
}
You need to change the offset position by doing something like this:
while (total_bytes < messageContent.Length)
{
strm.Write(messageContent, total_bytes , bufferLength);
total_bytes += bufferLength;
}
You are trying to write more data than you have. You code writes blocks of 2048 bytes at a time, and if the data is less, you will tell the write method to try to access bytes that are outside the array, which it of course won't.
All you should need to write the data is:
Stream strm = reqFTP.GetRequestStream();
strm.Write(messageContent, 0, messageContent.Length);
strm.Close();
If you need to write the data in chunks, you need to keep track of the offset in the array:
int buffLength = 2048;
int offset = 0;
Stream strm = reqFTP.GetRequestStream();
int total_bytes = (int)messageContent.Length;
while (total_bytes > 0) {
int len = Math.Min(buffLength, total_bytes);
strm.Write(messageContent, offset, len);
total_bytes -= len;
offset += len;
}
strm.Close();
Problem: When i ftp upload only one file at a time, the files are uploaded fine, But when i use multiple Background workers to upload files to ftp server i get exception:
ex {"The remote server returned an error: (550) File unavailable
(e.g., file not found, no access)."} System.Exception
{System.Net.WebException}
And only Some of the files get uploaded. I am pretty sure the file exits at that location, infact in another run the file it was complaining about that does not exist is downloaded but the error shifts on another file.
Code Description:
In below code i am downloading a file from one ftp server and putting it on another. This code is inside a BackgroundsWorker_DoWork Method. Background Workers are being created inside a loop.
void imageDownloadWorker_DoWork(object sender, DoWorkEventArgs e)
{
string[] ftpInfo = (string[])e.Argument;
try
{
///////////////////////////Downloading///////////////////////////////////////
string uri = String.Format("ftp://{0}/{1}/images/{2}", ftpInfo[1], ftpInfo[2], ftpInfo[5]);
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(uri);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.UseBinary = true;
request.Credentials = new NetworkCredential(ftpInfo[3], ftpInfo[4]);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream ftpStream = response.GetResponseStream();
long cl = response.ContentLength;
int bufferSize = 4096;
int readCount = 0;
byte[] buffer = new byte[bufferSize];
MemoryStream memStream = new MemoryStream();
readCount = ftpStream.Read(buffer, 0, bufferSize);
while (readCount > 0)
{
memStream.Write(buffer, 0, readCount);
readCount = ftpStream.Read(buffer, 0, bufferSize);
}
response.Close();
///////////////////////////Uploading///////////////////////////////////////
string uri1 = String.Format("ftp://{0}/{1}/{2}", "127.0.0.1", string.Empty, ftpInfo[5]);
FtpWebRequest request1 = (FtpWebRequest)WebRequest.Create(uri1);
request1.Credentials = new NetworkCredential("user", "password");
request1.KeepAlive = false;
request1.Method = WebRequestMethods.Ftp.UploadFile;
request1.UseBinary = true;
request1.ContentLength = memStream.Length;
int buffLength = 4096;
byte[] buff = new byte[buffLength];
int contentLen;
// Stream to which the file to be upload is written
Stream strm = request1.GetRequestStream();
memStream.Seek(0, SeekOrigin.Begin);
contentLen = memStream.Read(buff, 0, buffLength);
// Till Stream content ends
while (contentLen != 0)
{
// Write Content from the file stream to the FTP Upload Stream
strm.Write(buff, 0, contentLen);
contentLen = memStream.Read(buff, 0, buffLength);
}
// Close the file stream and the Request Stream
strm.Close();
ftpStream.Close();
memStream.Close();
}
catch(Exception ex)
{
MessageBox.Show("While Downloading File " + ftpInfo[5] + " " + ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
e.Result = null;
return;
}
Related Thread
Edit:
In File Zilla Server there is an option General Settings>Perfomance Settings>Number of Threads i have set that to 20 it didnt make any difference.
There maybe nothing wrong with your code. That error is a Permissions error.
Complete stab in the dark, but does the upload target server have a connection per IP limit? If so you may be falling foul of this by exceeding the concurrent connection limit from a single IP address.
I'm trying to write a program which will download a few files from and FTP, zip them up then upload them again to the same FTP location.
I have got it to attempt to download a file. If it fails, it will try again.
If NO errors occur, all files download and upload file.
If any errors occur when downloading, it will download them on the re-attempt, but fail then to upload.
I think the problems are down to not correctly closing a connection, but I can't for the life of me figure it out.
Here's my code; I've added where it fails:
Upload:
FileInfo fileInf = new FileInfo("directory" + zip + ".zip");
string uri = "ftp://address" + fileInf.Name;
FtpWebRequest reqFTP2;
reqFTP2 = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://address" + fileInf.Name));
reqFTP2.Credentials = new NetworkCredential("username", "password");
reqFTP2.KeepAlive = true;
reqFTP2.Method = WebRequestMethods.Ftp.UploadFile;
reqFTP2.UseBinary = true;
reqFTP2.ContentLength = fileInf.Length;
int buffLength = 2048;
byte[] buff = new byte[buffLength];
int contentLen;
FileStream fs = fileInf.OpenRead();
try
{
Stream strm = reqFTP2.GetRequestStream(); //FAILS HERE
contentLen = fs.Read(buff, 0, buffLength);
while (contentLen != 0)
{
strm.Write(buff, 0, contentLen);
contentLen = fs.Read(buff, 0, buffLength);
}
strm.Close();
fs.Close();
}
catch (Exception ex)
{
}
Download:
int errorOccured = 0;
while (errorOccured < 1)
{
FileStream outputStream = new FileStream("directory\\" + file, FileMode.Create);
FtpWebRequest reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://address/" + file));
reqFTP.Credentials = new NetworkCredential("username", "password");
try
{
reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
reqFTP.UseBinary = true;
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
Stream ftpStream = response.GetResponseStream();
long cl = response.ContentLength;
int bufferSize = 2048;
int readCount;
byte[] buffer = new byte[bufferSize];
readCount = ftpStream.Read(buffer, 0, bufferSize);
while (readCount > 0)
{
outputStream.Write(buffer, 0, readCount);
readCount = ftpStream.Read(buffer, 0, bufferSize);
}
ftpStream.Close();
outputStream.Close();
response.Close();
errorOccured++;
}
catch (Exception er)
{
outputStream.Close();
}
The error 504 – Command not implemented for that parameter.
implies that some option you are using in there is not implemented by the target FTP server. I think that your code is resulting in a bizarre request, suggestion would be to look at the FTP chatter that your process creates on the server side. For exmaple, does the server support PASV mode? FTP protocol in ACTV mode (the default behavior) is always a pain because it explicitly causes the client to open a "file receive port" on port 20 and listen. While most servers support PASV mode transfers, it can become a pain if you don't put them in the PASV mode explicitly. So look at the chatter, see if the server is in PASV mode, and if you still have trouble, look at the chatter to see if there are "Extra Spaces" passed on during FTP negotiation. FTP is quite dinky and there can be several pitfalls. :-)
For starters, wrap your streams in using blocks so that they are disposed appropriately.
See MSDN for more details.