~ubuntu-branches/ubuntu/trusty/patch/trusty-security

« back to all changes in this revision

Viewing changes to src/inp.c

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Berg
  • Date: 2009-12-02 10:25:26 UTC
  • mfrom: (5.1.1 sid)
  • Revision ID: james.westby@ubuntu.com-20091202102526-5luk0zsqhghu58l2
Tags: 2.6-2
* Update watch file.
* Section: vcs.
* Suggests: diffutils-doc instead of diff-doc, thanks Christoph Anton
  Mitterer for spotting. Closes: #558974.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* inputting files to be patched */
 
2
 
 
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.
 
6
 
 
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)
 
10
   any later version.
 
11
 
 
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.
 
16
 
 
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.  */
 
21
 
 
22
#define XTERN extern
 
23
#include <common.h>
 
24
#include <backupfile.h>
 
25
#include <pch.h>
 
26
#include <quotearg.h>
 
27
#include <util.h>
 
28
#include <xalloc.h>
 
29
#undef XTERN
 
30
#define XTERN
 
31
#include <inp.h>
 
32
 
 
33
/* Input-file-with-indexable-lines abstract type */
 
34
 
 
35
static char *i_buffer;                  /* plan A buffer */
 
36
static char const **i_ptr;              /* pointers to lines in plan A buffer */
 
37
 
 
38
static size_t tibufsize;                /* size of plan b buffers */
 
39
#ifndef TIBUFSIZE_MINIMUM
 
40
#define TIBUFSIZE_MINIMUM (8 * 1024)    /* minimum value for tibufsize */
 
41
#endif
 
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 */
 
48
 
 
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));
 
53
 
 
54
/* New patch--prepare to edit another file. */
 
55
 
 
56
void
 
57
re_input (void)
 
58
{
 
59
    if (using_plan_a) {
 
60
      if (i_buffer)
 
61
        {
 
62
          free (i_buffer);
 
63
          i_buffer = 0;
 
64
          free (i_ptr);
 
65
        }
 
66
    }
 
67
    else {
 
68
        close (tifd);
 
69
        tifd = -1;
 
70
        if (tibuf[0])
 
71
          {
 
72
            free (tibuf[0]);
 
73
            tibuf[0] = 0;
 
74
          }
 
75
        tiline[0] = tiline[1] = -1;
 
76
        tireclen = 0;
 
77
    }
 
78
}
 
79
 
 
80
/* Construct the line index, somehow or other. */
 
81
 
 
82
void
 
83
scan_input (char *filename)
 
84
{
 
85
    using_plan_a = ! (debug & 16) && plan_a (filename);
 
86
    if (!using_plan_a)
 
87
        plan_b(filename);
 
88
 
 
89
    if (verbosity != SILENT)
 
90
      {
 
91
        filename = quotearg (filename);
 
92
 
 
93
        if (verbosity == VERBOSE)
 
94
          say ("Patching file %s using Plan %s...\n",
 
95
               filename, using_plan_a ? "A" : "B");
 
96
        else
 
97
          say ("patching file %s\n", filename);
 
98
      }
 
99
}
 
100
 
 
101
/* Report whether a desired revision was found.  */
 
102
 
 
103
static void
 
104
report_revision (bool found_revision)
 
105
{
 
106
  char const *rev = quotearg (revision);
 
107
 
 
108
  if (found_revision)
 
109
    {
 
110
      if (verbosity == VERBOSE)
 
111
        say ("Good.  This file appears to be the %s version.\n", rev);
 
112
    }
 
113
  else if (force)
 
114
    {
 
115
      if (verbosity != SILENT)
 
116
        say ("Warning: this file doesn't appear to be the %s version -- patching anyway.\n",
 
117
             rev);
 
118
    }
 
119
  else if (batch)
 
120
    fatal ("This file doesn't appear to be the %s version -- aborting.",
 
121
           rev);
 
122
  else
 
123
    {
 
124
      ask ("This file doesn't appear to be the %s version -- patch anyway? [n] ",
 
125
           rev);
 
126
      if (*buf != 'y')
 
127
        fatal ("aborted");
 
128
    }
 
129
}
 
130
 
 
131
 
 
132
static void
 
133
too_many_lines (char const *filename)
 
134
{
 
135
  fatal ("File %s has too many lines", quotearg (filename));
 
136
}
 
137
 
 
138
 
 
139
void
 
140
get_input_file (char const *filename, char const *outname)
 
