383 lines
9.7 KiB
C
383 lines
9.7 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/*
|
|
* $TOG: unixf_storage.C /main/8 1998/04/17 11:50:39 mgreess $
|
|
*
|
|
* Copyright (c) 1993 HAL Computer Systems International, Ltd.
|
|
* All rights reserved. Unpublished -- rights reserved under
|
|
* the Copyright Laws of the United States. USE OF A COPYRIGHT
|
|
* NOTICE IS PRECAUTIONARY ONLY AND DOES NOT IMPLY PUBLICATION
|
|
* OR DISCLOSURE.
|
|
*
|
|
* THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION AND TRADE
|
|
* SECRETS OF HAL COMPUTER SYSTEMS INTERNATIONAL, LTD. USE,
|
|
* DISCLOSURE, OR REPRODUCTION IS PROHIBITED WITHOUT THE
|
|
* PRIOR EXPRESS WRITTEN PERMISSION OF HAL COMPUTER SYSTEMS
|
|
* INTERNATIONAL, LTD.
|
|
*
|
|
* RESTRICTED RIGHTS LEGEND
|
|
* Use, duplication, or disclosure by the Government is subject
|
|
* to the restrictions as set forth in subparagraph (c)(l)(ii)
|
|
* of the Rights in Technical Data and Computer Software clause
|
|
* at DFARS 252.227-7013.
|
|
*
|
|
* HAL COMPUTER SYSTEMS INTERNATIONAL, LTD.
|
|
* 1315 Dell Avenue
|
|
* Campbell, CA 95008
|
|
*
|
|
*/
|
|
|
|
|
|
#include "storage/unixf_storage.h"
|
|
|
|
#ifdef _IBMR2 /* connolly 2/21/95 from the AIX fsync() manpage */
|
|
extern "C" int fsync(int fd);
|
|
#endif
|
|
|
|
/***********************************************************/
|
|
// Constructor
|
|
/***********************************************************/
|
|
unixf_storage::
|
|
unixf_storage( char* file_path, char* file_name,
|
|
rep_policy* rep_p, int m
|
|
) :
|
|
abs_storage( file_path, file_name, UNIX_STORAGE_CODE, rep_p ),
|
|
fstream(), mode(m),
|
|
total_bytes(-1), v_file_exist(exist_file(file_name, file_path))
|
|
{
|
|
}
|
|
|
|
/***********************************************************/
|
|
// Destructor
|
|
/***********************************************************/
|
|
unixf_storage::~unixf_storage()
|
|
{
|
|
/*
|
|
MESSAGE(cerr, "~unixf storeage ()");
|
|
debug(cerr, my_path());
|
|
debug(cerr, my_name());
|
|
*/
|
|
if ( policy )
|
|
policy -> remove(*this);
|
|
|
|
#ifdef REPORT_IO_COUNT
|
|
#endif
|
|
}
|
|
|
|
void unixf_storage::remove()
|
|
{
|
|
#ifdef C_API
|
|
int fd = rdbuf() -> fd();
|
|
fsync(fd);
|
|
::close(fd);
|
|
#else
|
|
rdbuf() -> close();
|
|
#endif
|
|
del_file(my_name(), my_path());
|
|
/*
|
|
int md = mode;
|
|
_open(ios::trunc);
|
|
mode = md;
|
|
_open(mode);
|
|
*/
|
|
}
|
|
|
|
/***********************************************************/
|
|
// Open the physical file associated with this store
|
|
/***********************************************************/
|
|
int unixf_storage::_open(int new_mode)
|
|
{
|
|
char *fmt = NULL;
|
|
|
|
if ( ! ( *this ) ) {
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "fstream is in bad status @ %s:%d\n",
|
|
__FILE__, __LINE__);
|
|
#endif
|
|
throw(streamException(fstream::rdstate()));
|
|
}
|
|
|
|
rep_cell* replaced = 0;
|
|
|
|
if ( policy != 0 ) {
|
|
|
|
policy -> promote(*this, replaced);
|
|
|
|
if ( replaced ) {
|
|
unixf_storage* us = ((unixf_storage*)replaced);
|
|
us -> fstream::close();
|
|
if ( us -> fstream::fail() ) {
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "Can't close db file %s/%s @ %s:%d\n",
|
|
us->my_path(), us->my_name(), __FILE__, __LINE__);
|
|
#endif
|
|
throw(streamException(us -> fstream::rdstate()));
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( v_file_exist == false ) {
|
|
SET_BIT(new_mode, ios::out | ios::trunc);
|
|
v_file_exist = true;
|
|
}
|
|
|
|
//MESSAGE(cerr, "_open");
|
|
//debug(cerr, total_bytes);
|
|
|
|
if ( !BIT_TEST(mode, new_mode) ) {
|
|
|
|
if ( fstream::rdbuf() -> is_open() ) {
|
|
fstream::close();
|
|
|
|
if ( fstream::fail() ) {
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "Can't close db file %s/%s @ %s:%d\n",
|
|
path, name, __FILE__, __LINE__);
|
|
#endif
|
|
throw(streamException(fstream::rdstate()));
|
|
}
|
|
}
|
|
|
|
SET_BIT(mode, new_mode);
|
|
|
|
fmt = ::form("%s/%s", path, name);
|
|
#ifdef C_API
|
|
fstream::open((const char *) fmt, mode);
|
|
#else
|
|
fstream::open((const char *) fmt, (ios_base::openmode)mode);
|
|
#endif
|
|
// fstream::open((const char *) fmt, mode, open_file_prot());
|
|
|
|
} else {
|
|
|
|
if ( ! fstream::rdbuf() -> is_open() ) {
|
|
fmt = ::form("%s/%s", path, name);
|
|
#ifdef C_API
|
|
fstream::open((const char *) fmt, mode);
|
|
#else
|
|
fstream::open((const char *) fmt, (ios_base::openmode)mode);
|
|
#endif
|
|
// fstream::open((const char *) fmt, mode, open_file_prot());
|
|
}
|
|
|
|
}
|
|
|
|
if ( (!(*this)) || !fstream::rdbuf() -> is_open() ) {
|
|
MESSAGE(cerr, "_open failed");
|
|
debug(cerr, new_mode);
|
|
debug(cerr, mode);
|
|
debug(cerr, my_path());
|
|
debug(cerr, my_name());
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "Can't close db file %s/%s @ %s:%d\n",
|
|
path, name, __FILE__, __LINE__);
|
|
#endif
|
|
throw(streamException(fstream::rdstate()));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/***********************************************************/
|
|
// Read a string from the store. Use internal buffer.
|
|
/***********************************************************/
|
|
int
|
|
unixf_storage::readString(mmdb_pos_t loc, char* base, int len, int str_off)
|
|
{
|
|
_open(ios::in);
|
|
|
|
int offset = int(loc) + str_off;
|
|
|
|
seekg( offset, ios::beg );
|
|
if ( bad() ) {
|
|
MESSAGE(cerr, "seekg failed");
|
|
throw(streamException(fstream::rdstate()));
|
|
}
|
|
|
|
read( base, len );
|
|
if ( bad() || len != fstream::gcount() ) {
|
|
MESSAGE(cerr, "read() failed");
|
|
throw(streamException(fstream::rdstate()));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/***********************************************************/
|
|
// Write a string to the store. Use external buffer.
|
|
/***********************************************************/
|
|
int unixf_storage::updateString(mmdb_pos_t loc, const char* base, int len, int string_ofst, Boolean flush_opt)
|
|
{
|
|
/*
|
|
debug(cerr, len);
|
|
debug(cerr, loc);
|
|
debug(cerr, int(base));
|
|
debug(cerr, string_ofst);
|
|
debug(cerr, int(flush_opt));
|
|
*/
|
|
|
|
/*
|
|
fprintf(stderr, "updateString():");
|
|
fprintf(stderr, "len=%d, ", len);
|
|
fprintf(stderr, "loc=%d, ", loc);
|
|
fprintf(stderr, "string_ofst=%d, ", string_ofst);
|
|
fprintf(stderr, "flush option=%d\n", flush_opt);
|
|
*/
|
|
|
|
_open(ios::out);
|
|
|
|
#ifdef C_API
|
|
if ( ! seekg(loc+string_ofst, ios::beg) ) {
|
|
MESSAGE(cerr, form("seek() failed on %s", my_name()));
|
|
throw(streamException(fstream::rdstate()));
|
|
}
|
|
#else
|
|
if ( ! seekp(loc+string_ofst, ios::beg) ) {
|
|
MESSAGE(cerr, form("seek() failed on %s", my_name()));
|
|
throw(streamException(fstream::rdstate()));
|
|
}
|
|
#endif
|
|
|
|
if ( ! write( base, len ) ) {
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "write() failed on %s @ %s:%d\n",
|
|
my_name(), __FILE__, __LINE__);
|
|
#endif
|
|
throw(streamException(fstream::rdstate()));
|
|
}
|
|
|
|
if ( flush_opt == true )
|
|
flush();
|
|
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "%d bytes have been written at offset %ld in %s/%s @ %s:%d\n", len, loc+string_ofst, path, name, __FILE__, __LINE__);
|
|
#ifndef C_API
|
|
{
|
|
char fname[64];
|
|
snprintf(fname, sizeof(fname), "%s.%ld-%d", name, loc+string_ofst, len);
|
|
ofstream output(fname);
|
|
output.write(base, len);
|
|
output.flush();
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
if ( !(*this) ) {
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "write() failed on %s @ %s:%d\n",
|
|
my_name(), __FILE__, __LINE__);
|
|
#endif
|
|
throw(streamException(fstream::rdstate()));
|
|
}
|
|
|
|
total_bytes = MAX(total_bytes, int(loc)+len);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/***********************************************************/
|
|
// insert a string.
|
|
/***********************************************************/
|
|
int unixf_storage::appendString(mmdb_pos_t, const char* base, int len, Boolean flush_opt)
|
|
{
|
|
mmdb_pos_t loc = bytes();
|
|
updateString(loc, base, len, 0, flush_opt);
|
|
return 0;
|
|
}
|
|
|
|
/***********************************************************/
|
|
// Return the number of bytes in the store.
|
|
/***********************************************************/
|
|
int unixf_storage::bytes()
|
|
{
|
|
if ( total_bytes == -1 ) {
|
|
|
|
#ifdef C_API
|
|
_open(ios::in);
|
|
|
|
if ( !good() )
|
|
clear();
|
|
|
|
total_bytes = ::bytes(rdbuf() -> fd());
|
|
#else
|
|
char* info_lib_file = form("%s/%s", path, name);
|
|
|
|
total_bytes = ::bytes(info_lib_file);
|
|
#endif
|
|
}
|
|
|
|
return total_bytes;
|
|
}
|
|
|
|
Boolean unixf_storage::io_mode(int test_mode)
|
|
{
|
|
Boolean opened = false;
|
|
|
|
if ( fstream::rdbuf() -> is_open() ) {
|
|
opened = true ;
|
|
fstream::close();
|
|
}
|
|
|
|
#ifdef C_API
|
|
fstream::open(name, test_mode);
|
|
#else
|
|
fstream::open(name, (ios_base::openmode)test_mode);
|
|
#endif
|
|
// fstream::open(name, test_mode, open_file_prot());
|
|
|
|
if ( ! fstream::rdbuf() -> is_open() )
|
|
return false;
|
|
else {
|
|
fstream::close();
|
|
|
|
if ( opened == true )
|
|
#ifdef C_API
|
|
fstream::open(name, mode, open_file_prot());
|
|
#else
|
|
fstream::open(name, (ios_base::openmode)mode);
|
|
#endif
|
|
// fstream::open(name, mode, open_file_prot());
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
int unixf_storage::truncate(int target_length_in_bytes)
|
|
{
|
|
char *fmt = NULL;
|
|
|
|
_open(ios::out);
|
|
|
|
if ( total_bytes > target_length_in_bytes ) {
|
|
fmt = ::form("%s/%s", path, name);
|
|
if ( ::truncate((const char *) fmt, target_length_in_bytes) != 0 ) {
|
|
throw(systemException(errno));
|
|
}
|
|
|
|
total_bytes = target_length_in_bytes;
|
|
}
|
|
|
|
|
|
return 0;
|
|
}
|