PostgreSQL Source Code  git master
be-fsstubs.c File Reference
#include "postgres.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include "access/xact.h"
#include "catalog/pg_largeobject_metadata.h"
#include "libpq/be-fsstubs.h"
#include "libpq/libpq-fs.h"
#include "miscadmin.h"
#include "storage/fd.h"
#include "storage/large_object.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/snapmgr.h"
#include "varatt.h"
Include dependency graph for be-fsstubs.c:

Go to the source code of this file.

Macros

#define BUFSIZE   8192
 

Functions

static int newLOfd (void)
 
static void closeLOfd (int fd)
 
static Oid lo_import_internal (text *filename, Oid lobjOid)
 
Datum be_lo_open (PG_FUNCTION_ARGS)
 
Datum be_lo_close (PG_FUNCTION_ARGS)
 
int lo_read (int fd, char *buf, int len)
 
int lo_write (int fd, const char *buf, int len)
 
Datum be_lo_lseek (PG_FUNCTION_ARGS)
 
Datum be_lo_lseek64 (PG_FUNCTION_ARGS)
 
Datum be_lo_creat (PG_FUNCTION_ARGS)
 
Datum be_lo_create (PG_FUNCTION_ARGS)
 
Datum be_lo_tell (PG_FUNCTION_ARGS)
 
Datum be_lo_tell64 (PG_FUNCTION_ARGS)
 
Datum be_lo_unlink (PG_FUNCTION_ARGS)
 
Datum be_loread (PG_FUNCTION_ARGS)
 
Datum be_lowrite (PG_FUNCTION_ARGS)
 
Datum be_lo_import (PG_FUNCTION_ARGS)
 
Datum be_lo_import_with_oid (PG_FUNCTION_ARGS)
 
Datum be_lo_export (PG_FUNCTION_ARGS)
 
static void lo_truncate_internal (int32 fd, int64 len)
 
Datum be_lo_truncate (PG_FUNCTION_ARGS)
 
Datum be_lo_truncate64 (PG_FUNCTION_ARGS)
 
void AtEOXact_LargeObject (bool isCommit)
 
