1/*-------------------------------------------------------------------------
4 * Functions for direct access to files
7 * Copyright (c) 2004-2025, PostgreSQL Global Development Group
9 * Author: Andreas Pflug <pgadmin@pse-consulting.de>
12 * src/backend/utils/adt/genfile.c
14 *-------------------------------------------------------------------------
26#include "catalog/pg_tablespace_d.h"
42 * Convert a "text" filename argument to C string, and check it's allowable.
44 * Filename may be absolute or relative to the DataDir, but we only allow
45 * absolute paths that match DataDir or Log_directory.
47 * This does a privilege check against the 'pg_read_server_files' role, so
48 * this function is really only appropriate for callers who are only checking
49 * 'read' access. Do not use this function if you are looking for a check
50 * for 'write' or 'program' access without updating it to access the type
51 * of check as an argument and checking the appropriate role membership.
62 * Roles with privileges of the 'pg_read_server_files' role are allowed to
63 * access any files on the server as the PG user, so no need to do any
64 * further checks here.
70 * User isn't a member of the pg_read_server_files role, so check if it's
76 * Allow absolute paths if within DataDir or Log_directory, even
77 * though Log_directory might be outside DataDir.
83 (
errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
84 errmsg(
"absolute path not allowed")));
88 (
errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
89 errmsg(
"path must be in or below the data directory")));
96 * Read a section of a file, returning it as bytea
98 * Caller is responsible for all permissions checking.
100 * We read the whole of the file when bytes_to_read is negative.
110 /* clamp request size to what we can actually deliver */
113 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
114 errmsg(
"requested length too large")));
118 if (missing_ok && errno == ENOENT)
123 errmsg(
"could not open file \"%s\" for reading: %m",
127 if (
fseeko(file, (off_t) seek_offset,
128 (seek_offset >= 0) ? SEEK_SET : SEEK_END) != 0)
133 if (bytes_to_read >= 0)
135 /* If passed explicit read size just do it */
138 nbytes = fread(
VARDATA(
buf), 1, (
size_t) bytes_to_read, file);
142 /* Negative read size, read rest of file */
146 /* Leave room in the buffer for the varlena length word */
150 while (!(feof(file) || ferror(file)))
154 /* Minimum amount to read at a time */
155#define MIN_READ_SIZE 4096
158 * If not at end of file, and sbuf.len is equal to MaxAllocSize -
159 * 1, then either the file is too large, or there is nothing left
160 * to read. Attempt to read one more byte to see if the end of
161 * file has been reached. If not, the file is too large; we'd
162 * rather give the error message for that ourselves.
168 if (fread(rbuf, 1, 1, file) != 0 || !feof(file))
170 (
errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
171 errmsg(
"file length too large")));
176 /* OK, ensure that we can read at least MIN_READ_SIZE */
180 * stringinfo.c likes to allocate in powers of 2, so it's likely
181 * that much more space is available than we asked for. Use all
182 * of it, rather than making more fread calls than necessary.
184 rbytes = fread(sbuf.
data + sbuf.
len, 1,
185 (
size_t) (sbuf.
maxlen - sbuf.
len - 1), file);
190 /* Now we can commandeer the stringinfo's buffer as the result */
207 * Similar to read_binary_file, but we verify that the contents are valid
208 * in the database encoding.
220 /* Make sure the input is valid */
223 /* OK, we can cast it to text safely */
231 * Read a section of a file, returning it as text
233 * No superuser check done here- instead privileges are handled by the
236 * If read_to_eof is true, bytes_to_read must be -1, otherwise negative values
237 * are not allowed for bytes_to_read.
241 bool read_to_eof,
bool missing_ok)
244 Assert(bytes_to_read == -1);
245 else if (bytes_to_read < 0)
247 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
248 errmsg(
"requested length cannot be negative")));
251 seek_offset, bytes_to_read, missing_ok);
255 * Read a section of a file, returning it as bytea
257 * Parameters are interpreted the same as pg_read_file_common().
262 bool read_to_eof,
bool missing_ok)
265 Assert(bytes_to_read == -1);
266 else if (bytes_to_read < 0)
268 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
269 errmsg(
"requested length cannot be negative")));
272 seek_offset, bytes_to_read, missing_ok);
277 * Wrapper functions for the variants of SQL functions pg_read_file() and
278 * pg_read_binary_file().
280 * These are necessary to pass the sanity check in opr_sanity, which checks
281 * that all built-in functions that share the implementing C function take
282 * the same number of arguments.
422 bool missing_ok =
false;
424 /* check the optional argument */
432 if (missing_ok && errno == ENOENT)
441 * This record type had better match the output parameters declared for me
446 "size", INT8OID, -1, 0);
448 "access", TIMESTAMPTZOID, -1, 0);
450 "modification", TIMESTAMPTZOID, -1, 0);
452 "change", TIMESTAMPTZOID, -1, 0);
454 "creation", TIMESTAMPTZOID, -1, 0);
456 "isdir", BOOLOID, -1, 0);
459 memset(isnull,
false,
sizeof(isnull));
464 /* Unix has file status change time, while Win32 has creation time */
465#if !defined(WIN32) && !defined(__CYGWIN__)
482 * stat a file (1 argument version)
484 * note: this wrapper is necessary to pass the sanity check in opr_sanity,
485 * which checks that all built-in functions that share the implementing C
486 * function take the same number of arguments
495 * List a directory (returns the filenames only)
502 bool missing_ok =
false;
503 bool include_dot_dirs =
false;
509 /* check the optional arguments */
523 /* Return empty tuplestore if appropriate */
524 if (missing_ok && errno == ENOENT)
526 /* Otherwise, we can let ReadDir() throw the error */
529 while ((de =
ReadDir(dirdesc, location)) != NULL)
534 if (!include_dot_dirs &&
535 (strcmp(de->d_name,
".") == 0 ||
536 strcmp(de->d_name,
"..") == 0))
551 * List a directory (1 argument version)
553 * note: this wrapper is necessary to pass the sanity check in opr_sanity,
554 * which checks that all built-in functions that share the implementing C
555 * function take the same number of arguments.
564 * Generic function to return a directory listing of files.
566 * If the directory isn't there, silently return an empty set if missing_ok.
567 * Other unreadable-directory cases throw an error.
579 * Now walk the directory. Note that we must do this within a single SRF
580 * call, not leave the directory open across multiple calls, since we
581 * can't count on the SRF being run to completion.
586 /* Return empty tuplestore if appropriate */
587 if (missing_ok && errno == ENOENT)
589 /* Otherwise, we can let ReadDir() throw the error */
592 while ((de =
ReadDir(dirdesc, dir)) != NULL)
599 /* Skip hidden files */
600 if (de->d_name[0] ==
'.')
603 /* Get the file info */
604 snprintf(path,
sizeof(path),
"%s/%s", dir, de->d_name);
605 if (
stat(path, &attrib) < 0)
607 /* Ignore concurrently-deleted files, else complain */
612 errmsg(
"could not stat file \"%s\": %m", path)));
615 /* Ignore anything but regular files */
622 memset(nulls, 0,
sizeof(nulls));
631/* Function to return the list of files in the log directory */
638/* Function to return the list of files in the WAL directory */
646 * Generic function to return the list of files in pgsql_tmp
655 (
errcode(ERRCODE_UNDEFINED_OBJECT),
656 errmsg(
"tablespace with OID %u does not exist",
664 * Function to return the list of temporary files in the pg_default tablespace's
665 * pgsql_tmp directory
674 * Function to return the list of temporary files in the specified tablespace's
675 * pgsql_tmp directory
684 * Function to return the list of files in the WAL archive status directory.
693 * Function to return the list of files in the WAL summaries directory.
702 * Function to return the list of files in the PG_LOGICAL_SNAPSHOTS_DIR
712 * Function to return the list of files in the PG_LOGICAL_MAPPINGS_DIR
722 * Function to return the list of files in the PG_REPLSLOT_DIR/<slot_name>
738 (
errcode(ERRCODE_UNDEFINED_OBJECT),
739 errmsg(
"replication slot \"%s\" does not exist",
bool has_privs_of_role(Oid member, Oid role)
TimestampTz time_t_to_timestamptz(pg_time_t tm)
static Datum values[MAXATTR]
#define CStringGetTextDatum(s)
int errcode_for_file_access(void)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
DIR * AllocateDir(const char *dirname)
struct dirent * ReadDir(DIR *dir, const char *dirname)
FILE * AllocateFile(const char *name, const char *mode)
void TempTablespacePath(char *path, Oid tablespace)
#define PG_GETARG_TEXT_PP(n)
#define PG_RETURN_BYTEA_P(x)
#define PG_GETARG_INT64(n)
#define PG_RETURN_TEXT_P(x)
#define PG_GETARG_BOOL(n)
#define PG_RETURN_DATUM(x)
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
#define MAT_SRF_USE_EXPECTED_DESC
Datum pg_read_file_off_len_missing(PG_FUNCTION_ARGS)
Datum pg_ls_summariesdir(PG_FUNCTION_ARGS)
Datum pg_read_file_off_len(PG_FUNCTION_ARGS)
Datum pg_read_binary_file_all_missing(PG_FUNCTION_ARGS)
Datum pg_read_binary_file_all(PG_FUNCTION_ARGS)
Datum pg_ls_logicalsnapdir(PG_FUNCTION_ARGS)
Datum pg_ls_waldir(PG_FUNCTION_ARGS)
Datum pg_ls_replslotdir(PG_FUNCTION_ARGS)
Datum pg_ls_dir(PG_FUNCTION_ARGS)
static bytea * pg_read_binary_file_common(text *filename_t, int64 seek_offset, int64 bytes_to_read, bool read_to_eof, bool missing_ok)
Datum pg_ls_archive_statusdir(PG_FUNCTION_ARGS)
Datum pg_stat_file(PG_FUNCTION_ARGS)
static text * read_text_file(const char *filename, int64 seek_offset, int64 bytes_to_read, bool missing_ok)
static Datum pg_ls_tmpdir(FunctionCallInfo fcinfo, Oid tblspc)
static text * pg_read_file_common(text *filename_t, int64 seek_offset, int64 bytes_to_read, bool read_to_eof, bool missing_ok)
static bytea * read_binary_file(const char *filename, int64 seek_offset, int64 bytes_to_read, bool missing_ok)
Datum pg_read_binary_file_off_len(PG_FUNCTION_ARGS)
Datum pg_ls_dir_1arg(PG_FUNCTION_ARGS)
Datum pg_read_binary_file_off_len_missing(PG_FUNCTION_ARGS)
Datum pg_read_file_all(PG_FUNCTION_ARGS)
Datum pg_ls_tmpdir_noargs(PG_FUNCTION_ARGS)
Datum pg_ls_logdir(PG_FUNCTION_ARGS)
Datum pg_ls_logicalmapdir(PG_FUNCTION_ARGS)
Datum pg_stat_file_1arg(PG_FUNCTION_ARGS)
Datum pg_read_file_all_missing(PG_FUNCTION_ARGS)
Datum pg_ls_tmpdir_1arg(PG_FUNCTION_ARGS)
static Datum pg_ls_dir_files(FunctionCallInfo fcinfo, const char *dir, bool missing_ok)
static char * convert_and_check_filename(text *arg)
Assert(PointerIsAligned(start, uint64))
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
bool pg_verifymbstr(const char *mbstr, int len, bool noError)
void pfree(void *pointer)
#define is_absolute_path(filename)
bool path_is_prefix_of_path(const char *path1, const char *path2)
bool path_is_relative_and_below_cwd(const char *path)
void canonicalize_path(char *path)
static Datum Int64GetDatum(int64 X)
static Datum BoolGetDatum(bool X)
static Datum ObjectIdGetDatum(Oid X)
#define PG_LOGICAL_SNAPSHOTS_DIR
#define PG_LOGICAL_MAPPINGS_DIR
ReplicationSlot * SearchNamedReplicationSlot(const char *name, bool need_lock)
void enlargeStringInfo(StringInfo str, int needed)
void initStringInfo(StringInfo str)
Tuplestorestate * setResult
#define SearchSysCacheExists1(cacheId, key1)
TupleDesc CreateTemplateTupleDesc(int natts)
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
static Datum TimestampTzGetDatum(TimestampTz X)
static Size VARSIZE(const void *PTR)
static char * VARDATA(const void *PTR)
static void SET_VARSIZE(void *PTR, Size len)
char * text_to_cstring(const text *t)
#define fseeko(stream, offset, origin)