Datum lo_close(PG_FUNCTION_ARGS) { int32 fd = PG_GETARG_INT32(0); #ifdef PGXC ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Postgres-XC does not support large object yet"), errdetail("The feature is not currently supported"))); #endif if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("invalid large-object descriptor: %d", fd))); #if FSDB elog(DEBUG4, "lo_close(%d)", fd); #endif inv_close(cookies[fd]); deleteLOfd(fd); PG_RETURN_INT32(0); }
/* * AtEOSubXact_LargeObject * Take care of large objects at subtransaction commit/abort * * Reassign LOs created/opened during a committing subtransaction * to the parent subtransaction. On abort, just close them. */ void AtEOSubXact_LargeObject(bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid) { int i; if (fscxt == NULL) /* no LO operations in this xact */ return; for (i = 0; i < cookies_size; i++) { LargeObjectDesc *lo = cookies[i]; if (lo != NULL && lo->subid == mySubid) { if (isCommit) lo->subid = parentSubid; else { /* * Make sure we do not call inv_close twice if it errors out * for some reason. Better a leak than a crash. */ deleteLOfd(i); inv_close(lo); } } } }
/* * AtEOXact_LargeObject - * prepares large objects for transaction commit */ void AtEOXact_LargeObject(bool isCommit) { int i; if (fscxt == NULL) return; /* no LO operations in this xact */ /* * Close LO fds and clear cookies array so that LO fds are no longer good. * On abort we skip the close step. */ for (i = 0; i < cookies_size; i++) { if (cookies[i] != NULL) { if (isCommit) inv_close(cookies[i]); deleteLOfd(i); } } /* Needn't actually pfree since we're about to zap context */ cookies = NULL; cookies_size = 0; /* Release the LO memory context to prevent permanent memory leaks. */ MemoryContextDelete(fscxt); fscxt = NULL; /* Give inv_api.c a chance to clean up, too */ close_lo_relation(isCommit); }
/* * Update range within LO */ Datum be_lo_put(PG_FUNCTION_ARGS) { Oid loOid = PG_GETARG_OID(0); int64 offset = PG_GETARG_INT64(1); bytea *str = PG_GETARG_BYTEA_PP(2); LargeObjectDesc *loDesc; int written PG_USED_FOR_ASSERTS_ONLY; CreateFSContext(); loDesc = inv_open(loOid, INV_WRITE, fscxt); /* Permission check */ if (!lo_compat_privileges && pg_largeobject_aclcheck_snapshot(loDesc->id, GetUserId(), ACL_UPDATE, loDesc->snapshot) != ACLCHECK_OK) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied for large object %u", loDesc->id))); inv_seek(loDesc, offset, SEEK_SET); written = inv_write(loDesc, VARDATA_ANY(str), VARSIZE_ANY_EXHDR(str)); Assert(written == VARSIZE_ANY_EXHDR(str)); inv_close(loDesc); PG_RETURN_VOID(); }
Datum lo_unlink(PG_FUNCTION_ARGS) { Oid lobjId = PG_GETARG_OID(0); /* Must be owner of the largeobject */ if (!lo_compat_privileges && !pg_largeobject_ownercheck(lobjId, GetUserId())) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be owner of large object %u", lobjId))); /* * If there are any open LO FDs referencing that ID, close 'em. */ if (fscxt != NULL) { int i; for (i = 0; i < cookies_size; i++) { if (cookies[i] != NULL && cookies[i]->id == lobjId) { inv_close(cookies[i]); deleteLOfd(i); } } } /* * inv_drop does not create a need for end-of-transaction cleanup and * hence we don't need to have created fscxt. */ PG_RETURN_INT32(inv_drop(lobjId)); }
Datum lo_unlink(PG_FUNCTION_ARGS) { Oid lobjId = PG_GETARG_OID(0); /* * If there are any open LO FDs referencing that ID, close 'em. */ if (fscxt != NULL) { int i; for (i = 0; i < cookies_size; i++) { if (cookies[i] != NULL && cookies[i]->id == lobjId) { inv_close(cookies[i]); deleteLOfd(i); } } } /* * inv_drop does not create a need for end-of-transaction cleanup and * hence we don't need to have created fscxt. */ PG_RETURN_INT32(inv_drop(lobjId)); }
static Oid lo_import_internal(text *filename, Oid lobjOid) { File fd; int nbytes, tmp; char buf[BUFSIZE]; char fnamebuf[MAXPGPATH]; LargeObjectDesc *lobj; Oid oid; #ifndef ALLOW_DANGEROUS_LO_FUNCTIONS if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to use server-side lo_import()"), errhint("Anyone can use the client-side lo_import() provided by libpq."))); #endif CreateFSContext(); /* * open the file to be read in */ text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf)); fd = PathNameOpenFile(fnamebuf, O_RDONLY | PG_BINARY, S_IRWXU); if (fd < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not open server file \"%s\": %m", fnamebuf))); /* * create an inversion object */ oid = inv_create(lobjOid); /* * read in from the filesystem and write to the inversion object */ lobj = inv_open(oid, INV_WRITE, fscxt); while ((nbytes = FileRead(fd, buf, BUFSIZE)) > 0) { tmp = inv_write(lobj, buf, nbytes); Assert(tmp == nbytes); } if (nbytes < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not read server file \"%s\": %m", fnamebuf))); inv_close(lobj); FileClose(fd); return oid; }
/* * Read [offset, offset+nbytes) within LO; when nbytes is -1, read to end. */ static bytea * lo_get_fragment_internal(Oid loOid, int64 offset, int32 nbytes) { LargeObjectDesc *loDesc; int64 loSize; int64 result_length; int total_read PG_USED_FOR_ASSERTS_ONLY; bytea *result = NULL; /* * We don't actually need to store into fscxt, but create it anyway to * ensure that AtEOXact_LargeObject knows there is state to clean up */ CreateFSContext(); loDesc = inv_open(loOid, INV_READ, fscxt); /* * Compute number of bytes we'll actually read, accommodating nbytes == -1 * and reads beyond the end of the LO. */ loSize = inv_seek(loDesc, 0, SEEK_END); if (loSize > offset) { if (nbytes >= 0 && nbytes <= loSize - offset) result_length = nbytes; /* request is wholly inside LO */ else result_length = loSize - offset; /* adjust to end of LO */ } else result_length = 0; /* request is wholly outside LO */ /* * A result_length calculated from loSize may not fit in a size_t. Check * that the size will satisfy this and subsequently-enforced size limits. */ if (result_length > MaxAllocSize - VARHDRSZ) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("large object read request is too large"))); result = (bytea *) palloc(VARHDRSZ + result_length); inv_seek(loDesc, offset, SEEK_SET); total_read = inv_read(loDesc, VARDATA(result), result_length); Assert(total_read == result_length); SET_VARSIZE(result, result_length + VARHDRSZ); inv_close(loDesc); return result; }
static Oid lo_import_internal(text *filename, Oid lobjOid) { int fd; int nbytes, tmp PG_USED_FOR_ASSERTS_ONLY; char buf[BUFSIZE]; char fnamebuf[MAXPGPATH]; LargeObjectDesc *lobj; Oid oid; CreateFSContext(); /* * open the file to be read in */ text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf)); fd = OpenTransientFile(fnamebuf, O_RDONLY | PG_BINARY); if (fd < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not open server file \"%s\": %m", fnamebuf))); /* * create an inversion object */ oid = inv_create(lobjOid); /* * read in from the filesystem and write to the inversion object */ lobj = inv_open(oid, INV_WRITE, fscxt); while ((nbytes = read(fd, buf, BUFSIZE)) > 0) { tmp = inv_write(lobj, buf, nbytes); Assert(tmp == nbytes); } if (nbytes < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not read server file \"%s\": %m", fnamebuf))); inv_close(lobj); CloseTransientFile(fd); return oid; }
Datum lo_unlink(PG_FUNCTION_ARGS) { Oid lobjId = PG_GETARG_OID(0); #ifdef PGXC #ifdef XCP ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Postgres-XL does not yet support large objects"), errdetail("The feature is not currently supported"))); #else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Postgres-XC does not support large object yet"), errdetail("The feature is not currently supported"))); #endif #endif /* Must be owner of the largeobject */ if (!lo_compat_privileges && !pg_largeobject_ownercheck(lobjId, GetUserId())) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be owner of large object %u", lobjId))); /* * If there are any open LO FDs referencing that ID, close 'em. */ if (fscxt != NULL) { int i; for (i = 0; i < cookies_size; i++) { if (cookies[i] != NULL && cookies[i]->id == lobjId) { inv_close(cookies[i]); deleteLOfd(i); } } } /* * inv_drop does not create a need for end-of-transaction cleanup and * hence we don't need to have created fscxt. */ PG_RETURN_INT32(inv_drop(lobjId)); }
intgen_t query_test( int level ) { int i; inv_idbtoken_t tok; time_t *tm; inv_session_t *ses; invt_pr_ctx_t prctx; if (level == -2) { printf("mount pt %s\n",sesfile); tok = inv_open( INV_BY_MOUNTPT, INV_SEARCH_ONLY, sesfile ); if (! tok ) return -1; idx_DEBUG_print (tok->d_invindex_fd); return 1; } for (i = 7; i<8; i++) { printf("\n\n\n----------------------------------\n" "$ Searching fs %s\n", mnt_str[7-i] ); tok = inv_open( INV_BY_MOUNTPT, INV_SEARCH_ONLY, mnt_str[7-i] ); if (! tok ) return -1; prctx.index = i; if (level == -1 ) invmgr_inv_print( tok->d_invindex_fd, &prctx ); else { if (inv_lasttime_level_lessthan( tok, level, &tm ) && tm) { printf("\n\nTIME %s %ld\n", ctime(tm), (long) *tm ); free (tm); } if (inv_lastsession_level_lessthan( tok, level, &ses ) && ses) { DEBUG_sessionprint( ses, 99, &prctx); free ( ses->s_streams ); free ( ses ); } if (inv_lastsession_level_equalto( tok, level, &ses ) && ses) { printf("Gotcha\n"); DEBUG_sessionprint( ses, 99, &prctx ); free ( ses->s_streams ); free ( ses ); } } inv_close( tok ); } return 1; }
/* * Create LO with initial contents given by a bytea argument */ Datum lo_from_bytea(PG_FUNCTION_ARGS) { Oid loOid = PG_GETARG_OID(0); bytea *str = PG_GETARG_BYTEA_PP(1); LargeObjectDesc *loDesc; int written PG_USED_FOR_ASSERTS_ONLY; CreateFSContext(); loOid = inv_create(loOid); loDesc = inv_open(loOid, INV_WRITE, fscxt); written = inv_write(loDesc, VARDATA_ANY(str), VARSIZE_ANY_EXHDR(str)); Assert(written == VARSIZE_ANY_EXHDR(str)); inv_close(loDesc); PG_RETURN_OID(loOid); }
/* * Class: org_postgresql_pljava_internal_LargeObject * Method: _close * Signature: (J)V */ JNIEXPORT void JNICALL Java_org_postgresql_pljava_internal_LargeObject__1close(JNIEnv* env, jclass cls, jlong _this) { LargeObjectDesc* self = Invocation_getWrappedPointer(_this); if(self != 0) { BEGIN_NATIVE PG_TRY(); { inv_close(self); } PG_CATCH(); { Exception_throw_ERROR("inv_close"); } PG_END_TRY(); END_NATIVE }
/* * Update range within LO */ Datum lo_put(PG_FUNCTION_ARGS) { Oid loOid = PG_GETARG_OID(0); int64 offset = PG_GETARG_INT64(1); bytea *str = PG_GETARG_BYTEA_PP(2); LargeObjectDesc *loDesc; int written PG_USED_FOR_ASSERTS_ONLY; CreateFSContext(); loDesc = inv_open(loOid, INV_WRITE, fscxt); inv_seek(loDesc, offset, SEEK_SET); written = inv_write(loDesc, VARDATA_ANY(str), VARSIZE_ANY_EXHDR(str)); Assert(written == VARSIZE_ANY_EXHDR(str)); inv_close(loDesc); PG_RETURN_VOID(); }
Datum lo_close(PG_FUNCTION_ARGS) { int32 fd = PG_GETARG_INT32(0); if (fd < 0 || fd >= cookies_size || cookies[fd] == NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("invalid large-object descriptor: %d", fd))); #if FSDB elog(DEBUG4, "lo_close(%d)", fd); #endif inv_close(cookies[fd]); deleteLOfd(fd); PG_RETURN_INT32(0); }
intgen_t write_test( int nsess, int nstreams, int nmedia, int dumplevel ) { int i,j,k,m,fd; unsigned int stat; uuid_t *fsidp; inv_idbtoken_t tok1; inv_sestoken_t tok2; inv_stmtoken_t tok3; char *dev, *mnt; char label[120]; uuid_t fsidarr[8], labelid; uuid_t sesidarr[8]; char *str; char strbuf[128]; void *bufp; size_t sz; int rfd; #ifdef FIRSTTIME printf("first time!\n"); for (i=0; i<8; i++) { uuid_create( &fsidarr[i], &stat ); ASSERT ( stat == uuid_s_ok ); uuid_create( &sesidarr[i], &stat ); ASSERT ( stat == uuid_s_ok ); } fd = open( "uuids", O_RDWR | O_CREAT ); PUT_REC(fd, (void *)fsidarr, sizeof (uuid_t) * 8, 0L ); PUT_REC(fd, (void *)sesidarr, sizeof (uuid_t) * 8, sizeof (uuid_t) * 8 ); close(fd); #endif fd = open("uuids", O_RDONLY ); GET_REC( fd, fsidarr, sizeof (uuid_t) * 8, 0L ); GET_REC( fd, sesidarr, sizeof (uuid_t) * 8, sizeof (uuid_t) * 8 ); close(fd); #ifdef RECONS rfd = open( sesfile, O_RDWR | O_CREAT ); fchmod( rfd, INV_PERMS ); #endif for ( i = 0; i < nsess; i++ ) { j = i % 8; /*mnt = mnt_str[j]; dev = dev_str[7-j];*/ mnt = mnt_str[0]; dev = dev_str[7]; fsidp = &fsidarr[0]; /* j */ tok1 = inv_open( INV_BY_UUID, INV_SEARCH_N_MOD, fsidp ); ASSERT (tok1 != INV_TOKEN_NULL ); uuid_create( &labelid, &stat ); uuid_to_string( &labelid, &str, &stat ); strncpy( strbuf, str, 8 ); free (str); strbuf[8] = '\0'; sprintf(label,"%s_%s (%d)\0","SESSION_LABEL", strbuf, i ); tok2 = inv_writesession_open(tok1, fsidp, &labelid, label, (bool_t)i%2, (bool_t)i%2, dumplevel, nstreams, time(NULL), mnt, dev ); ASSERT (tok2 != INV_TOKEN_NULL ); for (m = 0; m<nstreams; m++) { tok3 = inv_stream_open( tok2,"/dev/rmt"); ASSERT (tok3 != INV_TOKEN_NULL ); for (k = 0; k<nmedia; k++ ) CREAT_mfiles( tok3, &labelid, k*100, k*100 + 99 ); inv_stream_close( tok3, BOOL_TRUE ); } #ifdef RECONS if (inv_get_sessioninfo( tok2, &bufp, &sz ) == BOOL_TRUE ) { put_invtrecord( rfd, fsidp, sizeof( uuid_t ), 0, SEEK_END, BOOL_FALSE ); put_invtrecord( rfd, &sz, sizeof( size_t ), 0, SEEK_END, BOOL_FALSE); put_invtrecord( rfd, bufp, sz, 0, SEEK_END, BOOL_FALSE ); } #endif #ifdef NOTDEF if (inv_get_sessioninfo( tok2, &bufp, &sz ) == BOOL_TRUE ) inv_put_sessioninfo( fsidp, bufp, sz ); #endif inv_writesession_close( tok2 ); inv_close( tok1 ); } #ifdef RECONS close( rfd ); #endif return 1; }
/* * lo_export - * exports an (inversion) large object. */ Datum lo_export(PG_FUNCTION_ARGS) { Oid lobjId = PG_GETARG_OID(0); text *filename = PG_GETARG_TEXT_PP(1); File fd; int nbytes, tmp; char buf[BUFSIZE]; char fnamebuf[MAXPGPATH]; LargeObjectDesc *lobj; mode_t oumask; #ifndef ALLOW_DANGEROUS_LO_FUNCTIONS if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to use server-side lo_export()"), errhint("Anyone can use the client-side lo_export() provided by libpq."))); #endif CreateFSContext(); /* * open the inversion object (no need to test for failure) */ lobj = inv_open(lobjId, INV_READ, fscxt); /* * open the file to be written to * * Note: we reduce backend's normal 077 umask to the slightly friendlier * 022. This code used to drop it all the way to 0, but creating * world-writable export files doesn't seem wise. */ text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf)); oumask = umask(S_IWGRP | S_IWOTH); fd = PathNameOpenFile(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); umask(oumask); if (fd < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create server file \"%s\": %m", fnamebuf))); /* * read in from the inversion file and write to the filesystem */ while ((nbytes = inv_read(lobj, buf, BUFSIZE)) > 0) { tmp = FileWrite(fd, buf, nbytes); if (tmp != nbytes) ereport(ERROR, (errcode_for_file_access(), errmsg("could not write server file \"%s\": %m", fnamebuf))); } FileClose(fd); inv_close(lobj); PG_RETURN_INT32(1); }
/* * lo_export - * exports an (inversion) large object. */ Datum be_lo_export(PG_FUNCTION_ARGS) { Oid lobjId = PG_GETARG_OID(0); text *filename = PG_GETARG_TEXT_PP(1); int fd; int nbytes, tmp; char buf[BUFSIZE]; char fnamebuf[MAXPGPATH]; LargeObjectDesc *lobj; mode_t oumask; CreateFSContext(); /* * open the inversion object (no need to test for failure) */ lobj = inv_open(lobjId, INV_READ, fscxt); /* * open the file to be written to * * Note: we reduce backend's normal 077 umask to the slightly friendlier * 022. This code used to drop it all the way to 0, but creating * world-writable export files doesn't seem wise. */ text_to_cstring_buffer(filename, fnamebuf, sizeof(fnamebuf)); oumask = umask(S_IWGRP | S_IWOTH); PG_TRY(); { fd = OpenTransientFilePerm(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); } PG_CATCH(); { umask(oumask); PG_RE_THROW(); } PG_END_TRY(); umask(oumask); if (fd < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not create server file \"%s\": %m", fnamebuf))); /* * read in from the inversion file and write to the filesystem */ while ((nbytes = inv_read(lobj, buf, BUFSIZE)) > 0) { tmp = write(fd, buf, nbytes); if (tmp != nbytes) ereport(ERROR, (errcode_for_file_access(), errmsg("could not write server file \"%s\": %m", fnamebuf))); } CloseTransientFile(fd); inv_close(lobj); PG_RETURN_INT32(1); }
/* * lo_import - * imports a file as an (inversion) large object. */ Datum lo_import(PG_FUNCTION_ARGS) { text *filename = PG_GETARG_TEXT_P(0); File fd; int nbytes, tmp; char buf[BUFSIZE]; char fnamebuf[MAXPGPATH]; LargeObjectDesc *lobj; Oid lobjOid; #ifndef ALLOW_DANGEROUS_LO_FUNCTIONS if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to use server-side lo_import()"), errhint("Anyone can use the client-side lo_import() provided by libpq."))); #endif CreateFSContext(); /* * open the file to be read in */ nbytes = VARSIZE(filename) - VARHDRSZ; if (nbytes >= MAXPGPATH) nbytes = MAXPGPATH - 1; memcpy(fnamebuf, VARDATA(filename), nbytes); fnamebuf[nbytes] = '\0'; fd = PathNameOpenFile(fnamebuf, O_RDONLY | PG_BINARY, 0666); if (fd < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not open server file \"%s\": %m", fnamebuf))); /* * create an inversion object */ lobjOid = inv_create(InvalidOid); /* * read in from the filesystem and write to the inversion object */ lobj = inv_open(lobjOid, INV_WRITE, fscxt); while ((nbytes = FileRead(fd, buf, BUFSIZE)) > 0) { tmp = inv_write(lobj, buf, nbytes); Assert(tmp == nbytes); } if (nbytes < 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not read server file \"%s\": %m", fnamebuf))); inv_close(lobj); FileClose(fd); PG_RETURN_OID(lobjOid); }