void AtEOSubXact_LargeObject (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
 
static bytealo_get_fragment_internal (Oid loOid, int64 offset, int32 nbytes)
 
Datum be_lo_get (PG_FUNCTION_ARGS)
 
Datum be_lo_get_fragment (PG_FUNCTION_ARGS)
 
Datum be_lo_from_bytea (PG_FUNCTION_ARGS)
 
Datum be_lo_put (PG_FUNCTION_ARGS)
 

Variables

static LargeObjectDesc ** cookies = NULL
 
static int cookies_size = 0
 
static bool lo_cleanup_needed = false
 
static MemoryContext fscxt = NULL
 

Macro Definition Documentation

◆ BUFSIZE

#define BUFSIZE   8192

Definition at line 61 of file be-fsstubs.c.

Function Documentation

◆ AtEOSubXact_LargeObject()

void AtEOSubXact_LargeObject ( bool  isCommit,
SubTransactionId  mySubid,
SubTransactionId  parentSubid 
)

Definition at line 648 of file be-fsstubs.c.

650 {
651  int i;
652 
653  if (fscxt == NULL) /* no LO operations in this xact */
654  return;
655 
656  for (i = 0; i < cookies_size; i++)
657  {
658  LargeObjectDesc *lo = cookies[i];
659 
660  if (lo != NULL && lo->subid == mySubid)
661  {
662  if (isCommit)
663  lo->subid = parentSubid;
664  else
665  closeLOfd(i);
666  }
667  }
668 }
static MemoryContext fscxt
Definition: be-fsstubs.c:75
static void closeLOfd(int fd)
Definition: be-fsstubs.c:716
static LargeObjectDesc ** cookies
Definition: be-fsstubs.c:71
static int cookies_size
Definition: be-fsstubs.c:72
int i
Definition: isn.c:73
SubTransactionId subid
Definition: large_object.h:43

References closeLOfd(), cookies, cookies_size, fscxt, i, and LargeObjectDesc::subid.

Referenced by AbortSubTransaction(), and CommitSubTransaction().

◆ AtEOXact_LargeObject()

void AtEOXact_LargeObject ( bool  isCommit)

Definition at line 602 of file be-fsstubs.c.

603 {
604  int i;
605 
606  if (!lo_cleanup_needed)
607  return; /* no LO operations in this xact */
608 
609  /*
610  * Close LO fds and clear cookies array so that LO fds are no longer good.
611  * The memory context and resource owner holding them are going away at
612  * the end-of-transaction anyway, but on commit, we need to close them to
613  * avoid warnings about leaked resources at commit. On abort we can skip
614  * this step.
615  */
616  if (isCommit)
617  {
618  for (i = 0; i < cookies_size; i++)
619  {
620  if (cookies[i] != NULL)
621  closeLOfd(i);
622  }
623  }
624 
625  /* Needn't actually pfree since we're about to zap context */
626  cookies = NULL;
627  cookies_size = 0;
628 
629  /* Release the LO memory context to prevent permanent memory leaks. */
630  if (fscxt)
632  fscxt = NULL;
633 
634  /* Give inv_api.c a chance to clean up, too */
635  close_lo_relation(isCommit);
636 
637  lo_cleanup_needed = false;
638 }
static bool lo_cleanup_needed
Definition: be-fsstubs.c:74
void close_lo_relation(bool isCommit)
Definition: inv_api.c:99
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:387

References close_lo_relation(), closeLOfd(), cookies, cookies_size, fscxt, i, lo_cleanup_needed, and MemoryContextDelete().

Referenced by AbortTransaction(), CommitTransaction(), and PrepareTransaction().

◆ be_lo_close()

Datum be_lo_close ( PG_FUNCTION_ARGS  )

Definition at line 126 of file be-fsstubs.c.

127 {
128  int32 fd = PG_GETARG_INT32(0);
129 
130  if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
131  ereport(ERROR,
132  (errcode(ERRCODE_UNDEFINED_OBJECT),
133  errmsg("invalid large-object descriptor: %d", fd)));
134 
135 #ifdef FSDB
136  elog(DEBUG4, "lo_close(%d)", fd);
137 #endif
138 
139  closeLOfd(fd);
140 
141  PG_RETURN_INT32(0);
142 }
signed int int32
Definition: c.h:478
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define DEBUG4
Definition: elog.h:27
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
static int fd(const char *x, int i)
Definition: preproc-init.c:105

References closeLOfd(), cookies, cookies_size, DEBUG4, elog(), ereport, errcode(), errmsg(), ERROR, fd(), PG_GETARG_INT32, and PG_RETURN_INT32.

◆ be_lo_creat()

Datum be_lo_creat ( PG_FUNCTION_ARGS  )

Definition at line 249 of file be-fsstubs.c.

250 {
251  Oid lobjId;
252 
253  PreventCommandIfReadOnly("lo_creat()");
254 
255  lo_cleanup_needed = true;
256  lobjId = inv_create(InvalidOid);
257 
258  PG_RETURN_OID(lobjId);
259 }
#define PG_RETURN_OID(x)
Definition: fmgr.h:360
Oid inv_create(Oid lobjId)
Definition: inv_api.c:212
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
void PreventCommandIfReadOnly(const char *cmdname)
Definition: utility.c:411

References inv_create(), InvalidOid, lo_cleanup_needed, PG_RETURN_OID, and PreventCommandIfReadOnly().

◆ be_lo_create()

Datum be_lo_create ( PG_FUNCTION_ARGS  )

Definition at line 262 of file be-fsstubs.c.

263 {
264  Oid lobjId = PG_GETARG_OID(0);
265 
266  PreventCommandIfReadOnly("lo_create()");
267 
268  lo_cleanup_needed = true;
269  lobjId = inv_create(lobjId);
270 
271  PG_RETURN_OID(lobjId);
272 }
#define PG_GETARG_OID(n)
Definition: fmgr.h:275

References inv_create(), lo_cleanup_needed, PG_GETARG_OID, PG_RETURN_OID, and PreventCommandIfReadOnly().

◆ be_lo_export()

Datum be_lo_export ( PG_FUNCTION_ARGS  )

Definition at line 481 of file be-fsstubs.c.

482 {
483  Oid lobjId = PG_GETARG_OID(0);
485  int fd;
486  int nbytes,
487  tmp;
488  char buf[BUFSIZE];
489  char fnamebuf[MAXPGPATH];
490  LargeObjectDesc *lobj;
491  mode_t oumask;
492 
493  /*
494  * open the inversion object (no need to test for failure)
495  */
496  lo_cleanup_needed = true;
497  lobj = inv_open(lobjId, INV_READ, CurrentMemoryContext);
498 
499  /*
500  * open the file to be written to
501  *
502  * Note: we reduce backend's normal 077 umask to the slightly friendlier
503  * 022. This code used to drop it all the way to 0, but creating
504  * world-writable export files doesn't seem wise.
505  */
506  text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf));
507  oumask = umask(S_IWGRP | S_IWOTH);
508  PG_TRY();
509  {
510  fd = OpenTransientFilePerm(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY,
512  }
513  PG_FINALLY();
514  {
515  umask(oumask);
516  }
517  PG_END_TRY();
518  if (fd < 0)
519  ereport(ERROR,
521  errmsg("could not create server file \"%s\": %m",
522  fnamebuf)));
523 
524  /*
525  * read in from the inversion file and write to the filesystem
526  */
527  while ((nbytes = inv_read(lobj, buf, BUFSIZE)) > 0)
528  {
529  tmp = write(fd, buf, nbytes);
530  if (tmp != nbytes)
531  ereport(ERROR,
533  errmsg("could not write server file \"%s\": %m",
534  fnamebuf)));
535  }
536 
537  if (CloseTransientFile(fd) != 0)
538  ereport(ERROR,
540  errmsg("could not close file \"%s\": %m",
541  fnamebuf)));
542 
543  inv_close(lobj);
544 
545  PG_RETURN_INT32(1);
546 }
#define BUFSIZE
Definition: be-fsstubs.c:61
#define PG_BINARY
Definition: c.h:1260
int errcode_for_file_access(void)
Definition: elog.c:881
#define PG_TRY(...)
Definition: elog.h:370
#define PG_END_TRY(...)
Definition: elog.h:395
#define PG_FINALLY(...)
Definition: elog.h:387
int CloseTransientFile(int fd)
Definition: fd.c:2609
int OpenTransientFilePerm(const char *fileName, int fileFlags, mode_t fileMode)
Definition: fd.c:2442
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define write(a, b, c)
Definition: win32.h:14
LargeObjectDesc * inv_open(Oid lobjId, int flags, MemoryContext mcxt)
Definition: inv_api.c:255
int inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
Definition: inv_api.c:490
void inv_close(LargeObjectDesc *obj_desc)
Definition: inv_api.c:339
#define INV_READ
Definition: libpq-fs.h:22
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
#define MAXPGPATH
static char * filename
Definition: pg_dumpall.c:119
static char * buf
Definition: pg_test_fsync.c:67
Definition: c.h:671
void text_to_cstring_buffer(const text *src, char *dst, size_t dst_len)
Definition: varlena.c:253
#define S_IROTH
Definition: win32_port.h:315
#define S_IRGRP
Definition: win32_port.h:303
#define S_IWOTH
Definition: win32_port.h:318
#define S_IRUSR
Definition: win32_port.h:291
#define S_IWUSR
Definition: win32_port.h:294
#define S_IWGRP
Definition: win32_port.h:306

