7
7
*
8
8
*
9
9
* IDENTIFICATION
10
- * $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.33 1999/05/25 16:08 :57 momjian Exp $
10
+ * $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.34 1999/05/31 22:53 :57 tgl Exp $
11
11
*
12
12
* NOTES
13
13
* This should be moved to a more appropriate place. It is here
14
14
* for lack of a better place.
15
15
*
16
16
* Builtin functions for open/close/read/write operations on large objects.
17
17
*
18
- * These functions operate in the current portal variable context, which
19
- * means the large object descriptors hang around between transactions and
20
- * are not deallocated until explicitly closed, or until the portal is
21
- * closed.
18
+ * These functions operate in a private GlobalMemoryContext, which means
19
+ * that large object descriptors hang around until we destroy the context.
20
+ * That happens in lo_commit(). It'd be possible to prolong the lifetime
21
+ * of the context so that LO FDs are good across transactions (for example,
22
+ * we could release the context only if we see that no FDs remain open).
23
+ * But we'd need additional state in order to do the right thing at the
24
+ * end of an aborted transaction. FDs opened during an aborted xact would
25
+ * still need to be closed, since they might not be pointing at valid
26
+ * relations at all. For now, we'll stick with the existing documented
27
+ * semantics of LO FDs: they're only good within a transaction.
28
+ *
22
29
*-------------------------------------------------------------------------
23
30
*/
24
31
37
44
#include <utils/memutils.h>
38
45
#include <lib/fstack.h>
39
46
#include <utils/mcxt.h>
47
+ #include <catalog/pg_shadow.h> /* for superuser() */
40
48
#include <storage/fd.h> /* for O_ */
41
49
#include <storage/large_object.h>
42
50
#include <libpq/be-fsstubs.h>
@@ -91,6 +99,11 @@ lo_open(Oid lobjId, int mode)
91
99
/* switch context back to orig. */
92
100
MemoryContextSwitchTo (currentContext );
93
101
102
+ #if FSDB
103
+ if (fd < 0 ) /* newLOfd couldn't find a slot */
104
+ elog (NOTICE , "Out of space for large object FDs" );
105
+ #endif
106
+
94
107
return fd ;
95
108
}
96
109
@@ -144,6 +157,8 @@ lo_read(int fd, char *buf, int len)
144
157
elog (ERROR , "lo_read: invalid large obj descriptor (%d)" , fd );
145
158
return -3 ;
146
159
}
160
+
161
+ Assert (fscxt != NULL );
147
162
currentContext = MemoryContextSwitchTo ((MemoryContext ) fscxt );
148
163
149
164
status = inv_read (cookies [fd ], buf , len );
@@ -168,6 +183,8 @@ lo_write(int fd, char *buf, int len)
168
183
elog (ERROR , "lo_write: invalid large obj descriptor (%d)" , fd );
169
184
return -3 ;
170
185
}
186
+
187
+ Assert (fscxt != NULL );
171
188
currentContext = MemoryContextSwitchTo ((MemoryContext ) fscxt );
172
189
173
190
status = inv_write (cookies [fd ], buf , len );
181
198
lo_lseek (int fd , int offset , int whence )
182
199
{
183
200
MemoryContext currentContext ;
184
- int ret ;
201
+ int status ;
185
202
186
203
if (fd < 0 || fd >= MAX_LOBJ_FDS )
187
204
{
@@ -194,13 +211,14 @@ lo_lseek(int fd, int offset, int whence)
194
211
return -3 ;
195
212
}
196
213
214
+ Assert (fscxt != NULL );
197
215
currentContext = MemoryContextSwitchTo ((MemoryContext ) fscxt );
198
216
199
- ret = inv_seek (cookies [fd ], offset , whence );
217
+ status = inv_seek (cookies [fd ], offset , whence );
200
218
201
219
MemoryContextSwitchTo (currentContext );
202
220
203
- return ret ;
221
+ return status ;
204
222
}
205
223
206
224
Oid
@@ -246,12 +264,26 @@ lo_tell(int fd)
246
264
elog (ERROR , "lo_tell: invalid large object descriptor (%d)" , fd );
247
265
return -3 ;
248
266
}
267
+
268
+ /*
269
+ * We assume we do not need to switch contexts for inv_tell.
270
+ * That is true for now, but is probably more than this module
271
+ * ought to assume...
272
+ */
249
273
return inv_tell (cookies [fd ]);
250
274
}
251
275
252
276
int
253
277
lo_unlink (Oid lobjId )
254
278
{
279
+ /*
280
+ * inv_destroy does not need a context switch, indeed it doesn't
281
+ * touch any LO-specific data structures at all. (Again, that's
282
+ * probably more than this module ought to be assuming.)
283
+ *
284
+ * XXX there ought to be some code to clean up any open LOs that
285
+ * reference the specified relation... as is, they remain "open".
286
+ */
255
287
return inv_destroy (lobjId );
256
288
}
257
289
@@ -297,24 +329,31 @@ lo_import(text *filename)
297
329
File fd ;
298
330
int nbytes ,
299
331
tmp ;
300
-
301
332
char buf [BUFSIZE ];
302
333
char fnamebuf [FNAME_BUFSIZE ];
303
334
LargeObjectDesc * lobj ;
304
335
Oid lobjOid ;
305
336
337
+ if (!superuser ())
338
+ elog (ERROR , "You must have Postgres superuser privilege to use "
339
+ "server-side lo_import().\n\tAnyone can use the "
340
+ "client-side lo_import() provided by libpq." );
341
+
306
342
/*
307
343
* open the file to be read in
308
344
*/
309
- StrNCpy (fnamebuf , VARDATA (filename ), VARSIZE (filename ) - VARHDRSZ + 1 );
345
+ nbytes = VARSIZE (filename ) - VARHDRSZ + 1 ;
346
+ if (nbytes > FNAME_BUFSIZE )
347
+ nbytes = FNAME_BUFSIZE ;
348
+ StrNCpy (fnamebuf , VARDATA (filename ), nbytes );
310
349
#ifndef __CYGWIN32__
311
350
fd = PathNameOpenFile (fnamebuf , O_RDONLY , 0666 );
312
351
#else
313
352
fd = PathNameOpenFile (fnamebuf , O_RDONLY | O_BINARY , 0666 );
314
353
#endif
315
354
if (fd < 0 )
316
355
{ /* error */
317
- elog (ERROR , "be_lo_import : can't open unix file \"%s\"\n " ,
356
+ elog (ERROR , "lo_import : can't open unix file \"%s\": %m " ,
318
357
fnamebuf );
319
358
}
320
359
@@ -341,10 +380,8 @@ lo_import(text *filename)
341
380
{
342
381
tmp = inv_write (lobj , buf , nbytes );
343
382
if (tmp < nbytes )
344
- {
345
383
elog (ERROR , "lo_import: error while reading \"%s\"" ,
346
384
fnamebuf );
347
- }
348
385
}
349
386
350
387
FileClose (fd );
@@ -363,12 +400,16 @@ lo_export(Oid lobjId, text *filename)
363
400
File fd ;
364
401
int nbytes ,
365
402
tmp ;
366
-
367
403
char buf [BUFSIZE ];
368
404
char fnamebuf [FNAME_BUFSIZE ];
369
405
LargeObjectDesc * lobj ;
370
406
mode_t oumask ;
371
407
408
+ if (!superuser ())
409
+ elog (ERROR , "You must have Postgres superuser privilege to use "
410
+ "server-side lo_export().\n\tAnyone can use the "
411
+ "client-side lo_export() provided by libpq." );
412
+
372
413
/*
373
414
* open the inversion "object"
374
415
*/
@@ -378,9 +419,16 @@ lo_export(Oid lobjId, text *filename)
378
419
379
420
/*
380
421
* open the file to be written to
422
+ *
423
+ * Note: we reduce backend's normal 077 umask to the slightly
424
+ * friendlier 022. This code used to drop it all the way to 0,
425
+ * but creating world-writable export files doesn't seem wise.
381
426
*/
382
- StrNCpy (fnamebuf , VARDATA (filename ), VARSIZE (filename ) - VARHDRSZ + 1 );
383
- oumask = umask ((mode_t ) 0 );
427
+ nbytes = VARSIZE (filename ) - VARHDRSZ + 1 ;
428
+ if (nbytes > FNAME_BUFSIZE )
429
+ nbytes = FNAME_BUFSIZE ;
430
+ StrNCpy (fnamebuf , VARDATA (filename ), nbytes );
431
+ oumask = umask ((mode_t ) 0022 );
384
432
#ifndef __CYGWIN32__
385
433
fd = PathNameOpenFile (fnamebuf , O_CREAT | O_WRONLY | O_TRUNC , 0666 );
386
434
#else
@@ -389,7 +437,7 @@ lo_export(Oid lobjId, text *filename)
389
437
umask (oumask );
390
438
if (fd < 0 )
391
439
{ /* error */
392
- elog (ERROR , "lo_export: can't open unix file \"%s\"" ,
440
+ elog (ERROR , "lo_export: can't open unix file \"%s\": %m " ,
393
441
fnamebuf );
394
442
}
395
443
@@ -400,10 +448,8 @@ lo_export(Oid lobjId, text *filename)
400
448
{
401
449
tmp = FileWrite (fd , buf , nbytes );
402
450
if (tmp < nbytes )
403
- {
404
451
elog (ERROR , "lo_export: error while writing \"%s\"" ,
405
452
fnamebuf );
406
- }
407
453
}
408
454
409
455
inv_close (lobj );
@@ -417,24 +463,34 @@ lo_export(Oid lobjId, text *filename)
417
463
* prepares large objects for transaction commit [PA, 7/17/98]
418
464
*/
419
465
void
420
- _lo_commit ( void )
466
+ lo_commit ( bool isCommit )
421
467
{
422
468
int i ;
423
469
MemoryContext currentContext ;
424
470
425
471
if (fscxt == NULL )
426
- return ;
472
+ return ; /* no LO operations in this xact */
427
473
428
474
currentContext = MemoryContextSwitchTo ((MemoryContext ) fscxt );
429
475
476
+ /* Clean out still-open index scans (not necessary if aborting)
477
+ * and clear cookies array so that LO fds are no longer good.
478
+ */
430
479
for (i = 0 ; i < MAX_LOBJ_FDS ; i ++ )
431
480
{
432
481
if (cookies [i ] != NULL )
433
- inv_cleanindex (cookies [i ]);
482
+ {
483
+ if (isCommit )
484
+ inv_cleanindex (cookies [i ]);
485
+ cookies [i ] = NULL ;
486
+ }
434
487
}
435
488
436
489
MemoryContextSwitchTo (currentContext );
437
490
491
+ /* Release the LO memory context to prevent permanent memory leaks. */
492
+ GlobalMemoryDestroy (fscxt );
493
+ fscxt = NULL ;
438
494
}
439
495
440
496
0 commit comments