00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "postgres.h"
00017
00018 #include <sys/file.h>
00019 #include <sys/stat.h>
00020 #include <unistd.h>
00021 #include <dirent.h>
00022
00023 #include "access/htup_details.h"
00024 #include "catalog/pg_type.h"
00025 #include "funcapi.h"
00026 #include "mb/pg_wchar.h"
00027 #include "miscadmin.h"
00028 #include "postmaster/syslogger.h"
00029 #include "storage/fd.h"
00030 #include "utils/builtins.h"
00031 #include "utils/memutils.h"
00032 #include "utils/timestamp.h"
00033
00034 typedef struct
00035 {
00036 char *location;
00037 DIR *dirdesc;
00038 } directory_fctx;
00039
00040
00041
00042
00043
00044
00045
00046
00047 static char *
00048 convert_and_check_filename(text *arg)
00049 {
00050 char *filename;
00051
00052 filename = text_to_cstring(arg);
00053 canonicalize_path(filename);
00054
00055 if (is_absolute_path(filename))
00056 {
00057
00058 if (path_contains_parent_reference(filename))
00059 ereport(ERROR,
00060 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00061 (errmsg("reference to parent directory (\"..\") not allowed"))));
00062
00063
00064
00065
00066
00067 if (!path_is_prefix_of_path(DataDir, filename) &&
00068 (!is_absolute_path(Log_directory) ||
00069 !path_is_prefix_of_path(Log_directory, filename)))
00070 ereport(ERROR,
00071 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00072 (errmsg("absolute path not allowed"))));
00073 }
00074 else if (!path_is_relative_and_below_cwd(filename))
00075 ereport(ERROR,
00076 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00077 (errmsg("path must be in or below the current directory"))));
00078
00079 return filename;
00080 }
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090 bytea *
00091 read_binary_file(const char *filename, int64 seek_offset, int64 bytes_to_read)
00092 {
00093 bytea *buf;
00094 size_t nbytes;
00095 FILE *file;
00096
00097 if (bytes_to_read < 0)
00098 {
00099 if (seek_offset < 0)
00100 bytes_to_read = -seek_offset;
00101 else
00102 {
00103 struct stat fst;
00104
00105 if (stat(filename, &fst) < 0)
00106 ereport(ERROR,
00107 (errcode_for_file_access(),
00108 errmsg("could not stat file \"%s\": %m", filename)));
00109
00110 bytes_to_read = fst.st_size - seek_offset;
00111 }
00112 }
00113
00114
00115 if (bytes_to_read > (MaxAllocSize - VARHDRSZ))
00116 ereport(ERROR,
00117 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00118 errmsg("requested length too large")));
00119
00120 if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
00121 ereport(ERROR,
00122 (errcode_for_file_access(),
00123 errmsg("could not open file \"%s\" for reading: %m",
00124 filename)));
00125
00126 if (fseeko(file, (off_t) seek_offset,
00127 (seek_offset >= 0) ? SEEK_SET : SEEK_END) != 0)
00128 ereport(ERROR,
00129 (errcode_for_file_access(),
00130 errmsg("could not seek in file \"%s\": %m", filename)));
00131
00132 buf = (bytea *) palloc((Size) bytes_to_read + VARHDRSZ);
00133
00134 nbytes = fread(VARDATA(buf), 1, (size_t) bytes_to_read, file);
00135
00136 if (ferror(file))
00137 ereport(ERROR,
00138 (errcode_for_file_access(),
00139 errmsg("could not read file \"%s\": %m", filename)));
00140
00141 SET_VARSIZE(buf, nbytes + VARHDRSZ);
00142
00143 FreeFile(file);
00144
00145 return buf;
00146 }
00147
00148
00149
00150
00151
00152 static text *
00153 read_text_file(const char *filename, int64 seek_offset, int64 bytes_to_read)
00154 {
00155 bytea *buf;
00156
00157 buf = read_binary_file(filename, seek_offset, bytes_to_read);
00158
00159
00160 pg_verifymbstr(VARDATA(buf), VARSIZE(buf) - VARHDRSZ, false);
00161
00162
00163 return (text *) buf;
00164 }
00165
00166
00167
00168
00169 Datum
00170 pg_read_file(PG_FUNCTION_ARGS)
00171 {
00172 text *filename_t = PG_GETARG_TEXT_P(0);
00173 int64 seek_offset = PG_GETARG_INT64(1);
00174 int64 bytes_to_read = PG_GETARG_INT64(2);
00175 char *filename;
00176
00177 if (!superuser())
00178 ereport(ERROR,
00179 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00180 (errmsg("must be superuser to read files"))));
00181
00182 filename = convert_and_check_filename(filename_t);
00183
00184 if (bytes_to_read < 0)
00185 ereport(ERROR,
00186 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00187 errmsg("requested length cannot be negative")));
00188
00189 PG_RETURN_TEXT_P(read_text_file(filename, seek_offset, bytes_to_read));
00190 }
00191
00192
00193
00194
00195 Datum
00196 pg_read_file_all(PG_FUNCTION_ARGS)
00197 {
00198 text *filename_t = PG_GETARG_TEXT_P(0);
00199 char *filename;
00200
00201 if (!superuser())
00202 ereport(ERROR,
00203 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00204 (errmsg("must be superuser to read files"))));
00205
00206 filename = convert_and_check_filename(filename_t);
00207
00208 PG_RETURN_TEXT_P(read_text_file(filename, 0, -1));
00209 }
00210
00211
00212
00213
00214 Datum
00215 pg_read_binary_file(PG_FUNCTION_ARGS)
00216 {
00217 text *filename_t = PG_GETARG_TEXT_P(0);
00218 int64 seek_offset = PG_GETARG_INT64(1);
00219 int64 bytes_to_read = PG_GETARG_INT64(2);
00220 char *filename;
00221
00222 if (!superuser())
00223 ereport(ERROR,
00224 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00225 (errmsg("must be superuser to read files"))));
00226
00227 filename = convert_and_check_filename(filename_t);
00228
00229 if (bytes_to_read < 0)
00230 ereport(ERROR,
00231 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00232 errmsg("requested length cannot be negative")));
00233
00234 PG_RETURN_BYTEA_P(read_binary_file(filename, seek_offset, bytes_to_read));
00235 }
00236
00237
00238
00239
00240 Datum
00241 pg_read_binary_file_all(PG_FUNCTION_ARGS)
00242 {
00243 text *filename_t = PG_GETARG_TEXT_P(0);
00244 char *filename;
00245
00246 if (!superuser())
00247 ereport(ERROR,
00248 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00249 (errmsg("must be superuser to read files"))));
00250
00251 filename = convert_and_check_filename(filename_t);
00252
00253 PG_RETURN_BYTEA_P(read_binary_file(filename, 0, -1));
00254 }
00255
00256
00257
00258
00259 Datum
00260 pg_stat_file(PG_FUNCTION_ARGS)
00261 {
00262 text *filename_t = PG_GETARG_TEXT_P(0);
00263 char *filename;
00264 struct stat fst;
00265 Datum values[6];
00266 bool isnull[6];
00267 HeapTuple tuple;
00268 TupleDesc tupdesc;
00269
00270 if (!superuser())
00271 ereport(ERROR,
00272 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00273 (errmsg("must be superuser to get file information"))));
00274
00275 filename = convert_and_check_filename(filename_t);
00276
00277 if (stat(filename, &fst) < 0)
00278 ereport(ERROR,
00279 (errcode_for_file_access(),
00280 errmsg("could not stat file \"%s\": %m", filename)));
00281
00282
00283
00284
00285
00286 tupdesc = CreateTemplateTupleDesc(6, false);
00287 TupleDescInitEntry(tupdesc, (AttrNumber) 1,
00288 "size", INT8OID, -1, 0);
00289 TupleDescInitEntry(tupdesc, (AttrNumber) 2,
00290 "access", TIMESTAMPTZOID, -1, 0);
00291 TupleDescInitEntry(tupdesc, (AttrNumber) 3,
00292 "modification", TIMESTAMPTZOID, -1, 0);
00293 TupleDescInitEntry(tupdesc, (AttrNumber) 4,
00294 "change", TIMESTAMPTZOID, -1, 0);
00295 TupleDescInitEntry(tupdesc, (AttrNumber) 5,
00296 "creation", TIMESTAMPTZOID, -1, 0);
00297 TupleDescInitEntry(tupdesc, (AttrNumber) 6,
00298 "isdir", BOOLOID, -1, 0);
00299 BlessTupleDesc(tupdesc);
00300
00301 memset(isnull, false, sizeof(isnull));
00302
00303 values[0] = Int64GetDatum((int64) fst.st_size);
00304 values[1] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_atime));
00305 values[2] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_mtime));
00306
00307 #if !defined(WIN32) && !defined(__CYGWIN__)
00308 values[3] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_ctime));
00309 isnull[4] = true;
00310 #else
00311 isnull[3] = true;
00312 values[4] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_ctime));
00313 #endif
00314 values[5] = BoolGetDatum(S_ISDIR(fst.st_mode));
00315
00316 tuple = heap_form_tuple(tupdesc, values, isnull);
00317
00318 pfree(filename);
00319
00320 PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
00321 }
00322
00323
00324
00325
00326
00327 Datum
00328 pg_ls_dir(PG_FUNCTION_ARGS)
00329 {
00330 FuncCallContext *funcctx;
00331 struct dirent *de;
00332 directory_fctx *fctx;
00333
00334 if (!superuser())
00335 ereport(ERROR,
00336 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00337 (errmsg("must be superuser to get directory listings"))));
00338
00339 if (SRF_IS_FIRSTCALL())
00340 {
00341 MemoryContext oldcontext;
00342
00343 funcctx = SRF_FIRSTCALL_INIT();
00344 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
00345
00346 fctx = palloc(sizeof(directory_fctx));
00347 fctx->location = convert_and_check_filename(PG_GETARG_TEXT_P(0));
00348
00349 fctx->dirdesc = AllocateDir(fctx->location);
00350
00351 if (!fctx->dirdesc)
00352 ereport(ERROR,
00353 (errcode_for_file_access(),
00354 errmsg("could not open directory \"%s\": %m",
00355 fctx->location)));
00356
00357 funcctx->user_fctx = fctx;
00358 MemoryContextSwitchTo(oldcontext);
00359 }
00360
00361 funcctx = SRF_PERCALL_SETUP();
00362 fctx = (directory_fctx *) funcctx->user_fctx;
00363
00364 while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL)
00365 {
00366 if (strcmp(de->d_name, ".") == 0 ||
00367 strcmp(de->d_name, "..") == 0)
00368 continue;
00369
00370 SRF_RETURN_NEXT(funcctx, CStringGetTextDatum(de->d_name));
00371 }
00372
00373 FreeDir(fctx->dirdesc);
00374
00375 SRF_RETURN_DONE(funcctx);
00376 }