References buf, BUFSIZE, CloseTransientFile(), CurrentMemoryContext, ereport, errcode_for_file_access(), errmsg(), ERROR, fd(), filename, inv_close(), inv_open(), inv_read(), INV_READ, lo_cleanup_needed, MAXPGPATH, OpenTransientFilePerm(), PG_BINARY, PG_END_TRY, PG_FINALLY, PG_GETARG_OID, PG_GETARG_TEXT_PP, PG_RETURN_INT32, PG_TRY, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR, text_to_cstring_buffer(), and write.

◆ be_lo_from_bytea()

Datum be_lo_from_bytea ( PG_FUNCTION_ARGS  )

Definition at line 827 of file be-fsstubs.c.

828 {
829  Oid loOid = PG_GETARG_OID(0);
831  LargeObjectDesc *loDesc;
832  int written PG_USED_FOR_ASSERTS_ONLY;
833 
834  PreventCommandIfReadOnly("lo_from_bytea()");
835 
836  lo_cleanup_needed = true;
837  loOid = inv_create(loOid);
838  loDesc = inv_open(loOid, INV_WRITE, CurrentMemoryContext);
839  written = inv_write(loDesc, VARDATA_ANY(str), VARSIZE_ANY_EXHDR(str));
840  Assert(written == VARSIZE_ANY_EXHDR(str));
841  inv_close(loDesc);
842 
843  PG_RETURN_OID(loOid);
844 }
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:166
#define PG_GETARG_BYTEA_PP(n)
Definition: fmgr.h:308
int inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
Definition: inv_api.c:583
#define INV_WRITE
Definition: libpq-fs.h:21
Assert(fmt[strlen(fmt) - 1] !='\n')
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317

References Assert(), CurrentMemoryContext, inv_close(), inv_create(), inv_open(), inv_write(), INV_WRITE, lo_cleanup_needed, PG_GETARG_BYTEA_PP, PG_GETARG_OID, PG_RETURN_OID, PG_USED_FOR_ASSERTS_ONLY, PreventCommandIfReadOnly(), generate_unaccent_rules::str, VARDATA_ANY, and VARSIZE_ANY_EXHDR.

◆ be_lo_get()

Datum be_lo_get ( PG_FUNCTION_ARGS  )

Definition at line 792 of file be-fsstubs.c.

793 {
794  Oid loOid = PG_GETARG_OID(0);
795  bytea *result;
796 
797  result = lo_get_fragment_internal(loOid, 0, -1);
798 
799  PG_RETURN_BYTEA_P(result);
800 }
static bytea * lo_get_fragment_internal(Oid loOid, int64 offset, int32 nbytes)
Definition: be-fsstubs.c:741
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371

References lo_get_fragment_internal(), PG_GETARG_OID, and PG_RETURN_BYTEA_P.

◆ be_lo_get_fragment()

Datum be_lo_get_fragment ( PG_FUNCTION_ARGS  )

Definition at line 806 of file be-fsstubs.c.

807 {
808  Oid loOid = PG_GETARG_OID(0);
809  int64 offset = PG_GETARG_INT64(1);
810  int32 nbytes = PG_GETARG_INT32(2);
811  bytea *result;
812 
813  if (nbytes < 0)
814  ereport(ERROR,
815  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
816  errmsg("requested length cannot be negative")));
817 
818  result = lo_get_fragment_internal(loOid, offset, nbytes);
819 
820  PG_RETURN_BYTEA_P(result);
821 }
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283

