|
@@ -21,6 +21,7 @@
|
|
|
#include <vector>
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
#include <assert.h>
|
|
|
|
|
+#include <errno.h>
|
|
|
#include <stdio.h>
|
|
#include <stdio.h>
|
|
|
#include <stdlib.h>
|
|
#include <stdlib.h>
|
|
|
#include <string.h>
|
|
#include <string.h>
|
|
@@ -35,7 +36,7 @@ class MemBlock {
|
|
|
char *start;
|
|
char *start;
|
|
|
size_t size;
|
|
size_t size;
|
|
|
char *free;
|
|
char *free;
|
|
|
- struct MemBlock *next;
|
|
|
|
|
|
|
+ MemBlock *next;
|
|
|
|
|
|
|
|
MemBlock(size_t size) : size(size), next(NULL)
|
|
MemBlock(size_t size) : size(size), next(NULL)
|
|
|
{
|
|
{
|
|
@@ -116,7 +117,7 @@ struct Change {
|
|
|
size_t add_len; /* bytes */
|
|
size_t add_len; /* bytes */
|
|
|
char *add;
|
|
char *add;
|
|
|
|
|
|
|
|
- Change(int off)
|
|
|
|
|
|
|
+ Change(size_t off)
|
|
|
{
|
|
{
|
|
|
offset = off;
|
|
offset = off;
|
|
|
del_cnt = add_cnt = add_len = 0;
|
|
del_cnt = add_cnt = add_len = 0;
|
|
@@ -388,30 +389,37 @@ class Patch {
|
|
|
|
|
|
|
|
public:
|
|
public:
|
|
|
|
|
|
|
|
- void read_diff(FileFd &f, Hashes * const h)
|
|
|
|
|
|
|
+ bool read_diff(FileFd &f, Hashes * const h)
|
|
|
{
|
|
{
|
|
|
char buffer[BLOCK_SIZE];
|
|
char buffer[BLOCK_SIZE];
|
|
|
bool cmdwanted = true;
|
|
bool cmdwanted = true;
|
|
|
|
|
|
|
|
- Change ch(0);
|
|
|
|
|
- while(f.ReadLine(buffer, sizeof(buffer)))
|
|
|
|
|
- {
|
|
|
|
|
|
|
+ Change ch(std::numeric_limits<size_t>::max());
|
|
|
|
|
+ if (f.ReadLine(buffer, sizeof(buffer)) == NULL)
|
|
|
|
|
+ return _error->Error("Reading first line of patchfile %s failed", f.Name().c_str());
|
|
|
|
|
+ do {
|
|
|
if (h != NULL)
|
|
if (h != NULL)
|
|
|
h->Add(buffer);
|
|
h->Add(buffer);
|
|
|
if (cmdwanted) {
|
|
if (cmdwanted) {
|
|
|
char *m, *c;
|
|
char *m, *c;
|
|
|
size_t s, e;
|
|
size_t s, e;
|
|
|
- s = strtol(buffer, &m, 10);
|
|
|
|
|
- if (m == buffer) {
|
|
|
|
|
- s = e = ch.offset + ch.add_cnt;
|
|
|
|
|
- c = buffer;
|
|
|
|
|
- } else if (*m == ',') {
|
|
|
|
|
- m++;
|
|
|
|
|
|
|
+ errno = 0;
|
|
|
|
|
+ s = strtoul(buffer, &m, 10);
|
|
|
|
|
+ if (unlikely(m == buffer || s == ULONG_MAX || errno != 0))
|
|
|
|
|
+ return _error->Error("Parsing patchfile %s failed: Expected an effected line start", f.Name().c_str());
|
|
|
|
|
+ else if (*m == ',') {
|
|
|
|
|
+ ++m;
|
|
|
e = strtol(m, &c, 10);
|
|
e = strtol(m, &c, 10);
|
|
|
|
|
+ if (unlikely(m == c || e == ULONG_MAX || errno != 0))
|
|
|
|
|
+ return _error->Error("Parsing patchfile %s failed: Expected an effected line end", f.Name().c_str());
|
|
|
|
|
+ if (unlikely(e < s))
|
|
|
|
|
+ return _error->Error("Parsing patchfile %s failed: Effected lines end %lu is before start %lu", f.Name().c_str(), e, s);
|
|
|
} else {
|
|
} else {
|
|
|
e = s;
|
|
e = s;
|
|
|
c = m;
|
|
c = m;
|
|
|
}
|
|
}
|
|
|
|
|
+ if (s > ch.offset)
|
|
|
|
|
+ return _error->Error("Parsing patchfile %s failed: Effected line is after previous effected line", f.Name().c_str());
|
|
|
switch(*c) {
|
|
switch(*c) {
|
|
|
case 'a':
|
|
case 'a':
|
|
|
cmdwanted = false;
|
|
cmdwanted = false;
|
|
@@ -422,6 +430,8 @@ class Patch {
|
|
|
ch.del_cnt = 0;
|
|
ch.del_cnt = 0;
|
|
|
break;
|
|
break;
|
|
|
case 'c':
|
|
case 'c':
|
|
|
|
|
+ if (unlikely(s == 0))
|
|
|
|
|
+ return _error->Error("Parsing patchfile %s failed: Change command can't effect line zero", f.Name().c_str());
|
|
|
cmdwanted = false;
|
|
cmdwanted = false;
|
|
|
ch.add = NULL;
|
|
ch.add = NULL;
|
|
|
ch.add_cnt = 0;
|
|
ch.add_cnt = 0;
|
|
@@ -430,6 +440,8 @@ class Patch {
|
|
|
ch.del_cnt = e - s + 1;
|
|
ch.del_cnt = e - s + 1;
|
|
|
break;
|
|
break;
|
|
|
case 'd':
|
|
case 'd':
|
|
|
|
|
+ if (unlikely(s == 0))
|
|
|
|
|
+ return _error->Error("Parsing patchfile %s failed: Delete command can't effect line zero", f.Name().c_str());
|
|
|
ch.offset = s - 1;
|
|
ch.offset = s - 1;
|
|
|
ch.del_cnt = e - s + 1;
|
|
ch.del_cnt = e - s + 1;
|
|
|
ch.add = NULL;
|
|
ch.add = NULL;
|
|
@@ -437,9 +449,11 @@ class Patch {
|
|
|
ch.add_len = 0;
|
|
ch.add_len = 0;
|
|
|
filechanges.add_change(ch);
|
|
filechanges.add_change(ch);
|
|
|
break;
|
|
break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ return _error->Error("Parsing patchfile %s failed: Unknown command", f.Name().c_str());
|
|
|
}
|
|
}
|
|
|
} else { /* !cmdwanted */
|
|
} else { /* !cmdwanted */
|
|
|
- if (buffer[0] == '.' && buffer[1] == '\n') {
|
|
|
|
|
|
|
+ if (strcmp(buffer, ".\n") == 0) {
|
|
|
cmdwanted = true;
|
|
cmdwanted = true;
|
|
|
filechanges.add_change(ch);
|
|
filechanges.add_change(ch);
|
|
|
} else {
|
|
} else {
|
|
@@ -465,7 +479,8 @@ class Patch {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
|
|
+ } while(f.ReadLine(buffer, sizeof(buffer)));
|
|
|
|
|
+ return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void write_diff(FILE *f)
|
|
void write_diff(FILE *f)
|
|
@@ -601,14 +616,14 @@ class RredMethod : public pkgAcqMethod {
|
|
|
<< std::endl;
|
|
<< std::endl;
|
|
|
|
|
|
|
|
FileFd p;
|
|
FileFd p;
|
|
|
|
|
+ Hashes patch_hash(I->ExpectedHashes);
|
|
|
// all patches are compressed, even if the name doesn't reflect it
|
|
// all patches are compressed, even if the name doesn't reflect it
|
|
|
- if (p.Open(patch_name, FileFd::ReadOnly, FileFd::Gzip) == false) {
|
|
|
|
|
- std::cerr << "Could not open patch file " << patch_name << std::endl;
|
|
|
|
|
|
|
+ if (p.Open(patch_name, FileFd::ReadOnly, FileFd::Gzip) == false ||
|
|
|
|
|
+ patch.read_diff(p, &patch_hash) == false)
|
|
|
|
|
+ {
|
|
|
_error->DumpErrors(std::cerr);
|
|
_error->DumpErrors(std::cerr);
|
|
|
- abort();
|
|
|
|
|
|
|
+ return false;
|
|
|
}
|
|
}
|
|
|
- Hashes patch_hash(I->ExpectedHashes);
|
|
|
|
|
- patch.read_diff(p, &patch_hash);
|
|
|
|
|
p.Close();
|
|
p.Close();
|
|
|
HashStringList const hsl = patch_hash.GetHashStringList();
|
|
HashStringList const hsl = patch_hash.GetHashStringList();
|
|
|
if (hsl != I->ExpectedHashes)
|
|
if (hsl != I->ExpectedHashes)
|
|
@@ -624,7 +639,6 @@ class RredMethod : public pkgAcqMethod {
|
|
|
FILE *out = fopen(Itm->DestFile.c_str(), "w");
|
|
FILE *out = fopen(Itm->DestFile.c_str(), "w");
|
|
|
|
|
|
|
|
Hashes hash(Itm->ExpectedHashes);
|
|
Hashes hash(Itm->ExpectedHashes);
|
|
|
-
|
|
|
|
|
patch.apply_against_file(out, inp, &hash);
|
|
patch.apply_against_file(out, inp, &hash);
|
|
|
|
|
|
|
|
fclose(out);
|
|
fclose(out);
|
|
@@ -657,6 +671,16 @@ class RredMethod : public pkgAcqMethod {
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ bool Configuration(std::string Message)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (pkgAcqMethod::Configuration(Message) == false)
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
|
|
+ DropPrivsOrDie();
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
public:
|
|
public:
|
|
|
RredMethod() : pkgAcqMethod("2.0",SingleInstance | SendConfig), Debug(false) {}
|
|
RredMethod() : pkgAcqMethod("2.0",SingleInstance | SendConfig), Debug(false) {}
|
|
|
};
|
|
};
|
|
@@ -685,7 +709,11 @@ int main(int argc, char **argv)
|
|
|
_error->DumpErrors(std::cerr);
|
|
_error->DumpErrors(std::cerr);
|
|
|
exit(1);
|
|
exit(1);
|
|
|
}
|
|
}
|
|
|
- patch.read_diff(p, NULL);
|
|
|
|
|
|
|
+ if (patch.read_diff(p, NULL) == false)
|
|
|
|
|
+ {
|
|
|
|
|
+ _error->DumpErrors(std::cerr);
|
|
|
|
|
+ exit(2);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (just_diff) {
|
|
if (just_diff) {
|