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

Generated by: LCOV version 1.11