References ereport, errcode(), errmsg(), ERROR, lo_get_fragment_internal(), PG_GETARG_INT32, PG_GETARG_INT64, PG_GETARG_OID, and PG_RETURN_BYTEA_P.

◆ be_lo_import()

Datum be_lo_import ( PG_FUNCTION_ARGS  )

Definition at line 398 of file be-fsstubs.c.

399 {
401 
403 }
static Oid lo_import_internal(text *filename, Oid lobjOid)
Definition: be-fsstubs.c:419

References filename, InvalidOid, lo_import_internal(), PG_GETARG_TEXT_PP, and PG_RETURN_OID.

◆ be_lo_import_with_oid()

Datum be_lo_import_with_oid ( PG_FUNCTION_ARGS  )

Definition at line 410 of file be-fsstubs.c.

411 {
413  Oid oid = PG_GETARG_OID(1);
414 
416 }

References filename, lo_import_internal(), PG_GETARG_OID, PG_GETARG_TEXT_PP, and PG_RETURN_OID.

◆ be_lo_lseek()

Datum be_lo_lseek ( PG_FUNCTION_ARGS  )

Definition at line 206 of file be-fsstubs.c.

207 {
208  int32 fd = PG_GETARG_INT32(0);
209  int32 offset = PG_GETARG_INT32(1);
210  int32 whence = PG_GETARG_INT32(2);
211  int64 status;
212 
213  if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
214  ereport(ERROR,
215  (errcode(ERRCODE_UNDEFINED_OBJECT),
216  errmsg("invalid large-object descriptor: %d", fd)));
217 
218  status = inv_seek(cookies[fd], offset, whence);
219 
220  /* guard against result overflow */
221  if (status != (int32) status)
222  ereport(ERROR,
223  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
224  errmsg("lo_lseek result out of range for large-object descriptor %d",
225  fd)));
226 
228 }
int64 inv_seek(LargeObjectDesc *obj_desc, int64 offset, int whence)
Definition: inv_api.c:428
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:224

References cookies, cookies_size, ereport, errcode(), errmsg(), ERROR, fd(), inv_seek(), PG_GETARG_INT32, PG_RETURN_INT32, and status().

◆ be_lo_lseek64()

Datum be_lo_lseek64 ( PG_FUNCTION_ARGS  )

Definition at line 231 of file be-fsstubs.c.

232 {
233  int32 fd = PG_GETARG_INT32(0);
234  int64 offset = PG_GETARG_INT64(1);
235  int32 whence = PG_GETARG_INT32(2);
236  int64 status;
237 
238  if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
239  ereport(ERROR,
240  (errcode(ERRCODE_UNDEFINED_OBJECT),
241  errmsg("invalid large-object descriptor: %d", fd)));
242 
243  status = inv_seek(cookies[fd], offset, whence);
244 
246 }
#define PG_RETURN_INT64(x)
Definition: fmgr.h:368

References cookies, cookies_size, ereport, errcode(), errmsg(), ERROR, fd(), inv_seek(), PG_GETARG_INT32, PG_GETARG_INT64, PG_RETURN_INT64, and status().

◆ be_lo_open()

Datum be_lo_open ( PG_FUNCTION_ARGS  )

Definition at line 87 of file be-fsstubs.c.

