Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Functions

genfile.c File Reference

#include "postgres.h"
#include <sys/file.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include "access/htup_details.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "postmaster/syslogger.h"
#include "storage/fd.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/timestamp.h"
Include dependency graph for genfile.c:

Go to the source code of this file.

Data Structures

struct  directory_fctx

Functions

static char * convert_and_check_filename (text *arg)
bytearead_binary_file (const char *filename, int64 seek_offset, int64 bytes_to_read)
static textread_text_file (const char *filename, int64 seek_offset, int64 bytes_to_read)
Datum pg_read_file (PG_FUNCTION_ARGS)
Datum pg_read_file_all (PG_FUNCTION_ARGS)
Datum pg_read_binary_file (PG_FUNCTION_ARGS)
Datum pg_read_binary_file_all (PG_FUNCTION_ARGS)
Datum pg_stat_file (PG_FUNCTION_ARGS)
Datum pg_ls_dir (PG_FUNCTION_ARGS)

Function Documentation

static char* convert_and_check_filename ( text arg  )  [static]

Definition at line 48 of file genfile.c.

References canonicalize_path(), DataDir, ereport, errcode(), errmsg(), ERROR, filename, is_absolute_path, Log_directory, path_contains_parent_reference(), path_is_prefix_of_path(), path_is_relative_and_below_cwd(), and text_to_cstring().

Referenced by pg_ls_dir(), pg_read_binary_file(), pg_read_binary_file_all(), pg_read_file(), pg_read_file_all(), and pg_stat_file().

{
    char       *filename;

    filename = text_to_cstring(arg);
    canonicalize_path(filename);    /* filename can change length here */

    if (is_absolute_path(filename))
    {
        /* Disallow '/a/b/data/..' */
        if (path_contains_parent_reference(filename))
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
            (errmsg("reference to parent directory (\"..\") not allowed"))));

        /*
         * Allow absolute paths if within DataDir or Log_directory, even
         * though Log_directory might be outside DataDir.
         */
        if (!path_is_prefix_of_path(DataDir, filename) &&
            (!is_absolute_path(Log_directory) ||
             !path_is_prefix_of_path(Log_directory, filename)))
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                     (errmsg("absolute path not allowed"))));
    }
    else if (!path_is_relative_and_below_cwd(filename))
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 (errmsg("path must be in or below the current directory"))));

    return filename;
}

Datum pg_ls_dir ( PG_FUNCTION_ARGS   ) 

Definition at line 328 of file genfile.c.

References AllocateDir(), convert_and_check_filename(), CStringGetTextDatum, dirent::d_name, directory_fctx::dirdesc, ereport, errcode(), errcode_for_file_access(), errmsg(), ERROR, FreeDir(), directory_fctx::location, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, palloc(), PG_GETARG_TEXT_P, ReadDir(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, superuser(), and FuncCallContext::user_fctx.

{
    FuncCallContext *funcctx;
    struct dirent *de;
    directory_fctx *fctx;

    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 (errmsg("must be superuser to get directory listings"))));

    if (SRF_IS_FIRSTCALL())
    {
        MemoryContext oldcontext;

        funcctx = SRF_FIRSTCALL_INIT();
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

        fctx = palloc(sizeof(directory_fctx));
        fctx->location = convert_and_check_filename(PG_GETARG_TEXT_P(0));

        fctx->dirdesc = AllocateDir(fctx->location);

        if (!fctx->dirdesc)
            ereport(ERROR,
                    (errcode_for_file_access(),
                     errmsg("could not open directory \"%s\": %m",
                            fctx->location)));

        funcctx->user_fctx = fctx;
        MemoryContextSwitchTo(oldcontext);
    }

    funcctx = SRF_PERCALL_SETUP();
    fctx = (directory_fctx *) funcctx->user_fctx;

    while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL)
    {
        if (strcmp(de->d_name, ".") == 0 ||
            strcmp(de->d_name, "..") == 0)
            continue;

        SRF_RETURN_NEXT(funcctx, CStringGetTextDatum(de->d_name));
    }

    FreeDir(fctx->dirdesc);

    SRF_RETURN_DONE(funcctx);
}

