Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * fe-lobj.c
4 : * Front-end large object interface
5 : *
6 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/interfaces/libpq/fe-lobj.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 :
16 : #ifdef WIN32
17 : /*
18 : * As unlink/rename are #define'd in port.h (via postgres_fe.h), io.h
19 : * must be included first on MS C. Might as well do it for all WIN32's
20 : * here.
21 : */
22 : #include <io.h>
23 : #endif
24 :
25 : #include "postgres_fe.h"
26 :
27 : #ifdef WIN32
28 : #include "win32.h"
29 : #else
30 : #include <unistd.h>
31 : #endif
32 :
33 : #include <fcntl.h>
34 : #include <limits.h>
35 : #include <sys/stat.h>
36 :
37 : #include "libpq-fe.h"
38 : #include "libpq-int.h"
39 : #include "libpq/libpq-fs.h" /* must come after sys/stat.h */
40 : #include "port/pg_bswap.h"
41 :
42 : #define LO_BUFSIZE 8192
43 :
44 : static int lo_initialize(PGconn *conn);
45 : static Oid lo_import_internal(PGconn *conn, const char *filename, Oid oid);
46 : static pg_int64 lo_hton64(pg_int64 host64);
47 : static pg_int64 lo_ntoh64(pg_int64 net64);
48 :
49 : /*
50 : * lo_open
51 : * opens an existing large object
52 : *
53 : * returns the file descriptor for use in later lo_* calls
54 : * return -1 upon failure.
55 : */
56 : int
9344 bruce 57 CBC 90 : lo_open(PGconn *conn, Oid lobjId, int mode)
58 : {
59 : int fd;
60 : int result_len;
61 : PQArgBlock argv[2];
62 : PGresult *res;
63 :
818 tgl 64 90 : if (lo_initialize(conn) < 0)
818 tgl 65 UBC 0 : return -1;
66 :
9345 bruce 67 CBC 90 : argv[0].isint = 1;
68 90 : argv[0].len = 4;
69 90 : argv[0].u.integer = lobjId;
70 :
71 90 : argv[1].isint = 1;
72 90 : argv[1].len = 4;
73 90 : argv[1].u.integer = mode;
74 :
75 90 : res = PQfn(conn, conn->lobjfuncs->fn_lo_open, &fd, &result_len, 1, argv, 2);
76 90 : if (PQresultStatus(res) == PGRES_COMMAND_OK)
77 : {
78 90 : PQclear(res);
79 90 : return fd;
80 : }
81 : else
82 : {
8956 tgl 83 UBC 0 : PQclear(res);
9345 bruce 84 0 : return -1;
85 : }
86 : }
87 :
88 : /*
89 : * lo_close
90 : * closes an existing large object
91 : *
92 : * returns 0 upon success
93 : * returns -1 upon failure.
94 : */
95 : int
9344 bruce 96 CBC 90 : lo_close(PGconn *conn, int fd)
97 : {
98 : PQArgBlock argv[1];
99 : PGresult *res;
100 : int retval;
101 : int result_len;
102 :
818 tgl 103 90 : if (lo_initialize(conn) < 0)
818 tgl 104 UBC 0 : return -1;
105 :
9345 bruce 106 CBC 90 : argv[0].isint = 1;
107 90 : argv[0].len = 4;
108 90 : argv[0].u.integer = fd;
109 90 : res = PQfn(conn, conn->lobjfuncs->fn_lo_close,
110 : &retval, &result_len, 1, argv, 1);
111 90 : if (PQresultStatus(res) == PGRES_COMMAND_OK)
112 : {
113 90 : PQclear(res);
114 90 : return retval;
115 : }
116 : else
117 : {
8956 tgl 118 UBC 0 : PQclear(res);
9345 bruce 119 0 : return -1;
120 : }
121 : }
122 :
123 : /*
124 : * lo_truncate
125 : * truncates an existing large object to the given size
126 : *
127 : * returns 0 upon success
128 : * returns -1 upon failure
129 : */
130 : int
5881 131 0 : lo_truncate(PGconn *conn, int fd, size_t len)
132 : {
133 : PQArgBlock argv[2];
134 : PGresult *res;
135 : int retval;
136 : int result_len;
137 :
818 tgl 138 0 : if (lo_initialize(conn) < 0)
139 0 : return -1;
140 :
141 : /* Must check this on-the-fly because it's not there pre-8.3 */
5881 bruce 142 0 : if (conn->lobjfuncs->fn_lo_truncate == 0)
143 : {
145 peter 144 UNC 0 : libpq_append_conn_error(conn, "cannot determine OID of function %s",
818 tgl 145 EUB : "lo_truncate");
5881 bruce 146 UIC 0 : return -1;
147 : }
148 :
149 : /*
150 : * Long ago, somebody thought it'd be a good idea to declare this function
151 : * as taking size_t ... but the underlying backend function only accepts a
152 : * signed int32 length. So throw error if the given value overflows
153 : * int32. (A possible alternative is to automatically redirect the call
154 : * to lo_truncate64; but if the caller wanted to rely on that backend
155 : * function being available, he could have called lo_truncate64 for
156 : * himself.)
3835 tgl 157 EUB : */
3835 tgl 158 UIC 0 : if (len > (size_t) INT_MAX)
3835 tgl 159 EUB : {
145 peter 160 UNC 0 : libpq_append_conn_error(conn, "argument of lo_truncate exceeds integer range");
3835 tgl 161 UIC 0 : return -1;
3835 tgl 162 EUB : }
163 :
5881 bruce 164 UBC 0 : argv[0].isint = 1;
5881 bruce 165 UIC 0 : argv[0].len = 4;
5881 bruce 166 UBC 0 : argv[0].u.integer = fd;
5624 bruce 167 EUB :
5881 bruce 168 UBC 0 : argv[1].isint = 1;
5881 bruce 169 UIC 0 : argv[1].len = 4;
3835 tgl 170 UBC 0 : argv[1].u.integer = (int) len;
171 :
5881 bruce 172 UIC 0 : res = PQfn(conn, conn->lobjfuncs->fn_lo_truncate,
5881 bruce 173 EUB : &retval, &result_len, 1, argv, 2);
174 :
5881 bruce 175 UBC 0 : if (PQresultStatus(res) == PGRES_COMMAND_OK)
5881 bruce 176 EUB : {
5881 bruce 177 UIC 0 : PQclear(res);
178 0 : return retval;
179 : }
5881 bruce 180 EUB : else
181 : {
5881 bruce 182 UIC 0 : PQclear(res);
183 0 : return -1;
184 : }
185 : }
186 :
187 : /*
188 : * lo_truncate64
189 : * truncates an existing large object to the given size
190 : *
191 : * returns 0 upon success
192 : * returns -1 upon failure
3836 ishii 193 EUB : */
194 : int
3836 ishii 195 UIC 0 : lo_truncate64(PGconn *conn, int fd, pg_int64 len)
196 : {
197 : PQArgBlock argv[2];
198 : PGresult *res;
199 : int retval;
3836 ishii 200 EUB : int result_len;
201 :
818 tgl 202 UIC 0 : if (lo_initialize(conn) < 0)
818 tgl 203 UBC 0 : return -1;
204 :
3836 ishii 205 0 : if (conn->lobjfuncs->fn_lo_truncate64 == 0)
206 : {
145 peter 207 UNC 0 : libpq_append_conn_error(conn, "cannot determine OID of function %s",
208 : "lo_truncate64");
3836 ishii 209 UBC 0 : return -1;
3836 ishii 210 EUB : }
211 :
3836 ishii 212 UIC 0 : argv[0].isint = 1;
3836 ishii 213 UBC 0 : argv[0].len = 4;
214 0 : argv[0].u.integer = fd;
3836 ishii 215 EUB :
3836 ishii 216 UBC 0 : len = lo_hton64(len);
3836 ishii 217 UIC 0 : argv[1].isint = 0;
3836 ishii 218 UBC 0 : argv[1].len = 8;
3836 ishii 219 UIC 0 : argv[1].u.ptr = (int *) &len;
220 :
3836 ishii 221 UBC 0 : res = PQfn(conn, conn->lobjfuncs->fn_lo_truncate64,
222 : &retval, &result_len, 1, argv, 2);
3836 ishii 223 EUB :
3836 ishii 224 UBC 0 : if (PQresultStatus(res) == PGRES_COMMAND_OK)
225 : {
3836 ishii 226 UIC 0 : PQclear(res);
227 0 : return retval;
3836 ishii 228 EUB : }
229 : else
230 : {
3836 ishii 231 UIC 0 : PQclear(res);
232 0 : return -1;
233 : }
234 : }
235 :
236 : /*
237 : * lo_read
238 : * read len bytes of the large object into buf
239 : *
240 : * returns the number of bytes read, or -1 on failure.
241 : * the CALLER must have allocated enough space to hold the result returned
9770 scrappy 242 ECB : */
243 :
244 : int
8550 bruce 245 GIC 371 : lo_read(PGconn *conn, int fd, char *buf, size_t len)
246 : {
247 : PQArgBlock argv[2];
9344 bruce 248 ECB : PGresult *res;
9344 bruce 249 EUB : int result_len;
250 :
818 tgl 251 GIC 371 : if (lo_initialize(conn) < 0)
818 tgl 252 UIC 0 : return -1;
253 :
254 : /*
255 : * Long ago, somebody thought it'd be a good idea to declare this function
256 : * as taking size_t ... but the underlying backend function only accepts a
3835 tgl 257 ECB : * signed int32 length. So throw error if the given value overflows
258 : * int32.
3835 tgl 259 EUB : */
3835 tgl 260 GBC 371 : if (len > (size_t) INT_MAX)
261 : {
145 peter 262 UNC 0 : libpq_append_conn_error(conn, "argument of lo_read exceeds integer range");
3835 tgl 263 LBC 0 : return -1;
3835 tgl 264 ECB : }
265 :
9345 bruce 266 CBC 371 : argv[0].isint = 1;
267 371 : argv[0].len = 4;
268 371 : argv[0].u.integer = fd;
269 :
270 371 : argv[1].isint = 1;
9345 bruce 271 GIC 371 : argv[1].len = 4;
3835 tgl 272 CBC 371 : argv[1].u.integer = (int) len;
273 :
9345 bruce 274 371 : res = PQfn(conn, conn->lobjfuncs->fn_lo_read,
2954 tgl 275 ECB : (void *) buf, &result_len, 0, argv, 2);
9345 bruce 276 GIC 371 : if (PQresultStatus(res) == PGRES_COMMAND_OK)
277 : {
278 371 : PQclear(res);
9345 bruce 279 GBC 371 : return result_len;
9345 bruce 280 EUB : }
281 : else
282 : {
8956 tgl 283 UIC 0 : PQclear(res);
9345 bruce 284 0 : return -1;
285 : }
286 : }
287 :
288 : /*
289 : * lo_write
290 : * write len bytes of buf into the large object fd
9770 scrappy 291 ECB : *
292 : * returns the number of bytes written, or -1 on failure.
293 : */
294 : int
6058 bruce 295 GIC 493 : lo_write(PGconn *conn, int fd, const char *buf, size_t len)
296 : {
297 : PQArgBlock argv[2];
9344 bruce 298 ECB : PGresult *res;
9344 bruce 299 EUB : int result_len;
300 : int retval;
301 :
818 tgl 302 GIC 493 : if (lo_initialize(conn) < 0)
818 tgl 303 UIC 0 : return -1;
304 :
305 : /*
306 : * Long ago, somebody thought it'd be a good idea to declare this function
3835 tgl 307 ECB : * as taking size_t ... but the underlying backend function only accepts a
308 : * signed int32 length. So throw error if the given value overflows
3835 tgl 309 EUB : * int32.
310 : */
3835 tgl 311 GIC 493 : if (len > (size_t) INT_MAX)
312 : {
145 peter 313 UNC 0 : libpq_append_conn_error(conn, "argument of lo_write exceeds integer range");
3835 tgl 314 LBC 0 : return -1;
315 : }
9770 scrappy 316 ECB :
9345 bruce 317 CBC 493 : argv[0].isint = 1;
318 493 : argv[0].len = 4;
9345 bruce 319 GIC 493 : argv[0].u.integer = fd;
9770 scrappy 320 ECB :
9345 bruce 321 GIC 493 : argv[1].isint = 0;
3835 tgl 322 CBC 493 : argv[1].len = (int) len;
1531 peter 323 GIC 493 : argv[1].u.ptr = (int *) unconstify(char *, buf);
9345 bruce 324 ECB :
9345 bruce 325 CBC 493 : res = PQfn(conn, conn->lobjfuncs->fn_lo_write,
326 : &retval, &result_len, 1, argv, 2);
9345 bruce 327 GIC 493 : if (PQresultStatus(res) == PGRES_COMMAND_OK)
328 : {
9345 bruce 329 GBC 493 : PQclear(res);
330 493 : return retval;
331 : }
332 : else
333 : {
8956 tgl 334 UIC 0 : PQclear(res);
9345 bruce 335 0 : return -1;
336 : }
337 : }
338 :
9770 scrappy 339 EUB : /*
340 : * lo_lseek
341 : * change the current read or write location on a large object
342 : */
343 : int
9344 bruce 344 UIC 0 : lo_lseek(PGconn *conn, int fd, int offset, int whence)
345 : {
9344 bruce 346 EUB : PQArgBlock argv[3];
347 : PGresult *res;
348 : int retval;
349 : int result_len;
9345 350 :
818 tgl 351 UBC 0 : if (lo_initialize(conn) < 0)
818 tgl 352 UIC 0 : return -1;
9345 bruce 353 EUB :
9345 bruce 354 UBC 0 : argv[0].isint = 1;
355 0 : argv[0].len = 4;
9345 bruce 356 UIC 0 : argv[0].u.integer = fd;
9345 bruce 357 EUB :
9345 bruce 358 UBC 0 : argv[1].isint = 1;
359 0 : argv[1].len = 4;
9345 bruce 360 UIC 0 : argv[1].u.integer = offset;
9345 bruce 361 EUB :
9345 bruce 362 UIC 0 : argv[2].isint = 1;
9345 bruce 363 UBC 0 : argv[2].len = 4;
9345 bruce 364 UIC 0 : argv[2].u.integer = whence;
9345 bruce 365 EUB :
9345 bruce 366 UBC 0 : res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek,
367 : &retval, &result_len, 1, argv, 3);
9345 bruce 368 UIC 0 : if (PQresultStatus(res) == PGRES_COMMAND_OK)
369 : {
9345 bruce 370 UBC 0 : PQclear(res);
371 0 : return retval;
372 : }
373 : else
374 : {
8956 tgl 375 UIC 0 : PQclear(res);
9345 bruce 376 0 : return -1;
377 : }
378 : }
379 :
3836 ishii 380 EUB : /*
381 : * lo_lseek64
382 : * change the current read or write location on a large object
383 : */
384 : pg_int64
3836 ishii 385 UIC 0 : lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence)
386 : {
3836 ishii 387 EUB : PQArgBlock argv[3];
388 : PGresult *res;
389 : pg_int64 retval;
390 : int result_len;
391 :
818 tgl 392 UBC 0 : if (lo_initialize(conn) < 0)
818 tgl 393 UIC 0 : return -1;
3836 ishii 394 EUB :
3836 ishii 395 UIC 0 : if (conn->lobjfuncs->fn_lo_lseek64 == 0)
396 : {
145 peter 397 UNC 0 : libpq_append_conn_error(conn, "cannot determine OID of function %s",
818 tgl 398 EUB : "lo_lseek64");
3836 ishii 399 UIC 0 : return -1;
3836 ishii 400 EUB : }
401 :
3836 ishii 402 UBC 0 : argv[0].isint = 1;
403 0 : argv[0].len = 4;
3836 ishii 404 UIC 0 : argv[0].u.integer = fd;
3836 ishii 405 EUB :
3836 ishii 406 UBC 0 : offset = lo_hton64(offset);
407 0 : argv[1].isint = 0;
3836 ishii 408 UIC 0 : argv[1].len = 8;
3836 ishii 409 UBC 0 : argv[1].u.ptr = (int *) &offset;
410 :
411 0 : argv[2].isint = 1;
3836 ishii 412 UIC 0 : argv[2].len = 4;
3836 ishii 413 UBC 0 : argv[2].u.integer = whence;
3836 ishii 414 EUB :
3836 ishii 415 UIC 0 : res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek64,
416 : (void *) &retval, &result_len, 0, argv, 3);
2954 tgl 417 0 : if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8)
3836 ishii 418 EUB : {
3836 ishii 419 UBC 0 : PQclear(res);
3835 tgl 420 UIC 0 : return lo_ntoh64(retval);
421 : }
422 : else
423 : {
3836 ishii 424 0 : PQclear(res);
425 0 : return -1;
426 : }
427 : }
428 :
429 : /*
430 : * lo_creat
431 : * create a new large object
6509 tgl 432 ECB : * the mode is ignored (once upon a time it had a use)
433 : *
434 : * returns the oid of the large object created or
435 : * InvalidOid upon failure
436 : */
437 : Oid
9344 bruce 438 GIC 7 : lo_creat(PGconn *conn, int mode)
9770 scrappy 439 ECB : {
9344 bruce 440 EUB : PQArgBlock argv[1];
441 : PGresult *res;
9344 bruce 442 ECB : int retval;
443 : int result_len;
9345 444 :
818 tgl 445 CBC 7 : if (lo_initialize(conn) < 0)
818 tgl 446 UIC 0 : return InvalidOid;
9345 bruce 447 ECB :
9345 bruce 448 GIC 7 : argv[0].isint = 1;
9345 bruce 449 CBC 7 : argv[0].len = 4;
450 7 : argv[0].u.integer = mode;
9345 bruce 451 GIC 7 : res = PQfn(conn, conn->lobjfuncs->fn_lo_creat,
452 : &retval, &result_len, 1, argv, 1);
453 7 : if (PQresultStatus(res) == PGRES_COMMAND_OK)
9345 bruce 454 EUB : {
9345 bruce 455 GBC 7 : PQclear(res);
9345 bruce 456 GIC 7 : return (Oid) retval;
457 : }
458 : else
459 : {
8956 tgl 460 UIC 0 : PQclear(res);
9345 bruce 461 0 : return InvalidOid;
462 : }
463 : }
464 :
465 : /*
466 : * lo_create
467 : * create a new large object
6509 tgl 468 EUB : * if lobjId isn't InvalidOid, it specifies the OID to (attempt to) create
469 : *
470 : * returns the oid of the large object created or
471 : * InvalidOid upon failure
472 : */
473 : Oid
6509 tgl 474 UIC 0 : lo_create(PGconn *conn, Oid lobjId)
6509 tgl 475 EUB : {
476 : PQArgBlock argv[1];
477 : PGresult *res;
478 : int retval;
479 : int result_len;
480 :
818 tgl 481 UBC 0 : if (lo_initialize(conn) < 0)
818 tgl 482 UIC 0 : return InvalidOid;
6509 tgl 483 EUB :
484 : /* Must check this on-the-fly because it's not there pre-8.1 */
6509 tgl 485 UIC 0 : if (conn->lobjfuncs->fn_lo_create == 0)
6509 tgl 486 EUB : {
145 peter 487 UNC 0 : libpq_append_conn_error(conn, "cannot determine OID of function %s",
818 tgl 488 EUB : "lo_create");
6509 tgl 489 UIC 0 : return InvalidOid;
6509 tgl 490 EUB : }
491 :
6509 tgl 492 UBC 0 : argv[0].isint = 1;
493 0 : argv[0].len = 4;
6509 tgl 494 UIC 0 : argv[0].u.integer = lobjId;
495 0 : res = PQfn(conn, conn->lobjfuncs->fn_lo_create,
496 : &retval, &result_len, 1, argv, 1);
6509 tgl 497 UBC 0 : if (PQresultStatus(res) == PGRES_COMMAND_OK)
6509 tgl 498 EUB : {
6509 tgl 499 UIC 0 : PQclear(res);
500 0 : return (Oid) retval;
501 : }
502 : else
503 : {
504 0 : PQclear(res);
505 0 : return InvalidOid;
506 : }
507 : }
6509 tgl 508 EUB :
509 :
510 : /*
511 : * lo_tell
512 : * returns the current seek location of the large object
513 : */
514 : int
9344 bruce 515 UBC 0 : lo_tell(PGconn *conn, int fd)
9770 scrappy 516 EUB : {
517 : int retval;
9344 bruce 518 : PQArgBlock argv[1];
519 : PGresult *res;
520 : int result_len;
521 :
818 tgl 522 UBC 0 : if (lo_initialize(conn) < 0)
818 tgl 523 UIC 0 : return -1;
9345 bruce 524 EUB :
9345 bruce 525 UIC 0 : argv[0].isint = 1;
9345 bruce 526 UBC 0 : argv[0].len = 4;
527 0 : argv[0].u.integer = fd;
528 :
9345 bruce 529 UIC 0 : res = PQfn(conn, conn->lobjfuncs->fn_lo_tell,
530 : &retval, &result_len, 1, argv, 1);
9345 bruce 531 UBC 0 : if (PQresultStatus(res) == PGRES_COMMAND_OK)
9345 bruce 532 EUB : {
9345 bruce 533 UIC 0 : PQclear(res);
534 0 : return retval;
535 : }
536 : else
537 : {
8956 tgl 538 0 : PQclear(res);
9345 bruce 539 0 : return -1;
540 : }
9770 scrappy 541 EUB : }
542 :
543 : /*
544 : * lo_tell64
545 : * returns the current seek location of the large object
546 : */
547 : pg_int64
3836 ishii 548 UBC 0 : lo_tell64(PGconn *conn, int fd)
3836 ishii 549 EUB : {
550 : pg_int64 retval;
551 : PQArgBlock argv[1];
552 : PGresult *res;
553 : int result_len;
554 :
818 tgl 555 UBC 0 : if (lo_initialize(conn) < 0)
818 tgl 556 UIC 0 : return -1;
557 :
3836 ishii 558 UBC 0 : if (conn->lobjfuncs->fn_lo_tell64 == 0)
3836 ishii 559 EUB : {
145 peter 560 UNC 0 : libpq_append_conn_error(conn, "cannot determine OID of function %s",
818 tgl 561 EUB : "lo_tell64");
3836 ishii 562 UIC 0 : return -1;
3836 ishii 563 EUB : }
564 :
3836 ishii 565 UBC 0 : argv[0].isint = 1;
566 0 : argv[0].len = 4;
3836 ishii 567 UIC 0 : argv[0].u.integer = fd;
568 :
569 0 : res = PQfn(conn, conn->lobjfuncs->fn_lo_tell64,
2954 tgl 570 EUB : (void *) &retval, &result_len, 0, argv, 1);
2954 tgl 571 UBC 0 : if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8)
572 : {
3836 ishii 573 UIC 0 : PQclear(res);
3835 tgl 574 0 : return lo_ntoh64(retval);
575 : }
576 : else
577 : {
3836 ishii 578 0 : PQclear(res);
579 0 : return -1;
580 : }
3836 ishii 581 ECB : }
582 :
583 : /*
584 : * lo_unlink
585 : * delete a file
586 : */
587 :
9770 scrappy 588 : int
9344 bruce 589 GBC 12 : lo_unlink(PGconn *conn, Oid lobjId)
590 : {
9344 bruce 591 ECB : PQArgBlock argv[1];
592 : PGresult *res;
593 : int result_len;
594 : int retval;
9345 595 :
818 tgl 596 GIC 12 : if (lo_initialize(conn) < 0)
818 tgl 597 LBC 0 : return -1;
598 :
9345 bruce 599 CBC 12 : argv[0].isint = 1;
600 12 : argv[0].len = 4;
9345 bruce 601 GIC 12 : argv[0].u.integer = lobjId;
602 :
603 12 : res = PQfn(conn, conn->lobjfuncs->fn_lo_unlink,
9345 bruce 604 EUB : &retval, &result_len, 1, argv, 1);
9345 bruce 605 GBC 12 : if (PQresultStatus(res) == PGRES_COMMAND_OK)
606 : {
9345 bruce 607 GIC 12 : PQclear(res);
608 12 : return retval;
609 : }
610 : else
611 : {
8956 tgl 612 UIC 0 : PQclear(res);
9345 bruce 613 0 : return -1;
614 : }
615 : }
616 :
617 : /*
9770 scrappy 618 ECB : * lo_import -
619 : * imports a file as an (inversion) large object.
620 : *
621 : * returns the oid of that object upon success,
622 : * returns InvalidOid upon failure
623 : */
624 :
625 : Oid
8550 bruce 626 GIC 7 : lo_import(PGconn *conn, const char *filename)
627 : {
5499 ishii 628 7 : return lo_import_internal(conn, filename, InvalidOid);
629 : }
630 :
631 : /*
632 : * lo_import_with_oid -
5499 ishii 633 EUB : * imports a file as an (inversion) large object.
634 : * large object id can be specified.
635 : *
636 : * returns the oid of that object upon success,
637 : * returns InvalidOid upon failure
638 : */
5499 ishii 639 ECB :
640 : Oid
5499 ishii 641 UIC 0 : lo_import_with_oid(PGconn *conn, const char *filename, Oid lobjId)
642 : {
643 0 : return lo_import_internal(conn, filename, lobjId);
644 : }
645 :
646 : static Oid
4022 tgl 647 GIC 7 : lo_import_internal(PGconn *conn, const char *filename, Oid oid)
648 : {
9344 bruce 649 ECB : int fd;
9344 bruce 650 EUB : int nbytes,
651 : tmp;
652 : char buf[LO_BUFSIZE];
9344 bruce 653 ECB : Oid lobjOid;
654 : int lobj;
655 : char sebuf[PG_STRERROR_R_BUFLEN];
656 :
818 tgl 657 GIC 7 : if (conn == NULL)
818 tgl 658 LBC 0 : return InvalidOid;
818 tgl 659 ECB :
660 : /* Since this is the beginning of a query cycle, reset the error state */
415 tgl 661 GBC 7 : pqClearConnErrorState(conn);
818 tgl 662 EUB :
9345 bruce 663 : /*
664 : * open the file to be read in
665 : */
8346 bruce 666 GIC 7 : fd = open(filename, O_RDONLY | PG_BINARY, 0666);
9345 667 7 : if (fd < 0)
668 : { /* error */
145 peter 669 UNC 0 : libpq_append_conn_error(conn, "could not open file \"%s\": %s",
1656 tgl 670 UIC 0 : filename, strerror_r(errno, sebuf, sizeof(sebuf)));
9345 bruce 671 UBC 0 : return InvalidOid;
672 : }
9345 bruce 673 ECB :
674 : /*
675 : * create an inversion object
9345 bruce 676 EUB : */
5499 ishii 677 GBC 7 : if (oid == InvalidOid)
5499 ishii 678 GIC 7 : lobjOid = lo_creat(conn, INV_READ | INV_WRITE);
679 : else
5499 ishii 680 LBC 0 : lobjOid = lo_create(conn, oid);
5499 ishii 681 ECB :
9345 bruce 682 GIC 7 : if (lobjOid == InvalidOid)
683 : {
5499 ishii 684 EUB : /* we assume lo_create() already set a suitable error message */
7874 tgl 685 UBC 0 : (void) close(fd);
9345 bruce 686 UIC 0 : return InvalidOid;
687 : }
688 :
9345 bruce 689 GIC 7 : lobj = lo_open(conn, lobjOid, INV_WRITE);
690 7 : if (lobj == -1)
9345 bruce 691 ECB : {
692 : /* we assume lo_open() already set a suitable error message */
7874 tgl 693 LBC 0 : (void) close(fd);
9345 bruce 694 0 : return InvalidOid;
695 : }
696 :
697 : /*
698 : * read in from the file and write to the large object
699 : */
9345 bruce 700 GIC 500 : while ((nbytes = read(fd, buf, LO_BUFSIZE)) > 0)
701 : {
9345 bruce 702 GBC 493 : tmp = lo_write(conn, lobj, buf, nbytes);
6143 tgl 703 493 : if (tmp != nbytes)
704 : {
705 : /*
706 : * If lo_write() failed, we are now in an aborted transaction so
6031 bruce 707 ECB : * there's no need for lo_close(); furthermore, if we tried it
708 : * we'd overwrite the useful error result with a useless one. So
709 : * just nail the doors shut and get out of town.
6143 tgl 710 EUB : */
7874 tgl 711 UIC 0 : (void) close(fd);
9345 bruce 712 UBC 0 : return InvalidOid;
9345 bruce 713 EUB : }
714 : }
715 :
6143 tgl 716 GBC 7 : if (nbytes < 0)
717 : {
718 : /* We must do lo_close before setting the errorMessage */
3835 tgl 719 UBC 0 : int save_errno = errno;
720 :
3835 tgl 721 UIC 0 : (void) lo_close(conn, lobj);
3835 tgl 722 LBC 0 : (void) close(fd);
723 : /* deliberately overwrite any error from lo_close */
415 724 0 : pqClearConnErrorState(conn);
145 peter 725 UNC 0 : libpq_append_conn_error(conn, "could not read from file \"%s\": %s",
3835 tgl 726 EUB : filename,
727 : strerror_r(save_errno, sebuf, sizeof(sebuf)));
3835 tgl 728 UIC 0 : return InvalidOid;
6143 tgl 729 ECB : }
730 :
9345 bruce 731 GIC 7 : (void) close(fd);
732 :
6143 tgl 733 7 : if (lo_close(conn, lobj) != 0)
734 : {
735 : /* we assume lo_close() already set a suitable error message */
6143 tgl 736 UIC 0 : return InvalidOid;
737 : }
9345 bruce 738 ECB :
9345 bruce 739 GIC 7 : return lobjOid;
9770 scrappy 740 ECB : }
741 :
742 : /*
743 : * lo_export -
744 : * exports an (inversion) large object.
745 : * returns -1 upon failure, 1 if OK
746 : */
747 : int
8550 bruce 748 GIC 3 : lo_export(PGconn *conn, Oid lobjId, const char *filename)
749 : {
6143 tgl 750 3 : int result = 1;
9344 bruce 751 ECB : int fd;
752 : int nbytes,
753 : tmp;
754 : char buf[LO_BUFSIZE];
9344 bruce 755 EUB : int lobj;
756 : char sebuf[PG_STRERROR_R_BUFLEN];
757 :
758 : /*
759 : * open the large object.
760 : */
9345 bruce 761 CBC 3 : lobj = lo_open(conn, lobjId, INV_READ);
762 3 : if (lobj == -1)
763 : {
764 : /* we assume lo_open() already set a suitable error message */
9345 bruce 765 UBC 0 : return -1;
766 : }
9345 bruce 767 EUB :
768 : /*
7874 tgl 769 : * create the file to be written to
9345 bruce 770 : */
8346 bruce 771 GIC 3 : fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666);
9345 772 3 : if (fd < 0)
3835 tgl 773 EUB : {
774 : /* We must do lo_close before setting the errorMessage */
3835 tgl 775 UIC 0 : int save_errno = errno;
776 :
777 0 : (void) lo_close(conn, lobj);
778 : /* deliberately overwrite any error from lo_close */
415 tgl 779 LBC 0 : pqClearConnErrorState(conn);
145 peter 780 UNC 0 : libpq_append_conn_error(conn, "could not open file \"%s\": %s",
3835 tgl 781 ECB : filename,
782 : strerror_r(save_errno, sebuf, sizeof(sebuf)));
7874 tgl 783 UIC 0 : return -1;
9345 bruce 784 EUB : }
785 :
786 : /*
6143 tgl 787 : * read in from the large object and write to the file
788 : */
9345 bruce 789 GBC 249 : while ((nbytes = lo_read(conn, lobj, buf, LO_BUFSIZE)) > 0)
9345 bruce 790 EUB : {
9345 bruce 791 GIC 246 : tmp = write(fd, buf, nbytes);
6143 tgl 792 246 : if (tmp != nbytes)
9345 bruce 793 EUB : {
794 : /* We must do lo_close before setting the errorMessage */
3835 tgl 795 UIC 0 : int save_errno = errno;
796 :
7874 797 0 : (void) lo_close(conn, lobj);
798 0 : (void) close(fd);
799 : /* deliberately overwrite any error from lo_close */
415 800 0 : pqClearConnErrorState(conn);
145 peter 801 UNC 0 : libpq_append_conn_error(conn, "could not write to file \"%s\": %s",
3835 tgl 802 ECB : filename,
1656 803 : strerror_r(save_errno, sebuf, sizeof(sebuf)));
9345 bruce 804 UIC 0 : return -1;
805 : }
9770 scrappy 806 EUB : }
807 :
808 : /*
809 : * If lo_read() failed, we are now in an aborted transaction so there's no
6031 bruce 810 ECB : * need for lo_close(); furthermore, if we tried it we'd overwrite the
811 : * useful error result with a useless one. So skip lo_close() if we got a
6031 bruce 812 EUB : * failure result.
6143 tgl 813 : */
6143 tgl 814 GBC 6 : if (nbytes < 0 ||
6143 tgl 815 GIC 3 : lo_close(conn, lobj) != 0)
816 : {
6143 tgl 817 ECB : /* assume lo_read() or lo_close() left a suitable error message */
6143 tgl 818 UIC 0 : result = -1;
819 : }
820 :
821 : /* if we already failed, don't overwrite that msg with a close error */
1373 peter 822 GIC 3 : if (close(fd) != 0 && result >= 0)
823 : {
145 peter 824 UNC 0 : libpq_append_conn_error(conn, "could not write to file \"%s\": %s",
1656 tgl 825 UIC 0 : filename, strerror_r(errno, sebuf, sizeof(sebuf)));
6143 826 0 : result = -1;
827 : }
828 :
6143 tgl 829 GIC 3 : return result;
9770 scrappy 830 ECB : }
831 :
832 :
833 : /*
834 : * lo_initialize
835 : *
836 : * Initialize for a new large-object operation on an existing connection.
837 : * Return 0 if OK, -1 on failure.
838 : *
839 : * If we haven't previously done so, we collect the function OIDs from
818 tgl 840 : * pg_proc for all functions that are required for large object operations.
9645 scrappy 841 EUB : */
842 : static int
9344 bruce 843 GIC 1063 : lo_initialize(PGconn *conn)
9645 scrappy 844 ECB : {
845 : PGresult *res;
846 : PGlobjfuncs *lobjfuncs;
9344 bruce 847 : int n;
6974 tgl 848 : const char *query;
849 : const char *fname;
850 : Oid foid;
851 :
852 : /* Nothing we can do with no connection */
818 tgl 853 GIC 1063 : if (conn == NULL)
4022 tgl 854 LBC 0 : return -1;
4022 tgl 855 ECB :
856 : /* Since this is the beginning of a query cycle, reset the error state */
415 tgl 857 GBC 1063 : pqClearConnErrorState(conn);
818 tgl 858 EUB :
859 : /* Nothing else to do if we already collected info */
818 tgl 860 CBC 1063 : if (conn->lobjfuncs != NULL)
818 tgl 861 GIC 1021 : return 0;
862 :
863 : /*
864 : * Allocate the structure to hold the function OIDs. We don't store it
865 : * into the PGconn until it's successfully filled.
9345 bruce 866 ECB : */
9345 bruce 867 GIC 42 : lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs));
7032 neilc 868 42 : if (lobjfuncs == NULL)
869 : {
145 peter 870 UNC 0 : libpq_append_conn_error(conn, "out of memory");
9345 bruce 871 UIC 0 : return -1;
872 : }
9334 bruce 873 GIC 42 : MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs));
874 :
875 : /*
876 : * Execute the query to get all the functions at once. (Not all of them
877 : * may exist in older server versions.)
878 : */
766 heikki.linnakangas 879 42 : query = "select proname, oid from pg_catalog.pg_proc "
880 : "where proname in ("
881 : "'lo_open', "
882 : "'lo_close', "
766 heikki.linnakangas 883 ECB : "'lo_creat', "
884 : "'lo_create', "
885 : "'lo_unlink', "
766 heikki.linnakangas 886 EUB : "'lo_lseek', "
887 : "'lo_lseek64', "
888 : "'lo_tell', "
889 : "'lo_tell64', "
766 heikki.linnakangas 890 ECB : "'lo_truncate', "
891 : "'lo_truncate64', "
766 heikki.linnakangas 892 EUB : "'loread', "
893 : "'lowrite') "
894 : "and pronamespace = (select oid from pg_catalog.pg_namespace "
895 : "where nspname = 'pg_catalog')";
896 :
6974 tgl 897 GIC 42 : res = PQexec(conn, query);
7032 neilc 898 42 : if (res == NULL)
899 : {
9345 bruce 900 UIC 0 : free(lobjfuncs);
9345 bruce 901 LBC 0 : return -1;
902 : }
9345 bruce 903 ECB :
9345 bruce 904 CBC 42 : if (res->resultStatus != PGRES_TUPLES_OK)
9345 bruce 905 ECB : {
9345 bruce 906 LBC 0 : free(lobjfuncs);
907 0 : PQclear(res);
145 peter 908 UNC 0 : libpq_append_conn_error(conn, "query to initialize large object functions did not return data");
9345 bruce 909 LBC 0 : return -1;
9345 bruce 910 ECB : }
911 :
8053 912 : /*
9345 913 : * Examine the result and put the OID's into the struct
914 : */
9345 bruce 915 CBC 588 : for (n = 0; n < PQntuples(res); n++)
9345 bruce 916 ECB : {
9345 bruce 917 CBC 546 : fname = PQgetvalue(res, n, 0);
918 546 : foid = (Oid) atoi(PQgetvalue(res, n, 1));
4121 peter_e 919 546 : if (strcmp(fname, "lo_open") == 0)
9345 bruce 920 42 : lobjfuncs->fn_lo_open = foid;
4121 peter_e 921 504 : else if (strcmp(fname, "lo_close") == 0)
9345 bruce 922 42 : lobjfuncs->fn_lo_close = foid;
4121 peter_e 923 462 : else if (strcmp(fname, "lo_creat") == 0)
9345 bruce 924 42 : lobjfuncs->fn_lo_creat = foid;
4121 peter_e 925 420 : else if (strcmp(fname, "lo_create") == 0)
6509 tgl 926 42 : lobjfuncs->fn_lo_create = foid;
4121 peter_e 927 378 : else if (strcmp(fname, "lo_unlink") == 0)
9345 bruce 928 42 : lobjfuncs->fn_lo_unlink = foid;
4121 peter_e 929 336 : else if (strcmp(fname, "lo_lseek") == 0)
9345 bruce 930 GIC 42 : lobjfuncs->fn_lo_lseek = foid;
3836 ishii 931 294 : else if (strcmp(fname, "lo_lseek64") == 0)
3836 ishii 932 CBC 42 : lobjfuncs->fn_lo_lseek64 = foid;
4121 peter_e 933 GIC 252 : else if (strcmp(fname, "lo_tell") == 0)
9345 bruce 934 42 : lobjfuncs->fn_lo_tell = foid;
3836 ishii 935 210 : else if (strcmp(fname, "lo_tell64") == 0)
936 42 : lobjfuncs->fn_lo_tell64 = foid;
4121 peter_e 937 168 : else if (strcmp(fname, "lo_truncate") == 0)
5881 bruce 938 42 : lobjfuncs->fn_lo_truncate = foid;
3836 ishii 939 CBC 126 : else if (strcmp(fname, "lo_truncate64") == 0)
3836 ishii 940 GIC 42 : lobjfuncs->fn_lo_truncate64 = foid;
4121 peter_e 941 GBC 84 : else if (strcmp(fname, "loread") == 0)
9345 bruce 942 GIC 42 : lobjfuncs->fn_lo_read = foid;
4121 peter_e 943 GBC 42 : else if (strcmp(fname, "lowrite") == 0)
9345 bruce 944 42 : lobjfuncs->fn_lo_write = foid;
945 : }
9645 scrappy 946 ECB :
9645 scrappy 947 GIC 42 : PQclear(res);
9645 scrappy 948 EUB :
949 : /*
3835 tgl 950 : * Finally check that we got all required large object interface functions
951 : * (ones that have been added later than the stone age are instead checked
952 : * only if used)
9345 bruce 953 ECB : */
9345 bruce 954 GIC 42 : if (lobjfuncs->fn_lo_open == 0)
9345 bruce 955 EUB : {
145 peter 956 UNC 0 : libpq_append_conn_error(conn, "cannot determine OID of function %s",
818 tgl 957 EUB : "lo_open");
9345 bruce 958 UIC 0 : free(lobjfuncs);
9345 bruce 959 LBC 0 : return -1;
960 : }
9345 bruce 961 GBC 42 : if (lobjfuncs->fn_lo_close == 0)
962 : {
145 peter 963 UNC 0 : libpq_append_conn_error(conn, "cannot determine OID of function %s",
964 : "lo_close");
9345 bruce 965 LBC 0 : free(lobjfuncs);
9345 bruce 966 UIC 0 : return -1;
9345 bruce 967 EUB : }
9345 bruce 968 GIC 42 : if (lobjfuncs->fn_lo_creat == 0)
9345 bruce 969 EUB : {
145 peter 970 UNC 0 : libpq_append_conn_error(conn, "cannot determine OID of function %s",
818 tgl 971 ECB : "lo_creat");
9345 bruce 972 UIC 0 : free(lobjfuncs);
9345 bruce 973 UBC 0 : return -1;
974 : }
9345 bruce 975 GBC 42 : if (lobjfuncs->fn_lo_unlink == 0)
9345 bruce 976 EUB : {
145 peter 977 UNC 0 : libpq_append_conn_error(conn, "cannot determine OID of function %s",
978 : "lo_unlink");
9345 bruce 979 UBC 0 : free(lobjfuncs);
9345 bruce 980 UIC 0 : return -1;
9345 bruce 981 EUB : }
9345 bruce 982 GBC 42 : if (lobjfuncs->fn_lo_lseek == 0)
983 : {
145 peter 984 UNC 0 : libpq_append_conn_error(conn, "cannot determine OID of function %s",
818 tgl 985 EUB : "lo_lseek");
9345 bruce 986 UIC 0 : free(lobjfuncs);
9345 bruce 987 UBC 0 : return -1;
9345 bruce 988 EUB : }
9345 bruce 989 GIC 42 : if (lobjfuncs->fn_lo_tell == 0)
990 : {
145 peter 991 UNC 0 : libpq_append_conn_error(conn, "cannot determine OID of function %s",
992 : "lo_tell");
9345 bruce 993 LBC 0 : free(lobjfuncs);
994 0 : return -1;
995 : }
9345 bruce 996 GIC 42 : if (lobjfuncs->fn_lo_read == 0)
997 : {
145 peter 998 UNC 0 : libpq_append_conn_error(conn, "cannot determine OID of function %s",
999 : "loread");
9345 bruce 1000 UIC 0 : free(lobjfuncs);
9345 bruce 1001 UBC 0 : return -1;
1002 : }
9345 bruce 1003 GIC 42 : if (lobjfuncs->fn_lo_write == 0)
1004 : {
145 peter 1005 UNC 0 : libpq_append_conn_error(conn, "cannot determine OID of function %s",
1006 : "lowrite");
9345 bruce 1007 UIC 0 : free(lobjfuncs);
1008 0 : return -1;
1009 : }
3836 tgl 1010 EUB :
8053 bruce 1011 : /*
1012 : * Put the structure into the connection control
1013 : */
9345 bruce 1014 GBC 42 : conn->lobjfuncs = lobjfuncs;
1015 42 : return 0;
1016 : }
3836 ishii 1017 EUB :
1018 : /*
1019 : * lo_hton64
1020 : * converts a 64-bit integer from host byte order to network byte order
1021 : */
1022 : static pg_int64
3836 ishii 1023 UIC 0 : lo_hton64(pg_int64 host64)
1024 : {
3835 tgl 1025 EUB : union
1026 : {
1027 : pg_int64 i64;
1028 : uint32 i32[2];
1029 : } swap;
1030 : uint32 t;
1031 :
1032 : /* High order half first, since we're doing MSB-first */
3835 tgl 1033 UIC 0 : t = (uint32) (host64 >> 32);
2016 andres 1034 UBC 0 : swap.i32[0] = pg_hton32(t);
1035 :
3836 ishii 1036 EUB : /* Now the low order half */
3835 tgl 1037 UBC 0 : t = (uint32) host64;
2016 andres 1038 0 : swap.i32[1] = pg_hton32(t);
1039 :
3835 tgl 1040 0 : return swap.i64;
1041 : }
1042 :
1043 : /*
1044 : * lo_ntoh64
1045 : * converts a 64-bit integer from network byte order to host byte order
1046 : */
1047 : static pg_int64
3836 ishii 1048 UIC 0 : lo_ntoh64(pg_int64 net64)
1049 : {
1050 : union
1051 : {
1052 : pg_int64 i64;
1053 : uint32 i32[2];
1054 : } swap;
1055 : pg_int64 result;
1056 :
3835 tgl 1057 0 : swap.i64 = net64;
1058 :
2016 andres 1059 0 : result = (uint32) pg_ntoh32(swap.i32[0]);
3836 ishii 1060 0 : result <<= 32;
2016 andres 1061 0 : result |= (uint32) pg_ntoh32(swap.i32[1]);
1062 :
3836 ishii 1063 0 : return result;
1064 : }
|