rred.cc 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  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>
  6. #include <sys/stat.h>
  7. #include <unistd.h>
  8. #include <utime.h>
  9. #include <stdio.h>
  10. #include <errno.h>
  11. #include <apti18n.h>
  12. const char *Prog;
  13. class RredMethod : public pkgAcqMethod
  14. {
  15. virtual bool Fetch(FetchItem *Itm);
  16. public:
  17. RredMethod() : pkgAcqMethod("1.1",SingleInstance | SendConfig) {};
  18. };
  19. #define BUF_SIZE (1024)
  20. // XX use enums
  21. #define MODE_CHANGED 0
  22. #define MODE_DELETED 1
  23. #define MODE_ADDED 2
  24. #define ED_ORDERING 1
  25. #define ED_PARSER 2
  26. #define ED_FAILURE 3
  27. int ed_rec(FILE *ed_cmds, FILE *in_file, FILE *out_file, int line,
  28. char *buffer, unsigned int bufsize, Hashes *hash) {
  29. int pos;
  30. int startline;
  31. int stopline;
  32. int mode;
  33. int written;
  34. char *idx;
  35. /* get the current command and parse it*/
  36. if (fgets(buffer, bufsize, ed_cmds) == NULL) {
  37. return line;
  38. }
  39. startline = strtol(buffer, &idx, 10);
  40. if (startline < line) {
  41. return ED_ORDERING;
  42. }
  43. if (*idx == ',') {
  44. idx++;
  45. stopline = strtol(idx, &idx, 10);
  46. }
  47. else {
  48. stopline = startline;
  49. }
  50. if (*idx == 'c') {
  51. mode = MODE_CHANGED;
  52. }
  53. else if (*idx == 'a') {
  54. mode = MODE_ADDED;
  55. }
  56. else if (*idx == 'd') {
  57. mode = MODE_DELETED;
  58. }
  59. else {
  60. return ED_PARSER;
  61. }
  62. /* get the current position */
  63. pos = ftell(ed_cmds);
  64. /* if this is add or change then go to the next full stop */
  65. if ((mode == MODE_CHANGED) || (mode == MODE_ADDED)) {
  66. do {
  67. fgets(buffer, bufsize, ed_cmds);
  68. while ((strlen(buffer) == (bufsize - 1))
  69. && (buffer[bufsize - 2] != '\n')) {
  70. fgets(buffer, bufsize, ed_cmds);
  71. buffer[0] = ' ';
  72. }
  73. } while (strncmp(buffer, ".", 1) != 0);
  74. }
  75. /* do the recursive call */
  76. line = ed_rec(ed_cmds, in_file, out_file, line, buffer, bufsize,
  77. hash);
  78. /* pass on errors */
  79. if (line < 0) {
  80. return line;
  81. }
  82. /* apply our hunk */
  83. fseek(ed_cmds, pos, SEEK_SET);
  84. /* first wind to the current position */
  85. if (mode != MODE_ADDED) {
  86. startline -= 1;
  87. }
  88. while (line < startline) {
  89. fgets(buffer, bufsize, in_file);
  90. written = fwrite(buffer, 1, strlen(buffer), out_file);
  91. hash->Add((unsigned char*)buffer, written);
  92. while ((strlen(buffer) == (bufsize - 1))
  93. && (buffer[bufsize - 2] != '\n')) {
  94. fgets(buffer, bufsize, in_file);
  95. written = fwrite(buffer, 1, strlen(buffer), out_file);
  96. hash->Add((unsigned char*)buffer, written);
  97. }
  98. line++;
  99. }
  100. /* include from ed script */
  101. if ((mode == MODE_ADDED) || (mode == MODE_CHANGED)) {
  102. do {
  103. fgets(buffer, bufsize, ed_cmds);
  104. if (strncmp(buffer, ".", 1) != 0) {
  105. written = fwrite(buffer, 1, strlen(buffer), out_file);
  106. hash->Add((unsigned char*)buffer, written);
  107. while ((strlen(buffer) == (bufsize - 1))
  108. && (buffer[bufsize - 2] != '\n')) {
  109. fgets(buffer, bufsize, ed_cmds);
  110. written = fwrite(buffer, 1, strlen(buffer), out_file);
  111. hash->Add((unsigned char*)buffer, written);
  112. }
  113. }
  114. else {
  115. break;
  116. }
  117. } while (1);
  118. }
  119. /* ignore the corresponding number of lines from input */
  120. if ((mode == MODE_DELETED) || (mode == MODE_CHANGED)) {
  121. while (line < stopline) {
  122. fgets(buffer, bufsize, in_file);
  123. while ((strlen(buffer) == (bufsize - 1))
  124. && (buffer[bufsize - 2] != '\n')) {
  125. fgets(buffer, bufsize, in_file);
  126. }
  127. line++;
  128. }
  129. }
  130. return line;
  131. }
  132. int ed_file(FILE *ed_cmds, FILE *in_file, FILE *out_file, Hashes *hash) {
  133. char buffer[BUF_SIZE];
  134. int result;
  135. int written;
  136. /* we do a tail recursion to read the commands in the right order */
  137. result = ed_rec(ed_cmds, in_file, out_file, 0, buffer, BUF_SIZE,
  138. hash);
  139. /* read the rest from infile */
  140. if (result > 0) {
  141. while (fgets(buffer, BUF_SIZE, in_file) != NULL) {
  142. written = fwrite(buffer, 1, strlen(buffer), out_file);
  143. // XXX add to hash
  144. // sha_process_bytes(buffer, written, &sha);
  145. }
  146. }
  147. else {
  148. // XXX better error handling
  149. fprintf(stderr, "Error: %i\n", result);
  150. return ED_FAILURE;
  151. }
  152. return 0;
  153. }
  154. // XXX do we need modification times as well?
  155. bool RredMethod::Fetch(FetchItem *Itm)
  156. {
  157. URI Get = Itm->Uri;
  158. string Path = Get.Host + Get.Path; // To account for relative paths
  159. // Path contains the filename to patch
  160. FetchResult Res;
  161. Res.Filename = Itm->DestFile;
  162. URIStart(Res);
  163. // Res.Filename the destination filename
  164. // Open the source and destination files
  165. FileFd From(Path,FileFd::ReadOnly);
  166. FileFd Patch(Path+".ed",FileFd::ReadOnly);
  167. FileFd To(Itm->DestFile,FileFd::WriteEmpty);
  168. To.EraseOnFailure();
  169. if (_error->PendingError() == true)
  170. return false;
  171. Hashes Hash;
  172. FILE* fFrom = fdopen(From.Fd(), "r");
  173. FILE* fPatch = fdopen(Patch.Fd(), "r");
  174. FILE* fTo = fdopen(To.Fd(), "w");
  175. // now do the actual patching
  176. ed_file(fPatch, fFrom, fTo, &Hash);
  177. // clean up
  178. fclose(fFrom);
  179. fclose(fPatch);
  180. fclose(fTo);
  181. To.Close();
  182. From.Close();
  183. Patch.Close();
  184. // XXX need to get the size
  185. // Res.Size = Buf.st_size;
  186. Res.TakeHashes(Hash);
  187. URIDone(Res);
  188. return true;
  189. }
  190. /*}}}*/
  191. int main(int argc, char *argv[])
  192. {
  193. RredMethod Mth;
  194. Prog = strrchr(argv[0],'/');
  195. Prog++;
  196. return Mth.Run();
  197. }