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