]>
git.saurik.com Git - apt-legacy.git/blob - methods/rred.cc
6fa57f3a60f58263da407f706ca31f9601a2aba3
   1 #include <apt-pkg/fileutl.h> 
   2 #include <apt-pkg/error.h> 
   3 #include <apt-pkg/acquire-method.h> 
   4 #include <apt-pkg/strutl.h> 
   5 #include <apt-pkg/hashes.h> 
  14 /* this method implements a patch functionality similar to "patch --ed" that is 
  15  * used by the "tiffany" incremental packages download stuff. it differs from  
  16  * "ed" insofar that it is way more restricted (and therefore secure). in the 
  17  * moment only the "c", "a" and "d" commands of ed are implemented (diff  
  18  * doesn't output any other). additionally the records must be reverse sorted  
  19  * by line number and may not overlap (diff *seems* to produce this kind of  
  25 class RredMethod 
: public pkgAcqMethod
 
  28    // the size of this doesn't really matter (except for performance)     
  29    const static int BUF_SIZE 
= 1024; 
  31    enum Mode 
{MODE_CHANGED
, MODE_DELETED
, MODE_ADDED
}; 
  33    enum State 
{ED_OK
, ED_ORDERING
, ED_PARSER
, ED_FAILURE
}; 
  34    // this applies a single hunk, it uses a tail recursion to  
  35    // reverse the hunks in the file 
  36    int ed_rec(FILE *ed_cmds
, FILE *in_file
, FILE *out_file
, int line
,  
  37       char *buffer
, unsigned int bufsize
, Hashes 
*hash
); 
  39    int ed_file(FILE *ed_cmds
, FILE *in_file
, FILE *out_file
, Hashes 
*hash
); 
  40    // the methods main method 
  41    virtual bool Fetch(FetchItem 
*Itm
); 
  45    RredMethod() : pkgAcqMethod("1.1",SingleInstance 
| SendConfig
) {}; 
  48 int RredMethod::ed_rec(FILE *ed_cmds
, FILE *in_file
, FILE *out_file
, int line
,  
  49       char *buffer
, unsigned int bufsize
, Hashes 
*hash
) { 
  57    /* get the current command and parse it*/ 
  58    if (fgets(buffer
, bufsize
, ed_cmds
) == NULL
) { 
  61    startline 
= strtol(buffer
, &idx
, 10); 
  62    if (startline 
< line
) { 
  67       stopline 
= strtol(idx
, &idx
, 10); 
  75                    std::clog 
<< "changing from line " << startline 
 
  76                              << " to " << stopline 
<< std::endl
; 
  79    else if (*idx 
== 'a') { 
  82                    std::clog 
<< "adding after line " << startline 
<< std::endl
; 
  85    else if (*idx 
== 'd') { 
  88                    std::clog 
<< "deleting from line " << startline 
 
  89                              <<  " to " << stopline 
<< std::endl
; 
  95    /* get the current position */ 
  97    /* if this is add or change then go to the next full stop */ 
  98    if ((mode 
== MODE_CHANGED
) || (mode 
== MODE_ADDED
)) { 
 100          fgets(buffer
, bufsize
, ed_cmds
); 
 101          while ((strlen(buffer
) == (bufsize 
- 1))  
 102                && (buffer
[bufsize 
- 2] != '\n')) { 
 103             fgets(buffer
, bufsize
, ed_cmds
); 
 106       } while (strncmp(buffer
, ".", 1) != 0); 
 108    /* do the recursive call */ 
 109    line 
= ed_rec(ed_cmds
, in_file
, out_file
, line
, buffer
, bufsize
,  
 116    fseek(ed_cmds
, pos
, SEEK_SET
);  
 117    /* first wind to the current position */ 
 118    if (mode 
!= MODE_ADDED
) { 
 121    while (line 
< startline
) { 
 122       fgets(buffer
, bufsize
, in_file
); 
 123       written 
= fwrite(buffer
, 1, strlen(buffer
), out_file
); 
 124       hash
->Add((unsigned char*)buffer
, written
); 
 125       while ((strlen(buffer
) == (bufsize 
- 1))  
 126             && (buffer
[bufsize 
- 2] != '\n')) { 
 127          fgets(buffer
, bufsize
, in_file
); 
 128          written 
= fwrite(buffer
, 1, strlen(buffer
), out_file
); 
 129          hash
->Add((unsigned char*)buffer
, written
); 
 133    /* include from ed script */ 
 134    if ((mode 
== MODE_ADDED
) || (mode 
== MODE_CHANGED
)) { 
 136          fgets(buffer
, bufsize
, ed_cmds
); 
 137          if (strncmp(buffer
, ".", 1) != 0) { 
 138             written 
= fwrite(buffer
, 1, strlen(buffer
), out_file
); 
 139             hash
->Add((unsigned char*)buffer
, written
); 
 140             while ((strlen(buffer
) == (bufsize 
- 1))  
 141                   && (buffer
[bufsize 
- 2] != '\n')) { 
 142                fgets(buffer
, bufsize
, ed_cmds
); 
 143                written 
= fwrite(buffer
, 1, strlen(buffer
), out_file
); 
 144                hash
->Add((unsigned char*)buffer
, written
); 
 152    /* ignore the corresponding number of lines from input */ 
 153    if ((mode 
== MODE_DELETED
) || (mode 
== MODE_CHANGED
)) { 
 154       while (line 
< stopline
) { 
 155          fgets(buffer
, bufsize
, in_file
); 
 156          while ((strlen(buffer
) == (bufsize 
- 1))  
 157                && (buffer
[bufsize 
- 2] != '\n')) { 
 158             fgets(buffer
, bufsize
, in_file
); 
 166 int RredMethod::ed_file(FILE *ed_cmds
, FILE *in_file
, FILE *out_file
,  
 168    char buffer
[BUF_SIZE
]; 
 172    /* we do a tail recursion to read the commands in the right order */ 
 173    result 
= ed_rec(ed_cmds
, in_file
, out_file
, 0, buffer
, BUF_SIZE
,  
 176    /* read the rest from infile */ 
 178       while (fgets(buffer
, BUF_SIZE
, in_file
) != NULL
) { 
 179          written 
= fwrite(buffer
, 1, strlen(buffer
), out_file
); 
 180          hash
->Add((unsigned char*)buffer
, written
); 
 190 bool RredMethod::Fetch(FetchItem 
*Itm
) 
 192    Debug 
= _config
->FindB("Debug::pkgAcquire::RRed",false); 
 194    string Path 
= Get
.Host 
+ Get
.Path
; // To account for relative paths 
 195    // Path contains the filename to patch 
 197    Res
.Filename 
= Itm
->DestFile
; 
 199    // Res.Filename the destination filename 
 202       std::clog 
<< "Patching " << Path 
<< " with " << Path 
 
 203          << ".ed and putting result into " << Itm
->DestFile 
<< std::endl
; 
 204    // Open the source and destination files (the d'tor of FileFd will do  
 205    // the cleanup/closing of the fds) 
 206    FileFd 
From(Path
,FileFd::ReadOnly
); 
 207    FileFd 
Patch(Path
+".ed",FileFd::ReadOnly
); 
 208    FileFd 
To(Itm
->DestFile
,FileFd::WriteEmpty
);    
 210    if (_error
->PendingError() == true) 
 214    FILE* fFrom 
= fdopen(From
.Fd(), "r"); 
 215    FILE* fPatch 
= fdopen(Patch
.Fd(), "r"); 
 216    FILE* fTo 
= fdopen(To
.Fd(), "w"); 
 217    // now do the actual patching 
 218    if (ed_file(fPatch
, fFrom
, fTo
, &Hash
) != ED_OK
) { 
 219      _error
->Errno("rred", _("Could not patch file"));   
 223    // write out the result 
 231    // Transfer the modification times 
 233    if (stat(Path
.c_str(),&Buf
) != 0) 
 234       return _error
->Errno("stat",_("Failed to stat")); 
 236    struct utimbuf TimeBuf
; 
 237    TimeBuf
.actime 
= Buf
.st_atime
; 
 238    TimeBuf
.modtime 
= Buf
.st_mtime
; 
 239    if (utime(Itm
->DestFile
.c_str(),&TimeBuf
) != 0) 
 240       return _error
->Errno("utime",_("Failed to set modification time")); 
 242    if (stat(Itm
->DestFile
.c_str(),&Buf
) != 0) 
 243       return _error
->Errno("stat",_("Failed to stat")); 
 246    Res
.LastModified 
= Buf
.st_mtime
; 
 247    Res
.Size 
= Buf
.st_size
; 
 248    Res
.TakeHashes(Hash
); 
 254 int main(int argc
, char *argv
[]) 
 258    Prog 
= strrchr(argv
[0],'/');