summaryrefslogtreecommitdiff
path: root/methods/copy.cc
blob: faf330ace57abf56a7b4579f6eae1e036f51bc07 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// -*- mode: cpp; mode: fold -*-
// Description								/*{{{*/
// $Id: copy.cc,v 1.7.2.1 2004/01/16 18:58:50 mdz Exp $
/* ######################################################################

   Copy URI - This method takes a uri like a file: uri and copies it
   to the destination file.
   
   ##################################################################### */
									/*}}}*/
// Include Files							/*{{{*/
#include <config.h>

#include <apt-pkg/fileutl.h>
#include <apt-pkg/strutl.h>
#include <apt-pkg/acquire-method.h>
#include <apt-pkg/error.h>
#include <apt-pkg/hashes.h>
#include <apt-pkg/configuration.h>

#include <string>
#include <sys/stat.h>
#include <sys/time.h>

#include <apti18n.h>
									/*}}}*/

class CopyMethod : public pkgAcqMethod
{
   virtual bool Fetch(FetchItem *Itm);
   void CalculateHashes(FetchResult &Res);
   
   public:
   
   CopyMethod() : pkgAcqMethod("1.0",SingleInstance | SendConfig) {};
};

void CopyMethod::CalculateHashes(FetchResult &Res)
{
   // For gzip indexes we need to look inside the gzip for the hash
   // We can not use the extension here as its not used in partial 
   // on a IMS hit
   FileFd::OpenMode OpenMode = FileFd::ReadOnly;
   if (_config->FindB("Acquire::GzipIndexes", false) == true)
      OpenMode = FileFd::ReadOnlyGzip;

   Hashes Hash;
   FileFd Fd(Res.Filename, OpenMode);
   Hash.AddFD(Fd);
   Res.TakeHashes(Hash);
}

// CopyMethod::Fetch - Fetch a file					/*{{{*/
// ---------------------------------------------------------------------
/* */
bool CopyMethod::Fetch(FetchItem *Itm)
{
   // this ensures that relative paths work in copy
   std::string File = Itm->Uri.substr(Itm->Uri.find(':')+1);

   // Stat the file and send a start message
   struct stat Buf;
   if (stat(File.c_str(),&Buf) != 0)
      return _error->Errno("stat",_("Failed to stat"));

   // Forumulate a result and send a start message
   FetchResult Res;
   Res.Size = Buf.st_size;
   Res.Filename = Itm->DestFile;
   Res.LastModified = Buf.st_mtime;
   Res.IMSHit = false;      
   URIStart(Res);

   // when the files are identical, just compute the hashes
   if(File == Itm->DestFile)
   {
      CalculateHashes(Res);
      URIDone(Res);
      return true;
   }
   
   // just calc the hashes if the source and destination are identical
   if (File == Itm->DestFile)
   {
      CalculateHashes(Res);
      URIDone(Res);
      return true;
   }

   // See if the file exists
   FileFd From(File,FileFd::ReadOnly);
   FileFd To(Itm->DestFile,FileFd::WriteAtomic);
   To.EraseOnFailure();
   if (_error->PendingError() == true)
   {
      To.OpFail();
      return false;
   }
   
   // Copy the file
   if (CopyFile(From,To) == false)
   {
      To.OpFail();
      return false;
   }

   From.Close();
   To.Close();

   // Transfer the modification times
   struct timeval times[2];
   times[0].tv_sec = Buf.st_atime;
   times[1].tv_sec = Buf.st_mtime;
   times[0].tv_usec = times[1].tv_usec = 0;
   if (utimes(Res.Filename.c_str(), times) != 0)
      return _error->Errno("utimes",_("Failed to set modification time"));

   CalculateHashes(Res);

   URIDone(Res);
   return true;
}
									/*}}}*/

int main()
{
   setlocale(LC_ALL, "");

   CopyMethod Mth;

   Mth.DropPrivsOrDie();
   return Mth.Run();
}