|
21 | 21 | #include <dirent.h>
|
22 | 22 |
|
23 | 23 | #include "access/htup_details.h"
|
| 24 | +#include "access/xlog_internal.h" |
24 | 25 | #include "catalog/pg_type.h"
|
25 | 26 | #include "funcapi.h"
|
26 | 27 | #include "mb/pg_wchar.h"
|
@@ -473,3 +474,96 @@ pg_ls_dir_1arg(PG_FUNCTION_ARGS)
|
473 | 474 | {
|
474 | 475 | return pg_ls_dir(fcinfo);
|
475 | 476 | }
|
| 477 | + |
| 478 | +/* Generic function to return a directory listing of files */ |
| 479 | +static Datum |
| 480 | +pg_ls_dir_files(FunctionCallInfo fcinfo, char *dir) |
| 481 | +{ |
| 482 | + FuncCallContext *funcctx; |
| 483 | + struct dirent *de; |
| 484 | + directory_fctx *fctx; |
| 485 | + |
| 486 | + if (SRF_IS_FIRSTCALL()) |
| 487 | + { |
| 488 | + MemoryContext oldcontext; |
| 489 | + TupleDesc tupdesc; |
| 490 | + |
| 491 | + funcctx = SRF_FIRSTCALL_INIT(); |
| 492 | + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); |
| 493 | + |
| 494 | + fctx = palloc(sizeof(directory_fctx)); |
| 495 | + |
| 496 | + tupdesc = CreateTemplateTupleDesc(3, false); |
| 497 | + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", |
| 498 | + TEXTOID, -1, 0); |
| 499 | + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "size", |
| 500 | + INT8OID, -1, 0); |
| 501 | + TupleDescInitEntry(tupdesc, (AttrNumber) 3, "modification", |
| 502 | + TIMESTAMPTZOID, -1, 0); |
| 503 | + funcctx->tuple_desc = BlessTupleDesc(tupdesc); |
| 504 | + |
| 505 | + fctx->location = pstrdup(dir); |
| 506 | + fctx->dirdesc = AllocateDir(fctx->location); |
| 507 | + |
| 508 | + if (!fctx->dirdesc) |
| 509 | + ereport(ERROR, |
| 510 | + (errcode_for_file_access(), |
| 511 | + errmsg("could not read directory \"%s\": %m", |
| 512 | + fctx->location))); |
| 513 | + |
| 514 | + funcctx->user_fctx = fctx; |
| 515 | + MemoryContextSwitchTo(oldcontext); |
| 516 | + } |
| 517 | + |
| 518 | + funcctx = SRF_PERCALL_SETUP(); |
| 519 | + fctx = (directory_fctx *) funcctx->user_fctx; |
| 520 | + |
| 521 | + while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL) |
| 522 | + { |
| 523 | + Datum values[3]; |
| 524 | + bool nulls[3]; |
| 525 | + char path[MAXPGPATH]; |
| 526 | + struct stat attrib; |
| 527 | + HeapTuple tuple; |
| 528 | + |
| 529 | + /* Skip hidden files */ |
| 530 | + if (de->d_name[0] == '.') |
| 531 | + continue; |
| 532 | + |
| 533 | + /* Get the file info */ |
| 534 | + snprintf(path, MAXPGPATH, "%s/%s", fctx->location, de->d_name); |
| 535 | + if (stat(path, &attrib) < 0) |
| 536 | + ereport(ERROR, |
| 537 | + (errcode_for_file_access(), |
| 538 | + errmsg("could not stat directory \"%s\": %m", dir))); |
| 539 | + |
| 540 | + /* Ignore anything but regular files */ |
| 541 | + if (!S_ISREG(attrib.st_mode)) |
| 542 | + continue; |
| 543 | + |
| 544 | + values[0] = CStringGetTextDatum(de->d_name); |
| 545 | + values[1] = Int64GetDatum((int64) attrib.st_size); |
| 546 | + values[2] = TimestampTzGetDatum(time_t_to_timestamptz(attrib.st_mtime)); |
| 547 | + memset(nulls, 0, sizeof(nulls)); |
| 548 | + |
| 549 | + tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); |
| 550 | + SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); |
| 551 | + } |
| 552 | + |
| 553 | + FreeDir(fctx->dirdesc); |
| 554 | + SRF_RETURN_DONE(funcctx); |
| 555 | +} |
| 556 | + |
| 557 | +/* Function to return the list of files in the log directory */ |
| 558 | +Datum |
| 559 | +pg_ls_logdir(PG_FUNCTION_ARGS) |
| 560 | +{ |
| 561 | + return pg_ls_dir_files(fcinfo, Log_directory); |
| 562 | +} |
| 563 | + |
| 564 | +/* Function to return the list of files in the WAL directory */ |
| 565 | +Datum |
| 566 | +pg_ls_waldir(PG_FUNCTION_ARGS) |
| 567 | +{ |
| 568 | + return pg_ls_dir_files(fcinfo, XLOGDIR); |
| 569 | +} |
0 commit comments