diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2005-08-12 18:23:56 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2005-08-12 18:23:56 +0000 |
commit | a43ea120bf7539232d9f41a3bf7f7986fde84837 (patch) | |
tree | d273c2bf155291a526c6b9c8700ab7803359ae36 /src/backend/utils/adt/genfile.c | |
parent | cb29f669b0b67b82f1f5422b3aaf0f54ac5d20ee (diff) | |
download | postgresql-a43ea120bf7539232d9f41a3bf7f7986fde84837.tar.gz postgresql-a43ea120bf7539232d9f41a3bf7f7986fde84837.zip |
Code & docs review for server instrumentation patch. File timestamps
should surely be timestamptz not timestamp; fix some but not all of the
holes in check_and_make_absolute(); other minor cleanup. Also put in
the missed catversion bump.
Diffstat (limited to 'src/backend/utils/adt/genfile.c')
-rw-r--r-- | src/backend/utils/adt/genfile.c | 198 |
1 files changed, 108 insertions, 90 deletions
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c index cd34b54da50..9e707c5d8e4 100644 --- a/src/backend/utils/adt/genfile.c +++ b/src/backend/utils/adt/genfile.c @@ -1,14 +1,15 @@ /*------------------------------------------------------------------------- * * genfile.c + * Functions for direct access to files * * - * Copyright (c) 2004, PostgreSQL Global Development Group + * Copyright (c) 2004-2005, PostgreSQL Global Development Group * * Author: Andreas Pflug <pgadmin@pse-consulting.de> * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/genfile.c,v 1.1 2005/08/12 03:24:08 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/genfile.c,v 1.2 2005/08/12 18:23:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,13 +20,15 @@ #include <unistd.h> #include <dirent.h> -#include "utils/builtins.h" -#include "miscadmin.h" -#include "storage/fd.h" +#include "access/heapam.h" #include "catalog/pg_type.h" #include "funcapi.h" +#include "miscadmin.h" +#include "postmaster/syslogger.h" +#include "storage/fd.h" +#include "utils/builtins.h" +#include "utils/memutils.h" -extern char *Log_directory; typedef struct { @@ -33,13 +36,16 @@ typedef struct DIR *dirdesc; } directory_fctx; + /* - * Return an absolute path. Argument may be absolute or - * relative to the DataDir. + * Validate a path and convert to absolute form. + * + * Argument may be absolute or relative to the DataDir (but we only allow + * absolute paths that match Log_directory). */ -static char *check_and_make_absolute(text *arg) +static char * +check_and_make_absolute(text *arg) { - int datadir_len = strlen(DataDir); int filename_len = VARSIZE(arg) - VARHDRSZ; char *filename = palloc(filename_len + 1); @@ -52,16 +58,21 @@ static char *check_and_make_absolute(text *arg) /* * Prevent reference to the parent directory. * "..a.." is a valid file name though. + * + * XXX this is BROKEN because it fails to prevent "C:.." on Windows. + * Need access to "skip_drive" functionality to do it right. (There + * is no actual security hole because we'll prepend the DataDir below, + * resulting in a just-plain-broken path, but we should give the right + * error message instead.) */ - if (strcmp(filename, "..") == 0 || /* beginning */ - strncmp(filename, "../", 3) == 0 || /* beginning */ - strcmp(filename, "/..") == 0 || /* beginning */ - strncmp(filename, "../", 3) == 0 || /* beginning */ - strstr(filename, "/../") != NULL || /* middle */ - strncmp(filename + filename_len - 3, "/..", 3) == 0) /* end */ + if (strcmp(filename, "..") == 0 || /* whole */ + strncmp(filename, "../", 3) == 0 || /* beginning */ + strstr(filename, "/../") != NULL || /* middle */ + (filename_len >= 3 && + strcmp(filename + filename_len - 3, "/..") == 0)) /* end */ ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - (errmsg("Reference to a parent directory (\"..\") not allowed")))); + (errmsg("reference to parent directory (\"..\") not allowed")))); if (is_absolute_path(filename)) { @@ -74,12 +85,12 @@ static char *check_and_make_absolute(text *arg) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - (errmsg("Absolute paths not allowed")))); - return NULL; + (errmsg("absolute path not allowed")))); + return NULL; /* keep compiler quiet */ } else { - char *absname = palloc(datadir_len + filename_len + 2); + char *absname = palloc(strlen(DataDir) + filename_len + 2); sprintf(absname, "%s/%s", DataDir, filename); pfree(filename); return absname; @@ -87,11 +98,16 @@ static char *check_and_make_absolute(text *arg) } -Datum pg_read_file(PG_FUNCTION_ARGS) +/* + * Read a section of a file, returning it as text + */ +Datum +pg_read_file(PG_FUNCTION_ARGS) { - int64 bytes_to_read = PG_GETARG_INT64(2); + text *filename_t = PG_GETARG_TEXT_P(0); int64 seek_offset = PG_GETARG_INT64(1); - char *buf = 0; + int64 bytes_to_read = PG_GETARG_INT64(2); + char *buf; size_t nbytes; FILE *file; char *filename; @@ -101,107 +117,108 @@ Datum pg_read_file(PG_FUNCTION_ARGS) (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to read files")))); - filename = check_and_make_absolute(PG_GETARG_TEXT_P(0)); + filename = check_and_make_absolute(filename_t); if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL) - { ereport(ERROR, (errcode_for_file_access(), - errmsg("could not open file %s for reading: %m", filename))); - PG_RETURN_NULL(); - } + 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) - { + 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))); - PG_RETURN_NULL(); - } + errmsg("could not seek in file \"%s\": %m", filename))); if (bytes_to_read < 0) - { ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("length cannot be negative"))); - } + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("requested length cannot be negative"))); + + /* 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"))); - buf = palloc(bytes_to_read + VARHDRSZ); + buf = palloc((Size) bytes_to_read + VARHDRSZ); - nbytes = fread(VARDATA(buf), 1, bytes_to_read, file); + nbytes = fread(VARDATA(buf), 1, (size_t) bytes_to_read, file); if (nbytes < 0) - { ereport(ERROR, (errcode_for_file_access(), - errmsg("could not read file %s: %m", filename))); - PG_RETURN_NULL(); - } + errmsg("could not read file \"%s\": %m", filename))); + VARATT_SIZEP(buf) = nbytes + VARHDRSZ; - pfree(filename); FreeFile(file); + pfree(filename); + PG_RETURN_TEXT_P(buf); } - -Datum pg_stat_file(PG_FUNCTION_ARGS) +/* + * stat a file + */ +Datum +pg_stat_file(PG_FUNCTION_ARGS) { - AttInMetadata *attinmeta; - char *filename = check_and_make_absolute(PG_GETARG_TEXT_P(0)); + text *filename_t = PG_GETARG_TEXT_P(0); + char *filename; struct stat fst; - char lenbuf[30], cbuf[30], abuf[30], mbuf[30], dirbuf[2]; - char *values[5] = {lenbuf, cbuf, abuf, mbuf, dirbuf}; - pg_time_t timestamp; + Datum values[5]; + bool isnull[5]; HeapTuple tuple; - TupleDesc tupdesc = CreateTemplateTupleDesc(5, false); + TupleDesc tupdesc; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser to get file information")))); - TupleDescInitEntry(tupdesc, (AttrNumber) 1, "length", INT8OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 2, "atime", TIMESTAMPOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 3, "mtime", TIMESTAMPOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 4, "ctime", TIMESTAMPOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 5, "isdir", BOOLOID, -1, 0); - attinmeta = TupleDescGetAttInMetadata(tupdesc); + filename = check_and_make_absolute(filename_t); if (stat(filename, &fst) < 0) - { ereport(ERROR, (errcode_for_file_access(), - errmsg("could not stat file %s: %m", filename))); - PG_RETURN_NULL(); - } - else - { - snprintf(lenbuf, 30, INT64_FORMAT, (int64)fst.st_size); - - timestamp = fst.st_atime; - pg_strftime(abuf, 30, "%F %T", pg_localtime(×tamp, global_timezone)); - - timestamp = fst.st_mtime; - pg_strftime(mbuf, 30, "%F %T", pg_localtime(×tamp, global_timezone)); + errmsg("could not stat file \"%s\": %m", filename))); + + tupdesc = CreateTemplateTupleDesc(5, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, + "length", INT8OID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, + "atime", TIMESTAMPTZOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 3, + "mtime", TIMESTAMPTZOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 4, + "ctime", TIMESTAMPTZOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 5, + "isdir", BOOLOID, -1, 0); + BlessTupleDesc(tupdesc); + + 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)); + values[3] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_ctime)); + values[4] = BoolGetDatum(fst.st_mode & S_IFDIR); + + memset(isnull, false, sizeof(isnull)); + + tuple = heap_form_tuple(tupdesc, values, isnull); - timestamp = fst.st_ctime; - pg_strftime(cbuf, 30, "%F %T", pg_localtime(×tamp, global_timezone)); - - if (fst.st_mode & S_IFDIR) - strcpy(dirbuf, "t"); - else - strcpy(dirbuf, "f"); + pfree(filename); - tuple = BuildTupleFromCStrings(attinmeta, values); - pfree(filename); - PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); - } + PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); } -Datum pg_ls_dir(PG_FUNCTION_ARGS) +/* + * List a directory (returns the filenames only) + */ +Datum +pg_ls_dir(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; struct dirent *de; @@ -227,7 +244,8 @@ Datum pg_ls_dir(PG_FUNCTION_ARGS) if (!fctx->dirdesc) ereport(ERROR, (errcode_for_file_access(), - errmsg("%s is not browsable: %m", fctx->location))); + errmsg("could not open directory \"%s\": %m", + fctx->location))); funcctx->user_fctx = fctx; MemoryContextSwitchTo(oldcontext); @@ -236,17 +254,16 @@ Datum pg_ls_dir(PG_FUNCTION_ARGS) funcctx = SRF_PERCALL_SETUP(); fctx = (directory_fctx*) funcctx->user_fctx; - if (!fctx->dirdesc) /* not a readable directory */ - SRF_RETURN_DONE(funcctx); - while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL) { int len = strlen(de->d_name); - text *result = palloc(len + VARHDRSZ); + text *result; - if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) + if (strcmp(de->d_name, ".") == 0 || + strcmp(de->d_name, "..") == 0) continue; + result = palloc(len + VARHDRSZ); VARATT_SIZEP(result) = len + VARHDRSZ; memcpy(VARDATA(result), de->d_name, len); @@ -254,5 +271,6 @@ Datum pg_ls_dir(PG_FUNCTION_ARGS) } FreeDir(fctx->dirdesc); + SRF_RETURN_DONE(funcctx); } |