LCOV - code coverage report
Current view: top level - src/interfaces/libpq - fe-lobj.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 147 403 36.5 %
Date: 2019-11-15 22:06:47 Functions: 10 20 50.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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          62 : 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          62 :     if (conn == NULL || conn->lobjfuncs == NULL)
      65             :     {
      66          42 :         if (lo_initialize(conn) < 0)
      67           0 :             return -1;
      68             :     }
      69             : 
      70          62 :     argv[0].isint = 1;
      71          62 :     argv[0].len = 4;
      72          62 :     argv[0].u.integer = lobjId;
      73             : 
      74          62 :     argv[1].isint = 1;
      75          62 :     argv[1].len = 4;
      76          62 :     argv[1].u.integer = mode;
      77             : 
      78          62 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_open, &fd, &result_len, 1, argv, 2);
      79          62 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
      80             :     {
      81          62 :         PQclear(res);
      82          62 :         return fd;
      83             :     }
      84             :     else
      85             :     {
      86           0 :         PQclear(res);
      87           0 :         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          62 : lo_close(PGconn *conn, int fd)
     100             : {
     101             :     PQArgBlock  argv[1];
     102             :     PGresult   *res;
     103             :     int         retval;
     104             :     int         result_len;
     105             : 
     106          62 :     if (conn == NULL || conn->lobjfuncs == NULL)
     107             :     {
     108           0 :         if (lo_initialize(conn) < 0)
     109           0 :             return -1;
     110             :     }
     111             : 
     112          62 :     argv[0].isint = 1;
     113          62 :     argv[0].len = 4;
     114          62 :     argv[0].u.integer = fd;
     115          62 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_close,
     116             :                &retval, &result_len, 1, argv, 1);
     117          62 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     118             :     {
     119          62 :         PQclear(res);
     120          62 :         return retval;
     121             :     }
     122             :     else
     123             :     {
     124           0 :         PQclear(res);
     125           0 :         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           0 : 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           0 :     if (conn == NULL || conn->lobjfuncs == NULL)
     145             :     {
     146           0 :         if (lo_initialize(conn) < 0)
     147           0 :             return -1;
     148             :     }
     149             : 
     150             :     /* Must check this on-the-fly because it's not there pre-8.3 */
     151           0 :     if (conn->lobjfuncs->fn_lo_truncate == 0)
     152             :     {
     153           0 :         printfPQExpBuffer(&conn->errorMessage,
     154           0 :                           libpq_gettext("cannot determine OID of function lo_truncate\n"));
     155           0 :         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           0 :     if (len > (size_t) INT_MAX)
     168             :     {
     169           0 :         printfPQExpBuffer(&conn->errorMessage,
     170           0 :                           libpq_gettext("argument of lo_truncate exceeds integer range\n"));
     171           0 :         return -1;
     172             :     }
     173             : 
     174           0 :     argv[0].isint = 1;
     175           0 :     argv[0].len = 4;
     176           0 :     argv[0].u.integer = fd;
     177             : 
     178           0 :     argv[1].isint = 1;
     179           0 :     argv[1].len = 4;
     180           0 :     argv[1].u.integer = (int) len;
     181             : 
     182           0 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_truncate,
     183             :                &retval, &result_len, 1, argv, 2);
     184             : 
     185           0 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     186             :     {
     187           0 :         PQclear(res);
     188           0 :         return retval;
     189             :     }
     190             :     else
     191             :     {
     192           0 :         PQclear(res);
     193           0 :         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           0 : 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           0 :     if (conn == NULL || conn->lobjfuncs == NULL)
     213             :     {
     214           0 :         if (lo_initialize(conn) < 0)
     215           0 :             return -1;
     216             :     }
     217             : 
     218           0 :     if (conn->lobjfuncs->fn_lo_truncate64 == 0)
     219             :     {
     220           0 :         printfPQExpBuffer(&conn->errorMessage,
     221           0 :                           libpq_gettext("cannot determine OID of function lo_truncate64\n"));
     222           0 :         return -1;
     223             :     }
     224             : 
     225           0 :     argv[0].isint = 1;
     226           0 :     argv[0].len = 4;
     227           0 :     argv[0].u.integer = fd;
     228             : 
     229           0 :     len = lo_hton64(len);
     230           0 :     argv[1].isint = 0;
     231           0 :     argv[1].len = 8;
     232           0 :     argv[1].u.ptr = (int *) &len;
     233             : 
     234           0 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_truncate64,
     235             :                &retval, &result_len, 1, argv, 2);
     236             : 
     237           0 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     238             :     {
     239           0 :         PQclear(res);
     240           0 :         return retval;
     241             :     }
     242             :     else
     243             :     {
     244           0 :         PQclear(res);
     245           0 :         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         428 : 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         428 :     if (conn == NULL || conn->lobjfuncs == NULL)
     265             :     {
     266           0 :         if (lo_initialize(conn) < 0)
     267           0 :             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         428 :     if (len > (size_t) INT_MAX)
     277             :     {
     278           0 :         printfPQExpBuffer(&conn->errorMessage,
     279           0 :                           libpq_gettext("argument of lo_read exceeds integer range\n"));
     280           0 :         return -1;
     281             :     }
     282             : 
     283         428 :     argv[0].isint = 1;
     284         428 :     argv[0].len = 4;
     285         428 :     argv[0].u.integer = fd;
     286             : 
     287         428 :     argv[1].isint = 1;
     288         428 :     argv[1].len = 4;
     289         428 :     argv[1].u.integer = (int) len;
     290             : 
     291         428 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_read,
     292             :                (void *) buf, &result_len, 0, argv, 2);
     293         428 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     294             :     {
     295         428 :         PQclear(res);
     296         428 :         return result_len;
     297             :     }
     298             :     else
     299             :     {
     300           0 :         PQclear(res);
     301           0 :         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         656 : 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         656 :     if (conn == NULL || conn->lobjfuncs == NULL)
     320             :     {
     321           0 :         if (lo_initialize(conn) < 0)
     322           0 :             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         656 :     if (len > (size_t) INT_MAX)
     332             :     {
     333           0 :         printfPQExpBuffer(&conn->errorMessage,
     334           0 :                           libpq_gettext("argument of lo_write exceeds integer range\n"));
     335           0 :         return -1;
     336             :     }
     337             : 
     338         656 :     argv[0].isint = 1;
     339         656 :     argv[0].len = 4;
     340         656 :     argv[0].u.integer = fd;
     341             : 
     342         656 :     argv[1].isint = 0;
     343         656 :     argv[1].len = (int) len;
     344         656 :     argv[1].u.ptr = (int *) unconstify(char *, buf);
     345             : 
     346         656 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_write,
     347             :                &retval, &result_len, 1, argv, 2);
     348         656 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     349             :     {
     350         656 :         PQclear(res);
     351         656 :         return retval;
     352             :     }
     353             :     else
     354             :     {
     355           0 :         PQclear(res);
     356           0 :         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           0 : 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           0 :     if (conn == NULL || conn->lobjfuncs == NULL)
     373             :     {
     374           0 :         if (lo_initialize(conn) < 0)
     375           0 :             return -1;
     376             :     }
     377             : 
     378           0 :     argv[0].isint = 1;
     379           0 :     argv[0].len = 4;
     380           0 :     argv[0].u.integer = fd;
     381             : 
     382           0 :     argv[1].isint = 1;
     383           0 :     argv[1].len = 4;
     384           0 :     argv[1].u.integer = offset;
     385             : 
     386           0 :     argv[2].isint = 1;
     387           0 :     argv[2].len = 4;
     388           0 :     argv[2].u.integer = whence;
     389             : 
     390           0 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek,
     391             :                &retval, &result_len, 1, argv, 3);
     392           0 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     393             :     {
     394           0 :         PQclear(res);
     395           0 :         return retval;
     396             :     }
     397             :     else
     398             :     {
     399           0 :         PQclear(res);
     400           0 :         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           0 : 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           0 :     if (conn == NULL || conn->lobjfuncs == NULL)
     417             :     {
     418           0 :         if (lo_initialize(conn) < 0)
     419           0 :             return -1;
     420             :     }
     421             : 
     422           0 :     if (conn->lobjfuncs->fn_lo_lseek64 == 0)
     423             :     {
     424           0 :         printfPQExpBuffer(&conn->errorMessage,
     425           0 :                           libpq_gettext("cannot determine OID of function lo_lseek64\n"));
     426           0 :         return -1;
     427             :     }
     428             : 
     429           0 :     argv[0].isint = 1;
     430           0 :     argv[0].len = 4;
     431           0 :     argv[0].u.integer = fd;
     432             : 
     433           0 :     offset = lo_hton64(offset);
     434           0 :     argv[1].isint = 0;
     435           0 :     argv[1].len = 8;
     436           0 :     argv[1].u.ptr = (int *) &offset;
     437             : 
     438           0 :     argv[2].isint = 1;
     439           0 :     argv[2].len = 4;
     440           0 :     argv[2].u.integer = whence;
     441             : 
     442           0 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek64,
     443             :                (void *) &retval, &result_len, 0, argv, 3);
     444           0 :     if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8)
     445             :     {
     446           0 :         PQclear(res);
     447           0 :         return lo_ntoh64(retval);
     448             :     }
     449             :     else
     450             :     {
     451           0 :         PQclear(res);
     452           0 :         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           8 : lo_creat(PGconn *conn, int mode)
     466             : {
     467             :     PQArgBlock  argv[1];
     468             :     PGresult   *res;
     469             :     int         retval;
     470             :     int         result_len;
     471             : 
     472           8 :     if (conn == NULL || conn->lobjfuncs == NULL)
     473             :     {
     474           4 :         if (lo_initialize(conn) < 0)
     475           0 :             return InvalidOid;
     476             :     }
     477             : 
     478           8 :     argv[0].isint = 1;
     479           8 :     argv[0].len = 4;
     480           8 :     argv[0].u.integer = mode;
     481           8 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_creat,
     482             :                &retval, &result_len, 1, argv, 1);
     483           8 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     484             :     {
     485           8 :         PQclear(res);
     486           8 :         return (Oid) retval;
     487             :     }
     488             :     else
     489             :     {
     490           0 :         PQclear(res);
     491           0 :         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           0 : lo_create(PGconn *conn, Oid lobjId)
     505             : {
     506             :     PQArgBlock  argv[1];
     507             :     PGresult   *res;
     508             :     int         retval;
     509             :     int         result_len;
     510             : 
     511           0 :     if (conn == NULL || conn->lobjfuncs == NULL)
     512             :     {
     513           0 :         if (lo_initialize(conn) < 0)
     514           0 :             return InvalidOid;
     515             :     }
     516             : 
     517             :     /* Must check this on-the-fly because it's not there pre-8.1 */
     518           0 :     if (conn->lobjfuncs->fn_lo_create == 0)
     519             :     {
     520           0 :         printfPQExpBuffer(&conn->errorMessage,
     521           0 :                           libpq_gettext("cannot determine OID of function lo_create\n"));
     522           0 :         return InvalidOid;
     523             :     }
     524             : 
     525           0 :     argv[0].isint = 1;
     526           0 :     argv[0].len = 4;
     527           0 :     argv[0].u.integer = lobjId;
     528           0 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_create,
     529             :                &retval, &result_len, 1, argv, 1);
     530           0 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     531             :     {
     532           0 :         PQclear(res);
     533           0 :         return (Oid) retval;
     534             :     }
     535             :     else
     536             :     {
     537           0 :         PQclear(res);
     538           0 :         return InvalidOid;
     539             :     }
     540             : }
     541             : 
     542             : 
     543             : /*
     544             :  * lo_tell
     545             :  *    returns the current seek location of the large object
     546             :  */
     547             : int
     548           0 : lo_tell(PGconn *conn, int fd)
     549             : {
     550             :     int         retval;
     551             :     PQArgBlock  argv[1];
     552             :     PGresult   *res;
     553             :     int         result_len;
     554             : 
     555           0 :     if (conn == NULL || conn->lobjfuncs == NULL)
     556             :     {
     557           0 :         if (lo_initialize(conn) < 0)
     558           0 :             return -1;
     559             :     }
     560             : 
     561           0 :     argv[0].isint = 1;
     562           0 :     argv[0].len = 4;
     563           0 :     argv[0].u.integer = fd;
     564             : 
     565           0 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_tell,
     566             :                &retval, &result_len, 1, argv, 1);
     567           0 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     568             :     {
     569           0 :         PQclear(res);
     570           0 :         return retval;
     571             :     }
     572             :     else
     573             :     {
     574           0 :         PQclear(res);
     575           0 :         return -1;
     576             :     }
     577             : }
     578             : 
     579             : /*
     580             :  * lo_tell64
     581             :  *    returns the current seek location of the large object
     582             :  */
     583             : pg_int64
     584           0 : lo_tell64(PGconn *conn, int fd)
     585             : {
     586             :     pg_int64    retval;
     587             :     PQArgBlock  argv[1];
     588             :     PGresult   *res;
     589             :     int         result_len;
     590             : 
     591           0 :     if (conn == NULL || conn->lobjfuncs == NULL)
     592             :     {
     593           0 :         if (lo_initialize(conn) < 0)
     594           0 :             return -1;
     595             :     }
     596             : 
     597           0 :     if (conn->lobjfuncs->fn_lo_tell64 == 0)
     598             :     {
     599           0 :         printfPQExpBuffer(&conn->errorMessage,
     600           0 :                           libpq_gettext("cannot determine OID of function lo_tell64\n"));
     601           0 :         return -1;
     602             :     }
     603             : 
     604           0 :     argv[0].isint = 1;
     605           0 :     argv[0].len = 4;
     606           0 :     argv[0].u.integer = fd;
     607             : 
     608           0 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_tell64,
     609             :                (void *) &retval, &result_len, 0, argv, 1);
     610           0 :     if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8)
     611             :     {
     612           0 :         PQclear(res);
     613           0 :         return lo_ntoh64(retval);
     614             :     }
     615             :     else
     616             :     {
     617           0 :         PQclear(res);
     618           0 :         return -1;
     619             :     }
     620             : }
     621             : 
     622             : /*
     623             :  * lo_unlink
     624             :  *    delete a file
     625             :  */
     626             : 
     627             : int
     628          12 : lo_unlink(PGconn *conn, Oid lobjId)
     629             : {
     630             :     PQArgBlock  argv[1];
     631             :     PGresult   *res;
     632             :     int         result_len;
     633             :     int         retval;
     634             : 
     635          12 :     if (conn == NULL || conn->lobjfuncs == NULL)
     636             :     {
     637           0 :         if (lo_initialize(conn) < 0)
     638           0 :             return -1;
     639             :     }
     640             : 
     641          12 :     argv[0].isint = 1;
     642          12 :     argv[0].len = 4;
     643          12 :     argv[0].u.integer = lobjId;
     644             : 
     645          12 :     res = PQfn(conn, conn->lobjfuncs->fn_lo_unlink,
     646             :                &retval, &result_len, 1, argv, 1);
     647          12 :     if (PQresultStatus(res) == PGRES_COMMAND_OK)
     648             :     {
     649          12 :         PQclear(res);
     650          12 :         return retval;
     651             :     }
     652             :     else
     653             :     {
     654           0 :         PQclear(res);
     655           0 :         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           8 : lo_import(PGconn *conn, const char *filename)
     669             : {
     670           8 :     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           0 : lo_import_with_oid(PGconn *conn, const char *filename, Oid lobjId)
     684             : {
     685           0 :     return lo_import_internal(conn, filename, lobjId);
     686             : }
     687             : 
     688             : static Oid
     689           8 : 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           8 :     fd = open(filename, O_RDONLY | PG_BINARY, 0666);
     703           8 :     if (fd < 0)
     704             :     {                           /* error */
     705           0 :         printfPQExpBuffer(&conn->errorMessage,
     706           0 :                           libpq_gettext("could not open file \"%s\": %s\n"),
     707           0 :                           filename, strerror_r(errno, sebuf, sizeof(sebuf)));
     708           0 :         return InvalidOid;
     709             :     }
     710             : 
     711             :     /*
     712             :      * create an inversion object
     713             :      */
     714           8 :     if (oid == InvalidOid)
     715           8 :         lobjOid = lo_creat(conn, INV_READ | INV_WRITE);
     716             :     else
     717           0 :         lobjOid = lo_create(conn, oid);
     718             : 
     719           8 :     if (lobjOid == InvalidOid)
     720             :     {
     721             :         /* we assume lo_create() already set a suitable error message */
     722           0 :         (void) close(fd);
     723           0 :         return InvalidOid;
     724             :     }
     725             : 
     726           8 :     lobj = lo_open(conn, lobjOid, INV_WRITE);
     727           8 :     if (lobj == -1)
     728             :     {
     729             :         /* we assume lo_open() already set a suitable error message */
     730           0 :         (void) close(fd);
     731           0 :         return InvalidOid;
     732             :     }
     733             : 
     734             :     /*
     735             :      * read in from the file and write to the large object
     736             :      */
     737         672 :     while ((nbytes = read(fd, buf, LO_BUFSIZE)) > 0)
     738             :     {
     739         656 :         tmp = lo_write(conn, lobj, buf, nbytes);
     740         656 :         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           0 :             (void) close(fd);
     749           0 :             return InvalidOid;
     750             :         }
     751             :     }
     752             : 
     753           8 :     if (nbytes < 0)
     754             :     {
     755             :         /* We must do lo_close before setting the errorMessage */
     756           0 :         int         save_errno = errno;
     757             : 
     758           0 :         (void) lo_close(conn, lobj);
     759           0 :         (void) close(fd);
     760           0 :         printfPQExpBuffer(&conn->errorMessage,
     761           0 :                           libpq_gettext("could not read from file \"%s\": %s\n"),
     762             :                           filename,
     763             :                           strerror_r(save_errno, sebuf, sizeof(sebuf)));
     764           0 :         return InvalidOid;
     765             :     }
     766             : 
     767           8 :     (void) close(fd);
     768             : 
     769           8 :     if (lo_close(conn, lobj) != 0)
     770             :     {
     771             :         /* we assume lo_close() already set a suitable error message */
     772           0 :         return InvalidOid;
     773             :     }
     774             : 
     775           8 :     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           4 : lo_export(PGconn *conn, Oid lobjId, const char *filename)
     785             : {
     786           4 :     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           4 :     lobj = lo_open(conn, lobjId, INV_READ);
     798           4 :     if (lobj == -1)
     799             :     {
     800             :         /* we assume lo_open() already set a suitable error message */
     801           0 :         return -1;
     802             :     }
     803             : 
     804             :     /*
     805             :      * create the file to be written to
     806             :      */
     807           4 :     fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666);
     808           4 :     if (fd < 0)
     809             :     {
     810             :         /* We must do lo_close before setting the errorMessage */
     811           0 :         int         save_errno = errno;
     812             : 
     813           0 :         (void) lo_close(conn, lobj);
     814           0 :         printfPQExpBuffer(&conn->errorMessage,
     815           0 :                           libpq_gettext("could not open file \"%s\": %s\n"),
     816             :                           filename,
     817             :                           strerror_r(save_errno, sebuf, sizeof(sebuf)));
     818           0 :         return -1;
     819             :     }
     820             : 
     821             :     /*
     822             :      * read in from the large object and write to the file
     823             :      */
     824         336 :     while ((nbytes = lo_read(conn, lobj, buf, LO_BUFSIZE)) > 0)
     825             :     {
     826         328 :         tmp = write(fd, buf, nbytes);
     827         328 :         if (tmp != nbytes)
     828             :         {
     829             :             /* We must do lo_close before setting the errorMessage */
     830           0 :             int         save_errno = errno;
     831             : 
     832           0 :             (void) lo_close(conn, lobj);
     833           0 :             (void) close(fd);
     834           0 :             printfPQExpBuffer(&conn->errorMessage,
     835           0 :                               libpq_gettext("could not write to file \"%s\": %s\n"),
     836             :                               filename,
     837             :                               strerror_r(save_errno, sebuf, sizeof(sebuf)));
     838           0 :             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           8 :     if (nbytes < 0 ||
     849           4 :         lo_close(conn, lobj) != 0)
     850             :     {
     851             :         /* assume lo_read() or lo_close() left a suitable error message */
     852           0 :         result = -1;
     853             :     }
     854             : 
     855             :     /* if we already failed, don't overwrite that msg with a close error */
     856           4 :     if (close(fd) != 0 && result >= 0)
     857             :     {
     858           0 :         printfPQExpBuffer(&conn->errorMessage,
     859           0 :                           libpq_gettext("could not write to file \"%s\": %s\n"),
     860           0 :                           filename, strerror_r(errno, sebuf, sizeof(sebuf)));
     861           0 :         result = -1;
     862             :     }
     863             : 
     864           4 :     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          46 : 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          46 :     if (!conn)
     886           0 :         return -1;
     887             : 
     888             :     /*
     889             :      * Allocate the structure to hold the functions OID's
     890             :      */
     891          46 :     lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs));
     892          46 :     if (lobjfuncs == NULL)
     893             :     {
     894           0 :         printfPQExpBuffer(&conn->errorMessage,
     895           0 :                           libpq_gettext("out of memory\n"));
     896           0 :         return -1;
     897             :     }
     898          46 :     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          46 :     if (conn->sversion >= 70300)
     906          46 :         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           0 :         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          46 :     res = PQexec(conn, query);
     935          46 :     if (res == NULL)
     936             :     {
     937           0 :         free(lobjfuncs);
     938           0 :         return -1;
     939             :     }
     940             : 
     941          46 :     if (res->resultStatus != PGRES_TUPLES_OK)
     942             :     {
     943           0 :         free(lobjfuncs);
     944           0 :         PQclear(res);
     945           0 :         printfPQExpBuffer(&conn->errorMessage,
     946           0 :                           libpq_gettext("query to initialize large object functions did not return data\n"));
     947           0 :         return -1;
     948             :     }
     949             : 
     950             :     /*
     951             :      * Examine the result and put the OID's into the struct
     952             :      */
     953         644 :     for (n = 0; n < PQntuples(res); n++)
     954             :     {
     955         598 :         fname = PQgetvalue(res, n, 0);
     956         598 :         foid = (Oid) atoi(PQgetvalue(res, n, 1));
     957         598 :         if (strcmp(fname, "lo_open") == 0)
     958          46 :             lobjfuncs->fn_lo_open = foid;
     959         552 :         else if (strcmp(fname, "lo_close") == 0)
     960          46 :             lobjfuncs->fn_lo_close = foid;
     961         506 :         else if (strcmp(fname, "lo_creat") == 0)
     962          46 :             lobjfuncs->fn_lo_creat = foid;
     963         460 :         else if (strcmp(fname, "lo_create") == 0)
     964          46 :             lobjfuncs->fn_lo_create = foid;
     965         414 :         else if (strcmp(fname, "lo_unlink") == 0)
     966          46 :             lobjfuncs->fn_lo_unlink = foid;
     967         368 :         else if (strcmp(fname, "lo_lseek") == 0)
     968          46 :             lobjfuncs->fn_lo_lseek = foid;
     969         322 :         else if (strcmp(fname, "lo_lseek64") == 0)
     970          46 :             lobjfuncs->fn_lo_lseek64 = foid;
     971         276 :         else if (strcmp(fname, "lo_tell") == 0)
     972          46 :             lobjfuncs->fn_lo_tell = foid;
     973         230 :         else if (strcmp(fname, "lo_tell64") == 0)
     974          46 :             lobjfuncs->fn_lo_tell64 = foid;
     975         184 :         else if (strcmp(fname, "lo_truncate") == 0)
     976          46 :             lobjfuncs->fn_lo_truncate = foid;
     977         138 :         else if (strcmp(fname, "lo_truncate64") == 0)
     978          46 :             lobjfuncs->fn_lo_truncate64 = foid;
     979          92 :         else if (strcmp(fname, "loread") == 0)
     980          46 :             lobjfuncs->fn_lo_read = foid;
     981          46 :         else if (strcmp(fname, "lowrite") == 0)
     982          46 :             lobjfuncs->fn_lo_write = foid;
     983             :     }
     984             : 
     985          46 :     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          46 :     if (lobjfuncs->fn_lo_open == 0)
     993             :     {
     994           0 :         printfPQExpBuffer(&conn->errorMessage,
     995           0 :                           libpq_gettext("cannot determine OID of function lo_open\n"));
     996           0 :         free(lobjfuncs);
     997           0 :         return -1;
     998             :     }
     999          46 :     if (lobjfuncs->fn_lo_close == 0)
    1000             :     {
    1001           0 :         printfPQExpBuffer(&conn->errorMessage,
    1002           0 :                           libpq_gettext("cannot determine OID of function lo_close\n"));
    1003           0 :         free(lobjfuncs);
    1004           0 :         return -1;
    1005             :     }
    1006          46 :     if (lobjfuncs->fn_lo_creat == 0)
    1007             :     {
    1008           0 :         printfPQExpBuffer(&conn->errorMessage,
    1009           0 :                           libpq_gettext("cannot determine OID of function lo_creat\n"));
    1010           0 :         free(lobjfuncs);
    1011           0 :         return -1;
    1012             :     }
    1013          46 :     if (lobjfuncs->fn_lo_unlink == 0)
    1014             :     {
    1015           0 :         printfPQExpBuffer(&conn->errorMessage,
    1016           0 :                           libpq_gettext("cannot determine OID of function lo_unlink\n"));
    1017           0 :         free(lobjfuncs);
    1018           0 :         return -1;
    1019             :     }
    1020          46 :     if (lobjfuncs->fn_lo_lseek == 0)
    1021             :     {
    1022           0 :         printfPQExpBuffer(&conn->errorMessage,
    1023           0 :                           libpq_gettext("cannot determine OID of function lo_lseek\n"));
    1024           0 :         free(lobjfuncs);
    1025           0 :         return -1;
    1026             :     }
    1027          46 :     if (lobjfuncs->fn_lo_tell == 0)
    1028             :     {
    1029           0 :         printfPQExpBuffer(&conn->errorMessage,
    1030           0 :                           libpq_gettext("cannot determine OID of function lo_tell\n"));
    1031           0 :         free(lobjfuncs);
    1032           0 :         return -1;
    1033             :     }
    1034          46 :     if (lobjfuncs->fn_lo_read == 0)
    1035             :     {
    1036           0 :         printfPQExpBuffer(&conn->errorMessage,
    1037           0 :                           libpq_gettext("cannot determine OID of function loread\n"));
    1038           0 :         free(lobjfuncs);
    1039           0 :         return -1;
    1040             :     }
    1041          46 :     if (lobjfuncs->fn_lo_write == 0)
    1042             :     {
    1043           0 :         printfPQExpBuffer(&conn->errorMessage,
    1044           0 :                           libpq_gettext("cannot determine OID of function lowrite\n"));
    1045           0 :         free(lobjfuncs);
    1046           0 :         return -1;
    1047             :     }
    1048             : 
    1049             :     /*
    1050             :      * Put the structure into the connection control
    1051             :      */
    1052          46 :     conn->lobjfuncs = lobjfuncs;
    1053          46 :     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           0 : 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           0 :     t = (uint32) (host64 >> 32);
    1072           0 :     swap.i32[0] = pg_hton32(t);
    1073             : 
    1074             :     /* Now the low order half */
    1075           0 :     t = (uint32) host64;
    1076           0 :     swap.i32[1] = pg_hton32(t);
    1077             : 
    1078           0 :     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           0 : 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           0 :     swap.i64 = net64;
    1096             : 
    1097           0 :     result = (uint32) pg_ntoh32(swap.i32[0]);
    1098           0 :     result <<= 32;
    1099           0 :     result |= (uint32) pg_ntoh32(swap.i32[1]);
    1100             : 
    1101           0 :     return result;
    1102             : }

Generated by: LCOV version 1.13