88 {
89  Oid lobjId = PG_GETARG_OID(0);
91  LargeObjectDesc *lobjDesc;
92  int fd;
93 
94 #ifdef FSDB
95  elog(DEBUG4, "lo_open(%u,%d)", lobjId, mode);
96 #endif
97 
98  if (mode & INV_WRITE)
99  PreventCommandIfReadOnly("lo_open(INV_WRITE)");
100 
101  /*
102  * Allocate a large object descriptor first. This will also create
103  * 'fscxt' if this is the first LO opened in this transaction.
104  */
105  fd = newLOfd();
106 
107  lobjDesc = inv_open(lobjId, mode, fscxt);
108  lobjDesc->subid = GetCurrentSubTransactionId();
109 
110  /*
111  * We must register the snapshot in TopTransaction's resowner so that it
112  * stays alive until the LO is closed rather than until the current portal
113  * shuts down.
114  */
115  if (lobjDesc->snapshot)
116  lobjDesc->snapshot = RegisterSnapshotOnOwner(lobjDesc->snapshot,
118 
119  Assert(cookies[fd] == NULL);
120  cookies[fd] = lobjDesc;
121 
123 }
static int newLOfd(void)
Definition: be-fsstubs.c:675
static PgChecksumMode mode
Definition: pg_checksums.c:65
ResourceOwner TopTransactionResourceOwner
Definition: resowner.c:148
Snapshot RegisterSnapshotOnOwner(Snapshot snapshot, ResourceOwner owner)
Definition: snapmgr.c:842
Snapshot snapshot
Definition: large_object.h:42
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:780

References Assert(), cookies, DEBUG4, elog(), fd(), fscxt, GetCurrentSubTransactionId(), inv_open(), INV_WRITE, mode, newLOfd(), PG_GETARG_INT32, PG_GETARG_OID, PG_RETURN_INT32, PreventCommandIfReadOnly(), RegisterSnapshotOnOwner(), LargeObjectDesc::snapshot, LargeObjectDesc::subid, and TopTransactionResourceOwner.

◆ be_lo_put()

Datum be_lo_put ( PG_FUNCTION_ARGS  )

Definition at line 850 of file be-fsstubs.c.

851 {
852  Oid loOid = PG_GETARG_OID(0);
853  int64 offset = PG_GETARG_INT64(1);
855  LargeObjectDesc *loDesc;
856  int written PG_USED_FOR_ASSERTS_ONLY;
857 
858  PreventCommandIfReadOnly("lo_put()");
859 
860  lo_cleanup_needed = true;
861  loDesc = inv_open(loOid, INV_WRITE, CurrentMemoryContext);
862 
863  /* Permission check */
864  if (!lo_compat_privileges &&
866  GetUserId(),
867  ACL_UPDATE,
868  loDesc->snapshot) != ACLCHECK_OK)
869  ereport(ERROR,
870  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
871  errmsg("permission denied for large object %u",
872  loDesc->id)));
873 
874  inv_seek(loDesc, offset, SEEK_SET);
875  written = inv_write(loDesc, VARDATA_ANY(str), VARSIZE_ANY_EXHDR(str));
876  Assert(written == VARSIZE_ANY_EXHDR(str));
877  inv_close(loDesc);
878 
879  PG_RETURN_VOID();
880 }
@ ACLCHECK_OK
Definition: acl.h:183
AclResult pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode, Snapshot snapshot)
Definition: aclchk.c:3970
#define PG_RETURN_VOID()
Definition: fmgr.h:349
bool lo_compat_privileges
Definition: inv_api.c:58
Oid GetUserId(void)
Definition: miscinit.c:502
#define ACL_UPDATE
Definition: parsenodes.h:85

References ACL_UPDATE, ACLCHECK_OK, Assert(), CurrentMemoryContext, ereport, errcode(), errmsg(), ERROR, GetUserId(), LargeObjectDesc::id, inv_close(), inv_open(), inv_seek(), inv_write(), INV_WRITE, lo_cleanup_needed, lo_compat_privileges, PG_GETARG_BYTEA_PP, PG_GETARG_INT64, PG_GETARG_OID, pg_largeobject_aclcheck_snapshot(), PG_RETURN_VOID, PG_USED_FOR_ASSERTS_ONLY, PreventCommandIfReadOnly(), LargeObjectDesc::snapshot, generate_unaccent_rules::str, VARDATA_ANY, and VARSIZE_ANY_EXHDR.

◆ be_lo_tell()

Datum be_lo_tell ( PG_FUNCTION_ARGS  )

Definition at line 275 of file be-fsstubs.c.

276 {
277  int32 fd = PG_GETARG_INT32(0);
278  int64 offset;
279 
280  if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
281  ereport(ERROR,
282  (errcode(ERRCODE_UNDEFINED_OBJECT),
283  errmsg("invalid large-object descriptor: %d", fd)));
284 
285  offset = inv_tell(cookies[fd]);
286 
287  /* guard against result overflow */
288  if (offset != (int32) offset)
289  ereport(ERROR,
290  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
291  errmsg("lo_tell result out of range for large-object descriptor %d",
292  fd)));
293 
294  PG_RETURN_INT32((int32) offset);
295 }
int64 inv_tell(LargeObjectDesc *obj_desc)
Definition: inv_api.c:477

References cookies, cookies_size, ereport, errcode(), errmsg(), ERROR, fd(), inv_tell(), PG_GETARG_INT32, and PG_RETURN_INT32.

◆ be_lo_tell64()

Datum be_lo_tell64 ( PG_FUNCTION_ARGS  )

Definition at line 298 of file be-fsstubs.c.

299 {
300  int32 fd = PG_GETARG_INT32(0);
301  int64 offset;
302 
303  if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
304  ereport(ERROR,
305  (errcode(ERRCODE_UNDEFINED_OBJECT),
306  errmsg("invalid large-object descriptor: %d", fd)));
307 
308  offset = inv_tell(cookies[fd]);
309 
310  PG_RETURN_INT64(offset);
311 }

References cookies, cookies_size, ereport, errcode(), errmsg(), ERROR, fd(), inv_tell(), PG_GETARG_INT32, and PG_RETURN_INT64.

◆ be_lo_truncate()

Datum be_lo_truncate ( PG_FUNCTION_ARGS  )

Definition at line 574 of file be-fsstubs.c.

