1
/* inputting files to be patched */
3
/* Copyright (C) 1986, 1988 Larry Wall
4
Copyright (C) 1991, 1992, 1993, 1997, 1998, 1999, 2002, 2003, 2006,
5
2009 Free Software Foundation, Inc.
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2, or (at your option)
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; see the file COPYING.
19
If not, write to the Free Software Foundation,
20
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
24
#include <backupfile.h>
33
/* Input-file-with-indexable-lines abstract type */
35
static char *i_buffer; /* plan A buffer */
36
static char const **i_ptr; /* pointers to lines in plan A buffer */
38
static size_t tibufsize; /* size of plan b buffers */
39
#ifndef TIBUFSIZE_MINIMUM
40
#define TIBUFSIZE_MINIMUM (8 * 1024) /* minimum value for tibufsize */
42
static int tifd = -1; /* plan b virtual string array */
43
static char *tibuf[2]; /* plan b buffers */
44
static LINENUM tiline[2] = {-1, -1}; /* 1st line in each buffer */
45
static LINENUM lines_per_buf; /* how many lines per buffer */
46
static size_t tireclen; /* length of records in tmp file */
47
static size_t last_line_size; /* size of last input line */
49
static bool plan_a (char const *); /* yield false if memory runs out */
50
static void plan_b (char const *);
51
static void report_revision (bool);
52
static void too_many_lines (char const *) __attribute__((noreturn));
54
/* New patch--prepare to edit another file. */
75
tiline[0] = tiline[1] = -1;
80
/* Construct the line index, somehow or other. */
83
scan_input (char *filename)
85
using_plan_a = ! (debug & 16) && plan_a (filename);
89
if (verbosity != SILENT)
91
filename = quotearg (filename);
93
if (verbosity == VERBOSE)
94
say ("Patching file %s using Plan %s...\n",
95
filename, using_plan_a ? "A" : "B");
97
say ("patching file %s\n", filename);
101
/* Report whether a desired revision was found. */
104
report_revision (bool found_revision)
106
char const *rev = quotearg (revision);
110
if (verbosity == VERBOSE)
111
say ("Good. This file appears to be the %s version.\n", rev);
115
if (verbosity != SILENT)
116
say ("Warning: this file doesn't appear to be the %s version -- patching anyway.\n",
120
fatal ("This file doesn't appear to be the %s version -- aborting.",
124
ask ("This file doesn't appear to be the %s version -- patch anyway? [n] ",
133
too_many_lines (char const *filename)
135
fatal ("File %s has too many lines", quotearg (filename));
140
get_input_file (char const *filename, char const *outname)
142
bool elsewhere = strcmp (filename, outname) != 0;
148
inerrno = stat (filename, &instat) == 0 ? 0 : errno;
150
/* Perhaps look for RCS or SCCS versions. */
155
&& (/* No one can write to it. */
156
(instat.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) == 0
157
/* Only the owner (who's not me) can write to it. */
158
|| ((instat.st_mode & (S_IWGRP|S_IWOTH)) == 0
159
&& instat.st_uid != geteuid ()))))
160
&& (invc = !! (cs = (version_controller
161
(filename, elsewhere,
162
inerrno ? (struct stat *) 0 : &instat,
163
&getbuf, &diffbuf))))) {
167
&& (instat.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) != 0)
168
/* Somebody can write to it. */
169
fatal ("File %s seems to be locked by somebody else under %s",
170
quotearg (filename), cs);
173
/* It might be checked out unlocked. See if it's safe to
174
check out the default version locked. */
176
if (verbosity == VERBOSE)
177
say ("Comparing file %s to default %s version...\n",
178
quotearg (filename), cs);
180
if (systemic (diffbuf) != 0)
182
say ("warning: Patching file %s, which does not match default %s version\n",
183
quotearg (filename), cs);
191
if (cs && version_get (filename, cs, ! inerrno, elsewhere, getbuf,
202
instat.st_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
205
else if (! S_ISREG (instat.st_mode))
206
fatal ("File %s is not a regular file -- can't patch",
207
quotearg (filename));
211
/* Try keeping everything in memory. */
214
plan_a (char const *filename)
216
register char const *s;
217
register char const *lim;
218
register char const **ptr;
219
register char *buffer;
220
register LINENUM iline;
221
size_t size = instat.st_size;
223
/* Fail if the file size doesn't fit in a size_t,
224
or if storage isn't available. */
225
if (! (size == instat.st_size
226
&& (buffer = malloc (size ? size : (size_t) 1))))
229
/* Read the input file, but don't bother reading it if it's empty.
230
When creating files, the files do not actually exist. */
233
int ifd = open (filename, O_RDONLY|binary_transput);
234
size_t buffered = 0, n;
236
pfatal ("can't open file %s", quotearg (filename));
238
while (size - buffered != 0)
240
n = read (ifd, buffer + buffered, size - buffered);
243
/* Some non-POSIX hosts exaggerate st_size in text mode;
244
or the file may have shrunk! */
248
if (n == (size_t) -1)
250
/* Perhaps size is too large for this host. */
258
if (close (ifd) != 0)
262
/* Scan the buffer and build array of pointers to lines. */
264
iline = 3; /* 1 unused, 1 for SOF, 1 for EOF if last line is incomplete */
265
for (s = buffer; (s = (char *) memchr (s, '\n', lim - s)); s++)
267
too_many_lines (filename);
268
if (! (iline == (size_t) iline
269
&& (size_t) iline * sizeof *ptr / sizeof *ptr == (size_t) iline
270
&& (ptr = (char const **) malloc ((size_t) iline * sizeof *ptr))))
276
for (s = buffer; ; s++)
279
if (! (s = (char *) memchr (s, '\n', lim - s)))
282
if (size && lim[-1] != '\n')
284
input_lines = iline - 1;
288
char const *rev = revision;
290
bool found_revision = false;
291
size_t revlen = strlen (rev);
295
char const *limrev = lim - revlen;
297
for (s = buffer; (s = (char *) memchr (s, rev0, limrev - s)); s++)
298
if (memcmp (s, rev, revlen) == 0
299
&& (s == buffer || ISSPACE ((unsigned char) s[-1]))
300
&& (s + 1 == limrev || ISSPACE ((unsigned char) s[revlen])))
302
found_revision = true;
307
report_revision (found_revision);
310
/* Plan A will work. */
316
/* Keep (virtually) nothing in memory. */
319
plan_b (char const *filename)
324
register size_t maxlen;
325
register bool found_revision;
327
register char const *rev;
328
register size_t revlen;
329
register LINENUM line = 1;
332
if (instat.st_size == 0)
333
filename = NULL_DEVICE;
334
if (! (ifp = fopen (filename, binary_transput ? "rb" : "r")))
335
pfatal ("Can't open file %s", quotearg (filename));
336
exclusive = TMPINNAME_needs_removal ? 0 : O_EXCL;
337
TMPINNAME_needs_removal = 1;
338
tifd = create_file (TMPINNAME, O_RDWR | O_BINARY | exclusive, (mode_t) 0,
344
found_revision = !rev;
345
revlen = rev ? strlen (rev) : 0;
347
while ((c = getc (ifp)) != EOF)
354
too_many_lines (filename);
364
found_revision = ISSPACE ((unsigned char) c);
367
else if (i != (size_t) -1)
368
i = rev[i]==c ? i + 1 : (size_t) -1;
370
if (i == (size_t) -1 && ISSPACE ((unsigned char) c))
376
report_revision (found_revision);
377
Fseek (ifp, 0, SEEK_SET); /* rewind file */
378
for (tibufsize = TIBUFSIZE_MINIMUM; tibufsize < maxlen; tibufsize <<= 1)
380
lines_per_buf = tibufsize / maxlen;
382
tibuf[0] = xmalloc (2 * tibufsize);
383
tibuf[1] = tibuf[0] + tibufsize;
385
for (line = 1; ; line++)
387
char *p = tibuf[0] + maxlen * (line % lines_per_buf);
389
if (! (line % lines_per_buf)) /* new block */
390
if (write (tifd, tibuf[0], tibufsize) != tibufsize)
392
if ((c = getc (ifp)) == EOF)
400
last_line_size = p - p0;
404
if ((c = getc (ifp)) == EOF)
406
last_line_size = p - p0;
413
if (ferror (ifp) || fclose (ifp) != 0)
416
if (line % lines_per_buf != 0)
417
if (write (tifd, tibuf[0], tibufsize) != tibufsize)
419
input_lines = line - 1;
422
/* Fetch a line from the input file.
423
WHICHBUF is ignored when the file is in memory. */
426
ifetch (LINENUM line, bool whichbuf, size_t *psize)
428
register char const *q;
429
register char const *p;
431
if (line < 1 || line > input_lines) {
437
*psize = i_ptr[line + 1] - p;
440
LINENUM offline = line % lines_per_buf;
441
LINENUM baseline = line - offline;
443
if (tiline[0] == baseline)
445
else if (tiline[1] == baseline)
448
tiline[whichbuf] = baseline;
449
if ((lseek (tifd, baseline/lines_per_buf * tibufsize, SEEK_SET)
451
|| read (tifd, tibuf[whichbuf], tibufsize) < 0)
454
p = tibuf[whichbuf] + (tireclen*offline);
455
if (line == input_lines)
456
*psize = last_line_size;
458
for (q = p; *q++ != '\n'; )