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