141
{
 
142
    bool elsewhere = strcmp (filename, outname) != 0;
 
143
    char const *cs;
 
144
    char *diffbuf;
 
145
    char *getbuf;
 
146
 
 
147
    if (inerrno == -1)
 
148
      inerrno = stat (filename, &instat) == 0 ? 0 : errno;
 
149
 
 
150
    /* Perhaps look for RCS or SCCS versions.  */
 
151
    if (patch_get
 
152
        && invc != 0
 
153
        && (inerrno
 
154
            || (! elsewhere
 
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))))) {
 
164
 
 
165
            if (!inerrno) {
 
166
                if (!elsewhere
 
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);
 
171
                if (diffbuf)
 
172
                  {
 
173
                    /* It might be checked out unlocked.  See if it's safe to
 
174
                       check out the default version locked.  */
 
175
 
 
176
                    if (verbosity == VERBOSE)
 
177
                      say ("Comparing file %s to default %s version...\n",
 
178
                           quotearg (filename), cs);
 
179
 
 
180
                    if (systemic (diffbuf) != 0)
 
181
                      {
 
182
                        say ("warning: Patching file %s, which does not match default %s version\n",
 
183
                             quotearg (filename), cs);
 
184
                        cs = 0;
 
185
                      }
 
186
                  }
 
187
                if (dry_run)
 
188
                  cs = 0;
 
189
            }
 
190
 
 
191
            if (cs && version_get (filename, cs, ! inerrno, elsewhere, getbuf,
 
192
                                   &instat))
 
193
              inerrno = 0;
 
194
 
 
195
            free (getbuf);
 
196
            if (diffbuf)
 
197
              free (diffbuf);
 
198
      }
 
199
 
 
200
    if (inerrno)
 
201
      {
 
202
        instat.st_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
 
203
        instat.st_size = 0;
 
204
      }
 
205
    else if (! S_ISREG (instat.st_mode))
 
206
      fatal ("File %s is not a regular file -- can't patch",
 
207
             quotearg (filename));
 
208
}
 
209
 
 
210
 
 
211
/* Try keeping everything in memory. */
 
212
 
 
213
static bool
 
214
plan_a (char const *filename)
 
215
{
 
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;
 
222
 
 
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))))
 
227
    return false;
 
228
 
 
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.  */
 
231
  if (size)
 
232
    {
 
233
      int ifd = open (filename, O_RDONLY|binary_transput);
 
234
      size_t buffered = 0, n;
 
235
      if (ifd < 0)
 
236
        pfatal ("can't open file %s", quotearg (filename));
 
237
 
 
238
      while (size - buffered != 0)
 
239
        {
 
240
          n = read (ifd, buffer + buffered, size - buffered);
 
241
          if (n == 0)
 
242
            {
 
243
              /* Some non-POSIX hosts exaggerate st_size in text mode;
 
244
                 or the file may have shrunk!  */
 
245
              size = buffered;
 
246
              break;
 
247
            }
 
248
          if (n == (size_t) -1)
 
249
            {
 
250
              /* Perhaps size is too large for this host.  */
 
251
              close (ifd);
 
252
              free (buffer);
 
253
              return false;
 
254
            }
 
255
          buffered += n;
 
256
        }
 
257
 
 
258
      if (close (ifd) != 0)
 
259
        read_fatal ();
 
260
    }
 
261
 
 
262
  /* Scan the buffer and build array of pointers to lines.  */
 
263
  lim = buffer + size;
 
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++)
 
266
    if (++iline < 0)
 
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))))
 
271
    {
 
272
      free (buffer);
 
273
      return false;
 
274
    }
 
275
  iline = 0;
 
276
  for (s = buffer;  ;  s++)
 
277
    {
 
278
      ptr[++iline] = s;
 
279
      if (! (s = (char *) memchr (s, '\n', lim - s)))
 
280
        break;
 
281
    }
 
282
  if (size && lim[-1] != '\n')
 
283
    ptr[++iline] = lim;
 
284
  input_lines = iline - 1;
 
285
 
 
286
  if (revision)
 
287
    {
 
288
      char const *rev = revision;
 
289
      int rev0 = rev[0];
 
290
      bool found_revision = false;
 
291
      size_t revlen = strlen (rev);
 
292
 
 
293
      if (revlen <= size)
 
294
        {
 
295
          char const *limrev = lim - revlen;
 
296
 
 
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])))
 
301
              {
 
302
                found_revision = true;
 
303
                break;
 
304
              }
 
305
        }
 
306
 
 
307
      report_revision (found_revision);
 
308
    }
 
309
 
 
310
  /* Plan A will work.  */
 
311
  i_buffer = buffer;
 
312
  i_ptr = ptr;
 
313
  return true;
 
314
}
 
315
 
 
316
/* Keep (virtually) nothing in memory. */
 
317
 
 
318
static void
 
319
plan_b (char const *filename)
 
320
{
 
321
  register FILE *ifp;
 
322
  register int c;
 
323
  register size_t len;
 
324
  register size_t maxlen;
 
325
  register bool found_revision;
 
326
  register size_t i;
 
327
  register char const *rev;
 
328
  register size_t revlen;
 
329
  register LINENUM line = 1;
 
330
  int exclusive;
 
331
 
 
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,
 
339
                      true);
 
