PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
genfile.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * genfile.c
4  * Functions for direct access to files
5  *
6  *
7  * Copyright (c) 2004-2017, PostgreSQL Global Development Group
8  *
9  * Author: Andreas Pflug <pgadmin@pse-consulting.de>
10  *
11  * IDENTIFICATION
12  * src/backend/utils/adt/genfile.c
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17 
18 #include <sys/file.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <dirent.h>
22 
23 #include "access/htup_details.h"
24 #include "catalog/pg_type.h"
25 #include "funcapi.h"
26 #include "mb/pg_wchar.h"
27 #include "miscadmin.h"
28 #include "postmaster/syslogger.h"
29 #include "storage/fd.h"
30 #include "utils/builtins.h"
31 #include "utils/memutils.h"
32 #include "utils/timestamp.h"
33 
34 typedef struct
35 {
36  char *location;
37  DIR *dirdesc;
40 
41 
42 /*
43  * Convert a "text" filename argument to C string, and check it's allowable.
44  *
45  * Filename may be absolute or relative to the DataDir, but we only allow
46  * absolute paths that match DataDir or Log_directory.
47  */
48 static char *
50 {
51  char *filename;
52 
53  filename = text_to_cstring(arg);
54  canonicalize_path(filename); /* filename can change length here */
55 
56  if (is_absolute_path(filename))
57  {
58  /* Disallow '/a/b/data/..' */
59  if (path_contains_parent_reference(filename))
60  ereport(ERROR,
61  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
62  (errmsg("reference to parent directory (\"..\") not allowed"))));
63 
64  /*
65  * Allow absolute paths if within DataDir or Log_directory, even
66  * though Log_directory might be outside DataDir.
67  */
68  if (!path_is_prefix_of_path(DataDir, filename) &&
71  ereport(ERROR,
72  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
73  (errmsg("absolute path not allowed"))));
74  }
75  else if (!path_is_relative_and_below_cwd(filename))
76  ereport(ERROR,
77  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
78  (errmsg("path must be in or below the current directory"))));
79 
80  return filename;
81 }
82 
83 
84 /*
85  * Read a section of a file, returning it as bytea
86  *
87  * Caller is responsible for all permissions checking.
88  *
89  * We read the whole of the file when bytes_to_read is negative.
90  */
91 static bytea *
92 read_binary_file(const char *filename, int64 seek_offset, int64 bytes_to_read,
93  bool missing_ok)
94 {
95  bytea *buf;
96  size_t nbytes;
97  FILE *file;
98 
99  if (bytes_to_read < 0)
100  {
101  if (seek_offset < 0)
102  bytes_to_read = -seek_offset;
103  else
104  {
105  struct stat fst;
106 
107  if (stat(filename, &fst) < 0)
108  {
109  if (missing_ok && errno == ENOENT)
110  return NULL;
111  else
112  ereport(ERROR,
114  errmsg("could not stat file \"%s\": %m", filename)));
115  }
116 
117  bytes_to_read = fst.st_size - seek_offset;
118  }
119  }
120 
121  /* not sure why anyone thought that int64 length was a good idea */
122  if (bytes_to_read > (MaxAllocSize - VARHDRSZ))
123  ereport(ERROR,
124  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
125  errmsg("requested length too large")));
126 
127  if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
128  {
129  if (missing_ok && errno == ENOENT)
130  return NULL;
131  else
132  ereport(ERROR,
134  errmsg("could not open file \"%s\" for reading: %m",
135  filename)));
136  }
137 
138  if (fseeko(file, (off_t) seek_offset,
139  (seek_offset >= 0) ? SEEK_SET : SEEK_END) != 0)
140  ereport(ERROR,
142  errmsg("could not seek in file \"%s\": %m", filename)));
143 
144  buf = (bytea *) palloc((Size) bytes_to_read + VARHDRSZ);
145 
146  nbytes = fread(VARDATA(buf), 1, (size_t) bytes_to_read, file);
147 
148  if (ferror(file))
149  ereport(ERROR,
151  errmsg("could not read file \"%s\": %m", filename)));
152 
153  SET_VARSIZE(buf, nbytes + VARHDRSZ);
154 
155  FreeFile(file);
156 
157  return buf;
158 }
159 
160 /*
161  * Similar to read_binary_file, but we verify that the contents are valid
162  * in the database encoding.
163  */
164 static text *
165 read_text_file(const char *filename, int64 seek_offset, int64 bytes_to_read,
166  bool missing_ok)
167 {
168  bytea *buf;
169 
170  buf = read_binary_file(filename, seek_offset, bytes_to_read, missing_ok);
171 
172  if (buf != NULL)
173  {
174  /* Make sure the input is valid */
175  pg_verifymbstr(VARDATA(buf), VARSIZE(buf) - VARHDRSZ, false);
176 
177  /* OK, we can cast it to text safely */
178  return (text *) buf;
179  }
180  else
181  return NULL;
182 }
183 
184 /*
185  * Read a section of a file, returning it as text
186  */
187 Datum
189 {
190  text *filename_t = PG_GETARG_TEXT_P(0);
191  int64 seek_offset = 0;
192  int64 bytes_to_read = -1;
193  bool missing_ok = false;
194  char *filename;
195  text *result;
196 
197  if (!superuser())
198  ereport(ERROR,
199  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
200  (errmsg("must be superuser to read files"))));
201 
202  /* handle optional arguments */
203  if (PG_NARGS() >= 3)
204  {
205  seek_offset = PG_GETARG_INT64(1);
206  bytes_to_read = PG_GETARG_INT64(2);
207 
208  if (bytes_to_read < 0)
209  ereport(ERROR,
210  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
211  errmsg("requested length cannot be negative")));
212  }
213  if (PG_NARGS() >= 4)
214  missing_ok = PG_GETARG_BOOL(3);
215 
216  filename = convert_and_check_filename(filename_t);
217 
218  result = read_text_file(filename, seek_offset, bytes_to_read, missing_ok);
219  if (result)
220  PG_RETURN_TEXT_P(result);
221  else
222  PG_RETURN_NULL();
223 }
224 
225 /*
226  * Read a section of a file, returning it as bytea
227  */
228 Datum
230 {
231  text *filename_t = PG_GETARG_TEXT_P(0);
232  int64 seek_offset = 0;
233  int64 bytes_to_read = -1;
234  bool missing_ok = false;
235  char *filename;
236  bytea *result;
237 
238  if (!superuser())
239  ereport(ERROR,
240  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
241  (errmsg("must be superuser to read files"))));
242 
243  /* handle optional arguments */
244  if (PG_NARGS() >= 3)
245  {
246  seek_offset = PG_GETARG_INT64(1);
247  bytes_to_read = PG_GETARG_INT64(2);
248 
249  if (bytes_to_read < 0)
250  ereport(ERROR,
251  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
252  errmsg("requested length cannot be negative")));
253  }
254  if (PG_NARGS() >= 4)
255  missing_ok = PG_GETARG_BOOL(3);
256 
257  filename = convert_and_check_filename(filename_t);
258 
259  result = read_binary_file(filename, seek_offset,
260  bytes_to_read, missing_ok);
261  if (result)
262  PG_RETURN_BYTEA_P(result);
263  else
264  PG_RETURN_NULL();
265 }
266 
267 
268 /*
269  * Wrapper functions for the 1 and 3 argument variants of pg_read_file()
270  * and pg_binary_read_file().
271  *
272  * These are necessary to pass the sanity check in opr_sanity, which checks
273  * that all built-in functions that share the implementing C function take
274  * the same number of arguments.
275  */
276 Datum
278 {
279  return pg_read_file(fcinfo);
280 }
281 
282 Datum
284 {
285  return pg_read_file(fcinfo);
286 }
287 
288 Datum
290 {
291  return pg_read_binary_file(fcinfo);
292 }
293 
294 Datum
296 {
297  return pg_read_binary_file(fcinfo);
298 }
299 
300 /*
301  * stat a file
302  */
303 Datum
305 {
306  text *filename_t = PG_GETARG_TEXT_P(0);
307  char *filename;
308  struct stat fst;
309  Datum values[6];
310  bool isnull[6];
311  HeapTuple tuple;
312  TupleDesc tupdesc;
313  bool missing_ok = false;
314 
315  if (!superuser())
316  ereport(ERROR,
317  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
318  (errmsg("must be superuser to get file information"))));
319 
320  /* check the optional argument */
321  if (PG_NARGS() == 2)
322  missing_ok = PG_GETARG_BOOL(1);
323 
324  filename = convert_and_check_filename(filename_t);
325 
326  if (stat(filename, &fst) < 0)
327  {
328  if (missing_ok && errno == ENOENT)
329  PG_RETURN_NULL();
330  else
331  ereport(ERROR,
333  errmsg("could not stat file \"%s\": %m", filename)));
334  }
335 
336  /*
337  * This record type had better match the output parameters declared for me
338  * in pg_proc.h.
339  */
340  tupdesc = CreateTemplateTupleDesc(6, false);
341  TupleDescInitEntry(tupdesc, (AttrNumber) 1,
342  "size", INT8OID, -1, 0);
343  TupleDescInitEntry(tupdesc, (AttrNumber) 2,
344  "access", TIMESTAMPTZOID, -1, 0);
345  TupleDescInitEntry(tupdesc, (AttrNumber) 3,
346  "modification", TIMESTAMPTZOID, -1, 0);
347  TupleDescInitEntry(tupdesc, (AttrNumber) 4,
348  "change", TIMESTAMPTZOID, -1, 0);
349  TupleDescInitEntry(tupdesc, (AttrNumber) 5,
350  "creation", TIMESTAMPTZOID, -1, 0);
351  TupleDescInitEntry(tupdesc, (AttrNumber) 6,
352  "isdir", BOOLOID, -1, 0);
353  BlessTupleDesc(tupdesc);
354 
355  memset(isnull, false, sizeof(isnull));
356 
357  values[0] = Int64GetDatum((int64) fst.st_size);
358  values[1] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_atime));
359  values[2] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_mtime));
360  /* Unix has file status change time, while Win32 has creation time */
361 #if !defined(WIN32) && !defined(__CYGWIN__)
362  values[3] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_ctime));
363  isnull[4] = true;
364 #else
365  isnull[3] = true;
366  values[4] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_ctime));
367 #endif
368  values[5] = BoolGetDatum(S_ISDIR(fst.st_mode));
369 
370  tuple = heap_form_tuple(tupdesc, values, isnull);
371 
372  pfree(filename);
373 
375 }
376 
377 /*
378  * stat a file (1 argument version)
379  *
380  * note: this wrapper is necessary to pass the sanity check in opr_sanity,
381  * which checks that all built-in functions that share the implementing C
382  * function take the same number of arguments
383  */
384 Datum
386 {
387  return pg_stat_file(fcinfo);
388 }
389 
390 /*
391  * List a directory (returns the filenames only)
392  */
393 Datum
395 {
396  FuncCallContext *funcctx;
397  struct dirent *de;
398  directory_fctx *fctx;
399  MemoryContext oldcontext;
400 
401  if (!superuser())
402  ereport(ERROR,
403  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
404  (errmsg("must be superuser to get directory listings"))));
405 
406  if (SRF_IS_FIRSTCALL())
407  {
408  bool missing_ok = false;
409  bool include_dot_dirs = false;
410 
411  /* check the optional arguments */
412  if (PG_NARGS() == 3)
413  {
414  if (!PG_ARGISNULL(1))
415  missing_ok = PG_GETARG_BOOL(1);
416  if (!PG_ARGISNULL(2))
417  include_dot_dirs = PG_GETARG_BOOL(2);
418  }
419 
420  funcctx = SRF_FIRSTCALL_INIT();
421  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
422 
423  fctx = palloc(sizeof(directory_fctx));
425 
426  fctx->include_dot_dirs = include_dot_dirs;
427  fctx->dirdesc = AllocateDir(fctx->location);
428 
429  if (!fctx->dirdesc)
430  {
431  if (missing_ok && errno == ENOENT)
432  {
433  MemoryContextSwitchTo(oldcontext);
434  SRF_RETURN_DONE(funcctx);
435  }
436  else
437  ereport(ERROR,
439  errmsg("could not open directory \"%s\": %m",
440  fctx->location)));
441  }
442  funcctx->user_fctx = fctx;
443  MemoryContextSwitchTo(oldcontext);
444  }
445 
446  funcctx = SRF_PERCALL_SETUP();
447  fctx = (directory_fctx *) funcctx->user_fctx;
448 
449  while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL)
450  {
451  if (!fctx->include_dot_dirs &&
452  (strcmp(de->d_name, ".") == 0 ||
453  strcmp(de->d_name, "..") == 0))
454  continue;
455 
457  }
458 
459  FreeDir(fctx->dirdesc);
460 
461  SRF_RETURN_DONE(funcctx);
462 }
463 
464 /*
465  * List a directory (1 argument version)
466  *
467  * note: this wrapper is necessary to pass the sanity check in opr_sanity,
468  * which checks that all built-in functions that share the implementing C
469  * function take the same number of arguments.
470  */
471 Datum
473 {
474  return pg_ls_dir(fcinfo);
475 }
#define TIMESTAMPTZOID
Definition: pg_type.h:513
static char * convert_and_check_filename(text *arg)
Definition: genfile.c:49
#define VARDATA(PTR)
Definition: postgres.h:305
char * Log_directory
Definition: syslogger.c:66
#define VARSIZE(PTR)
Definition: postgres.h:306
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:285
bool path_is_prefix_of_path(const char *path1, const char *path2)
Definition: path.c:438
#define VARHDRSZ
Definition: c.h:441
Datum pg_read_file_all(PG_FUNCTION_ARGS)
Definition: genfile.c:283
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void canonicalize_path(char *path)
Definition: path.c:254
int errcode(int sqlerrcode)
Definition: elog.c:575
bool superuser(void)
Definition: superuser.c:47
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:230
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:313
#define fseeko(stream, offset, origin)
Definition: win32.h:247
bool include_dot_dirs
Definition: genfile.c:38
Definition: dirent.h:9
#define PG_BINARY_R
Definition: c.h:1040
bool path_contains_parent_reference(const char *path)
Definition: path.c:376
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:289
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:291
void pfree(void *pointer)
Definition: mcxt.c:992
Datum pg_read_binary_file_off_len(PG_FUNCTION_ARGS)
Definition: genfile.c:289
Datum pg_stat_file(PG_FUNCTION_ARGS)
Definition: genfile.c:304
Definition: dirent.c:25
#define ERROR
Definition: elog.h:43
Datum pg_read_file_off_len(PG_FUNCTION_ARGS)
Definition: genfile.c:277
#define TimestampTzGetDatum(X)
Definition: timestamp.h:32
DIR * dirdesc
Definition: adminpack.c:51
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:1031
static bytea * read_binary_file(const char *filename, int64 seek_offset, int64 bytes_to_read, bool missing_ok)
Definition: genfile.c:92
static char * buf
Definition: pg_test_fsync.c:65
int errcode_for_file_access(void)
Definition: elog.c:598
#define is_absolute_path(filename)
Definition: port.h:77
bool path_is_relative_and_below_cwd(const char *path)
Definition: path.c:405
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2043
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2284
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:2102
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:493
#define ereport(elevel, rest)
Definition: elog.h:122
Datum pg_read_binary_file(PG_FUNCTION_ARGS)
Definition: genfile.c:229
Datum pg_ls_dir_1arg(PG_FUNCTION_ARGS)
Definition: genfile.c:472
#define MaxAllocSize
Definition: memutils.h:40
Datum pg_ls_dir(PG_FUNCTION_ARGS)
Definition: genfile.c:394
uintptr_t Datum
Definition: postgres.h:374
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:297
TimestampTz time_t_to_timestamptz(pg_time_t tm)
Definition: timestamp.c:1669
#define BoolGetDatum(X)
Definition: postgres.h:410
#define INT8OID
Definition: pg_type.h:304
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:314
Datum pg_read_file(PG_FUNCTION_ARGS)
Definition: genfile.c:188
#define PG_ARGISNULL(n)
Definition: fmgr.h:166
#define NULL
Definition: c.h:226
Datum pg_read_binary_file_all(PG_FUNCTION_ARGS)
Definition: genfile.c:295
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2350
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:109
size_t Size
Definition: c.h:353
Datum pg_stat_file_1arg(PG_FUNCTION_ARGS)
Definition: genfile.c:385
#define PG_NARGS()
Definition: fmgr.h:160
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:222
#define BOOLOID
Definition: pg_type.h:288
TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid)
Definition: tupdesc.c:41
char * location
Definition: adminpack.c:50
int FreeFile(FILE *file)
Definition: fd.c:2226
static Datum values[MAXATTR]
Definition: bootstrap.c:162
char * text_to_cstring(const text *t)
Definition: varlena.c:184
static char * filename
Definition: pg_dumpall.c:84
void * user_fctx
Definition: funcapi.h:90
void * palloc(Size size)
Definition: mcxt.c:891
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define PG_GETARG_TEXT_P(n)
Definition: fmgr.h:269
#define CStringGetTextDatum(s)
Definition: builtins.h:90
void * arg
char * DataDir
Definition: globals.c:59
Definition: c.h:435
#define PG_FUNCTION_ARGS
Definition: fmgr.h:150
bool pg_verifymbstr(const char *mbstr, int len, bool noError)
Definition: wchar.c:1866
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:330
char d_name[MAX_PATH]
Definition: dirent.h:14
static text * read_text_file(const char *filename, int64 seek_offset, int64 bytes_to_read, bool missing_ok)
Definition: genfile.c:165
#define PG_GETARG_INT64(n)
Definition: fmgr.h:238
int16 AttrNumber
Definition: attnum.h:21
#define PG_RETURN_NULL()
Definition: fmgr.h:289
int FreeDir(DIR *dir)
Definition: fd.c:2393
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:309
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:287