|
20 | 20 | #include "postgres_fe.h"
|
21 | 21 | #include "libpq-fe.h"
|
22 | 22 |
|
| 23 | +#include <fcntl.h> |
23 | 24 | #include <locale.h>
|
24 | <
10000
code>25 | #include <signal.h>
|
25 | 26 | #include <sys/types.h>
|
@@ -294,50 +295,77 @@ get_pgpid(void)
|
294 | 295 | static char **
|
295 | 296 | readfile(const char *path)
|
296 | 297 | {
|
297 |
| - FILE *infile; |
298 |
| - int maxlength = 1, |
299 |
| - linelen = 0; |
300 |
| - int nlines = 0; |
| 298 | + int fd; |
| 299 | + int nlines; |
301 | 300 | char **result;
|
302 | 301 | char *buffer;
|
303 |
| - int c; |
| 302 | + char *linebegin; |
| 303 | + int i; |
| 304 | + int n; |
| 305 | + int len; |
| 306 | + struct stat statbuf; |
304 | 307 |
|
305 |
| - if ((infile = fopen(path, "r")) == NULL) |
| 308 | + /* |
| 309 | + * Slurp the file into memory. |
| 310 | + * |
| 311 | + * The file can change concurrently, so we read the whole file into memory |
| 312 | + * with a single read() call. That's not guaranteed to get an atomic |
| 313 | + * snapshot, but in practice, for a small file, it's close enough for the |
| 314 | + * current use. |
| 315 | + */ |
| 316 | + fd = open(path, O_RDONLY | PG_BINARY, 0); |
| 317 | + if (fd < 0) |
306 | 318 | return NULL;
|
| 319 | + if (fstat(fd, &statbuf) < 0) |
| 320 | + return NULL; |
| 321 | + if (statbuf.st_size == 0) |
| 322 | + { |
| 323 | + /* empty file */ |
| 324 | + result = (char **) pg_malloc(sizeof(char *)); |
| 325 | + *result = NULL; |
| 326 | + return result; |
| 327 | + } |
| 328 | + buffer = pg_malloc(statbuf.st_size + 1); |
307 | 329 |
|
308 |
| - /* pass over the file twice - the first time to size the result */<
E29B
/div> |
| 330 | + len = read(fd, buffer, statbuf.st_size + 1); |
| 331 | + close(fd); |
| 332 | + if (len != statbuf.st_size) |
| 333 | + { |
| 334 | + /* oops, the file size changed between fstat and read */ |
| 335 | + free(buffer); |
| 336 | + return NULL; |
| 337 | + } |
309 | 338 |
|
310 |
| - while ((c = fgetc(infile)) != EOF) |
| 339 | + /* count newlines */ |
| 340 | + nlines = 0; |
| 341 | + for (i = 0; i < len - 1; i++) |
311 | 342 | {
|
312 |
| - linelen++; |
313 |
| - if (c == '\n') |
314 |
| - { |
| 343 | + if (buffer[i] == '\n') |
315 | 344 | nlines++;
|
316 |
| - if (linelen > maxlength) |
317 |
| - maxlength = linelen; |
318 |
| - linelen = 0; |
319 |
| - } |
320 | 345 | }
|
| 346 | + nlines++; /* account for the last line */ |
321 | 347 |
|
322 |
| - /* handle last line without a terminating newline (yuck) */ |
323 |
| - if (linelen) |
324 |
| - nlines++; |
325 |
| - if (linelen > maxlength) |
326 |
| - maxlength = linelen; |
327 |
| - |
328 |
| - /* set up the result and the line buffer */ |
| 348 | + /* set up the result buffer */ |
329 | 349 | result = (char **) pg_malloc((nlines + 1) * sizeof(char *));
|
330 |
| - buffer = (char *) pg_malloc(maxlength + 1); |
331 | 350 |
|
332 |
| - /* now reprocess the file and store the lines */ |
333 |
| - rewind(infile); |
334 |
| - nlines = 0; |
335 |
| - while (fgets(buffer, maxlength + 1, infile) != NULL) |
336 |
| - result[nlines++] = xstrdup(buffer); |
| 351 | + /* now split the buffer into lines */ |
| 352 | + linebegin = buffer; |
| 353 | + n = 0; |
| 354 | + for (i = 0; i < len; i++) |
| 355 | + { |
| 356 | + if (buffer[i] == '\n' || i == len - 1) |
| 357 | + { |
| 358 | + int slen = &buffer[i] - linebegin + 1; |
| 359 | + char *linebuf = pg_malloc(slen + 1); |
| 360 | + memcpy(linebuf, linebegin, slen); |
| 361 | + linebuf[slen] = '\0'; |
| 362 | + result[n++] = linebuf; |
| 363 | + linebegin = &buffer[i + 1]; |
| 364 | + } |
| 365 | + } |
| 366 | + result[n] = NULL; |
337 | 367 |
|
338 |
| - fclose(infile); |
339 | 368 | free(buffer);
|
340 |
| - result[nlines] = NULL; |
341 | 369 |
|
342 | 370 | return result;
|
343 | 371 | }
|
|
0 commit comments