PostgreSQL Source Code  git master
be-fsstubs.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * be-fsstubs.c
4  * Builtin functions for open/close/read/write operations on large objects
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/libpq/be-fsstubs.c
12  *
13  * NOTES
14  * This should be moved to a more appropriate place. It is here
15  * for lack of a better place.
16  *
17  * These functions store LargeObjectDesc structs in a private MemoryContext,
18  * which means that large object descriptors hang around until we destroy
19  * the context at transaction end. It'd be possible to prolong the lifetime
20  * of the context so that LO FDs are good across transactions (for example,
21  * we could release the context only if we see that no FDs remain open).
22  * But we'd need additional state in order to do the right thing at the
23  * end of an aborted transaction. FDs opened during an aborted xact would
24  * still need to be closed, since they might not be pointing at valid
25  * relations at all. Locking semantics are also an interesting problem
26  * if LOs stay open across transactions. For now, we'll stick with the
27  * existing documented semantics of LO FDs: they're only good within a
28  * transaction.
29  *
30  * As of PostgreSQL 8.0, much of the angst expressed above is no longer
31  * relevant, and in fact it'd be pretty easy to allow LO FDs to stay
32  * open across transactions. (Snapshot relevancy would still be an issue.)
33  * However backwards compatibility suggests that we should stick to the
34  * status quo.
35  *
36  *-------------------------------------------------------------------------
37  */
38 
39 #include "postgres.h"
40 
41 #include <fcntl.h>
42 #include <sys/stat.h>
43 #include <unistd.h>
44 
45 #include "libpq/be-fsstubs.h"
46 #include "libpq/libpq-fs.h"
47 #include "miscadmin.h"
48 #include "storage/fd.h"
49 #include "storage/large_object.h"
50 #include "utils/acl.h"
51 #include "utils/builtins.h"
52 #include "utils/memutils.h"
53 
54 /* define this to enable debug logging */
55 /* #define FSDB 1 */
56 /* chunk size for lo_import/lo_export transfers */
57 #define BUFSIZE 8192
58 
59 /*
60  * LO "FD"s are indexes into the cookies array.
61  *
62  * A non-null entry is a pointer to a LargeObjectDesc allocated in the
63  * LO private memory context "fscxt". The cookies array itself is also
64  * dynamically allocated in that context. Its current allocated size is
65  * cookies_len entries, of which any unused entries will be NULL.
66  */
67 static LargeObjectDesc **cookies = NULL;
68 static int cookies_size = 0;
69 
70 static MemoryContext fscxt = NULL;
71 
72 #define CreateFSContext() \
73  do { \
74  if (fscxt == NULL) \
75  fscxt = AllocSetContextCreate(TopMemoryContext, \
76  "Filesystem", \
77  ALLOCSET_DEFAULT_SIZES); \
78  } while (0)
79 
80 
81 static int newLOfd(LargeObjectDesc *lobjCookie);
82 static void deleteLOfd(int fd);
83 static Oid lo_import_internal(text *filename, Oid lobjOid);
84 
85 
86 /*****************************************************************************
87  * File Interfaces for Large Objects
88  *****************************************************************************/
89 
90 Datum
92 {
93  Oid lobjId = PG_GETARG_OID(0);
94  int32 mode = PG_GETARG_INT32(1);
95  LargeObjectDesc *lobjDesc;
96  int fd;
97 
98 #if FSDB
99  elog(DEBUG4, "lo_open(%u,%d)", lobjId, mode);
100 #endif
101 
102  CreateFSContext();
103 
104  lobjDesc = inv_open(lobjId, mode, fscxt);
105 
106  fd = newLOfd(lobjDesc);
107 
108  PG_RETURN_INT32(fd);
109 }
110 
111 Datum
113 {
114  int32 fd = PG_GETARG_INT32(0);
115 
116  if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
117  ereport(ERROR,
118  (errcode(ERRCODE_UNDEFINED_OBJECT),
119  errmsg("invalid large-object descriptor: %d", fd)));
120 
121 #if FSDB
122  elog(DEBUG4, "lo_close(%d)", fd);
123 #endif
124 
125  inv_close(cookies[fd]);
126 
127  deleteLOfd(fd);
128 
129  PG_RETURN_INT32(0);
130 }
131 
132 
133 /*****************************************************************************
134  * Bare Read/Write operations --- these are not fmgr-callable!
135  *
136  * We assume the large object supports byte oriented reads and seeks so
137  * that our work is easier.
138  *
139  *****************************************************************************/
140 
141 int
142 lo_read(int fd, char *buf, int len)
143 {
144  int status;
145  LargeObjectDesc *lobj;
146 
147  if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
148  ereport(ERROR,
149  (errcode(ERRCODE_UNDEFINED_OBJECT),
150  errmsg("invalid large-object descriptor: %d", fd)));
151  lobj = cookies[fd];
152 
153  /*
154  * Check state. inv_read() would throw an error anyway, but we want the
155  * error to be about the FD's state not the underlying privilege; it might
156  * be that the privilege exists but user forgot to ask for read mode.
157  */
158  if ((lobj->flags & IFS_RDLOCK) == 0)
159  ereport(ERROR,
160  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
161  errmsg("large object descriptor %d was not opened for reading",
162  fd)));
163 
164  status = inv_read(lobj, buf, len);
165 
166  return status;
167 }
168 
169 int
170 lo_write(int fd, const char *buf, int len)
171 {
172  int status;
173  LargeObjectDesc *lobj;
174 
175  if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
176  ereport(ERROR,
177  (errcode(ERRCODE_UNDEFINED_OBJECT),
178  errmsg("invalid large-object descriptor: %d", fd)));
179  lobj = cookies[fd];
180 
181  /* see comment in lo_read() */
182  if ((lobj->flags & IFS_WRLOCK) == 0)
183  ereport(ERROR,
184  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
185  errmsg("large object descriptor %d was not opened for writing",
186  fd)));
187 
188  status = inv_write(lobj, buf, len);
189 
190  return status;
191 }
192 
193 Datum
195 {
196  int32 fd = PG_GETARG_INT32(0);
197  int32 offset = PG_GETARG_INT32(1);
198  int32 whence = PG_GETARG_INT32(2);
199  int64 status;
200 
201  if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
202  ereport(ERROR,
203  (errcode(ERRCODE_UNDEFINED_OBJECT),
204  errmsg("invalid large-object descriptor: %d", fd)));
205 
206  status = inv_seek(cookies[fd], offset, whence);
207 
208  /* guard against result overflow */
209  if (status != (int32) status)
210  ereport(ERROR,
211  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
212  errmsg("lo_lseek result out of range for large-object descriptor %d",
213  fd)));
214 
215  PG_RETURN_INT32((int32) status);
216 }
217 
218 Datum
220 {
221  int32 fd = PG_GETARG_INT32(0);
222  int64 offset = PG_GETARG_INT64(1);
223  int32 whence = PG_GETARG_INT32(2);
224  int64 status;
225 
226  if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
227  ereport(ERROR,
228  (errcode(ERRCODE_UNDEFINED_OBJECT),
229  errmsg("invalid large-object descriptor: %d", fd)));
230 
231  status = inv_seek(cookies[fd], offset, whence);
232 
233  PG_RETURN_INT64(status);
234 }
235 
236 Datum
238 {
239  Oid lobjId;
240 
241  /*
242  * We don't actually need to store into fscxt, but create it anyway to
243  * ensure that AtEOXact_LargeObject knows there is state to clean up
244  */
245  CreateFSContext();
246 
247  lobjId = inv_create(InvalidOid);
248 
249  PG_RETURN_OID(lobjId);
250 }
251 
252 Datum
254 {
255  Oid lobjId = PG_GETARG_OID(0);
256 
257  /*
258  * We don't actually need to store into fscxt, but create it anyway to
259  * ensure that AtEOXact_LargeObject knows there is state to clean up
260  */
261  CreateFSContext();
262 
263  lobjId = inv_create(lobjId);
264 
265  PG_RETURN_OID(lobjId);
266 }
267 
268 Datum
270 {
271  int32 fd = PG_GETARG_INT32(0);
272  int64 offset;
273 
274  if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
275  ereport(ERROR,
276  (errcode(ERRCODE_UNDEFINED_OBJECT),
277  errmsg("invalid large-object descriptor: %d", fd)));
278 
279  offset = inv_tell(cookies[fd]);
280 
281  /* guard against result overflow */
282  if (offset != (int32) offset)
283  ereport(ERROR,
284  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
285  errmsg("lo_tell result out of range for large-object descriptor %d",
286  fd)));
287 
288  PG_RETURN_INT32((int32) offset);
289 }
290 
291 Datum
293 {
294  int32 fd = PG_GETARG_INT32(0);
295  int64 offset;
296 
297  if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
298  ereport(ERROR,
299  (errcode(ERRCODE_UNDEFINED_OBJECT),
300  errmsg("invalid large-object descriptor: %d", fd)));
301 
302  offset = inv_tell(cookies[fd]);
303 
304  PG_RETURN_INT64(offset);
305 }
306 
307 Datum
309 {
310  Oid lobjId = PG_GETARG_OID(0);
311 
312  /*
313  * Must be owner of the large object. It would be cleaner to check this
314  * in inv_drop(), but we want to throw the error before not after closing
315  * relevant FDs.
316  */
317  if (!lo_compat_privileges &&
319  ereport(ERROR,
320  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
321  errmsg("must be owner of large object %u", lobjId)));
322 
323  /*
324  * If there are any open LO FDs referencing that ID, close 'em.
325  */
326  if (fscxt != NULL)
327  {
328  int i;
329 
330  for (i = 0; i < cookies_size; i++)
331  {
332  if (cookies[i] != NULL && cookies[i]->id == lobjId)
333  {
334  inv_close(cookies[i]);
335  deleteLOfd(i);
336  }
337  }
338  }
339 
340  /*
341  * inv_drop does not create a need for end-of-transaction cleanup and
342  * hence we don't need to have created fscxt.
343  */
344  PG_RETURN_INT32(inv_drop(lobjId));
345 }
346 
347 /*****************************************************************************
348  * Read/Write using bytea
349  *****************************************************************************/
350 
351 Datum
353 {
354  int32 fd = PG_GETARG_INT32(0);
355  int32 len = PG_GETARG_INT32(1);
356  bytea *retval;
357  int totalread;
358 
359  if (len < 0)
360  len = 0;
361 
362  retval = (bytea *) palloc(VARHDRSZ + len);
363  totalread = lo_read(fd, VARDATA(retval), len);
364  SET_VARSIZE(retval, totalread + VARHDRSZ);
365 
366  PG_RETURN_BYTEA_P(retval);
367 }
368 
369 Datum
371 {
372  int32 fd = PG_GETARG_INT32(0);
373  bytea *wbuf = PG_GETARG_BYTEA_PP(1);
374  int bytestowrite;
375  int totalwritten;
376 
377  bytestowrite = VARSIZE_ANY_EXHDR(wbuf);
378  totalwritten = lo_write(fd, VARDATA_ANY(wbuf), bytestowrite);
379  PG_RETURN_INT32(totalwritten);
380 }
381 
382 /*****************************************************************************
383  * Import/Export of Large Object
384  *****************************************************************************/
385 
386 /*
387  * lo_import -
388  * imports a file as an (inversion) large object.
389  */
390 Datum
392 {
394 
396 }
397 
398 /*
399  * lo_import_with_oid -
400  * imports a file as an (inversion) large object specifying oid.
401  */
402 Datum
404 {
406  Oid oid = PG_GETARG_OID(1);
407 
408  PG_RETURN_OID(lo_import_internal(filename, oid));
409 }
410 
411 static Oid
413 {
414  int fd;
415  int nbytes,
417  char buf[BUFSIZE];
418  char fnamebuf[MAXPGPATH];
419  LargeObjectDesc *lobj;
420  Oid oid;
421 
422  CreateFSContext();
423 
424  /*
425  * open the file to be read in
426  */
427  text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf));
428  fd = OpenTransientFile(fnamebuf, O_RDONLY | PG_BINARY);
429  if (fd < 0)
430  ereport(ERROR,
432  errmsg("could not open server file \"%s\": %m",
433  fnamebuf)));
434 
435  /*
436  * create an inversion object
437  */
438  oid = inv_create(lobjOid);
439 
440  /*
441  * read in from the filesystem and write to the inversion object
442  */
443  lobj = inv_open(oid, INV_WRITE, fscxt);
444 
445  while ((nbytes = read(fd, buf, BUFSIZE)) > 0)
446  {
447  tmp = inv_write(lobj, buf, nbytes);
448  Assert(tmp == nbytes);
449  }
450 
451  if (nbytes < 0)
452  ereport(ERROR,
454  errmsg("could not read server file \"%s\": %m",
455  fnamebuf)));
456 
457  inv_close(lobj);
458  CloseTransientFile(fd);
459 
460  return oid;
461 }
462 
463 /*
464  * lo_export -
465  * exports an (inversion) large object.
466  */
467 Datum
469 {
470  Oid lobjId = PG_GETARG_OID(0);
472  int fd;
473  int nbytes,
474  tmp;
475  char buf[BUFSIZE];
476  char fnamebuf[MAXPGPATH];
477  LargeObjectDesc *lobj;
478  mode_t oumask;
479 
480  CreateFSContext();
481 
482  /*
483  * open the inversion object (no need to test for failure)
484  */
485  lobj = inv_open(lobjId, INV_READ, fscxt);
486 
487  /*
488  * open the file to be written to
489  *
490  * Note: we reduce backend's normal 077 umask to the slightly friendlier
491  * 022. This code used to drop it all the way to 0, but creating
492  * world-writable export files doesn't seem wise.
493  */
494  text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf));
495  oumask = umask(S_IWGRP | S_IWOTH);
496  PG_TRY();
497  {
498  fd = OpenTransientFilePerm(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY,
500  }
501  PG_CATCH();
502  {
503  umask(oumask);
504  PG_RE_THROW();
505  }
506  PG_END_TRY();
507  umask(oumask);
508  if (fd < 0)
509  ereport(ERROR,
511  errmsg("could not create server file \"%s\": %m",
512  fnamebuf)));
513 
514  /*
515  * read in from the inversion file and write to the filesystem
516  */
517  while ((nbytes = inv_read(lobj, buf, BUFSIZE)) > 0)
518  {
519  tmp = write(fd, buf, nbytes);
520  if (tmp != nbytes)
521  ereport(ERROR,
523  errmsg("could not write server file \"%s\": %m",
524  fnamebuf)));
525  }
526 
527  CloseTransientFile(fd);
528  inv_close(lobj);
529 
530  PG_RETURN_INT32(1);
531 }
532 
533 /*
534  * lo_truncate -
535  * truncate a large object to a specified length
536  */
537 static void
539 {
540  LargeObjectDesc *lobj;
541 
542  if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL)
543  ereport(ERROR,
544  (errcode(ERRCODE_UNDEFINED_OBJECT),
545  errmsg("invalid large-object descriptor: %d", fd)));
546  lobj = cookies[fd];
547 
548  /* see comment in lo_read() */
549  if ((lobj->flags & IFS_WRLOCK) == 0)
550  ereport(ERROR,
551  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
552  errmsg("large object descriptor %d was not opened for writing",
553  fd)));
554 
555  inv_truncate(lobj, len);
556 }
557 
558 Datum
560 {
561  int32 fd = PG_GETARG_INT32(0);
562  int32 len = PG_GETARG_INT32(1);
563 
564  lo_truncate_internal(fd, len);
565  PG_RETURN_INT32(0);
566 }
567 
568 Datum
570 {
571  int32 fd = PG_GETARG_INT32(0);
572  int64 len = PG_GETARG_INT64(1);
573 
574  lo_truncate_internal(fd, len);
575  PG_RETURN_INT32(0);
576 }
577 
578 /*
579  * AtEOXact_LargeObject -
580  * prepares large objects for transaction commit
581  */
582 void
583 AtEOXact_LargeObject(bool isCommit)
584 {
585  int i;
586 
587  if (fscxt == NULL)
588  return; /* no LO operations in this xact */
589 
590  /*
591  * Close LO fds and clear cookies array so that LO fds are no longer good.
592  * On abort we skip the close step.
593  */
594  for (i = 0; i < cookies_size; i++)
595  {
596  if (cookies[i] != NULL)
597  {
598  if (isCommit)
599  inv_close(cookies[i]);
600  deleteLOfd(i);
601  }
602  }
603 
604  /* Needn't actually pfree since we're about to zap context */
605  cookies = NULL;
606  cookies_size = 0;
607 
608  /* Release the LO memory context to prevent permanent memory leaks. */
609  MemoryContextDelete(fscxt);
610  fscxt = NULL;
611 
612  /* Give inv_api.c a chance to clean up, too */
613  close_lo_relation(isCommit);
614 }
615 
616 /*
617  * AtEOSubXact_LargeObject
618  * Take care of large objects at subtransaction commit/abort
619  *
620  * Reassign LOs created/opened during a committing subtransaction
621  * to the parent subtransaction. On abort, just close them.
622  */
623 void
625  SubTransactionId parentSubid)
626 {
627  int i;
628 
629  if (fscxt == NULL) /* no LO operations in this xact */
630  return;
631 
632  for (i = 0; i < cookies_size; i++)
633  {
634  LargeObjectDesc *lo = cookies[i];
635 
636  if (lo != NULL && lo->subid == mySubid)
637  {
638  if (isCommit)
639  lo->subid = parentSubid;
640  else
641  {
642  /*
643  * Make sure we do not call inv_close twice if it errors out
644  * for some reason. Better a leak than a crash.
645  */
646  deleteLOfd(i);
647  inv_close(lo);
648  }
649  }
650  }
651 }
652 
653 /*****************************************************************************
654  * Support routines for this file
655  *****************************************************************************/
656 
657 static int
659 {
660  int i,
661  newsize;
662 
663  /* Try to find a free slot */
664  for (i = 0; i < cookies_size; i++)
665  {
666  if (cookies[i] == NULL)
667  {
668  cookies[i] = lobjCookie;
669  return i;
670  }
671  }
672 
673  /* No free slot, so make the array bigger */
674  if (cookies_size <= 0)
675  {
676  /* First time through, arbitrarily make 64-element array */
677  i = 0;
678  newsize = 64;
679  cookies = (LargeObjectDesc **)
680  MemoryContextAllocZero(fscxt, newsize * sizeof(LargeObjectDesc *));
681  cookies_size = newsize;
682  }
683  else
684  {
685  /* Double size of array */
686  i = cookies_size;
687  newsize = cookies_size * 2;
688  cookies = (LargeObjectDesc **)
689  repalloc(cookies, newsize * sizeof(LargeObjectDesc *));
690  MemSet(cookies + cookies_size, 0,
691  (newsize - cookies_size) * sizeof(LargeObjectDesc *));
692  cookies_size = newsize;
693  }
694 
695  Assert(cookies[i] == NULL);
696  cookies[i] = lobjCookie;
697  return i;
698 }
699 
700 static void
702 {
703  cookies[fd] = NULL;
704 }
705 
706 /*****************************************************************************
707  * Wrappers oriented toward SQL callers
708  *****************************************************************************/
709 
710 /*
711  * Read [offset, offset+nbytes) within LO; when nbytes is -1, read to end.
712  */
713 static bytea *
714 lo_get_fragment_internal(Oid loOid, int64 offset, int32 nbytes)
715 {
716  LargeObjectDesc *loDesc;
717  int64 loSize;
718  int64 result_length;
719  int total_read PG_USED_FOR_ASSERTS_ONLY;
720  bytea *result = NULL;
721 
722  /*
723  * We don't actually need to store into fscxt, but create it anyway to
724  * ensure that AtEOXact_LargeObject knows there is state to clean up
725  */
726  CreateFSContext();
727 
728  loDesc = inv_open(loOid, INV_READ, fscxt);
729 
730  /*
731  * Compute number of bytes we'll actually read, accommodating nbytes == -1
732  * and reads beyond the end of the LO.
733  */
734  loSize = inv_seek(loDesc, 0, SEEK_END);
735  if (loSize > offset)
736  {
737  if (nbytes >= 0 && nbytes <= loSize - offset)
738  result_length = nbytes; /* request is wholly inside LO */
739  else
740  result_length = loSize - offset; /* adjust to end of LO */
741  }
742  else
743  result_length = 0; /* request is wholly outside LO */
744 
745  /*
746  * A result_length calculated from loSize may not fit in a size_t. Check
747  * that the size will satisfy this and subsequently-enforced size limits.
748  */
749  if (result_length > MaxAllocSize - VARHDRSZ)
750  ereport(ERROR,
751  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
752  errmsg("large object read request is too large")));
753 
754  result = (bytea *) palloc(VARHDRSZ + result_length);
755 
756  inv_seek(loDesc, offset, SEEK_SET);
757  total_read = inv_read(loDesc, VARDATA(result), result_length);
758  Assert(total_read == result_length);
759  SET_VARSIZE(result, result_length + VARHDRSZ);
760 
761  inv_close(loDesc);
762 
763  return result;
764 }
765 
766 /*
767  * Read entire LO
768  */
769 Datum
771 {
772  Oid loOid = PG_GETARG_OID(0);
773  bytea *result;
774 
775  result = lo_get_fragment_internal(loOid, 0, -1);
776 
777  PG_RETURN_BYTEA_P(result);
778 }
779 
780 /*
781  * Read range within LO
782  */
783 Datum
785 {
786  Oid loOid = PG_GETARG_OID(0);
787  int64 offset = PG_GETARG_INT64(1);
788  int32 nbytes = PG_GETARG_INT32(2);
789  bytea *result;
790 
791  if (nbytes < 0)
792  ereport(ERROR,
793  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
794  errmsg("requested length cannot be negative")));
795 
796  result = lo_get_fragment_internal(loOid, offset, nbytes);
797 
798  PG_RETURN_BYTEA_P(result);
799 }
800 
801 /*
802  * Create LO with initial contents given by a bytea argument
803  */
804 Datum
806 {
807  Oid loOid = PG_GETARG_OID(0);
809  LargeObjectDesc *loDesc;
810  int written PG_USED_FOR_ASSERTS_ONLY;
811 
812  CreateFSContext();
813 
814  loOid = inv_create(loOid);
815  loDesc = inv_open(loOid, INV_WRITE, fscxt);
816  written = inv_write(loDesc, VARDATA_ANY(str), VARSIZE_ANY_EXHDR(str));
817  Assert(written == VARSIZE_ANY_EXHDR(str));
818  inv_close(loDesc);
819 
820  PG_RETURN_OID(loOid);
821 }
822 
823 /*
824  * Update range within LO
825  */
826 Datum
828 {
829  Oid loOid = PG_GETARG_OID(0);
830  int64 offset = PG_GETARG_INT64(1);
832  LargeObjectDesc *loDesc;
833  int written PG_USED_FOR_ASSERTS_ONLY;
834 
835  CreateFSContext();
836 
837  loDesc = inv_open(loOid, INV_WRITE, fscxt);
838 
839  /* Permission check */
840  if (!lo_compat_privileges &&
842  GetUserId(),
843  ACL_UPDATE,
844  loDesc->snapshot) != ACLCHECK_OK)
845  ereport(ERROR,
846  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
847  errmsg("permission denied for large object %u",
848  loDesc->id)));
849 
850  inv_seek(loDesc, offset, SEEK_SET);
851  written = inv_write(loDesc, VARDATA_ANY(str), VARSIZE_ANY_EXHDR(str));
852  Assert(written == VARSIZE_ANY_EXHDR(str));
853  inv_close(loDesc);
854 
855  PG_RETURN_VOID();
856 }
Datum be_lo_get(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:770
static void deleteLOfd(int fd)
Definition: be-fsstubs.c:701
#define IFS_RDLOCK
Definition: large_object.h:48
#define PG_GETARG_INT32(n)
Definition: fmgr.h:234
int64 inv_seek(LargeObjectDesc *obj_desc, int64 offset, int whence)
Definition: inv_api.c:432
Datum be_lo_truncate(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:559
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:198
#define S_IRGRP
Definition: win32_port.h:283
Datum be_lo_tell64(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:292
#define VARDATA_ANY(PTR)
Definition: postgres.h:347
#define VARDATA(PTR)
Definition: postgres.h:303
void inv_truncate(LargeObjectDesc *obj_desc, int64 len)
Definition: inv_api.c:784
bool lo_compat_privileges
Definition: inv_api.c:57
#define BUFSIZE
Definition: be-fsstubs.c:57
bool pg_largeobject_ownercheck(Oid lobj_oid, Oid roleid)
Definition: aclchk.c:4737
Oid inv_create(Oid lobjId)
Definition: inv_api.c:211
Oid GetUserId(void)
Definition: miscinit.c:284
#define write(a, b, c)
Definition: win32.h:14
#define PG_RETURN_INT64(x)
Definition: fmgr.h:327
Datum be_lo_tell(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:269
Datum be_loread(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:352
#define VARHDRSZ
Definition: c.h:503
Datum be_lo_put(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:827
static Oid lo_import_internal(text *filename, Oid lobjOid)
Definition: be-fsstubs.c:412
#define S_IWOTH
Definition: win32_port.h:298
int OpenTransientFilePerm(const char *fileName, int fileFlags, mode_t fileMode)
Definition: fd.c:2401
void inv_close(LargeObjectDesc *obj_desc)
Definition: inv_api.c:339
#define PG_RETURN_INT32(x)
Definition: fmgr.h:314
Datum be_lo_lseek(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:194
#define S_IROTH
Definition: win32_port.h:295
int errcode(int sqlerrcode)
Definition: elog.c:575
#define MemSet(start, val, len)
Definition: c.h:863
#define CreateFSContext()
Definition: be-fsstubs.c:72
uint32 SubTransactionId
Definition: c.h:459
static void lo_truncate_internal(int32 fd, int64 len)
Definition: be-fsstubs.c:538
Datum be_lo_from_bytea(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:805
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:330
unsigned int Oid
Definition: postgres_ext.h:31
#define DEBUG4
Definition: elog.h:22
SubTransactionId subid
Definition: large_object.h:43
static int fd(const char *x, int i)
Definition: preproc-init.c:105
void text_to_cstring_buffer(const text *src, char *dst, size_t dst_len)
Definition: varlena.c:214
#define PG_BINARY
Definition: c.h:1035
Datum be_lo_get_fragment(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:784
#define IFS_WRLOCK
Definition: large_object.h:49
Datum be_lo_open(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:91
signed int int32
Definition: c.h:294
Datum be_lo_close(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:112
int64 inv_tell(LargeObjectDesc *obj_desc)
Definition: inv_api.c:481
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:273
#define INV_READ
Definition: libpq-fs.h:22
#define S_IWUSR
Definition: win32_port.h:274
#define ERROR
Definition: elog.h:43
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2392
Snapshot snapshot
Definition: large_object.h:42
#define MAXPGPATH
static bytea * lo_get_fragment_internal(Oid loOid, int64 offset, int32 nbytes)
Definition: be-fsstubs.c:714
int inv_drop(Oid lobjId)
Definition: inv_api.c:355
static char * buf
Definition: pg_test_fsync.c:67
int lo_read(int fd, char *buf, int len)
Definition: be-fsstubs.c:142
Datum be_lo_create(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:253
#define PG_GETARG_OID(n)
Definition: fmgr.h:240
int errcode_for_file_access(void)
Definition: elog.c:598
#define S_IWGRP
Definition: win32_port.h:286
#define ereport(elevel, rest)
Definition: elog.h:122
Datum be_lo_truncate64(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:569
int lo_write(int fd, const char *buf, int len)
Definition: be-fsstubs.c:170
Datum be_lo_import_with_oid(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:403
#define MaxAllocSize
Definition: memutils.h:40
int CloseTransientFile(int fd)
Definition: fd.c:2562
void AtEOSubXact_LargeObject(bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
Definition: be-fsstubs.c:624
Datum be_lo_lseek64(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:219
#define ACL_UPDATE
Definition: parsenodes.h:74
void close_lo_relation(bool isCommit)
Definition: inv_api.c:98
uintptr_t Datum
Definition: postgres.h:372
Datum be_lo_creat(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:237
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:728
#define InvalidOid
Definition: postgres_ext.h:36
#define PG_RETURN_VOID()
Definition: fmgr.h:309
#define PG_CATCH()
Definition: elog.h:293
Datum be_lo_unlink(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:308
#define Assert(condition)
Definition: c.h:680
#define PG_GETARG_BYTEA_PP(n)
Definition: fmgr.h:272
#define PG_RE_THROW()
Definition: elog.h:314
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:949
#define INV_WRITE
Definition: libpq-fs.h:21
#define S_IRUSR
Definition: win32_port.h:271
static int cookies_size
Definition: be-fsstubs.c:68
Datum be_lo_import(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:391
static char * filename
Definition: pg_dumpall.c:90
Datum be_lo_export(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:468
LargeObjectDesc * inv_open(Oid lobjId, int flags, MemoryContext mcxt)
Definition: inv_api.c:252
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:340
void * palloc(Size size)
Definition: mcxt.c:835
int errmsg(const char *fmt,...)
Definition: elog.c:797
static MemoryContext fscxt
Definition: be-fsstubs.c:70
int i
AclResult pg_largeobject_aclcheck_snapshot(Oid lobj_oid, Oid roleid, AclMode mode, Snapshot snapshot)
Definition: aclchk.c:4528
Definition: c.h:497
#define PG_FUNCTION_ARGS
Definition: fmgr.h:158
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:328
#define elog
Definition: elog.h:219
static LargeObjectDesc ** cookies
Definition: be-fsstubs.c:67
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:122
#define PG_TRY()
Definition: elog.h:284
void AtEOXact_LargeObject(bool isCommit)
Definition: be-fsstubs.c:583
Datum be_lowrite(PG_FUNCTION_ARGS)
Definition: be-fsstubs.c:370
static int newLOfd(LargeObjectDesc *lobjCookie)
Definition: be-fsstubs.c:658
#define PG_GETARG_INT64(n)
Definition: fmgr.h:247
int inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
Definition: inv_api.c:494
#define PG_RETURN_OID(x)
Definition: fmgr.h:320
#define PG_END_TRY()
Definition: elog.h:300
#define read(a, b, c)
Definition: win32.h:13
int inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes)
Definition: inv_api.c:587