Datum pg_read_binary_file ( PG_FUNCTION_ARGS   ) 

Definition at line 215 of file genfile.c.

References convert_and_check_filename(), ereport, errcode(), errmsg(), ERROR, filename, PG_GETARG_INT64, PG_GETARG_TEXT_P, PG_RETURN_BYTEA_P, read_binary_file(), and superuser().

{
    text       *filename_t = PG_GETARG_TEXT_P(0);
    int64       seek_offset = PG_GETARG_INT64(1);
    int64       bytes_to_read = PG_GETARG_INT64(2);
    char       *filename;

    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 (errmsg("must be superuser to read files"))));

    filename = convert_and_check_filename(filename_t);

    if (bytes_to_read < 0)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("requested length cannot be negative")));

    PG_RETURN_BYTEA_P(read_binary_file(filename, seek_offset, bytes_to_read));
}

Datum pg_read_binary_file_all ( PG_FUNCTION_ARGS   ) 

Definition at line 241 of file genfile.c.

References convert_and_check_filename(), ereport, errcode(), errmsg(), ERROR, filename, PG_GETARG_TEXT_P, PG_RETURN_BYTEA_P, read_binary_file(), and superuser().

{
    text       *filename_t = PG_GETARG_TEXT_P(0);
    char       *filename;

    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 (errmsg("must be superuser to read files"))));

    filename = convert_and_check_filename(filename_t);

    PG_RETURN_BYTEA_P(read_binary_file(filename, 0, -1));
}

Datum pg_read_file ( PG_FUNCTION_ARGS   ) 

Definition at line 170 of file genfile.c.

References convert_and_check_filename(), ereport, errcode(), errmsg(), ERROR, filename, PG_GETARG_INT64, PG_GETARG_TEXT_P, PG_RETURN_TEXT_P, read_text_file(), and superuser().

{
    text       *filename_t = PG_GETARG_TEXT_P(0);
    int64       seek_offset = PG_GETARG_INT64(1);
    int64       bytes_to_read = PG_GETARG_INT64(2);
    char       *filename;

    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 (errmsg("must be superuser to read files"))));

    filename = convert_and_check_filename(filename_t);

    if (bytes_to_read < 0)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("requested length cannot be negative")));

    PG_RETURN_TEXT_P(read_text_file(filename, seek_offset, bytes_to_read));
}

Datum pg_read_file_all ( PG_FUNCTION_ARGS   ) 

Definition at line 196 of file genfile.c.

References convert_and_check_filename(), ereport, errcode(), errmsg(), ERROR, filename, PG_GETARG_TEXT_P, PG_RETURN_TEXT_P, read_text_file(), and superuser().

{
    text       *filename_t = PG_GETARG_TEXT_P(0);
    char       *filename;

    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 (errmsg("must be superuser to read files"))));

    filename = convert_and_check_filename(filename_t);

    PG_RETURN_TEXT_P(read_text_file(filename, 0, -1));
}

Datum pg_stat_file ( PG_FUNCTION_ARGS   ) 

Definition at line 260 of file genfile.c.

References BlessTupleDesc(), BoolGetDatum, BOOLOID, convert_and_check_filename(), CreateTemplateTupleDesc(), ereport, errcode(), errcode_for_file_access(), errmsg(), ERROR, filename, heap_form_tuple(), HeapTupleGetDatum, Int64GetDatum(), INT8OID, pfree(), PG_GETARG_TEXT_P, PG_RETURN_DATUM, superuser(), time_t_to_timestamptz(), TimestampTzGetDatum, TIMESTAMPTZOID, TupleDescInitEntry(), and values.