340
  i = 0;
 
341
  len = 0;
 
342
  maxlen = 1;
 
343
  rev = revision;
 
344
  found_revision = !rev;
 
345
  revlen = rev ? strlen (rev) : 0;
 
346
 
 
347
  while ((c = getc (ifp)) != EOF)
 
348
    {
 
349
      len++;
 
350
 
 
351
      if (c == '\n')
 
352
        {
 
353
          if (++line < 0)
 
354
            too_many_lines (filename);
 
355
          if (maxlen < len)
 
356
              maxlen = len;
 
357
          len = 0;
 
358
        }
 
359
 
 
360
      if (!found_revision)
 
361
        {
 
362
          if (i == revlen)
 
363
            {
 
364
              found_revision = ISSPACE ((unsigned char) c);
 
365
              i = (size_t) -1;
 
366
            }
 
367
          else if (i != (size_t) -1)
 
368
            i = rev[i]==c ? i + 1 : (size_t) -1;
 
369
 
 
370
          if (i == (size_t) -1  &&  ISSPACE ((unsigned char) c))
 
371
            i = 0;
 
372
        }
 
373
    }
 
374
 
 
375
  if (revision)
 
376
    report_revision (found_revision);
 
377
  Fseek (ifp, 0, SEEK_SET);             /* rewind file */
 
378
  for (tibufsize = TIBUFSIZE_MINIMUM;  tibufsize < maxlen;  tibufsize <<= 1)
 
379
    continue;
 
380
  lines_per_buf = tibufsize / maxlen;
 
381
  tireclen = maxlen;
 
382
  tibuf[0] = xmalloc (2 * tibufsize);
 
383
  tibuf[1] = tibuf[0] + tibufsize;
 
384
 
 
385
  for (line = 1; ; line++)
 
386
    {
 
387
      char *p = tibuf[0] + maxlen * (line % lines_per_buf);
 
388
      char const *p0 = p;
 
389
      if (! (line % lines_per_buf))     /* new block */
 
390
        if (write (tifd, tibuf[0], tibufsize) != tibufsize)
 
391
          write_fatal ();
 
392
      if ((c = getc (ifp)) == EOF)
 
393
        break;
 
394
 
 
395
      for (;;)
 
396
        {
 
397
          *p++ = c;
 
398
          if (c == '\n')
 
399
            {
 
400
              last_line_size = p - p0;
 
401
              break;
 
402
            }
 
403
 
 
404
          if ((c = getc (ifp)) == EOF)
 
405
            {
 
406
              last_line_size = p - p0;
 
407
              line++;
 
408
              goto EOF_reached;
 
409
            }
 
410
        }
 
411
    }
 
412
 EOF_reached:
 
413
  if (ferror (ifp)  ||  fclose (ifp) != 0)
 
414
    read_fatal ();
 
415
 
 
416
  if (line % lines_per_buf  !=  0)
 
417
    if (write (tifd, tibuf[0], tibufsize) != tibufsize)
 
418
      write_fatal ();
 
419
  input_lines = line - 1;
 
420
}
 
421
 
 
422
/* Fetch a line from the input file.
 
423
   WHICHBUF is ignored when the file is in memory.  */
 
424
 
 
425
char const *
 
426
ifetch (LINENUM line, bool whichbuf, size_t *psize)
 
427
{
 
428
    register char const *q;
 
429
    register char const *p;
 
430
 
 
431
    if (line < 1 || line > input_lines) {
 
432
        *psize = 0;
 
433
        return "";
 
434
    }
 
435
    if (using_plan_a) {
 
436
        p = i_ptr[line];
 
437
        *psize = i_ptr[line + 1] - p;
 
438
        return p;
 
439
    } else {
 
440
        LINENUM offline = line % lines_per_buf;
 
441
        LINENUM baseline = line - offline;
 
442
 
 
443
        if (tiline[0] == baseline)
 
444
            whichbuf = false;
 
445
        else if (tiline[1] == baseline)
 
446
            whichbuf = true;
 
447
        else {
 
448
            tiline[whichbuf] = baseline;
 
449
            if ((lseek (tifd, baseline/lines_per_buf * tibufsize, SEEK_SET)
 
450
                 == -1)
 
451
                || read (tifd, tibuf[whichbuf], tibufsize) < 0)
 
452
              read_fatal ();
 
453
        }
 
454
        p = tibuf[whichbuf] + (tireclen*offline);
 
455
        if (line == input_lines)
 
456
            *psize = last_line_size;
 
457
        else {
 
458
            for (q = p;  *q++ != '\n';  )
 
459
                continue;
 
460
            *psize = q - p;
 
461
        }
 
462
        return p;
 
463
    }
 
464
}