You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

520 lines
13 KiB

// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
Merge apt--authentication--0 Patches applied: * apt@arch.ubuntu.com/apt--experimental--0.6--base-0 tag of apt@arch.ubuntu.com/apt--MAIN--0--patch-1190 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-1 Creation of branch v0_6 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-2 Creation of branch v0_6 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-3 Creation of branch v0_6 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-4 Creation of branch v0_6 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-5 Creation of branch v0_6 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-6 Creation of branch v0_6 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-7 Merge working copy of v0.6 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-8 0.6.0 is headed for experimental, not unstable * apt@arch.ubuntu.com/apt--experimental--0.6--patch-9 Date * apt@arch.ubuntu.com/apt--experimental--0.6--patch-10 Update LIB_APT_PKG_MAJOR * apt@arch.ubuntu.com/apt--experimental--0.6--patch-11 - Fix a heap corruption bug in pkgSrcRecords::pkgSrcRec... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-12 Resynch * apt@arch.ubuntu.com/apt--experimental--0.6--patch-13 * Merge apt 0.5.17 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-14 * Rearrange Release file authentication code to be more... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-15 * Convert distribution "../project/experimental" to "ex... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-16 Merge 1.11 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-17 Merge 1.7 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-18 Merge 1.10 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-19 * Make a number of Release file errors into warnings; f... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-20 * Add space between package names when multiple unauthe... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-21 * Provide apt-key with a secret keyring and a trustdb, ... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-22 * Fix typo in apt-key(8) (standard input is '-', not '/') * apt@arch.ubuntu.com/apt--experimental--0.6--patch-23 0.6.2 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-24 Resynch * apt@arch.ubuntu.com/apt--experimental--0.6--patch-25 * Fix MetaIndexURI for flat ("foo/") sources * apt@arch.ubuntu.com/apt--experimental--0.6--patch-26 0.6.3 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-27 * Use the top-level Release file in LoadReleaseInfo, ra... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-28 0.6.4 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-29 Clarify * apt@arch.ubuntu.com/apt--experimental--0.6--patch-30 * Move the authentication check into a separate functio... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-31 * Fix display of unauthenticated packages when they are... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-32 * Move the authentication check into a separate functio... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-33 * Restore the ugly hack I removed from indexRecords::Lo... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-34 0.6.6 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-35 * Forgot to revert part of the changes to tagfile in 0.... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-36 * Add a config option and corresponding command line option * apt@arch.ubuntu.com/apt--experimental--0.6--patch-37 0.6.8 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-38 hopefully avoid more segfaults * apt@arch.ubuntu.com/apt--experimental--0.6--patch-39 XXX * apt@arch.ubuntu.com/apt--experimental--0.6--patch-40 * Another tagfile workaround * apt@arch.ubuntu.com/apt--experimental--0.6--patch-41 * Use "Codename" (woody, sarge, etc.) to supply the val... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-42 * Support IMS requests of Release.gpg and Release * apt@arch.ubuntu.com/apt--experimental--0.6--patch-43 * Have pkgAcquireIndex calculate an MD5 sum if one is n... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-44 * Merge 0.5.18 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-45 apt (0.6.13) experimental; urgency=low * apt@arch.ubuntu.com/apt--experimental--0.6--patch-46 0.6.13 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-47 Merge 0.5.20 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-48 The source list works a bit differently in 0.6; fix the... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-49 * s/Debug::Acquire::gpg/&v/ * apt@arch.ubuntu.com/apt--experimental--0.6--patch-50 * Honor the [vendor] syntax in sources.list again (thou... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-51 * Don't ship vendors.list(5) since it isn't used yet * apt@arch.ubuntu.com/apt--experimental--0.6--patch-52 * Revert change from 0.6.10; it was right in the first ... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-53 * Fix some cases where the .gpg file could be left in p... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-54 Print a warning if gnupg is not installed * apt@arch.ubuntu.com/apt--experimental--0.6--patch-55 * Handle more IMS stuff correctly * apt@arch.ubuntu.com/apt--experimental--0.6--patch-56 0.6.17 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-57 * Merge 0.5.21 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-58 * Add new Debian Archive Automatic Signing Key to the d... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-59 0.6.18 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-60 * Merge 0.5.22 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-61 * Convert apt-key(8) to docbook XML * apt@arch.ubuntu.com/apt--experimental--0.6--patch-62 Merge 0.5.23 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-63 Remove bogus partial 0.5.22 changelog entry * apt@arch.ubuntu.com/apt--experimental--0.6--patch-64 Make the auth warning a bit less redundant * apt@arch.ubuntu.com/apt--experimental--0.6--patch-65 * Merge 0.5.24 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-66 * Make the unauthenticated packages prompt more intuiti... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-67 Merge 0.5.25 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-68 * Remove obsolete pkgIterator::TargetVer() (Closes: #230159) * apt@arch.ubuntu.com/apt--experimental--0.6--patch-69 * Reverse test in CheckAuth to match new prompt (Closes... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-70 Update version * apt@arch.ubuntu.com/apt--experimental--0.6--patch-71 Fix backwards sense of CheckAuth prompt * apt@arch.ubuntu.com/apt--experimental--0.6--patch-72 0.6.24 * apt@arch.ubuntu.com/apt--experimental--0.6--patch-73 Close bug * apt@arch.ubuntu.com/apt--experimental--0.6--patch-74 * Fix handling of two-part sources for sources.list deb... * apt@arch.ubuntu.com/apt--experimental--0.6--patch-75 0.6.25 * apt@packages.debian.org/apt--authentication--0--base-0 tag of apt@arch.ubuntu.com/apt--experimental--0.6--patch-75 * apt@packages.debian.org/apt--authentication--0--patch-1 Michael Vogt's merge of apt--experimental--0 onto apt--main--0 * apt@packages.debian.org/apt--authentication--0--patch-2 Merge from apt--main--0 * apt@packages.debian.org/apt--authentication--0--patch-3 Merge from main * apt@packages.debian.org/apt--authentication--0--patch-4 Merge from main * apt@packages.debian.org/apt--authentication--0--patch-5 Update version number in configure.in * apt@packages.debian.org/apt--authentication--0--patch-6 Merge from main * apt@packages.debian.org/apt--authentication--0--patch-7 Merge from main * apt@packages.debian.org/apt--authentication--0--patch-8 Merge from mvo's branch * apt@packages.debian.org/apt--authentication--0--patch-9 Merge from mvo's tree * apt@packages.debian.org/apt--authentication--0--patch-10 Merge from mvo * apt@packages.debian.org/apt--authentication--0--patch-11 Fix permissions AGAIN * michael.vogt@canonical.com--2004--laptop/apt--authentication-mvo--0--base-0 tag of michael.vogt@canonical.com--2004/apt--authentication-mvo--0--patch-12 * michael.vogt@canonical.com--2004--laptop/apt--authentication-mvo--0--patch-1 * star-merged matt's changes (bz2 support for data-members in debs) * michael.vogt@canonical.com--2004/apt--authentication-mvo--0--patch-1 tag of apt@packages.debian.org/apt--authentication--0--base-0 * michael.vogt@canonical.com--2004/apt--authentication-mvo--0--patch-2 merged "tla apply-delta -A foo@ apt@arch.ubuntu.com/apt--MAIN--0--patch-1190 apt@arch.ubuntu.com/apt--MAIN--0--patch-1343" and cleaned up conflicts * michael.vogt@canonical.com--2004/apt--authentication-mvo--0--patch-3 * missing bits from the merge added * michael.vogt@canonical.com--2004/apt--authentication-mvo--0--patch-4 * star-merged with apt@packages.debian.org/apt--main--0 * michael.vogt@canonical.com--2004/apt--authentication-mvo--0--patch-5 * tree-synced to the apt--authentication tree * michael.vogt@canonical.com--2004/apt--authentication-mvo--0--patch-6 * use the ubuntu-key in this version * michael.vogt@canonical.com--2004/apt--authentication-mvo--0--patch-7 * imported the patches from mdz * michael.vogt@canonical.com--2004/apt--authentication-mvo--0--patch-8 * apt-get update --print-uris works now as before (fallback to 0.5.x behaviour) * michael.vogt@canonical.com--2004/apt--authentication-mvo--0--patch-9 * fix for the "if any source unauthenticated, all other sources are unauthenticated too" problem * michael.vogt@canonical.com--2004/apt--authentication-mvo--0--patch-10 * reworked the "--print-uris" patch. it no longer uses: "APT::Get::Print-URIs" in the library * michael.vogt@canonical.com--2004/apt--authentication-mvo--0--patch-11 * version of the library set to 3.6 * michael.vogt@canonical.com--2004/apt--authentication-mvo--0--patch-12 * changelog finallized, will upload to people.ubuntulinux.org/~mvo/apt-authentication * michael.vogt@canonical.com--2004/apt--main-authentication--0--base-0 tag of apt@packages.debian.org/apt--main--0--patch-22 * michael.vogt@canonical.com--2004/apt--main-authentication--0--patch-1 * star-merge from apt--experimental--0.6 * michael.vogt@canonical.com--2004/apt--main-authentication--0--patch-2 * compile failure fix for methods/http.cc, po-file fixes
17 years ago
// $Id: rsh.cc,v 1.6.2.1 2004/01/16 18:58:50 mdz Exp $
/* ######################################################################
RSH method - Transfer files via rsh compatible program
Written by Ben Collins <bcollins@debian.org>, Copyright (c) 2000
Licensed under the GNU General Public License v2 [no exception clauses]
##################################################################### */
/*}}}*/
// Include Files /*{{{*/
#include "rsh.h"
#include <apt-pkg/error.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <utime.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <errno.h>
#include <stdarg.h>
#include <apti18n.h>
/*}}}*/
const char *Prog;
unsigned long TimeOut = 120;
Configuration::Item const *RshOptions = 0;
time_t RSHMethod::FailTime = 0;
string RSHMethod::FailFile;
int RSHMethod::FailFd = -1;
// RSHConn::RSHConn - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* */
RSHConn::RSHConn(URI Srv) : Len(0), WriteFd(-1), ReadFd(-1),
ServerName(Srv), Process(-1) {}
/*}}}*/
// RSHConn::RSHConn - Destructor /*{{{*/
// ---------------------------------------------------------------------
/* */
RSHConn::~RSHConn()
{
Close();
}
/*}}}*/
// RSHConn::Close - Forcibly terminate the connection /*{{{*/
// ---------------------------------------------------------------------
/* Often this is called when things have gone wrong to indicate that the
connection is no longer usable. */
void RSHConn::Close()
{
if (Process == -1)
return;
close(WriteFd);
close(ReadFd);
kill(Process,SIGINT);
ExecWait(Process,"",true);
WriteFd = -1;
ReadFd = -1;
Process = -1;
}
/*}}}*/
// RSHConn::Open - Connect to a host /*{{{*/
// ---------------------------------------------------------------------
/* */
bool RSHConn::Open()
{
// Use the already open connection if possible.
if (Process != -1)
return true;
if (Connect(ServerName.Host,ServerName.User) == false)
return false;
return true;
}
/*}}}*/
// RSHConn::Connect - Fire up rsh and connect /*{{{*/
// ---------------------------------------------------------------------
/* */
bool RSHConn::Connect(string Host, string User)
{
// Create the pipes
int Pipes[4] = {-1,-1,-1,-1};
if (pipe(Pipes) != 0 || pipe(Pipes+2) != 0)
{
_error->Errno("pipe",_("Failed to create IPC pipe to subprocess"));
for (int I = 0; I != 4; I++)
close(Pipes[I]);
return false;
}
for (int I = 0; I != 4; I++)
SetCloseExec(Pipes[I],true);
Process = ExecFork();
// The child
if (Process == 0)
{
const char *Args[400];
unsigned int i = 0;
dup2(Pipes[1],STDOUT_FILENO);
dup2(Pipes[2],STDIN_FILENO);
// Probably should do
// dup2(open("/dev/null",O_RDONLY),STDERR_FILENO);
// Insert user-supplied command line options
Configuration::Item const *Opts = RshOptions;
if (Opts != 0)
{
Opts = Opts->Child;
for (; Opts != 0; Opts = Opts->Next)
{
if (Opts->Value.empty() == true)
continue;
Args[i++] = Opts->Value.c_str();
}
}
Args[i++] = Prog;
if (User.empty() == false) {
Args[i++] = "-l";
Args[i++] = User.c_str();
}
if (Host.empty() == false) {
Args[i++] = Host.c_str();
}
Args[i++] = "/bin/sh";
Args[i] = 0;
execvp(Args[0],(char **)Args);
exit(100);
}
ReadFd = Pipes[0];
WriteFd = Pipes[3];
SetNonBlock(Pipes[0],true);
SetNonBlock(Pipes[3],true);
close(Pipes[1]);
close(Pipes[2]);
return true;
}
/*}}}*/
// RSHConn::ReadLine - Very simple buffered read with timeout /*{{{*/
// ---------------------------------------------------------------------
/* */
bool RSHConn::ReadLine(string &Text)
{
if (Process == -1 || ReadFd == -1)
return false;
// Suck in a line
while (Len < sizeof(Buffer))
{
// Scan the buffer for a new line
for (unsigned int I = 0; I != Len; I++)
{
// Escape some special chars
if (Buffer[I] == 0)
Buffer[I] = '?';
// End of line?
if (Buffer[I] != '\n')
continue;
I++;
Text = string(Buffer,I);
memmove(Buffer,Buffer+I,Len - I);
Len -= I;
return true;
}
// Wait for some data..
if (WaitFd(ReadFd,false,TimeOut) == false)
{
Close();
return _error->Error(_("Connection timeout"));
}
// Suck it back
int Res = read(ReadFd,Buffer + Len,sizeof(Buffer) - Len);
if (Res <= 0)
{
_error->Errno("read",_("Read error"));
Close();
return false;
}
Len += Res;
}
return _error->Error(_("A response overflowed the buffer."));
}
/*}}}*/
// RSHConn::WriteMsg - Send a message with optional remote sync. /*{{{*/
// ---------------------------------------------------------------------
/* The remote sync flag appends a || echo which will insert blank line
once the command completes. */
bool RSHConn::WriteMsg(string &Text,bool Sync,const char *Fmt,...)
{
va_list args;
va_start(args,Fmt);
// sprintf the description
char S[512];
vsnprintf(S,sizeof(S) - 4,Fmt,args);
if (Sync == true)
strcat(S," 2> /dev/null || echo\n");
else
strcat(S," 2> /dev/null\n");
// Send it off
unsigned long Len = strlen(S);
unsigned long Start = 0;
while (Len != 0)
{
if (WaitFd(WriteFd,true,TimeOut) == false)
{
Close();
return _error->Error(_("Connection timeout"));
}
int Res = write(WriteFd,S + Start,Len);
if (Res <= 0)
{
_error->Errno("write",_("Write error"));
Close();
return false;
}
Len -= Res;
Start += Res;
}
if (Sync == true)
return ReadLine(Text);
return true;
}
/*}}}*/
// RSHConn::Size - Return the size of the file /*{{{*/
// ---------------------------------------------------------------------
/* Right now for successfull transfer the file size must be known in
advance. */
bool RSHConn::Size(const char *Path,unsigned long &Size)
{
// Query the size
string Msg;
Size = 0;
if (WriteMsg(Msg,true,"find %s -follow -printf '%%s\\n'",Path) == false)
return false;
// FIXME: Sense if the bad reply is due to a File Not Found.
char *End;
Size = strtoul(Msg.c_str(),&End,10);
if (End == Msg.c_str())
return _error->Error(_("File not found"));
return true;
}
/*}}}*/
// RSHConn::ModTime - Get the modification time in UTC /*{{{*/
// ---------------------------------------------------------------------
/* */
bool RSHConn::ModTime(const char *Path, time_t &Time)
{
Time = time(&Time);
// Query the mod time
string Msg;
if (WriteMsg(Msg,true,"TZ=UTC find %s -follow -printf '%%TY%%Tm%%Td%%TH%%TM%%TS\\n'",Path) == false)
return false;
// Parse it
return FTPMDTMStrToTime(Msg.c_str(), Time);
}
/*}}}*/
// RSHConn::Get - Get a file /*{{{*/
// ---------------------------------------------------------------------
/* */
bool RSHConn::Get(const char *Path,FileFd &To,unsigned long Resume,
Hashes &Hash,bool &Missing, unsigned long Size)
{
Missing = false;
// Round to a 2048 byte block
Resume = Resume - (Resume % 2048);
if (To.Truncate(Resume) == false)
return false;
if (To.Seek(0) == false)
return false;
if (Resume != 0) {
if (Hash.AddFD(To.Fd(),Resume) == false) {
_error->Errno("read",_("Problem hashing file"));
return false;
}
}
// FIXME: Detect file-not openable type errors.
string Jnk;
if (WriteMsg(Jnk,false,"dd if=%s bs=2048 skip=%u", Path, Resume / 2048) == false)
return false;
// Copy loop
unsigned int MyLen = Resume;
unsigned char Buffer[4096];
while (MyLen < Size)
{
// Wait for some data..
if (WaitFd(ReadFd,false,TimeOut) == false)
{
Close();
return _error->Error(_("Data socket timed out"));
}
// Read the data..
int Res = read(ReadFd,Buffer,sizeof(Buffer));
if (Res == 0)
{
Close();
return _error->Error(_("Connection closed prematurely"));
}
if (Res < 0)
{
if (errno == EAGAIN)
continue;
break;
}
MyLen += Res;
Hash.Add(Buffer,Res);
if (To.Write(Buffer,Res) == false)
{
Close();
return false;
}
}
return true;
}
/*}}}*/
// RSHMethod::RSHMethod - Constructor /*{{{*/
// ---------------------------------------------------------------------
/* */
RSHMethod::RSHMethod() : pkgAcqMethod("1.0",SendConfig)
{
signal(SIGTERM,SigTerm);
signal(SIGINT,SigTerm);
Server = 0;
FailFd = -1;
};
/*}}}*/
// RSHMethod::Configuration - Handle a configuration message /*{{{*/
// ---------------------------------------------------------------------
bool RSHMethod::Configuration(string Message)
{
char ProgStr[100];
if (pkgAcqMethod::Configuration(Message) == false)
return false;
snprintf(ProgStr, sizeof ProgStr, "Acquire::%s::Timeout", Prog);
TimeOut = _config->FindI(ProgStr,TimeOut);
snprintf(ProgStr, sizeof ProgStr, "Acquire::%s::Options", Prog);
RshOptions = _config->Tree(ProgStr);
return true;
}
/*}}}*/
// RSHMethod::SigTerm - Clean up and timestamp the files on exit /*{{{*/
// ---------------------------------------------------------------------
/* */
void RSHMethod::SigTerm(int sig)
{
if (FailFd == -1)
_exit(100);
close(FailFd);
// Timestamp
struct utimbuf UBuf;
UBuf.actime = FailTime;
UBuf.modtime = FailTime;
utime(FailFile.c_str(),&UBuf);
_exit(100);
}
/*}}}*/
// RSHMethod::Fetch - Fetch a URI /*{{{*/
// ---------------------------------------------------------------------
/* */
bool RSHMethod::Fetch(FetchItem *Itm)
{
URI Get = Itm->Uri;
const char *File = Get.Path.c_str();
FetchResult Res;
Res.Filename = Itm->DestFile;
Res.IMSHit = false;
// Connect to the server
if (Server == 0 || Server->Comp(Get) == false) {
delete Server;
Server = new RSHConn(Get);
}
// Could not connect is a transient error..
if (Server->Open() == false) {
Server->Close();
Fail(true);
return true;
}
// We say this mainly because the pause here is for the
// ssh connection that is still going
Status(_("Connecting to %s"), Get.Host.c_str());
// Get the files information
unsigned long Size;
if (Server->Size(File,Size) == false ||
Server->ModTime(File,FailTime) == false)
{
//Fail(true);
//_error->Error(_("File not found")); // Will be handled by Size
return false;
}
Res.Size = Size;
// See if it is an IMS hit
if (Itm->LastModified == FailTime) {
Res.Size = 0;
Res.IMSHit = true;
URIDone(Res);
return true;
}
// See if the file exists
struct stat Buf;
if (stat(Itm->DestFile.c_str(),&Buf) == 0) {
if (Size == (unsigned)Buf.st_size && FailTime == Buf.st_mtime) {
Res.Size = Buf.st_size;
Res.LastModified = Buf.st_mtime;
Res.ResumePoint = Buf.st_size;
URIDone(Res);
return true;
}
// Resume?
if (FailTime == Buf.st_mtime && Size > (unsigned)Buf.st_size)
Res.ResumePoint = Buf.st_size;
}
// Open the file
Hashes Hash;
{
FileFd Fd(Itm->DestFile,FileFd::WriteAny);
if (_error->PendingError() == true)
return false;
URIStart(Res);
FailFile = Itm->DestFile;
FailFile.c_str(); // Make sure we dont do a malloc in the signal handler
FailFd = Fd.Fd();
bool Missing;
if (Server->Get(File,Fd,Res.ResumePoint,Hash,Missing,Res.Size) == false)
{
Fd.Close();
// Timestamp
struct utimbuf UBuf;
UBuf.actime = FailTime;
UBuf.modtime = FailTime;
utime(FailFile.c_str(),&UBuf);
// If the file is missing we hard fail otherwise transient fail
if (Missing == true)
return false;
Fail(true);
return true;
}
Res.Size = Fd.Size();
}
Res.LastModified = FailTime;
Res.TakeHashes(Hash);
// Timestamp
struct utimbuf UBuf;
UBuf.actime = FailTime;
UBuf.modtime = FailTime;
utime(Queue->DestFile.c_str(),&UBuf);
FailFd = -1;
URIDone(Res);
return true;
}
/*}}}*/
int main(int argc, const char *argv[])
{
setlocale(LC_ALL, "");
RSHMethod Mth;
Prog = strrchr(argv[0],'/');
Prog++;
return Mth.Run();
}