{
    text       *filename_t = PG_GETARG_TEXT_P(0);
    char       *filename;
    struct stat fst;
    Datum       values[6];
    bool        isnull[6];
    HeapTuple   tuple;
    TupleDesc   tupdesc;

    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 (errmsg("must be superuser to get file information"))));

    filename = convert_and_check_filename(filename_t);

    if (stat(filename, &fst) < 0)
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not stat file \"%s\": %m", filename)));

    /*
     * This record type had better match the output parameters declared for me
     * in pg_proc.h.
     */
    tupdesc = CreateTemplateTupleDesc(6, false);
    TupleDescInitEntry(tupdesc, (AttrNumber) 1,
                       "size", INT8OID, -1, 0);
    TupleDescInitEntry(tupdesc, (AttrNumber) 2,
                       "access", TIMESTAMPTZOID, -1, 0);
    TupleDescInitEntry(tupdesc, (AttrNumber) 3,
                       "modification", TIMESTAMPTZOID, -1, 0);
    TupleDescInitEntry(tupdesc, (AttrNumber) 4,
                       "change", TIMESTAMPTZOID, -1, 0);
    TupleDescInitEntry(tupdesc, (AttrNumber) 5,
                       "creation", TIMESTAMPTZOID, -1, 0);
    TupleDescInitEntry(tupdesc, (AttrNumber) 6,
                       "isdir", BOOLOID, -1, 0);
    BlessTupleDesc(tupdesc);

    memset(isnull, false, sizeof(isnull));

    values[0] = Int64GetDatum((int64) fst.st_size);
    values[1] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_atime));
    values[2] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_mtime));
    /* Unix has file status change time, while Win32 has creation time */
#if !defined(WIN32) && !defined(__CYGWIN__)
    values[3] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_ctime));
    isnull[4] = true;
#else
    isnull[3] = true;
    values[4] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_ctime));
#endif
    values[5] = BoolGetDatum(S_ISDIR(fst.st_mode));

    tuple = heap_form_tuple(tupdesc, values, isnull);

    pfree(filename);

    PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
}

bytea* read_binary_file ( const char *  filename,
int64  seek_offset,
int64  bytes_to_read 
)

Definition at line 91 of file genfile.c.

References AllocateFile(), buf, ereport, errcode(), errcode_for_file_access(), errmsg(), ERROR, FreeFile(), fseeko, MaxAllocSize, NULL, palloc(), PG_BINARY_R, SET_VARSIZE, VARDATA, and VARHDRSZ.

Referenced by pg_read_binary_file(), pg_read_binary_file_all(), read_extension_script_file(), and read_text_file().

{
    bytea      *buf;
    size_t      nbytes;
    FILE       *file;

    if (bytes_to_read < 0)
    {
        if (seek_offset < 0)
            bytes_to_read = -seek_offset;
        else
        {
            struct stat fst;

            if (stat(filename, &fst) < 0)
                ereport(ERROR,
                        (errcode_for_file_access(),
                         errmsg("could not stat file \"%s\": %m", filename)));

            bytes_to_read = fst.st_size - seek_offset;
        }
    }

    /* not sure why anyone thought that int64 length was a good idea */
    if (bytes_to_read > (MaxAllocSize - VARHDRSZ))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("requested length too large")));

    if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not open file \"%s\" for reading: %m",
                        filename)));

    if (fseeko(file, (off_t) seek_offset,
               (seek_offset >= 0) ? SEEK_SET : SEEK_END) != 0)
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not seek in file \"%s\": %m", filename)));

    buf = (bytea *) palloc((Size) bytes_to_read + VARHDRSZ);

    nbytes = fread(VARDATA(buf), 1, (size_t) bytes_to_read, file);

    if (ferror(file))
        ereport(ERROR,
                (errcode_for_file_access(),
                 errmsg("could not read file \"%s\": %m", filename)));

    SET_VARSIZE(buf, nbytes + VARHDRSZ);

    FreeFile(file);

    return buf;
}

static text* read_text_file ( const char *  filename,
int64  seek_offset,
int64  bytes_to_read 
) [static]

Definition at line 153 of file genfile.c.

References buf, pg_verifymbstr(), read_binary_file(), VARDATA, VARHDRSZ, and VARSIZE.

Referenced by pg_read_file(), and pg_read_file_all().

{
    bytea      *buf;

    buf = read_binary_file(filename, seek_offset, bytes_to_read);

    /* Make sure the input is valid */
    pg_verifymbstr(VARDATA(buf), VARSIZE(buf) - VARHDRSZ, false);

    /* OK, we can cast it to text safely */
    return (text *) buf;
}