575 {
576  int32 fd = PG_GETARG_INT32(0);
578 
579  PreventCommandIfReadOnly("lo_truncate()");
580 
582  PG_RETURN_INT32(0);
583 }
static void lo_truncate_internal(int32 fd, int64 len)
Definition: be-fsstubs.c:553
const void size_t len

References fd(), len, lo_truncate_internal(), PG_GETARG_INT32, PG_RETURN_INT32, and PreventCommandIfReadOnly().

◆ be_lo_truncate64()

Datum be_lo_truncate64 ( PG_FUNCTION_ARGS  )

Definition at line 586 of file be-fsstubs.c.

587 {
588  int32 fd = PG_GETARG_INT32(0);
589  int64 len = PG_GETARG_INT64(1);
590 
591  PreventCommandIfReadOnly("lo_truncate64()");
592 
594  PG_RETURN_INT32(0);
595 }

References fd(), len, lo_truncate_internal(), PG_GETARG_INT32, PG_GETARG_INT64, PG_RETURN_INT32, and PreventCommandIfReadOnly().

◆ be_lo_unlink()

Datum be_lo_unlink ( PG_FUNCTION_ARGS  )

Definition at line 314 of file be-fsstubs.c.

315 {
316  Oid lobjId = PG_GETARG_OID(0);
317 
318  PreventCommandIfReadOnly("lo_unlink()");
319 
320  /*
321  * Must be owner of the large object. It would be cleaner to check this
322  * in inv_drop(), but we want to throw the error before not after closing
323  * relevant FDs.
324  */
325  if (!lo_compat_privileges &&
326  !object_ownercheck(LargeObjectMetadataRelationId, lobjId, GetUserId()))
327  ereport(ERROR,
328  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
329  errmsg("must be owner of large object %u", lobjId)));
330 
331  /*
332  * If there are any open LO FDs referencing that ID, close 'em.
333  */
334  if (fscxt != NULL)
335  {
336  int i;
337 
338  for (i = 0; i < cookies_size; i++)
339  {
340  if (cookies[i] != NULL && cookies[i]->id == lobjId)
341  closeLOfd(i);
342  }
343  }
344 
345  /*
346  * inv_drop does not create a need for end-of-transaction cleanup and
347  * hence we don't need to set lo_cleanup_needed.
348  */
349  PG_RETURN_INT32(inv_drop(lobjId));
350 }
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:3984
int inv_drop(Oid lobjId)
Definition: inv_api.c:351

References closeLOfd(), cookies, cookies_size, ereport, errcode(), errmsg(), ERROR, fscxt, GetUserId(), i, inv_drop(), lo_compat_privileges, object_ownercheck(), PG_GETARG_OID, PG_RETURN_INT32, and PreventCommandIfReadOnly().

Referenced by lo_manage().

◆ be_loread()

Datum be_loread ( PG_FUNCTION_ARGS  )

Definition at line 357 of file be-fsstubs.c.

358 {
359  int32 fd = PG_GETARG_INT32(0);
361  bytea *retval;
362  int totalread;
363 
364  if (len < 0)
365  len = 0;
366 
367  retval = (bytea *) palloc(VARHDRSZ + len);
368  totalread = lo_read(fd, VARDATA(retval), len);
369  SET_VARSIZE(retval, totalread + VARHDRSZ);
370 
371  PG_RETURN_BYTEA_P(retval);
372 }
int lo_read(int fd, char *buf, int len)
Definition: be-fsstubs.c:154
#define VARHDRSZ
Definition: c.h:676
void * palloc(Size size)
Definition: mcxt.c:1210
#define VARDATA(PTR)
Definition: varatt.h:278
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305

References fd(), len, lo_read(), palloc(), PG_GETARG_INT32, PG_RETURN_BYTEA_P, SET_VARSIZE, VARDATA, and VARHDRSZ.

◆ be_lowrite()

Datum be_lowrite ( PG_FUNCTION_ARGS  )

Definition at line 375 of file be-fsstubs.c.

376 {
377  int32 fd = PG_GETARG_INT32(0);
378  bytea *wbuf = PG_GETARG_BYTEA_PP(1);
379  int bytestowrite;
380  int totalwritten;
381 
382  PreventCommandIfReadOnly("lowrite()");
383 
384  bytestowrite = VARSIZE_ANY_EXHDR(wbuf);
385  totalwritten = lo_write(fd, VARDATA_ANY(wbuf), bytestowrite);
386  PG_RETURN_INT32(totalwritten);
387 }
int lo_write(int fd, const char *buf, int len)
Definition: be-fsstubs.c:182

References fd(), lo_write(), PG_GETARG_BYTEA_PP, PG_GETARG_INT32, PG_RETURN_INT32, PreventCommandIfReadOnly(), VARDATA_ANY, and VARSIZE_ANY_EXHDR.

◆ closeLOfd()

static void closeLOfd ( int  fd)
static

Definition at line 716 of file be-fsstubs.c.

