diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..e72f527
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,30 @@
+language: c
+services:
+ - docker
+env:
+ - ORACLE_HOME=$HOME/instantclient_18_3 LD_LIBRARY_PATH=$ORACLE_HOME PATH=$ORACLE_HOME:$PATH
+addons:
+ apt:
+ update: true
+ packages:
+ - libpopt-dev
+sudo: required
+before_install:
+- echo "$DOCKER_PASSWORD" | docker login --username $DOCKER_USERNAME --password-stdin
+- docker run --detach
+ --privileged
+ --publish 127.0.0.1:1521:1521
+ --env ORACLE_PWD
+ maxsatula/agile:18.4.0-xe
+- |
+ (cd $HOME
+ for t in basic sdk sqlplus tools
+ do
+ f=instantclient-${t}-linux.x64-18.3.0.0.0dbru.zip
+ wget https://github.com/bumpx/oracle-instantclient/raw/master/$f
+ unzip -q $f && rm $f
+ done)
+- .travis/oracle/wait.sh
+- .travis/oracle/customize.sh
+before_script: autoreconf --install
+script: ./configure --with-oci=y --with-oci-include=$ORACLE_HOME/sdk/include --with-oci-lib=$ORACLE_HOME && make && .travis/test.sh
diff --git a/.travis/oracle/customize.sh b/.travis/oracle/customize.sh
new file mode 100755
index 0000000..3ab0d5a
--- /dev/null
+++ b/.travis/oracle/customize.sh
@@ -0,0 +1,36 @@
+#!/bin/sh -e
+
+sqlplus -L -S sys/$ORACLE_PWD@127.0.0.1:1521/XEPDB1 AS SYSDBA <
@@ -276,64 +276,3 @@ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- {description}
- Copyright (C) {year} {fullname}
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- {signature of Ty Coon}, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
\ No newline at end of file
diff --git a/ChangeLog b/ChangeLog
index 640a663..802b321 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2019-01-12 Max Satula
+
+* Allow connection as SYSASM, SYSBKP, SYSDGD, SYSKMT, and SYSRAC
+
+2017-07-16 Max Satula
+
+* Add man page
+
+2017-07-12 Max Satula
+
+* Fix crash in --ls when Oracle directory object points
+ to a nonexistent directory
+* Do not print column names if no files found in --ls
+
2016-04-18 Max Satula
* Fix compiler warnings
diff --git a/Makefile.am b/Makefile.am
index ac2609b..b301451 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,6 @@
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = progressmeter yesno src
dist_noinst_SCRIPTS = updateforeigns.sh win/build.cmd
-dist_noinst_DATA = m4/ax_lib_oracle_oci.m4.patch win/README.md
+dist_noinst_DATA = README.md win/README.md
dist_noinst_HEADERS = win/include/config.h win/include/unistd.h
+dist_man1_MANS = ocp.1
diff --git a/NEWS b/NEWS
index c0cd62a..4e5a2e0 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,11 @@
+ocp 0.3
+
+* added man page
+* added --sysasm, --sysbkp, --sysdgd, --syskmt, and --sysrac options
+ to connect to Oracle with roles introduced in 12c
+
+----------------------------------------------------------------------------
+
ocp 0.2
* added --sysdba and --sysoper options to connect to Oracle accordingly
diff --git a/README.md b/README.md
index 463bb58..6ce5877 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,9 @@
ocp
===
+[![Build Status](https://travis-ci.org/maxsatula/ocp.svg?branch=develop)](https://travis-ci.org/maxsatula/ocp)
+[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=P3D68AUUXLNQU&lc=US&item_number=github%2docp¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted)
+
`ocp` is a command line tool to download and upload files from/to Oracle Database directories (e.g. DATA_PUMP_DIR)
using Oracle SQL Net connection only. Hence no other kind of filesystem access required to a database server.
diff --git a/configure.ac b/configure.ac
index 4af2918..272b792 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.63])
-AC_INIT([ocp],[0.2],[Max Satula ])
+AC_INIT([ocp],[0.3],[Max Satula ])
AM_INIT_AUTOMAKE
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR([src/ocp.h])
@@ -20,18 +20,18 @@ AC_SYS_LARGEFILE
# Checks for libraries.
AX_LIB_ORACLE_OCI
if test "x${HAVE_ORACLE_OCI}" = xno; then
- AC_MSG_ERROR([----------------------------------------------
+ AC_MSG_ERROR([
+----------------------------------------------
This software requires Oracle installation
1. Have you set \$ORACLE_HOME?
2. Check if Oracle Home 64/32-bit is OK
3. Check whether native compiler (not GCC)
is used for non-Linux platforms
-----------------------------------------------)])
+----------------------------------------------])
fi
AC_SUBST([ORACLE_OCI_CFLAGS])
AC_SUBST([ORACLE_OCI_LDFLAGS])
-#AC_SEARCH_LIBS([OCIEnvCreate], [clntsh])
AC_SEARCH_LIBS([poptGetContext], [popt])
AC_SEARCH_LIBS([deflateInit2_], [z])
AC_SEARCH_LIBS([clock_gettime], [rt])
diff --git a/m4/ax_lib_oracle_oci.m4 b/m4/ax_lib_oracle_oci.m4
index 9a99b97..a08a7b0 100644
--- a/m4/ax_lib_oracle_oci.m4
+++ b/m4/ax_lib_oracle_oci.m4
@@ -26,7 +26,7 @@
# NOTE: These options described above do not take yes|no values. If 'yes'
# value is passed, then WARNING message will be displayed, 'no' value, as
# well as the --without-oci-* variations will cause the macro to not check
-# enything.
+# anything.
#
# This macro calls:
#
@@ -48,7 +48,7 @@
# and this notice are preserved. This file is offered as-is, without any
# warranty.
-#serial 13
+#serial 16
AC_DEFUN([AX_LIB_ORACLE_OCI],
[
@@ -156,8 +156,11 @@ Please, locate Oracle directories using --with-oci or \
dnl Depending on later Oracle version detection,
dnl -lnnz10 flag might be removed for older Oracle < 10.x
saved_LDFLAGS="$LDFLAGS"
- oci_ldflags="-L$oracle_lib_dir -lclntsh"
+ saved_LIBS="$LIBS"
+ oci_ldflags="-L$oracle_lib_dir"
+ oci_libs="-lclntsh"
LDFLAGS="$LDFLAGS $oci_ldflags"
+ LIBS="$LIBS $oci_libs"
dnl
dnl Check OCI headers
@@ -170,11 +173,11 @@ Please, locate Oracle directories using --with-oci or \
[[
#if defined(OCI_MAJOR_VERSION)
#if OCI_MAJOR_VERSION == 10 && OCI_MINOR_VERSION == 2
-// Oracle 10.2 detected
+/* Oracle 10.2 detected */
#endif
#elif defined(OCI_V7_SYNTAX)
-// OK, older Oracle detected
-// TODO - mloskot: find better macro to check for older versions;
+/* OK, older Oracle detected */
+/* TODO - mloskot: find better macro to check for older versions; */
#else
# error Oracle oci.h header not found
#endif
@@ -214,7 +217,7 @@ if (envh) OCIHandleFree(envh, OCI_HTYPE_ENV);
]]
)],
[
- ORACLE_OCI_LDFLAGS="$oci_ldflags"
+ ORACLE_OCI_LDFLAGS="$oci_ldflags $oci_libs"
oci_lib_found="yes"
AC_MSG_RESULT([yes])
],
@@ -228,6 +231,7 @@ if (envh) OCIHandleFree(envh, OCI_HTYPE_ENV);
CPPFLAGS="$saved_CPPFLAGS"
LDFLAGS="$saved_LDFLAGS"
+ LIBS="$saved_LIBS"
fi
dnl
diff --git a/m4/ax_lib_oracle_oci.m4.patch b/m4/ax_lib_oracle_oci.m4.patch
deleted file mode 100644
index 7e12a8d..0000000
--- a/m4/ax_lib_oracle_oci.m4.patch
+++ /dev/null
@@ -1,38 +0,0 @@
---- ax_lib_oracle_oci.m4.orig 2015-03-29 12:02:04.246725378 -0400
-+++ ax_lib_oracle_oci.m4 2015-03-29 12:02:43.611724292 -0400
-@@ -163,7 +163,7 @@
- dnl
- AC_MSG_CHECKING([for Oracle OCI headers in $oracle_include_dir])
-
-- AC_LANG_PUSH(C++)
-+ AC_LANG_PUSH(C)
- AC_COMPILE_IFELSE([
- AC_LANG_PROGRAM([[@%:@include ]],
- [[
-@@ -194,7 +194,7 @@
- AC_MSG_RESULT([not found])
- ]
- )
-- AC_LANG_POP([C++])
-+ AC_LANG_POP([C])
-
- dnl
- dnl Check OCI libraries
-@@ -203,7 +203,7 @@
-
- AC_MSG_CHECKING([for Oracle OCI libraries in $oracle_lib_dir])
-
-- AC_LANG_PUSH(C++)
-+ AC_LANG_PUSH(C)
- AC_LINK_IFELSE([
- AC_LANG_PROGRAM([[@%:@include ]],
- [[
-@@ -222,7 +222,7 @@
- AC_MSG_RESULT([not found])
- ]
- )
-- AC_LANG_POP([C++])
-+ AC_LANG_POP([C])
- fi
-
- CPPFLAGS="$saved_CPPFLAGS"
diff --git a/ocp.1 b/ocp.1
new file mode 100644
index 0000000..81168e8
--- /dev/null
+++ b/ocp.1
@@ -0,0 +1,587 @@
+.TH OCP 1 2019-01-12 GNU "ocp man page"
+
+.SH NAME
+ocp \- copy a file from/to an Oracle database server
+
+.SH SYNOPSIS
+.BI ocp " CONNECTION ORACLEDIRECTORY" : "SOURCE TARGET"
+.RI [ OPTIONS " ...]"
+
+.PP
+.BI ocp " CONNECTION SOURCE ORACLEDIRECTORY" :\c
+.RI [ TARGET "] [" OPTIONS " ...]"
+
+.PP
+.BI ocp " CONNECTION " \-\-list\-directories
+.RI [ OPTIONS " ...]"
+
+.PP
+.BI ocp " CONNECTION " \-\-ls= ORACLEDIRECTORY
+.RI [ PATTERN " ...] [" OPTIONS " ...]"
+
+.PP
+.BI ocp " CONNECTION " \-\-rm " ORACLEDIRECTORY" : FILENAME
+.RI [ OPTIONS " ...]"
+
+.PP
+.BI ocp " CONNECTION " \-\-gzip " ORACLEDIRECTORY" : FILENAME
+.RI [ OPTIONS " ...]"
+
+.PP
+.BI ocp " CONNECTION " \-\-gunzip " ORACLEDIRECTORY" : FILENAME
+.RI [ OPTIONS " ...]"
+
+.PP
+.BI ocp " CONNECTION "
+.BR \-\-install | \-\-deinstall
+.RI [ OPTIONS " ...]"
+
+.PP
+.BR "ocp \-?" | \-\-help | \-\-usage
+
+.SH DESCRIPTION
+.PP
+.B ocp
+is a command line tool to transfer files between a local system and an
+Oracle database server via database connection.
+.PP
+Here are Oracle privileges required in most cases.
+.IP \(bu
+CREATE SESSION
+.IP \(bu
+READ ON DIRECTORY
+.I ORACLEDIRECTORY
+.IP \(bu
+WRITE ON DIRECTORY
+.I ORACLEDIRECTORY
+.IP \(bu
+EXECUTE ON SYS.UTL_FILE, which is granted to PUBLIC by default.
+.PP
+Some special cases require additional privileges, which are described
+later.
+.PP
+.B ocp
+can run in multiple modes, as described below.
+
+.SS File transfer
+File transfer is a primary purpose of
+.BR ocp .
+When
+.IR SOURCE " and " TARGET
+are specified as arguments, then
+.B ocp
+copies a file.
+
+.PP
+If
+.I ORACLEDIRECTORY
+with a following colon (:) precedes
+.IR SOURCE ,
+then a file is searched on a database server and downloaded to a path
+specified as
+.IR TARGET .
+Correspondingly, if
+.I ORACLEDIRECTORY
+with a following colon precedes
+.IR TARGET ,
+then a local
+.I SOURCE
+file is uploaded to a database server.
+
+.PP
+A local file can be either specified as a simple filename, a relative
+or an absolute path. For a remote side, only Oracle directory name and
+filename separated by a colon are allowed.
+
+.PP
+In download mode a local target may refer to a directory, in this case
+a file is copied with the name unchanged. For example, a simple dot
+.RB ( . )
+tells to copy a file into a current directory with the same name.
+
+.PP
+In upload mode a target file
+name is optional, but the colon must be specified after an Oracle
+directory name. If remote filename is omitted, a file is copied with
+the name unchanged.
+
+.PP
+To be able to use
+.B ocp
+in a pipeline, a dash (\-) can be specified as a local filename. That
+means standard input is used during upload, or standard output is used
+during download. In this case remote filename cannot be omitted.
+
+.SS File transfer with on the fly compression
+Similar to a regular file transfer, but the file contents is
+compressed on the source site (either local or remote) before being
+transferred over a network to target, where it is immediately
+decompressed back to original. Therefore, compressed data is used
+temporary just to reduce network traffic. That might be a good option
+for slow networks, but where extra CPU load is affordable. In both
+upload and download modes, the whole compressed file is temporarily
+placed into a Temporary LOB object, so make sure that TEMP tablespace
+is large enough.
+
+.PP
+On the fly compression turns on when any of the following switches
+specified during transfer:
+.BR \-1 .. \-9 , \-\-fast , \-\-best .
+
+.PP
+On the fly compression requires EXECUTE ON SYS.UTL_COMPRESS privilege,
+which is granted to PUBLIC by default.
+
+.SS List Oracle directories
+To list all the Oracle directories accessible to a database user, use
+.B \-\-list\-directories
+option.
+
+.PP
+Output is one Oracle directory per line, with two characters
+indicating privileges, Oracle directory name, and the full path name
+of the operating system directory of the database server, enclosed in
+parentheses.
+
+.PP
+The first character in each line tells whether a database user can
+read the directory, and its meaning is as follows.
+.TP
+.B \-
+no read privilege
+.TP
+.B r
+READ ON DIRECTORY
+.TP
+.B R
+READ ON DIRECTORY WITH GRANT OPTION
+
+.PP
+Similarly, the second character in each line tells whether a database user can
+write into the directory, and its meaning is as follows.
+.TP
+.B \-
+no write privilege
+.TP
+.B w
+WRITE ON DIRECTORY
+.TP
+.B W
+WRITE ON DIRECTORY WITH GRANT OPTION
+
+.SS List files in Oracle directory
+To list files of an Oracle directory, use
+.B \-\-ls
+option and specify an Oracle directory name as an argument.
+Optionally, one or more file matching patterns can be specified as
+additional command line arguments to filter an output.
+.PP
+Beware while using an asterisk wildcard
+.RB ( * )
+in patterns, as shell may resolve it with some filename on a local
+system before passing to
+.BR ocp ,
+so most likely asterisks must be escaped by a backslash in UNIX
+systems command line.
+.PP
+Java permissions are required.
+.PP
+To be able to list filenames, run as DBA
+.PP
+.BI "dbms_java.grant_permission( '" user "', 'SYS:java.io.FilePermission', '" path "', 'read' )"
+.PP
+The second permission is recommended but not mandatory. It allows to
+view file sizes and last modified times, not just filenames. Also, it
+allowes to calculate MD5 and SHA1 hashes. If you need any of these,
+run as DBA
+.PP
+.BI "dbms_java.grant_permission( '" user "', 'SYS:java.io.FilePermission', '" path "/*', 'read' )"
+.PP
+Where
+.I user
+is an Oracle user and
+.I path
+is the full path name of the operating system directory of the
+database server.
+
+.PP
+Listing files in Oracle directory requires some objects to be created
+in the Oracle database beforehand, which can be done with help of
+.B \-\-install
+option.
+
+.SS Remove file from Oracle directory
+Remove a file from a database server. Use
+.B \-\-rm
+and specify Oracle directory name and filename separated by a colon.
+
+.SS Compress and decompress file in Oracle directory
+Files in Oracle directory can be remotely compressed and decompressed
+using
+.BR gzip (1)
+compatible algorithm. The operation runs on a Database server and does
+not involve any file transfer over network.
+
+When compressing
+.RB ( \-\-gzip " option),"
+a
+.B .gz
+suffix is added to a filename.
+Conversely, when decompressing
+.RB ( \-\-gunzip " option),"
+the suffix is removed.
+
+.PP
+The whole compressed file is temporarily placed into a Temporary LOB
+object, so make sure that TEMP tablespace is large enough.
+
+.PP
+Compression and decompression require EXECUTE ON SYS.UTL_COMPRESS
+privilege, which is granted to PUBLIC by default.
+
+.SS Supporting objects maintenance
+List files in Oracle directory is the only feature that requires some
+supporting objects to reside in a database.
+
+.PP
+Thus, before using
+.BR \-\-ls ,
+run
+.B ocp
+with
+.B \-\-install
+option first to install those objects.
+It is safe to run
+.BR ocp " with " \-\-install
+multiple times when objects are already in the database, as it drops
+and recreates them.
+The objects are installed locally in the database user schema, which
+is why these objects have to be installed for every Oracle account
+which intends to list files in Oracle directory, even if these
+accounts are in the same database.
+
+CREATE TYPE and CREATE PROCEDURE privileges are required at the time
+of supporting objects installation.
+
+.PP
+Once
+.BR \-\-ls
+is not needed anymore,
+.B \-\-deinstall
+option may be used to clean up the mess by dropping the supported
+objects previously created by
+.BR \-\-install
+option.
+
+.SS Monitoring
+.PP
+.B ocp
+activities may be monitored in Oracle database.
+MODULE column of V$SESSION view has a value of \(aqocp\(aq, which is one of the ways how
+.B ocp
+sessions can be identified,
+and ACTION column points out what exact kind of acivity is happening.
+Also, whenever (de-)compression is involved, the progress can be
+tracked via V$SESSION_LONGOPS view.
+
+.SS License warning
+.PP
+Whenever compression or decompression is involved, either standalone or as a part of file transfer,
+.B ocp
+uses UTL_COMPRESS package. There is controversy whether use of this
+package requries a license for Oracle Advanced Compression option,
+please contact your Oracle representative for details.
+Author of
+.B ocp
+program is not responsible for any legal consequences
+caused by possible Oracle licensing violation while using
+.BR ocp .
+
+.SH OPTIONS
+
+.TP
+.B \-b \-\-background
+Submit an Oracle Scheduler job and exit immediately.
+.B ocp
+does not wait until (de-)compression finishes.
+Can only be specified together with either
+.B \-\-gzip
+or
+.BR \-\-gunzip .
+Requires CREATE JOB privilege.
+
+.TP
+.B \-c \-\-continue
+Continue copying a partially transferred file. This is useful when
+you want to finish up a transfer started by a previous instance of
+.BR ocp ,
+or by another program.
+Implies
+.B \-\-keep\-partial
+and overrides previous
+.B \-f \-i
+options.
+Applicable only for file transfer mode, with or without on the fly
+compression.
+
+.TP
+.B \-f \-\-force
+If a destination file already exists, overwrite it without asking.
+Overrides previous
+.B \-i \-c
+options.
+Applicable for file transfer mode, with or without on the fly
+compression, and for stand alone compression and decompression.
+
+.TP
+.B \-i \-\-interactive
+Prompt before overwrite (overrides previous
+.B \-f \-c
+options).
+Applicable for file transfer mode, with or without on the fly
+compression, and for stand alone compression and decompression.
+
+.TP
+.B \-k \-\-keep
+Keep (do not delete) source file after (de-)compression finishes.
+Can only be used with either
+.BR \-\-gzip " or " \-\-gunzip .
+
+.TP
+.B \-\-keep\-partial
+If an error or another sort of interruption occurred during file
+transfer, do not delete partially transferred file on
+destination. Keeping an incomplete file may be useful to retry transfer with
+.B \-\-continue
+opton.
+Applicable only for file transfer mode, with or without on the fly
+compression.
+
+.TP
+.B \-\-md5
+Calculate MD5 hashes on listed files and display them instead of size
+and last modified time columns.
+Can only be used with
+.BR \-\-ls .
+
+.TP
+.B \-\-sha1
+Calculate SHA1 hashes on listed files and display them instead of size
+and last modified time columns.
+Can only be used with
+.BR \-\-ls .
+
+.TP
+.B \-\-sysdba
+Connect to a database as SYSDBA
+.TP
+.B \-\-sysoper
+Connect to a database as SYSOPER
+.TP
+.B \-\-sysasm
+Connect to a database as SYSASM
+.TP
+.B \-\-sysbkp
+Connect to a database as SYSBKP
+.TP
+.B \-\-sysdgd
+Connect to a database as SYSDGD
+.TP
+.B \-\-syskmt
+Connect to a database as SYSKMT
+.TP
+.B \-\-sysrac
+Connect to a database as SYSRAC
+
+.TP
+.B \-\-usage
+Display brief usage message
+
+.TP
+.BI \- # " \-\-fast \-\-best"
+Regulate the speed of compression using the specified digit
+.IR # ,
+where
+.B \-1
+or
+.B \-\-fast
+indicates the fastest compression method (less compression)
+and
+.B \-9
+or
+.B \-\-best
+indicates the slowest compression method (best compression).
+The default compression level is
+.BR \-6
+(that is, biased towards high compression at expense of speed).
+Can only be specified for file transfer or when using
+.BR \-\-gzip .
+
+.TP
+.B \-? \-\-help
+Show help message
+
+.SH "EXIT STATUS"
+
+.IP 0
+Success
+
+.IP 1
+Error in command line arguments
+
+.IP 2
+Error in OCI object initialization
+
+.IP 3
+Failed to login to a database
+
+.IP 4
+Local filesystem related error
+
+.IP 5
+Oracle error
+
+.IP 6
+(De-)compression error on a local side
+
+.IP 7
+Error listing files in Oracle directory
+
+.SH ENVIRONMENT
+
+.PP
+Since
+.B ocp
+connects to an Oracle database, it requires Oracle client installed on
+the system. Either full or Instant Client is good.
+
+.SH BUGS
+
+When downloading a file through SHARED server connection, Oracle may
+give corrupt data. Upload works fine. Nonetheless, it is poor practice
+to use SHARED server for file transfer.
+.B ocp
+protects from download attempts via SHARED server connection whenever
+possible. The best option is to use DEDICATED server connection
+instead, however if by some reason environment does not allow that,
+use on the fly compression (does not matter which compression method)
+as a workaround.
+
+.SH EXAMPLES
+
+.PP
+.B ocp scott/tiger@orcl DATA_PUMP_DIR:myfile.dmp . \-i
+.PP
+Connect as user
+.B scott
+with password
+.B tiger
+using connection string
+.B orcl
+and download
+.B myfile.dmp
+from Oracle directory
+.B DATA_PUMP_DIR
+to a current directory of the local system. If a file already exists
+in the current directory, prompt before overwrite.
+
+.PP
+.B ocp scott@orcl file2.dmp DATA_PUMP_DIR: \-c
+.PP
+As user
+.B scott
+connect to
+.B orcl
+database, ask for a password interactively,
+and upload
+.B file2.dmp
+to Oracle directory
+.B DATA_PUMP_DIR\c
+, keeping the same filename. If a file already exists on the Oracle
+side, assume it is partially uploaded file and resume transfer
+operation from the point it was interrupted.
+
+.PP
+.B ocp /@oraclehost:1521/mydb.example.com MY_PUMP_DIR:source.dmp ~/Downloads/dest.dmp \-9
+.PP
+Use External Password Store (Oracle Wallet) for database
+authentication and easy connect naming method, download
+.B source.dmp
+and save it as
+.B dest.dmp
+on a local file system in
+.B Downloads
+subdirectory of the home directory. Use best on the fly compression
+method.
+
+.PP
+.B ocp /@canada SRC_DIR:myfile.dmp \- | ocp /@australia \- DEST_DIR:myfile.dmp
+.PP
+If
+.BR canada " and " australia
+databases cannot access each other over network directly, two
+.B ocp
+invocations can be pipelined on a third intermediate system which have
+connection to both databases, as shown above.
+
+.PP
+.B ocp user123/weakpassword@mydb \-\-list-directories
+.PP
+List Oracle directories and access levels for
+.B user123
+database user.
+
+.PP
+.B ocp /@mydb \-\-install
+.PP
+.B ocp /@mydb \-\-ls=DATA_PUMP_DIR bkp_201[0\-5]\e*.dmp expdp_{prod,test,qa,dev}.dmp
+.PP
+Install supporting objects before the first use of
+.B \-\-ls
+and then list files (with sizes and last modified times, if user has privileges)
+matching two patterns.
+
+.PP
+.B ocp /@mydb \-\-ls=DATA_PUMP_DIR \-\-sha1
+.PP
+List all files in
+.B DATA_PUMP_DIR
+Oracle directory and calculate their SHA1 hashes.
+
+.PP
+.B ocp sys/oracle@proddb \-\-gzip MY_DIR2:bigfile.dmp \-f \-\-sysdba
+.PP
+Connect as
+.B SYS
+user with
+.B SYSDBA
+role and compress
+.B bigfile.dmp
+file in
+.B MY_DIR2
+Oracle directory using default compression method into
+.BR bigfile.dmp.gz .
+If file
+.B bigfile.dmp.gz
+already exists, overwrite it without asking.
+Wait until Oracle server completes compression.
+
+.PP
+.B ocp /@proddb \-\-gunzip DATA_PUMP_DIR:another_file.dmp.gz \-k \-b
+.PP
+Submit an Oracle Scheduler job to decompress
+.B another_file.dmp.gz
+into
+.B another_file.dmp
+and exit immediately without waiting for completion. Once job
+finishes decompression, it will not delete an original file
+.BR another_file.dmp.gz .
+
+.SH AUTHOR
+
+Written by Max Satula.
+
+.SH "SEE ALSO"
+.UR https://github.com/maxsatula/ocp
+Project page
+.UE
diff --git a/progressmeter/atomicio.c b/progressmeter/atomicio.c
index 336bd83..d61f09b 100644
--- a/progressmeter/atomicio.c
+++ b/progressmeter/atomicio.c
@@ -35,8 +35,7 @@
/*
* Modified by Max Satula by adding of an extra include below
*/
-#define __need_IOV_MAX
-#include
+#define __USE_XOPEN
#include
#include "atomicio.h"
diff --git a/progressmeter/atomicio.c.patch b/progressmeter/atomicio.c.patch
index f501421..555b2da 100644
--- a/progressmeter/atomicio.c.patch
+++ b/progressmeter/atomicio.c.patch
@@ -1,14 +1,13 @@
--- atomicio.c.orig 2015-03-29 12:02:02.508726981 -0400
+++ atomicio.c 2015-03-29 11:54:55.114741280 -0400
-@@ -32,6 +32,11 @@
+@@ -32,6 +32,10 @@
#include
#include
#include
+/*
+ * Modified by Max Satula by adding of an extra include below
+ */
-+#define __need_IOV_MAX
-+#include
++#define __USE_XOPEN
#include
#include "atomicio.h"
diff --git a/progressmeter/atomicio.h b/progressmeter/atomicio.h
index 0d728ac..8b3cc6e 100644
--- a/progressmeter/atomicio.h
+++ b/progressmeter/atomicio.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: atomicio.h,v 1.11 2010/09/22 22:58:51 djm Exp $ */
+/* $OpenBSD: atomicio.h,v 1.12 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2006 Damien Miller. All rights reserved.
@@ -29,6 +29,8 @@
#ifndef _ATOMICIO_H
#define _ATOMICIO_H
+struct iovec;
+
/*
* Ensure all of data on socket comes through. f==read || f==vwrite
*/
diff --git a/progressmeter/misc.c b/progressmeter/misc.c
index 50a77c1..36bc740 100644
--- a/progressmeter/misc.c
+++ b/progressmeter/misc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.c,v 1.107 2016/11/30 00:28:31 dtucker Exp $ */
+/* $OpenBSD: misc.c,v 1.136 2018/12/27 03:25:25 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2005,2006 Damien Miller. All rights reserved.
@@ -32,13 +32,18 @@
#include
#include
+void
+monotime_ts(struct timespec *ts)
+{
+ /*if (*/clock_gettime(CLOCK_MONOTONIC, ts)/* != 0)
+ fatal("clock_gettime: %s", strerror(errno))*/;
+}
+
double
monotime_double(void)
{
struct timespec ts;
- /*if (*/clock_gettime(CLOCK_MONOTONIC, &ts)/* != 0)
- fatal("clock_gettime: %s", strerror(errno))*/;
-
- return (ts.tv_sec + (double)ts.tv_nsec / 1000000000);
+ monotime_ts(&ts);
+ return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0;
}
diff --git a/src/compress.c b/src/compress.c
index 10c5cb4..d90567e 100644
--- a/src/compress.c
+++ b/src/compress.c
@@ -75,7 +75,7 @@ void Compress(struct ORACLEALLINONE *oraAllInOne, char* pDirectory, int compress
#endif
if (ociResult)
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to compress file in oracle directory\n");
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to compress file in oracle directory\n");
ReleaseStmt(oraAllInOne);
SetSessionAction(oraAllInOne, 0);
@@ -121,7 +121,7 @@ void Uncompress(struct ORACLEALLINONE *oraAllInOne, char* pDirectory, int isKeep
#endif
if (ociResult)
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to uncompress file in oracle directory\n");
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to uncompress file in oracle directory\n");
ReleaseStmt(oraAllInOne);
SetSessionAction(oraAllInOne, 0);
@@ -154,7 +154,7 @@ void SubmitCompressJob(struct ORACLEALLINONE *oraAllInOne, char* pDirectory, int
PrepareStmtAndBind(oraAllInOne, &oraStmtCompress);
if (ExecuteStmt(oraAllInOne))
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to submit a compression job\n");
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to submit a compression job\n");
printf("Submitted a job %s\n", vJobName);
ReleaseStmt(oraAllInOne);
@@ -183,7 +183,7 @@ void SubmitUncompressJob(struct ORACLEALLINONE *oraAllInOne, char* pDirectory, i
PrepareStmtAndBind(oraAllInOne, &oraStmtUncompress);
if (ExecuteStmt(oraAllInOne))
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to submit a decompression job\n");
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to submit a decompression job\n");
printf("Submitted a job %s\n", vJobName);
ReleaseStmt(oraAllInOne);
diff --git a/src/exitstatus.h b/src/exitstatus.h
new file mode 100644
index 0000000..b86f7a8
--- /dev/null
+++ b/src/exitstatus.h
@@ -0,0 +1,35 @@
+/*****************************************************************************
+Copyright (C) 2018 Max Satula
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+*****************************************************************************/
+
+#ifndef _EXITSTATUS_H_
+#define _EXITSTATUS_H_
+
+/* Program return values */
+
+#define RET_DONOTEXIT -1 /* Print error message but do not exit program */
+#define RET_OK 0 /* Success */
+#define RET_USAGE 1 /* Error in command line arguments */
+#define RET_OCIINIT 2 /* Error in OCI object initialization */
+#define RET_LOGIN 3 /* Failed to login to a database */
+#define RET_FS 4 /* Local filesystem related error */
+#define RET_ORA 5 /* Oracle error */
+#define RET_ZLIB 6 /* LIBZ error */
+#define RET_LS 7 /* Error listing files in Oracle directory */
+
+#endif
diff --git a/src/j_ocp_DirList.java b/src/j_ocp_DirList.java
index be32555..b98c940 100644
--- a/src/j_ocp_DirList.java
+++ b/src/j_ocp_DirList.java
@@ -20,7 +20,7 @@
public class j_ocp_DirList
{
public static ARRAY getList(String directory, String pattern, String hashAlgorithm)
- throws SQLException, NoSuchAlgorithmException
+ throws SQLException, NoSuchAlgorithmException, FileNotFoundException
{
Connection conn = new OracleDriver().defaultConnection();
ArrayDescriptor arrayDescriptor = new ArrayDescriptor("T_OCP_FILE_LIST", conn);
@@ -42,6 +42,9 @@ public boolean accept(File dir, String name) {
} else {
files = path.listFiles();
}
+ if (files == null) {
+ throw new FileNotFoundException(directory);
+ }
Object[][] result = new Object[files.length][4];
for (int i = 0; i < files.length; i++)
{
diff --git a/src/j_ocp_DirList.text b/src/j_ocp_DirList.text
index 95e3a22..5f6ca8b 100644
--- a/src/j_ocp_DirList.text
+++ b/src/j_ocp_DirList.text
@@ -20,7 +20,7 @@ import java.util.regex.PatternSyntaxException;\n\
public class j_ocp_DirList\n\
{\n\
public static ARRAY getList(String directory, String pattern, String hashAlgorithm)\n\
- throws SQLException, NoSuchAlgorithmException\n\
+ throws SQLException, NoSuchAlgorithmException, FileNotFoundException\n\
{\n\
Connection conn = new OracleDriver().defaultConnection();\n\
ArrayDescriptor arrayDescriptor = new ArrayDescriptor(\"T_OCP_FILE_LIST\", conn);\n\
@@ -42,6 +42,9 @@ public class j_ocp_DirList\n\
} else {\n\
files = path.listFiles();\n\
}\n\
+ if (files == null) {\n\
+ throw new FileNotFoundException(directory);\n\
+ }\n\
Object[][] result = new Object[files.length][4];\n\
for (int i = 0; i < files.length; i++)\n\
{\n\
diff --git a/src/ls.c b/src/ls.c
index 60f844a..61909e0 100644
--- a/src/ls.c
+++ b/src/ls.c
@@ -85,24 +85,6 @@ SELECT t.file_name,\n\
SetSessionAction(oraAllInOne, "LS");
PrepareStmtAndBind(oraAllInOne, &oraStmtLs);
- if (hashAlgorithm != HASH_NONE)
- {
- printf("Contents of %s directory\n\
-%-40s %s hash\n\
----------------------------------------- ",
- pDirectory, "File Name", vHashAlgorithm);
- for (j = 0; j < hashLength*2; j++)
- printf("-");
- printf("\n");
- }
- else
- {
- printf("Contents of %s directory\n\
-%-40s %-12s %s\n\
----------------------------------------- ------------ -------------------\n",
- pDirectory, "File Name", " Size", "Last Modified");
- }
-
i = 0;
totalBytes = 0;
foundKnownSize = foundUnknownSize = 0;
@@ -111,6 +93,17 @@ SELECT t.file_name,\n\
{
if (hashAlgorithm != HASH_NONE)
{
+ if (!i)
+ {
+ printf("Contents of %s directory\n\
+%-40s %s hash\n\
+---------------------------------------- ",
+ pDirectory, "File Name", vHashAlgorithm);
+ for (j = 0; j < hashLength*2; j++)
+ printf("-");
+ printf("\n");
+ }
+
printf("%-40s ",
vFileName);
if (oraStmtLs.oraDefines[3].indp != -1)
@@ -122,25 +115,37 @@ SELECT t.file_name,\n\
}
printf("\n");
}
- else if (oraStmtLs.oraDefines[1].indp != -1 &&
- oraStmtLs.oraDefines[2].indp != -1)
- {
- printf("%-40s %12lld %02d/%02d/%d %02d:%02d:%02d\n",
- vFileName,
- (long long)vBytes,
- (int)vLastModified[2],
- (int)vLastModified[3],
- ((int)vLastModified[0]-100) * 100 + ((int)vLastModified[1] - 100),
- (int)vLastModified[4] - 1,
- (int)vLastModified[5] - 1,
- (int)vLastModified[6] - 1);
- totalBytes += vBytes;
- foundKnownSize = 1;
- }
else
{
- printf("%-40s (no access) (no access)\n", vFileName);
- foundUnknownSize = 1;
+ if (!i)
+ {
+ printf("Contents of %s directory\n\
+%-40s %-12s %s\n\
+---------------------------------------- ------------ -------------------\n",
+ pDirectory, "File Name", " Size", "Last Modified");
+ }
+
+ if (oraStmtLs.oraDefines[1].indp != -1 &&
+ oraStmtLs.oraDefines[2].indp != -1)
+ {
+
+ printf("%-40s %12lld %02d/%02d/%d %02d:%02d:%02d\n",
+ vFileName,
+ (long long)vBytes,
+ (int)vLastModified[2],
+ (int)vLastModified[3],
+ ((int)vLastModified[0]-100) * 100 + ((int)vLastModified[1] - 100),
+ (int)vLastModified[4] - 1,
+ (int)vLastModified[5] - 1,
+ (int)vLastModified[6] - 1);
+ totalBytes += vBytes;
+ foundKnownSize = 1;
+ }
+ else
+ {
+ printf("%-40s (no access) (no access)\n", vFileName);
+ foundUnknownSize = 1;
+ }
}
i++;
@@ -149,18 +154,21 @@ SELECT t.file_name,\n\
}
if (ociResult != OCI_NO_DATA)
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to list files in oracle directory\n");
+ ExitWithError(oraAllInOne, RET_LS, ERROR_OCI, "Failed to list files in oracle directory\n");
- if (hashAlgorithm == HASH_NONE)
+ if (i)
{
- if (i)
- printf("---------------------------------------- ------------ -------------------\n");
- printf("%5d File(s)", i);
- if (!foundKnownSize && foundUnknownSize)
- printf("\n");
- else
- printf(" %39lld%s\n", totalBytes, foundUnknownSize ? "+" : "");
+ if (hashAlgorithm == HASH_NONE)
+ {
+ printf("---------------------------------------- ------------ -------------------\n%5d File(s)", i);
+ if (!foundKnownSize && foundUnknownSize)
+ printf("\n");
+ else
+ printf(" %39lld%s\n", totalBytes, foundUnknownSize ? "+" : "");
+ }
}
+ else
+ printf("No files found\n");
ReleaseStmt(oraAllInOne);
SetSessionAction(oraAllInOne, 0);
diff --git a/src/lsdir.c b/src/lsdir.c
index 3050607..8f478ff 100644
--- a/src/lsdir.c
+++ b/src/lsdir.c
@@ -81,7 +81,7 @@ SELECT d.directory_name,\n\
}
if (ociResult != OCI_NO_DATA)
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to list oracle directories\n");
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to list oracle directories\n");
ReleaseStmt(oraAllInOne);
SetSessionAction(oraAllInOne, 0);
diff --git a/src/main.c b/src/main.c
index b104e7f..62c8412 100644
--- a/src/main.c
+++ b/src/main.c
@@ -65,8 +65,7 @@ void ExitWithUsage(poptContext* poptcon)
#else
fprintf(stderr, "Try to run with --help or --usage option\n");
#endif
- exit(1);
- /* 1 - Error in command line arguments */
+ exit(RET_USAGE);
}
void SplitToDirectoryAndFileName(poptContext *poptcon, char* pDirectory, char* pFileName)
@@ -109,14 +108,14 @@ void ConfirmOverwrite(struct ORACLEALLINONE *oraAllInOne, struct PROGRAM_OPTIONS
switch (programOptions->transferMode)
{
case TRANSFER_MODE_FAIL:
- ExitWithError(oraAllInOne, 1, ERROR_NONE, "File already exists on destination\n");
+ ExitWithError(oraAllInOne, RET_FS, ERROR_NONE, "File already exists on destination\n");
break;
case TRANSFER_MODE_INTERACTIVE:
/* TODO: if !isatty then just fail w/o asking? */
fprintf (stderr, "%s: overwrite %s? ",
PACKAGE, fileName);
if (!yesno())
- ExitWithError(oraAllInOne, 0, ERROR_NONE, 0);
+ ExitWithError(oraAllInOne, RET_OK, ERROR_NONE, 0);
break;
}
}
@@ -189,8 +188,13 @@ int main(int argc, const char *argv[])
{ "list-directories", '\0', POPT_ARG_NONE, 0, ACTION_LSDIR, "List Oracle directories" },
{ "ls", '\0', POPT_ARG_STRING, &programOptions.lsDirectoryName, ACTION_LS, "List files in Oracle directory", "DIRECTORY" },
{ "rm", '\0', POPT_ARG_NONE, 0, ACTION_RM, "Remove file from Oracle directory" },
- { "sysdba", '\0', POPT_ARG_VAL, &programOptions.adminMode, OCI_SYSDBA, "Connect as SYSDBA" },
+ { "sysdba", '\0', POPT_ARG_VAL, &programOptions.adminMode, OCI_SYSDBA, "Connect as SYSDBA" },
{ "sysoper", '\0', POPT_ARG_VAL, &programOptions.adminMode, OCI_SYSOPER, "Connect as SYSOPER" },
+ { "sysasm", '\0', POPT_ARG_VAL, &programOptions.adminMode, OCI_SYSASM, "Connect as SYSASM" },
+ { "sysbkp", '\0', POPT_ARG_VAL, &programOptions.adminMode, OCI_SYSBKP, "Connect as SYSBKP" },
+ { "sysdgd", '\0', POPT_ARG_VAL, &programOptions.adminMode, OCI_SYSDGD, "Connect as SYSDGD" },
+ { "syskmt", '\0', POPT_ARG_VAL, &programOptions.adminMode, OCI_SYSKMT, "Connect as SYSKMT" },
+ { "sysrac", '\0', POPT_ARG_VAL, &programOptions.adminMode, OCI_SYSRAC, "Connect as SYSRAC" },
{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, transferModeOptions, 0, "Transfer options:" },
{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, compressionOptions, 0, "Compression options:" },
{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, lsOptions, 0, "File list options:" },
@@ -465,7 +469,7 @@ int main(int argc, const char *argv[])
}
#endif
if (!pwdptr)
- ExitWithError(&oraAllInOne, 1, ERROR_OS, 0);
+ ExitWithError(&oraAllInOne, RET_USAGE, ERROR_OS, 0);
OracleLogon(&oraAllInOne, connectionString, pwdptr, dbconptr, programOptions.adminMode, PACKAGE, programOptions.numberOfOracleSessions);
@@ -533,5 +537,5 @@ int main(int argc, const char *argv[])
break;
}
- ExitWithError(&oraAllInOne, 0, ERROR_NONE, 0);
+ ExitWithError(&oraAllInOne, RET_OK, ERROR_NONE, 0);
}
diff --git a/src/oracle.c b/src/oracle.c
index 18de297..185fb7b 100644
--- a/src/oracle.c
+++ b/src/oracle.c
@@ -24,6 +24,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include
#include "oracle.h"
+#define ORA_JAVA_EXCEPTION 29532
+
struct BINDVARIABLE NO_BIND_VARIABLES[] = { { 0 } };
struct ORACLEDEFINE NO_ORACLE_DEFINES[] = { { 0 } };
@@ -60,7 +62,7 @@ void PrepareStmtAndBind2(struct ORACLEALLINONE *oraAllInOne, struct ORACLESTATEM
strlen(oracleStatement->sql),
0, 0, OCI_NTV_SYNTAX, OCI_DEFAULT))
{
- ExitWithError(oraAllInOne, 2, ERROR_OCI, "Failed to prepare %s\n", oracleStatement->sql);
+ ExitWithError(oraAllInOne, RET_OCIINIT, ERROR_OCI, "Failed to prepare %s\n", oracleStatement->sql);
}
for (i = 0; oracleStatement->oraDefines[i].value; i++)
@@ -74,7 +76,7 @@ void PrepareStmtAndBind2(struct ORACLEALLINONE *oraAllInOne, struct ORACLESTATEM
&oracleStatement->oraDefines[i].indp,
0, 0, OCI_DEFAULT))
{
- ExitWithError(oraAllInOne, 2, ERROR_OCI, "Failed to set up SQL query output field #%d\n", i + 1);
+ ExitWithError(oraAllInOne, RET_OCIINIT, ERROR_OCI, "Failed to set up SQL query output field #%d\n", i + 1);
}
}
@@ -90,7 +92,7 @@ void PrepareStmtAndBind2(struct ORACLEALLINONE *oraAllInOne, struct ORACLESTATEM
oracleStatement->bindVariables[i].dty,
0, 0, 0, 0, 0, OCI_DEFAULT))
{
- ExitWithError(oraAllInOne, 2, ERROR_OCI, "Failed to bind %s\n", oracleStatement->bindVariables[i].name);
+ ExitWithError(oraAllInOne, RET_OCIINIT, ERROR_OCI, "Failed to bind %s\n", oracleStatement->bindVariables[i].name);
}
}
}
@@ -134,6 +136,9 @@ void ExitWithError(struct ORACLEALLINONE *oraAllInOne, int exitCode, enum ERROR_
int i;
sb4 errorCode;
char errorMsg[MAX_FMT_SIZE];
+ char* msgPtr;
+
+ static const char* javaFileNotFoundException = "java.io.FileNotFoundException: ";
fflush(stdout);
if (message)
@@ -153,7 +158,16 @@ void ExitWithError(struct ORACLEALLINONE *oraAllInOne, int exitCode, enum ERROR_
if (oraAllInOne->errhp)
{
OCIErrorGet(oraAllInOne->errhp, 1, 0, &errorCode, errorMsg, sizeof(errorMsg), OCI_HTYPE_ERROR);
- fprintf(stderr, "%s", errorMsg);
+ if (exitCode == RET_LS && errorCode == ORA_JAVA_EXCEPTION &&
+ (msgPtr = strstr(errorMsg, javaFileNotFoundException)))
+ {
+ fprintf(stderr, "Directory does not exist on the database server: %s",
+ msgPtr + strlen(javaFileNotFoundException));
+ }
+ else
+ {
+ fprintf(stderr, "%s", errorMsg);
+ }
}
break;
case ERROR_OS:
@@ -176,17 +190,19 @@ void ExitWithError(struct ORACLEALLINONE *oraAllInOne, int exitCode, enum ERROR_
for (i = 0; i < MAX_ORA_SESSIONS; i++)
{
- if (oraAllInOne->svchp[i])
- {
- OCISessionEnd(oraAllInOne->svchp[i], oraAllInOne->errhp, oraAllInOne->usrhp[i], OCI_DEFAULT);
- OCIHandleFree(oraAllInOne->svchp[i], OCI_HTYPE_SVCCTX);
- oraAllInOne->svchp[i] = 0;
- }
if (oraAllInOne->usrhp[i])
{
+ OCISessionEnd(oraAllInOne->svchp[i], oraAllInOne->errhp, oraAllInOne->usrhp[i], OCI_DEFAULT);
OCIHandleFree(oraAllInOne->usrhp[i], OCI_HTYPE_SESSION);
oraAllInOne->usrhp[i] = 0;
}
+
+ if (oraAllInOne->svchp[i])
+ {
+ OCIHandleFree(oraAllInOne->svchp[i], OCI_HTYPE_SVCCTX);
+ oraAllInOne->svchp[i] = 0;
+ }
+
if (oraAllInOne->srvhp[i])
{
OCIServerDetach(oraAllInOne->srvhp[i], oraAllInOne->errhp, OCI_DEFAULT);
@@ -200,6 +216,7 @@ void ExitWithError(struct ORACLEALLINONE *oraAllInOne, int exitCode, enum ERROR_
OCIHandleFree(oraAllInOne->errhp, OCI_HTYPE_ERROR);
oraAllInOne->errhp = 0;
}
+
if (oraAllInOne->envhp)
{
OCITerminate(OCI_DEFAULT);
@@ -226,43 +243,42 @@ void OracleLogon(struct ORACLEALLINONE *oraAllInOne,
(void (*)(void *, void *))0,
(size_t)0, (void **)0))
{
- ExitWithError(oraAllInOne, 2, ERROR_NONE, "Failed to create OCI environment\n");
- /* 2 - Error in OCI object initialization */
+ ExitWithError(oraAllInOne, RET_OCIINIT, ERROR_NONE, "Failed to create OCI environment\n");
}
if (OCIHandleAlloc( (dvoid *) oraAllInOne->envhp, (dvoid **) &oraAllInOne->errhp,
(ub4) OCI_HTYPE_ERROR, 0, (dvoid **) 0))
{
- ExitWithError(oraAllInOne, 2, ERROR_NONE, "Failed to initialize OCIError\n");
+ ExitWithError(oraAllInOne, RET_OCIINIT, ERROR_NONE, "Failed to initialize OCIError\n");
}
for (i = 0; i < numberOfConnections; i++)
{
if (OCIHandleAlloc(oraAllInOne->envhp, (void*) &oraAllInOne->srvhp[i], OCI_HTYPE_SERVER, 0, 0))
{
- ExitWithError(oraAllInOne, 3, ERROR_OCI, "Failed to attach to a server\n");
+ ExitWithError(oraAllInOne, RET_LOGIN, ERROR_OCI, "Failed to attach to a server\n");
}
if (OCIServerAttach(oraAllInOne->srvhp[i], oraAllInOne->errhp,
(text*)connection, (ub4)strlen(connection), OCI_DEFAULT))
{
- ExitWithError(oraAllInOne, 3, ERROR_OCI, "Failed to attach to server\n");
+ ExitWithError(oraAllInOne, RET_LOGIN, ERROR_OCI, "Failed to attach to server\n");
}
if (OCIHandleAlloc(oraAllInOne->envhp, (void*) &oraAllInOne->svchp[i], OCI_HTYPE_SVCCTX, 0, 0))
{
- ExitWithError(oraAllInOne, 3, ERROR_OCI, "Failed to login to a database\n");
+ ExitWithError(oraAllInOne, RET_LOGIN, ERROR_OCI, "Failed to login to a database\n");
}
if (OCIAttrSet(oraAllInOne->svchp[i], OCI_HTYPE_SVCCTX,
oraAllInOne->srvhp[i], 0, OCI_ATTR_SERVER, oraAllInOne->errhp))
{
- ExitWithError(oraAllInOne, 3, ERROR_OCI, "Failed to login to a database\n");
+ ExitWithError(oraAllInOne, RET_LOGIN, ERROR_OCI, "Failed to login to a database\n");
}
if (OCIHandleAlloc(oraAllInOne->envhp, (void*) &oraAllInOne->usrhp[i], OCI_HTYPE_SESSION, 0, 0))
{
- ExitWithError(oraAllInOne, 3, ERROR_OCI, "Failed to login to a database\n");
+ ExitWithError(oraAllInOne, RET_LOGIN, ERROR_OCI, "Failed to login to a database\n");
}
if (*userName)
@@ -274,7 +290,7 @@ void OracleLogon(struct ORACLEALLINONE *oraAllInOne,
(text*)password, (ub4)strlen(password),
OCI_ATTR_PASSWORD, oraAllInOne->errhp))
{
- ExitWithError(oraAllInOne, 3, ERROR_OCI, "Failed to login to a database\n");
+ ExitWithError(oraAllInOne, RET_LOGIN, ERROR_OCI, "Failed to login to a database\n");
}
attrType = OCI_CRED_RDBMS;
}
@@ -285,24 +301,23 @@ void OracleLogon(struct ORACLEALLINONE *oraAllInOne,
oraAllInOne->usrhp[i], attrType, adminMode))
{
case OCI_SUCCESS_WITH_INFO:
- ExitWithError(oraAllInOne, -1, ERROR_OCI, 0);
+ ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, 0);
case OCI_SUCCESS:
break;
default:
- ExitWithError(oraAllInOne, 3, ERROR_OCI, "Failed to login to a database\n");
- /* 3 - Failed to login to a database */
+ ExitWithError(oraAllInOne, RET_LOGIN, ERROR_OCI, "Failed to login to a database\n");
}
if (OCIAttrSet(oraAllInOne->svchp[i], OCI_HTYPE_SVCCTX,
oraAllInOne->usrhp[i], 0, OCI_ATTR_SESSION, oraAllInOne->errhp))
{
- ExitWithError(oraAllInOne, 3, ERROR_OCI, "Failed to login to a database\n");
+ ExitWithError(oraAllInOne, RET_LOGIN, ERROR_OCI, "Failed to login to a database\n");
}
if (OCIAttrSet(oraAllInOne->usrhp[i], OCI_HTYPE_SESSION,
(void*)module, strlen(module), OCI_ATTR_MODULE, oraAllInOne->errhp))
{
- ExitWithError(oraAllInOne, -1, ERROR_OCI, "Could not set MODULE in V$SESSION\n");
+ ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Could not set MODULE in V$SESSION\n");
}
}
}
@@ -312,7 +327,7 @@ void SetSessionAction2(struct ORACLEALLINONE *oraAllInOne, const char* action, i
if (OCIAttrSet(oraAllInOne->usrhp[index], OCI_HTYPE_SESSION,
(void*)action, action ? strlen(action) : 0, OCI_ATTR_ACTION, oraAllInOne->errhp))
{
- ExitWithError(oraAllInOne, -1, ERROR_OCI, "Could not set ACTION in V$SESSION\n");
+ ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Could not set ACTION in V$SESSION\n");
}
}
@@ -334,7 +349,7 @@ void ExecuteSimpleSqls(struct ORACLEALLINONE *oraAllInOne, struct ORACLESIMPLESQ
if (!oracleSimpleSqls->errCodeToIgnore ||
(OCIErrorGet(oraAllInOne->errhp, 1, 0, &errorCode, errorMsg, sizeof(errorMsg), OCI_HTYPE_ERROR),
errorCode != oracleSimpleSqls->errCodeToIgnore))
- ExitWithError(oraAllInOne, 4, ERROR_OCI, 0);
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, 0);
}
ReleaseStmt(oraAllInOne);
oracleSimpleSqls++;
@@ -358,6 +373,6 @@ select sys_context('USERENV', 'SID'),\n\
PrepareStmtAndBind2(oraAllInOne, &oraStmtGetSid, index);
if (ExecuteStmt2(oraAllInOne, index))
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Cannot get SID of the current session\n");
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Cannot get SID of the current session\n");
ReleaseStmt2(oraAllInOne, index);
}
diff --git a/src/oracle.h b/src/oracle.h
index e8bd833..f577a66 100644
--- a/src/oracle.h
+++ b/src/oracle.h
@@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define _ORACLE_H_
#include
+#include "exitstatus.h"
#define MAX_FMT_SIZE 4096
#define ORA_IDENTIFIER_SIZE 30
diff --git a/src/orafileattr.c b/src/orafileattr.c
index d1354b6..882ffd7 100644
--- a/src/orafileattr.c
+++ b/src/orafileattr.c
@@ -58,7 +58,7 @@ end;",
PrepareStmtAndBind(oraAllInOne, &oraStmtFattr);
if (ExecuteStmt(oraAllInOne))
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to get remote file attributes\n");
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to get remote file attributes\n");
ReleaseStmt(oraAllInOne);
}
diff --git a/src/rm.c b/src/rm.c
index fba2042..fbce7af 100644
--- a/src/rm.c
+++ b/src/rm.c
@@ -42,7 +42,7 @@ void Rm(struct ORACLEALLINONE *oraAllInOne, char* pDirectory, char* pFileName)
PrepareStmtAndBind(oraAllInOne, &oraStmtRm);
if (ExecuteStmt(oraAllInOne))
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to remove file in oracle directory\n");
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to remove file in oracle directory\n");
ReleaseStmt(oraAllInOne);
SetSessionAction(oraAllInOne, 0);
diff --git a/src/transfer.c b/src/transfer.c
index 39dc0c5..f63eff3 100644
--- a/src/transfer.c
+++ b/src/transfer.c
@@ -182,7 +182,7 @@ select server\n\
}
else if (strcmp(vServerType, "DEDICATED"))
{
- ExitWithError(oraAllInOne, 4, ERROR_NONE, "Must connect through DEDICATED server, got %s\n", vServerType);
+ ExitWithError(oraAllInOne, RET_LOGIN, ERROR_NONE, "Must connect through DEDICATED server, got %s\n", vServerType);
}
ReleaseStmt(oraAllInOne);
}
@@ -221,7 +221,7 @@ select server\n\
PrepareStmtAndBind(oraAllInOne, &oraStmtOpen);
if (ExecuteStmt(oraAllInOne))
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to open an Oracle remote file for %s\n",
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to open an Oracle remote file for %s\n",
readingDirection ? "reading" : "writing");
ReleaseStmt(oraAllInOne);
@@ -252,21 +252,21 @@ select server\n\
if (!isStdUsed && (fp = fopen(pLocalFile, readingDirection ? (isResume ? "ab" : "wb") : "rb")) == NULL)
{
- ExitWithError(oraAllInOne, -1, ERROR_OS, "Error opening a local %s file for %s\n",
+ ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OS, "Error opening a local %s file for %s\n",
readingDirection ? "destination" : "source",
readingDirection ? "writing" : "reading");
- /* 4 - Local filesystem related errors */
+
if (!readingDirection && !isKeepPartial)
{
PrepareStmtAndBind(oraAllInOne, &oraStmtClose);
if (ExecuteStmt(oraAllInOne))
{
- ExitWithError(oraAllInOne, -1, ERROR_OCI, "Error closing an Oracle remote file\n");
+ ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Error closing an Oracle remote file\n");
}
ReleaseStmt(oraAllInOne);
Rm(oraAllInOne, pDirectory, pRemoteFile);
}
- ExitWithError(oraAllInOne, 4, ERROR_NONE, 0);
+ ExitWithError(oraAllInOne, RET_FS, ERROR_NONE, 0);
}
if (isStdUsed)
@@ -281,14 +281,14 @@ select server\n\
{
if (!isStdUsed)
fclose(fp);
- ExitWithError(oraAllInOne, -1, ERROR_OCI, "Failed execution of %s\n",
+ ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Failed execution of %s\n",
oraAllInOne->currentStmt[0]->sql);
if (!isKeepPartial)
{
if (unlink(pLocalFile))
- ExitWithError(oraAllInOne, 3, ERROR_OS, "Could not remove partial file %s\n", pLocalFile);
+ ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OS, "Could not remove partial file %s\n", pLocalFile);
}
- ExitWithError(oraAllInOne, 3, ERROR_NONE, 0);
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_NONE, 0);
}
else
{
@@ -297,13 +297,13 @@ select server\n\
{
if (!isStdUsed)
fclose(fp);
- ExitWithError(oraAllInOne, -1, ERROR_OS, "Error writing to a local file\n");
+ ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OS, "Error writing to a local file\n");
if (!isKeepPartial)
{
if (unlink(pLocalFile))
- ExitWithError(oraAllInOne, 4, ERROR_OS, "Could not remove partial file %s\n", pLocalFile);
+ ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OS, "Could not remove partial file %s\n", pLocalFile);
}
- ExitWithError(oraAllInOne, 4, ERROR_NONE, 0);
+ ExitWithError(oraAllInOne, RET_FS, ERROR_NONE, 0);
}
cnt += vSize;
}
@@ -317,7 +317,7 @@ select server\n\
if (fseek(fp, cnt, SEEK_SET))
{
fclose(fp);
- ExitWithError(oraAllInOne, 4, ERROR_OS, "Error setting reading position in a local file\n");
+ ExitWithError(oraAllInOne, RET_FS, ERROR_OS, "Error setting reading position in a local file\n");
}
}
@@ -327,18 +327,18 @@ select server\n\
{
if (!isStdUsed)
fclose(fp);
- ExitWithError(oraAllInOne, -1, ERROR_OS, "Error reading from a local file\n");
+ ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OS, "Error reading from a local file\n");
if (!isKeepPartial)
{
PrepareStmtAndBind(oraAllInOne, &oraStmtClose);
if (ExecuteStmt(oraAllInOne))
{
- ExitWithError(oraAllInOne, -1, ERROR_OCI, "Error closing an Oracle remote file\n");
+ ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Error closing an Oracle remote file\n");
}
ReleaseStmt(oraAllInOne);
Rm(oraAllInOne, pDirectory, pRemoteFile);
}
- ExitWithError(oraAllInOne, 4, ERROR_NONE, 0);
+ ExitWithError(oraAllInOne, RET_FS, ERROR_NONE, 0);
}
if (OCIBindByName(oraAllInOne->currentStmt[0]->stmthp, &ociBind, oraAllInOne->errhp,
@@ -347,18 +347,18 @@ select server\n\
{
if (!isStdUsed)
fclose(fp);
- ExitWithError(oraAllInOne, -1, ERROR_OCI, "Failed to bind :buffer\n");
+ ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Failed to bind :buffer\n");
if (!isKeepPartial)
{
PrepareStmtAndBind(oraAllInOne, &oraStmtClose);
if (ExecuteStmt(oraAllInOne))
{
- ExitWithError(oraAllInOne, -1, ERROR_OCI, "Error closing an Oracle remote file\n");
+ ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Error closing an Oracle remote file\n");
}
ReleaseStmt(oraAllInOne);
Rm(oraAllInOne, pDirectory, pRemoteFile);
}
- ExitWithError(oraAllInOne, 4, ERROR_NONE, 0);
+ ExitWithError(oraAllInOne, RET_OCIINIT, ERROR_NONE, 0);
}
if (ExecuteStmt(oraAllInOne))
@@ -366,19 +366,19 @@ select server\n\
if (!isStdUsed)
fclose(fp);
OCIHandleFree(ociBind, OCI_HTYPE_BIND);
- ExitWithError(oraAllInOne, -1, ERROR_OCI, "Failed execution of %s\n",
+ ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Failed execution of %s\n",
oraAllInOne->currentStmt[0]->sql);
if (!isKeepPartial)
{
PrepareStmtAndBind(oraAllInOne, &oraStmtClose);
if (ExecuteStmt(oraAllInOne))
{
- ExitWithError(oraAllInOne, -1, ERROR_OCI, "Error closing an Oracle remote file\n");
+ ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Error closing an Oracle remote file\n");
}
ReleaseStmt(oraAllInOne);
Rm(oraAllInOne, pDirectory, pRemoteFile);
}
- ExitWithError(oraAllInOne, 4, ERROR_NONE, 0);
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_NONE, 0);
}
OCIHandleFree(ociBind, OCI_HTYPE_BIND);
cnt += vActualSize;
@@ -396,7 +396,7 @@ select server\n\
PrepareStmtAndBind(oraAllInOne, &oraStmtClose);
if (ExecuteStmt(oraAllInOne))
{
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Error closing an Oracle remote file\n");
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Error closing an Oracle remote file\n");
}
ReleaseStmt(oraAllInOne);
SetSessionAction(oraAllInOne, 0);
diff --git a/src/transfercompr.c b/src/transfercompr.c
index d121858..1d5d79c 100644
--- a/src/transfercompr.c
+++ b/src/transfercompr.c
@@ -85,7 +85,7 @@ void DownloadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDire
SetSessionAction(oraAllInOne, "GZIP_AND_DOWNLOAD: GZIP");
if (OCIDescriptorAlloc(oraAllInOne->envhp, (void**)&oraAllInOne->blob, OCI_DTYPE_LOB, 0, 0))
{
- ExitWithError(oraAllInOne, 4, ERROR_NONE, "Failed to allocate BLOB\n");
+ ExitWithError(oraAllInOne, RET_OCIINIT, ERROR_NONE, "Failed to allocate BLOB\n");
}
cnt = 0;
@@ -115,13 +115,13 @@ void DownloadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDire
#endif
if (ociResult)
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to compress file in oracle directory\n");
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to compress file in oracle directory\n");
#ifndef _WIN32
if (showProgress)
{
if (OCILobGetLength2(oraAllInOne->svchp[0], oraAllInOne->errhp, oraAllInOne->blob, (oraub8*)&sourceSize))
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Error getting BLOB length\n");
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Error getting BLOB length\n");
strcpy(progressLine, "TRANSFER & GUNZIP: ");
strncat(progressLine, basename(pLocalFile), MAX_FMT_SIZE - 1 - strlen(progressLine));
start_progress_meter(progressLine, sourceSize, &cnt);
@@ -131,7 +131,7 @@ void DownloadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDire
SetSessionAction(oraAllInOne, "GZIP_AND_DOWNLOAD: DOWNLOAD");
if (!isStdUsed && (fp = fopen(pLocalFile, isResume ? "ab" : "wb")) == NULL)
{
- ExitWithError(oraAllInOne, 4, ERROR_OS, "Error opening a local file for writing\n");
+ ExitWithError(oraAllInOne, RET_FS, ERROR_OS, "Error opening a local file for writing\n");
}
if (isStdUsed)
fp = stdout;
@@ -146,7 +146,7 @@ void DownloadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDire
{
if (!isStdUsed)
fclose(fp);
- ExitWithError(oraAllInOne, 5, ERROR_NONE, "ZLIB initialization failed\n");
+ ExitWithError(oraAllInOne, RET_ZLIB, ERROR_NONE, "ZLIB initialization failed\n");
}
vSize = 0;
@@ -170,7 +170,7 @@ void DownloadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDire
(void)inflateEnd(&zStrm);
if (!isStdUsed)
fclose(fp);
- ExitWithError(oraAllInOne, 5, ERROR_NONE, "ZLIB inflate failed: %d, size %d\n", zRet, vSize);
+ ExitWithError(oraAllInOne, RET_ZLIB, ERROR_NONE, "ZLIB inflate failed: %d, size %d\n", zRet, vSize);
}
fwrite(zOut, sizeof(unsigned char), ORA_BLOB_BUFFER_SIZE - zStrm.avail_out, fp);
@@ -179,13 +179,13 @@ void DownloadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDire
(void)inflateEnd(&zStrm);
if (!isStdUsed)
fclose(fp);
- ExitWithError(oraAllInOne, -1, ERROR_OS, "Error writing to a local file\n");
+ ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OS, "Error writing to a local file\n");
if (!isKeepPartial)
{
if (unlink(pLocalFile))
- ExitWithError(oraAllInOne, 4, ERROR_OS, "Could not remove partial file %s\n", pLocalFile);
+ ExitWithError(oraAllInOne, RET_FS, ERROR_OS, "Could not remove partial file %s\n", pLocalFile);
}
- ExitWithError(oraAllInOne, 4, ERROR_NONE, 0);
+ ExitWithError(oraAllInOne, RET_FS, ERROR_NONE, 0);
}
}
while (zStrm.avail_out == 0);
@@ -205,7 +205,7 @@ void DownloadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDire
if (ociResult != OCI_SUCCESS)
{
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Error reading BLOB\n");
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Error reading BLOB\n");
}
ReleaseStmt(oraAllInOne);
@@ -215,7 +215,7 @@ void DownloadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDire
if (OCIDescriptorFree(oraAllInOne->blob, OCI_DTYPE_LOB))
{
- ExitWithError(oraAllInOne, 4, ERROR_NONE, "Failed to free BLOB\n");
+ ExitWithError(oraAllInOne, RET_OCIINIT, ERROR_NONE, "Failed to free BLOB\n");
}
oraAllInOne->blob = 0;
}
@@ -268,17 +268,14 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect
SetSessionAction(oraAllInOne, "UPLOAD_AND_GUNZIP: UPLOAD");
if (OCIDescriptorAlloc(oraAllInOne->envhp, (void**)&oraAllInOne->blob, OCI_DTYPE_LOB, 0, 0))
{
- ExitWithError(oraAllInOne, 4, ERROR_NONE, "Failed to allocate BLOB\n");
+ ExitWithError(oraAllInOne, RET_OCIINIT, ERROR_NONE, "Failed to allocate BLOB\n");
}
if (OCILobCreateTemporary(oraAllInOne->svchp[0], oraAllInOne->errhp, oraAllInOne->blob, OCI_DEFAULT, 0, OCI_TEMP_BLOB, TRUE/*cache*/, OCI_DURATION_SESSION))
{
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to create temporary BLOB\n");
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to create temporary BLOB\n");
}
- /*if (OCILobOpen(oraAllInOne->svchp[0], oraAllInOne->errhp, oraAllInOne->blob, OCI_LOB_READWRITE))
- {
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to open temporary BLOB for write\n");
- }*/
+
piece = OCI_FIRST_PIECE;
#ifndef _WIN32
@@ -310,7 +307,7 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect
if (!isStdUsed && (fp = fopen(pLocalFile, "rb")) == NULL)
{
- ExitWithError(oraAllInOne, 4, ERROR_OS, "Error opening a local file for reading\n");
+ ExitWithError(oraAllInOne, RET_FS, ERROR_OS, "Error opening a local file for reading\n");
}
if (isStdUsed)
fp = stdin;
@@ -320,7 +317,7 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect
if (fseek(fp, cnt, SEEK_SET))
{
fclose(fp);
- ExitWithError(oraAllInOne, 4, ERROR_OS, "Error setting reading position in a local file\n");
+ ExitWithError(oraAllInOne, RET_FS, ERROR_OS, "Error setting reading position in a local file\n");
}
}
@@ -333,7 +330,7 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect
{
if (!isStdUsed)
fclose(fp);
- ExitWithError(oraAllInOne, 5, ERROR_NONE, "ZLIB initialization failed\n");
+ ExitWithError(oraAllInOne, RET_ZLIB, ERROR_NONE, "ZLIB initialization failed\n");
}
while (!feof(fp))
@@ -345,7 +342,7 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect
(void)deflateEnd(&zStrm);
if (!isStdUsed)
fclose(fp);
- ExitWithError(oraAllInOne, 4, ERROR_OS, "Error reading from a local file\n");
+ ExitWithError(oraAllInOne, RET_FS, ERROR_OS, "Error reading from a local file\n");
}
zFlush = feof(fp) ? Z_FINISH : Z_NO_FLUSH;
@@ -361,7 +358,7 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect
(void)deflateEnd(&zStrm);
if (!isStdUsed)
fclose(fp);
- ExitWithError(oraAllInOne, 5, ERROR_NONE, "ZLIB deflate failed: %d, size %d\n", zRet, zStrm.avail_in);
+ ExitWithError(oraAllInOne, RET_ZLIB, ERROR_NONE, "ZLIB deflate failed: %d, size %d\n", zRet, zStrm.avail_in);
}
if (zRet == Z_STREAM_END)
@@ -376,7 +373,7 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect
(void)deflateEnd(&zStrm);
if (!isStdUsed)
fclose(fp);
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Error writing to BLOB\n");
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Error writing to BLOB\n");
}
if (piece == OCI_FIRST_PIECE)
piece = OCI_NEXT_PIECE;
@@ -392,16 +389,6 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect
if (!isStdUsed)
fclose(fp);
- /*vSize = 0;
- if (OCILobWrite2(oraAllInOne->svchp[0], oraAllInOne->errhp, oraAllInOne->blob, &vSize, 0, 1, blobBuffer, 0, OCI_LAST_PIECE, 0, 0, 0, 0))
- {
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Error writing last piece to BLOB\n");
- }
- if (OCILobClose(oraAllInOne->svchp[0], oraAllInOne->errhp, oraAllInOne->blob))
- {
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to close temporary BLOB\n");
- }*/
-
isError = 0;
strcpy(vOpenMode, isResume ? "ab" : "wb");
SetSessionAction(oraAllInOne, "UPLOAD_AND_GUNZIP: GUNZIP");
@@ -419,7 +406,7 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect
#endif
if (ociResult)
{
- ExitWithError(oraAllInOne, -1, ERROR_OCI, "Failed to decompress file in oracle directory\n");
+ ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Failed to decompress file in oracle directory\n");
isError = 1;
}
else
@@ -431,7 +418,7 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect
if (OCIDescriptorFree(oraAllInOne->blob, OCI_DTYPE_LOB))
{
if (!isError)
- ExitWithError(oraAllInOne, -1, ERROR_NONE, "Failed to free BLOB\n");
+ ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_NONE, "Failed to free BLOB\n");
isError = 1;
}
oraAllInOne->blob = 0;
@@ -440,6 +427,6 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect
{
if (!isKeepPartial)
Rm(oraAllInOne, pDirectory, pRemoteFile);
- ExitWithError(oraAllInOne, 4, ERROR_NONE, 0);
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_NONE, 0);
}
}
diff --git a/src/trydir.c b/src/trydir.c
index b51b253..19b87ec 100644
--- a/src/trydir.c
+++ b/src/trydir.c
@@ -53,7 +53,7 @@ SELECT MIN(DECODE(directory_name, :directory, 1, 2))\n\
PrepareStmtAndBind(oraAllInOne, &oraStmtTryDirectory);
if (ExecuteStmt(oraAllInOne))
- ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to get an Oracle Directory\n");
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to get an Oracle Directory\n");
ReleaseStmt(oraAllInOne);
@@ -62,11 +62,11 @@ SELECT MIN(DECODE(directory_name, :directory, 1, 2))\n\
case 1:
break;
case 2:
- ExitWithError(oraAllInOne, -1, ERROR_NONE, "WARNING: directory \"%s\" not found, converting to uppercase\n", pDirectory);
+ ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_NONE, "WARNING: directory \"%s\" not found, converting to uppercase\n", pDirectory);
for (ptr = pDirectory; *ptr; ptr++)
*ptr = toupper(*ptr);
break;
default:
- ExitWithError(oraAllInOne, 4, ERROR_NONE, "Directory \"%s\" does not exist\n", pDirectory);
+ ExitWithError(oraAllInOne, RET_ORA, ERROR_NONE, "Directory \"%s\" does not exist\n", pDirectory);
}
}
diff --git a/updateforeigns.sh b/updateforeigns.sh
index 82c3dcd..9e683fa 100755
--- a/updateforeigns.sh
+++ b/updateforeigns.sh
@@ -40,7 +40,7 @@ done
download "http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/lib/libc/string/strlcat.c" \
progressmeter/strlcat.c.orig
download "http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/ax_lib_oracle_oci.m4" \
- m4/ax_lib_oracle_oci.m4.orig
+ m4/ax_lib_oracle_oci.m4
download "http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=lib/yesno.h;hb=HEAD" \
yesno/yesno.h
download "http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=lib/yesno.c;hb=HEAD" \
@@ -59,7 +59,7 @@ done
# 2.2. Medium case, sources need a slight patch
for file in progressmeter/progressmeter.c progressmeter/atomicio.c progressmeter/strlcat.c \
- m4/ax_lib_oracle_oci.m4 src/Globs.java; do
+ src/Globs.java; do
patch --backup-if-mismatch -u -o ${file} ${file}.orig ${file}.patch
done
@@ -81,13 +81,13 @@ cat << EOF
EOF
-grep -Ezo '(\w+)(\s*)monotime_double([^)]*)\)' progressmeter/misc.c.orig
+grep -Ezo '(\w+)(\s*)monotime_double([^)]*)\)' progressmeter/misc.c.orig | sed 's/\x00/\n/'
cat << EOF
; /* taken from the original OpenSSH misc.h/misc.c */
EOF
-grep -Ezo '(\w+)(\s*)strlcat([^)]*)\)' progressmeter/strlcat.c.orig
+grep -Ezo '(\w+)(\s*)strlcat([^)]*)\)' progressmeter/strlcat.c.orig | sed 's/\x00/\n/'
cat << EOF
; /* declaration for strlcat.c */
@@ -112,10 +112,15 @@ cat << EOF
#include
EOF
-grep -Ezo '(\w+)(\s*)monotime_double([^}]*)}' ${filename} | sed \
+
+grep -Ezo '(\w+)(\s*)monotime_ts([^}]*)}' ${filename} | sed \
-e 's/if (/\/*if (*\//' \
-e 's/ != 0)/\/* != 0)/' \
- -e 's/strerror(errno))/strerror(errno))*\//'
+ -e 's/strerror(errno))/strerror(errno))*\//' \
+ -e 's/\x00/\n\n/'
+
+grep -Ezo '(\w+)(\s*)monotime_double([^}]*)}' ${filename} | sed \
+ -e 's/\x00/\n/'
) > progressmeter/misc.c
# 3. Remove intermediate files
@@ -126,6 +131,5 @@ rm progressmeter/progressmeter.h.orig \
progressmeter/atomicio.c.orig \
progressmeter/misc.c.orig \
progressmeter/strlcat.c.orig \
- m4/ax_lib_oracle_oci.m4.orig \
src/Globs.java.orig
diff --git a/win/README.md b/win/README.md
index 1f00c98..b47c373 100644
--- a/win/README.md
+++ b/win/README.md
@@ -8,12 +8,12 @@ Here are dependencies required to run pre-compiled `ocp.exe`
### Oracle Client
-Download and unpack Oracle **Instant Client Package - Basic Lite** for Microsoft Windows (32-bit) version 12.1.0.2.0 from http://www.oracle.com/technetwork/topics/winsoft-085727.html
-`instantclient-basiclite-nt-12.1.0.2.0.zip` (33,851,306 bytes)
+Download and unpack Oracle **Basic Light Package** for Microsoft Windows (32-bit) version 18.3.0.0.0 from http://www.oracle.com/technetwork/topics/winsoft-085727.html
+`instantclient-basiclite-nt-18.3.0.0.0dbru.zip` (3,544,0728 bytes)
Full Oracle Client (or Server) installations will also work. Use 32-bit installations only.
-As usual, make sure Oracle Instant Client directory is in `PATH` environment variable. If using full installation, then `%ORACLE_HOME%\bin` should be in `PATH`.
+As usual, make sure Oracle Instant Client directory is in `PATH` environment variable. If using full Oracle Client installation, then `%ORACLE_HOME%\bin` should be in `PATH`.
### GnuWin32 Libraries
@@ -25,22 +25,22 @@ Download and unpack archives, and put files to a directory with `ocp.exe` or to
| http://gnuwin32.sourceforge.net/downlinks/popt-dep-zip.php | popt-1.8-1-dep.zip | bin\libintl-2.dll, bin\libiconv-2.dll |
| http://gnuwin32.sourceforge.net/downlinks/zlib-bin-zip.php | zlib-1.2.3-bin.zip | bin\zlib1.dll |
-### Microsoft Visual C++ 2010 SP1 Redistributable Package (x86)
+### Visual C++ Redistributable Packages for Visual Studio 2013 (x86)
-Download and install `vcredist_x86.exe` from https://www.microsoft.com/en-us/download/details.aspx?id=8328
+Download and install `vcredist_x86.exe` from https://www.microsoft.com/en-us/download/details.aspx?id=40784
Build
-----
-Here are dependencies required to compile `ocp.exe` from source. Please follow instructions in **Runtime** section above (except **Microsoft Visual C++ 2010 SP1 Redistributable Package (x86)**, that one is automatically supplied by **Microsoft Visual C++ 2010 Express SP1** installation), then proceed with the steps below.
+Here are dependencies required to compile `ocp.exe` from source. Please follow instructions in **Runtime** section above (except **Visual C++ Redistributable Packages for Visual Studio 2013 (x86)**, that one is automatically supplied by **Visual Studio Community 2013** installation), then proceed with the steps below.
-A version 2010 of Visual C++ (MSVC) was chosen because Oracle Instant Client 12.1.0.2.0 already has **Microsoft Visual C++ 2010 SP1 Redistributable Package (x86)** as its runtime dependency (it requires `MSVCR100.dll` file).
+A version 2013 of Visual C++ (MSVC) was chosen because Oracle Instant Client 18.3.0.0.0 already has **Visual C++ Redistributable Packages for Visual Studio 2013 (x86)** as its runtime dependency (it requires `MSVCR120.dll` file).
Thus, compiling `ocp` with the same MSVC version as Oracle used for their Instant Client will avoid dependencies on more than one version of `MSVCR*.dll`.
### Oracle Client
-If using Instant Client, download and unpack to the same directory Oracle **Instant Client Package - SDK** for Microsoft Windows (32-bit) version 12.1.0.2.0 from http://www.oracle.com/technetwork/topics/winsoft-085727.html
-`instantclient-sdk-nt-12.1.0.2.0.zip` (1,951,770 bytes)
+If using Instant Client, download and unpack to the same directory Oracle **SDK Package** for Microsoft Windows (32-bit) version 18.3.0.0.0 from http://www.oracle.com/technetwork/topics/winsoft-085727.html
+`instantclient-sdk-nt-18.3.0.0.0dbru.zip` (1,499,306 bytes)
### GnuWin32 Libraries
@@ -51,15 +51,14 @@ Download and unpack archives to `win` subdirectory of ocp source tree:
| http://gnuwin32.sourceforge.net/downlinks/popt-lib-zip.php | popt-1.8-1-lib.zip |
| http://gnuwin32.sourceforge.net/downlinks/zlib-lib-zip.php | zlib-1.2.3-lib.zip |
-### Microsoft Visual C++ 2010 Express SP1
+### Visual Studio Community 2013
- 1. Download and install **Microsoft Visual C++ 2010 Express**,
- deselect any options during installation, as they are unnecessary.
- 2. Download and install **Microsoft Visual Studio 2010 Service Pack 1**
+Download and install **Visual Studio Community 2013**,
+deselect any options during installation, as they are unnecessary.
### Run Compilation
-Run **Visual Studio Command Prompt (2010)**
+Run **VS2013 x86 Native Tools Command Prompt**
Then review `win\build.cmd`, edit if necessary, and execute:
```
diff --git a/win/build.cmd b/win/build.cmd
index 07d64db..3865e37 100644
--- a/win/build.cmd
+++ b/win/build.cmd
@@ -3,7 +3,7 @@ rem
rem 1. Review and edit include\config.h (update version information) if necessary
rem 2. Adjust the two variables (%INSTANT_CLIENT% and %OCP_ROOT%) if necessary
-set INSTANT_CLIENT=c:\instantclient_12_1
+set INSTANT_CLIENT=c:\instantclient_18_3
set OCP_ROOT=..
set ICINCHOME=%INSTANT_CLIENT%\sdk\include
diff --git a/win/include/config.h b/win/include/config.h
index c0ff84e..0e10191 100644
--- a/win/include/config.h
+++ b/win/include/config.h
@@ -19,7 +19,7 @@
#undef PACKAGE_TARNAME
/* Define to the version of this package. */
-#define PACKAGE_VERSION "0.2"
+#define PACKAGE_VERSION "0.3"
/* Version number of package */
-#define VERSION "0.2"
+#define VERSION "0.3"
diff --git a/yesno/yesno.c b/yesno/yesno.c
index 12168b2..0a58727 100644
--- a/yesno/yesno.c
+++ b/yesno/yesno.c
@@ -1,6 +1,6 @@
/* yesno.c -- read a yes/no response from stdin
- Copyright (C) 1990, 1998, 2001, 2003-2017 Free Software Foundation, Inc.
+ Copyright (C) 1990, 1998, 2001, 2003-2019 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -13,7 +13,7 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program. If not, see . */
+ along with this program. If not, see . */
#include
diff --git a/yesno/yesno.h b/yesno/yesno.h
index be127b0..0c1b259 100644
--- a/yesno/yesno.h
+++ b/yesno/yesno.h
@@ -1,5 +1,5 @@
/* declare yesno
- Copyright (C) 2004, 2009-2017 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2009-2019 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -12,7 +12,7 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program. If not, see . */
+ along with this program. If not, see . */
#ifndef YESNO_H_
# define YESNO_H_