25 |
|
* behaviour |
26 |
|
* |
27 |
|
* $OpenBSD: inp.c,v 1.36 2012/04/10 14:46:34 ajacoutot Exp $ |
28 |
< |
* $FreeBSD: stable/11/usr.bin/patch/inp.c 286795 2015-08-15 00:42:33Z delphij $ |
28 |
> |
* $FreeBSD: stable/10/usr.bin/patch/inp.c 287223 2015-08-27 21:52:09Z delphij $ |
29 |
|
*/ |
30 |
|
|
31 |
|
#include <sys/types.h> |
62 |
|
static int tifd = -1; /* plan b virtual string array */ |
63 |
|
static char *tibuf[2]; /* plan b buffers */ |
64 |
|
static LINENUM tiline[2] = {-1, -1}; /* 1st line in each buffer */ |
65 |
< |
static size_t lines_per_buf; /* how many lines per buffer */ |
66 |
< |
static size_t tibuflen; /* plan b buffer length */ |
67 |
< |
static size_t tireclen; /* length of records in tmp file */ |
65 |
> |
static LINENUM lines_per_buf; /* how many lines per buffer */ |
66 |
> |
static int tireclen; /* length of records in tmp file */ |
67 |
|
|
68 |
|
static bool rev_in_string(const char *); |
69 |
|
static bool reallocate_lines(size_t *); |
137 |
|
static bool |
138 |
|
plan_a(const char *filename) |
139 |
|
{ |
140 |
< |
int ifd, statfailed; |
141 |
< |
char *p, *s; |
140 |
> |
int ifd, statfailed, pstat; |
141 |
> |
char *p, *s, lbuf[INITLINELEN]; |
142 |
|
struct stat filestat; |
143 |
|
ptrdiff_t sz; |
144 |
|
size_t i; |
145 |
|
size_t iline, lines_allocated; |
146 |
+ |
pid_t pid; |
147 |
|
|
148 |
|
#ifdef DEBUGGING |
149 |
|
if (debug & 8) |
169 |
|
close(creat(filename, 0666)); |
170 |
|
statfailed = stat(filename, &filestat); |
171 |
|
} |
172 |
< |
if (statfailed) |
173 |
< |
fatal("can't find %s\n", filename); |
172 |
> |
if (statfailed && check_only) |
173 |
> |
fatal("%s not found, -C mode, can't probe further\n", filename); |
174 |
> |
/* For nonexistent or read-only files, look for RCS versions. */ |
175 |
> |
|
176 |
> |
if (statfailed || |
177 |
> |
/* No one can write to it. */ |
178 |
> |
(filestat.st_mode & 0222) == 0 || |
179 |
> |
/* I can't write to it. */ |
180 |
> |
((filestat.st_mode & 0022) == 0 && filestat.st_uid != getuid())) { |
181 |
> |
char *filebase, *filedir; |
182 |
> |
struct stat cstat; |
183 |
> |
char *tmp_filename1, *tmp_filename2; |
184 |
> |
char *argp[4] = { NULL }; |
185 |
> |
posix_spawn_file_actions_t file_actions; |
186 |
> |
|
187 |
> |
tmp_filename1 = strdup(filename); |
188 |
> |
tmp_filename2 = strdup(filename); |
189 |
> |
if (tmp_filename1 == NULL || tmp_filename2 == NULL) |
190 |
> |
fatal("strdupping filename"); |
191 |
> |
|
192 |
> |
filebase = basename(tmp_filename1); |
193 |
> |
filedir = dirname(tmp_filename2); |
194 |
> |
|
195 |
> |
memset(argp, 0, sizeof(argp)); |
196 |
> |
|
197 |
> |
#define try(f, a1, a2, a3) \ |
198 |
> |
(snprintf(lbuf, sizeof(lbuf), f, a1, a2, a3), stat(lbuf, &cstat) == 0) |
199 |
> |
|
200 |
> |
/* |
201 |
> |
* else we can't write to it but it's not under a version |
202 |
> |
* control system, so just proceed. |
203 |
> |
*/ |
204 |
> |
if (try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX) || |
205 |
> |
try("%s/RCS/%s%s", filedir, filebase, "") || |
206 |
> |
try("%s/%s%s", filedir, filebase, RCSSUFFIX)) { |
207 |
> |
if (!statfailed) { |
208 |
> |
if ((filestat.st_mode & 0222) != 0) |
209 |
> |
/* The owner can write to it. */ |
210 |
> |
fatal("file %s seems to be locked " |
211 |
> |
"by somebody else under RCS\n", |
212 |
> |
filename); |
213 |
> |
/* |
214 |
> |
* It might be checked out unlocked. See if |
215 |
> |
* it's safe to check out the default version |
216 |
> |
* locked. |
217 |
> |
*/ |
218 |
> |
if (verbose) |
219 |
> |
say("Comparing file %s to default " |
220 |
> |
"RCS version...\n", filename); |
221 |
> |
|
222 |
> |
argp[0] = __DECONST(char *, RCSDIFF); |
223 |
> |
argp[1] = __DECONST(char *, filename); |
224 |
> |
posix_spawn_file_actions_init(&file_actions); |
225 |
> |
posix_spawn_file_actions_addopen(&file_actions, |
226 |
> |
STDOUT_FILENO, _PATH_DEVNULL, O_WRONLY, 0); |
227 |
> |
if (posix_spawn(&pid, RCSDIFF, &file_actions, |
228 |
> |
NULL, argp, NULL) == 0) { |
229 |
> |
pid = waitpid(pid, &pstat, 0); |
230 |
> |
if (pid == -1 || WEXITSTATUS(pstat) != 0) |
231 |
> |
fatal("can't check out file %s: " |
232 |
> |
"differs from default RCS version\n", |
233 |
> |
filename); |
234 |
> |
} else |
235 |
> |
fatal("posix_spawn: %s\n", strerror(errno)); |
236 |
> |
posix_spawn_file_actions_destroy(&file_actions); |
237 |
> |
} |
238 |
> |
|
239 |
> |
if (verbose) |
240 |
> |
say("Checking out file %s from RCS...\n", |
241 |
> |
filename); |
242 |
> |
|
243 |
> |
argp[0] = __DECONST(char *, CHECKOUT); |
244 |
> |
argp[1] = __DECONST(char *, "-l"); |
245 |
> |
argp[2] = __DECONST(char *, filename); |
246 |
> |
if (posix_spawn(&pid, CHECKOUT, NULL, NULL, argp, |
247 |
> |
NULL) == 0) { |
248 |
> |
pid = waitpid(pid, &pstat, 0); |
249 |
> |
if (pid == -1 || WEXITSTATUS(pstat) != 0 || |
250 |
> |
stat(filename, &filestat)) |
251 |
> |
fatal("can't check out file %s from RCS\n", |
252 |
> |
filename); |
253 |
> |
} else |
254 |
> |
fatal("posix_spawn: %s\n", strerror(errno)); |
255 |
> |
} else if (statfailed) { |
256 |
> |
fatal("can't find %s\n", filename); |
257 |
> |
} |
258 |
> |
free(tmp_filename1); |
259 |
> |
free(tmp_filename2); |
260 |
> |
} |
261 |
> |
|
262 |
|
filemode = filestat.st_mode; |
263 |
|
if (!S_ISREG(filemode)) |
264 |
|
fatal("%s is not a normal file--can't patch\n", filename); |
340 |
|
/* now check for revision, if any */ |
341 |
|
|
342 |
|
if (revision != NULL) { |
343 |
< |
if (i_womp == NULL || !rev_in_string(i_womp)) { |
343 |
> |
if (!rev_in_string(i_womp)) { |
344 |
|
if (force) { |
345 |
|
if (verbose) |
346 |
|
say("Warning: this file doesn't appear " |
370 |
|
plan_b(const char *filename) |
371 |
|
{ |
372 |
|
FILE *ifp; |
373 |
< |
size_t i = 0, j, len, maxlen = 1; |
374 |
< |
char *lbuf = NULL, *p; |
373 |
> |
size_t i = 0, j, maxlen = 1; |
374 |
> |
char *p; |
375 |
|
bool found_revision = (revision == NULL); |
376 |
|
|
377 |
|
using_plan_a = false; |
380 |
|
unlink(TMPINNAME); |
381 |
|
if ((tifd = open(TMPINNAME, O_EXCL | O_CREAT | O_WRONLY, 0666)) < 0) |
382 |
|
pfatal("can't open file %s", TMPINNAME); |
383 |
< |
while ((p = fgetln(ifp, &len)) != NULL) { |
384 |
< |
if (p[len - 1] == '\n') |
297 |
< |
p[len - 1] = '\0'; |
298 |
< |
else { |
299 |
< |
/* EOF without EOL, copy and add the NUL */ |
300 |
< |
if ((lbuf = malloc(len + 1)) == NULL) |
301 |
< |
fatal("out of memory\n"); |
302 |
< |
memcpy(lbuf, p, len); |
303 |
< |
lbuf[len] = '\0'; |
304 |
< |
p = lbuf; |
305 |
< |
|
306 |
< |
last_line_missing_eol = true; |
307 |
< |
len++; |
308 |
< |
} |
309 |
< |
if (revision != NULL && !found_revision && rev_in_string(p)) |
383 |
> |
while (fgets(buf, buf_size, ifp) != NULL) { |
384 |
> |
if (revision != NULL && !found_revision && rev_in_string(buf)) |
385 |
|
found_revision = true; |
386 |
< |
if (len > maxlen) |
387 |
< |
maxlen = len; /* find longest line */ |
386 |
> |
if ((i = strlen(buf)) > maxlen) |
387 |
> |
maxlen = i; /* find longest line */ |
388 |
|
} |
389 |
< |
free(lbuf); |
390 |
< |
if (ferror(ifp)) |
391 |
< |
pfatal("can't read file %s", filename); |
389 |
> |
last_line_missing_eol = i > 0 && buf[i - 1] != '\n'; |
390 |
> |
if (last_line_missing_eol && maxlen == i) |
391 |
> |
maxlen++; |
392 |
|
|
393 |
|
if (revision != NULL) { |
394 |
|
if (!found_revision) { |
413 |
|
revision); |
414 |
|
} |
415 |
|
fseek(ifp, 0L, SEEK_SET); /* rewind file */ |
416 |
+ |
lines_per_buf = BUFFERSIZE / maxlen; |
417 |
|
tireclen = maxlen; |
418 |
< |
tibuflen = maxlen > BUFFERSIZE ? maxlen : BUFFERSIZE; |
343 |
< |
lines_per_buf = tibuflen / maxlen; |
344 |
< |
tibuf[0] = malloc(tibuflen + 1); |
418 |
> |
tibuf[0] = malloc(BUFFERSIZE + 1); |
419 |
|
if (tibuf[0] == NULL) |
420 |
|
fatal("out of memory\n"); |
421 |
< |
tibuf[1] = malloc(tibuflen + 1); |
421 |
> |
tibuf[1] = malloc(BUFFERSIZE + 1); |
422 |
|
if (tibuf[1] == NULL) |
423 |
|
fatal("out of memory\n"); |
424 |
|
for (i = 1;; i++) { |
425 |
|
p = tibuf[0] + maxlen * (i % lines_per_buf); |
426 |
|
if (i % lines_per_buf == 0) /* new block */ |
427 |
< |
if (write(tifd, tibuf[0], tibuflen) != |
354 |
< |
(ssize_t) tibuflen) |
427 |
> |
if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE) |
428 |
|
pfatal("can't write temp file"); |
429 |
|
if (fgets(p, maxlen + 1, ifp) == NULL) { |
430 |
|
input_lines = i - 1; |
431 |
|
if (i % lines_per_buf != 0) |
432 |
< |
if (write(tifd, tibuf[0], tibuflen) != |
360 |
< |
(ssize_t) tibuflen) |
432 |
> |
if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE) |
433 |
|
pfatal("can't write temp file"); |
434 |
|
break; |
435 |
|
} |
471 |
|
tiline[whichbuf] = baseline; |
472 |
|
|
473 |
|
if (lseek(tifd, (off_t) (baseline / lines_per_buf * |
474 |
< |
tibuflen), SEEK_SET) < 0) |
474 |
> |
BUFFERSIZE), SEEK_SET) < 0) |
475 |
|
pfatal("cannot seek in the temporary input file"); |
476 |
|
|
477 |
< |
if (read(tifd, tibuf[whichbuf], tibuflen) != |
406 |
< |
(ssize_t) tibuflen) |
477 |
> |
if (read(tifd, tibuf[whichbuf], BUFFERSIZE) < 0) |
478 |
|
pfatal("error reading tmp file %s", TMPINNAME); |
479 |
|
} |
480 |
|
return tibuf[whichbuf] + (tireclen * offline); |