717 {
718  LargeObjectDesc *lobj;
719 
720  /*
721  * Make sure we do not try to free twice if this errors out for some
722  * reason. Better a leak than a crash.
723  */
724  lobj = cookies[fd];
725  cookies[fd] = NULL;
726 
727  if (lobj->snapshot)
730  inv_close(lobj);
731 }
void UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner)
Definition: snapmgr.c:884

References cookies, fd(), inv_close(), LargeObjectDesc::snapshot, TopTransactionResourceOwner, and UnregisterSnapshotFromOwner().

Referenced by AtEOSubXact_LargeObject(), AtEOXact_LargeObject(), be_lo_close(), and be_lo_unlink().

◆ lo_get_fragment_internal()

static bytea* lo_get_fragment_internal ( Oid  loOid,
int64  offset,
int32  nbytes 
)
static

Definition at line 741 of file be-fsstubs.c.

742 {
743  LargeObjectDesc *loDesc;
744  int64 loSize;
745  int64 result_length;
746  int total_read PG_USED_FOR_ASSERTS_ONLY;
747  bytea *result = NULL;
748 
749  lo_cleanup_needed = true;
750  loDesc = inv_open(loOid, INV_READ, CurrentMemoryContext);
751 
752  /*
753  * Compute number of bytes we'll actually read, accommodating nbytes == -1
754  * and reads beyond the end of the LO.
755  */
756  loSize = inv_seek(loDesc, 0, SEEK_END);
757  if (loSize > offset)
758  {
759  if (nbytes >= 0 && nbytes <= loSize - offset)
760  result_length = nbytes; /* request is wholly inside LO */
761  else
762  result_length = loSize - offset; /* adjust to end of LO */
763  }
764  else
765  result_length = 0; /* request is wholly outside LO */
766 
767  /*
768  * A result_length calculated from loSize may not fit in a size_t. Check
769  * that the size will satisfy this and subsequently-enforced size limits.
770  */
771  if (result_length > MaxAllocSize - VARHDRSZ)
772  ereport(ERROR,
773  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
774  errmsg("large object read request is too large")));
775 
776  result = (bytea *) palloc(VARHDRSZ + result_length);
777 
778  inv_seek(loDesc, offset, SEEK_SET);
779  total_read = inv_read(loDesc, VARDATA(result), result_length);
780  Assert(total_read == result_length);
781  SET_VARSIZE(result, result_length + VARHDRSZ);
782 
783  inv_close(loDesc);
784 
785  return result;
786 }
#define MaxAllocSize
Definition: memutils.h:40

References Assert(), CurrentMemoryContext, ereport, errcode(), errmsg(), ERROR, inv_close(), inv_open(), inv_read(), INV_READ, inv_seek(), lo_cleanup_needed, MaxAllocSize, palloc(), PG_USED_FOR_ASSERTS_ONLY, SET_VARSIZE, VARDATA, and VARHDRSZ.

Referenced by be_lo_get(), and be_lo_get_fragment().

◆ lo_import_internal()

static Oid lo_import_internal ( text filename,
Oid  lobjOid 
)
static

Definition at line 419 of file be-fsstubs.c.

420 {
421  int fd;
422  int nbytes,
424  char buf[BUFSIZE];
425  char fnamebuf[MAXPGPATH];
426  LargeObjectDesc *lobj;
427  Oid oid;
428 
429  PreventCommandIfReadOnly("lo_import()");
430 
431  /*
432  * open the file to be read in
433  */
434  text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf));
435  fd = OpenTransientFile(fnamebuf, O_RDONLY | PG_BINARY);
436  if (fd < 0)
437  ereport(ERROR,
439  errmsg("could not open server file \"%s\": %m",
440  fnamebuf)));
441 
442  /*
443  * create an inversion object
444  */
445  lo_cleanup_needed = true;
446  oid = inv_create(lobjOid);
447 
448  /*
449  * read in from the filesystem and write to the inversion object
450  */
452 
453  while ((nbytes = read(fd, buf, BUFSIZE)) > 0)
454  {
455  tmp = inv_write(lobj, buf, nbytes);
456  Assert(tmp == nbytes);
457  }
458 
459  if (nbytes < 0)
460  ereport(ERROR,
462  errmsg("could not read server file \"%s\": %m",
463  fnamebuf)));
464 
465  inv_close(lobj);
466 
467  if (CloseTransientFile(fd) != 0)
468  ereport(ERROR,
470  errmsg("could not close file \"%s\": %m",
471  fnamebuf)));
472 
473  return oid;
474 }
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2433
#define read(a, b, c)
Definition: win32.h:13

References Assert(), buf, BUFSIZE, CloseTransientFile(), CurrentMemoryContext, ereport, errcode_for_file_access(), errmsg(), ERROR, fd(), filename, inv_close(), inv_create(), inv_open(), inv_write(), INV_WRITE, lo_cleanup_needed, MAXPGPATH, OpenTransientFile(), PG_BINARY, PG_USED_FOR_ASSERTS_ONLY, PreventCommandIfReadOnly(), read, and text_to_cstring_buffer().

Referenced by be_lo_import(), and be_lo_import_with_oid().

◆ lo_read()

int lo_read ( int  fd,
char *  buf,
int  len 
)

Definition at line 154 of file be-fsstubs.c.

155 {
156  int status;
157  LargeObjectDesc *lobj;
158 
159  if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
160  ereport(ERROR,
161  (errcode(ERRCODE_UNDEFINED_OBJECT),
162  errmsg("invalid large-object descriptor: %d", fd)));
163  lobj = cookies[fd];
164 
165  /*
166  * Check state. inv_read() would throw an error anyway, but we want the
167  * error to be about the FD's state not the underlying privilege; it might
168  * be that the privilege exists but user forgot to ask for read mode.
169  */
170  if ((lobj->flags & IFS_RDLOCK) == 0)
171  ereport(ERROR,
172  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
173  errmsg("large object descriptor %d was not opened for reading",
174  fd)));
175 
176  status = inv_read(lobj, buf, len);
177 
178  return status;
179 }
#define IFS_RDLOCK
Definition: large_object.h:48

References buf, cookies, cookies_size, ereport, errcode(), errmsg(), ERROR, fd(), LargeObjectDesc::flags, IFS_RDLOCK, inv_read(), len, and status().

Referenced by be_loread(), dumpLOs(), exportFile(), and pickout().

◆ lo_truncate_internal()

static void lo_truncate_internal ( int32  fd,
int64  len 
)
static

Definition at line 553 of file be-fsstubs.c.

554 {
555  LargeObjectDesc *lobj;
556 
557  if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
558  ereport(ERROR,
559  (errcode(ERRCODE_UNDEFINED_OBJECT),
560  errmsg("invalid large-object descriptor: %d", fd)));
561  lobj = cookies[fd];
562 
563  /* see comment in lo_read() */
564  if ((lobj->flags & IFS_WRLOCK) == 0)
565  ereport(ERROR,
566  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
567  errmsg("large object descriptor %d was not opened for writing",
568  fd)));
569 
570  inv_truncate(lobj, len);
571 }
void inv_truncate(LargeObjectDesc *obj_desc, int64 len)
Definition: inv_api.c:780
#define IFS_WRLOCK
Definition: large_object.h:49

References cookies, cookies_size, ereport, errcode(), errmsg(), ERROR, fd(), LargeObjectDesc::flags, IFS_WRLOCK, inv_truncate(), and len.

Referenced by be_lo_truncate(), and be_lo_truncate64().

◆ lo_write()

int lo_write ( int  fd,
const char *  buf,
int  len 
)

Definition at line 182 of file be-fsstubs.c.

183 {
184  int status;
185  LargeObjectDesc *lobj;
186 
187  if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
188  ereport(ERROR,
189  (errcode(ERRCODE_UNDEFINED_OBJECT),
190  errmsg("invalid large-object descriptor: %d", fd)));
191  lobj = cookies[fd];
192 
193  /* see comment in lo_read() */
194  if ((lobj->flags & IFS_WRLOCK) == 0)
195  ereport(ERROR,
196  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
197  errmsg("large object descriptor %d was not opened for writing",
198  fd)));
199 
200  status = inv_write(lobj, buf, len);
201 
202  return status;
203 }

References buf, cookies, cookies_size, ereport, errcode(), errmsg(), ERROR, fd(), LargeObjectDesc::flags, IFS_WRLOCK, inv_write(), len, and status().

Referenced by be_lowrite(), dump_lo_buf(), importFile(), and overwrite().

◆ newLOfd()

static int newLOfd ( void  )
static

Definition at line 675 of file be-fsstubs.c.

676 {
677  int i,
678  newsize;
679 
680  lo_cleanup_needed = true;
681  if (fscxt == NULL)
683  "Filesystem",
685 
686  /* Try to find a free slot */
687  for (i = 0; i < cookies_size; i++)
688  {
689  if (cookies[i] == NULL)
690  return i;
691  }
692 
693  /* No free slot, so make the array bigger */
694  if (cookies_size <= 0)
695  {
696  /* First time through, arbitrarily make 64-element array */
697  i = 0;
698  newsize = 64;
699  cookies = (LargeObjectDesc **)
700  MemoryContextAllocZero(fscxt, newsize * sizeof(LargeObjectDesc *));
701  }
702  else
703  {
704  /* Double size of array */
705  i = cookies_size;
706  newsize = cookies_size * 2;
707  cookies =
709  }
710  cookies_size = newsize;
711 
712  return i;
713 }
MemoryContext TopMemoryContext
Definition: mcxt.c:141
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1048
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:153
#define repalloc0_array(pointer, type, oldcount, count)
Definition: palloc.h:110

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, cookies, cookies_size, fscxt, i, lo_cleanup_needed, MemoryContextAllocZero(), repalloc0_array, and TopMemoryContext.

Referenced by be_lo_open().

Variable Documentation

◆ cookies

◆ cookies_size

◆ fscxt

MemoryContext fscxt = NULL
static

◆ lo_cleanup_needed