/*
file.* - file io classes
Copyright (C) 1999-2004 Matthew Mueller <donut AT dakotacom.net>
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "file.h"
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "sockstuff.h"
#include "strreps.h"
#include "path.h"
void xxrename(const char *oldpath, const char *newpath) {
#ifdef WIN32
//On windows rename will not replace an existing file, so check first and remove it.
if (fexists(newpath)) {
if (unlink(newpath))
throw FileEx(Ex_INIT, "rename: unlink %s: %s(%i)\n",newpath,strerror(errno),errno);
}
#endif
if (rename(oldpath, newpath))
throw FileEx(Ex_INIT, "rename %s > %s: %s(%i)\n",oldpath,newpath,strerror(errno),errno);
}
void copyfile(c_file *of, c_file *nf) {
char buf[4096];
int len;
while ((len=of->read(buf, 4096)) != 0)
nf->write(buf, len);
}
int c_file_buffy::bfill(uchar *b,int l){
return fileptr->read(b,l);
}
c_file::c_file(const char *fname): m_name(fname){
rbuffer=NULL;
}
c_file::~c_file(){
// close();//cant call it here, since doclose is already gone
delete rbuffer;
}
ssize_t c_file::vputf(const char *buf, va_list ap){
char *fpbuf;
int i,l;
l=vasprintf(&fpbuf,buf,ap);
try {
i=write(fpbuf,l);
} catch (...) {
free(fpbuf);
throw;
}
free(fpbuf);
return i;
}
ssize_t c_file::putf(const char *data,...){
va_list ap;
va_start(ap,data);
ssize_t r=vputf(data, ap);
va_end(ap);
return r;
}
ssize_t c_file::read(void *data,size_t len){
ssize_t i=doread(data,len);
if (i<0) throw FileEx(Ex_INIT,"read %s (%s)", name(), dostrerror());
return i;
}
void c_file::readfull(void *data,size_t len){
size_t cur=0;
ssize_t i;
while (cur < len) {
i=doread((char*)data+cur, len-cur);
if (i<0) throw FileEx(Ex_INIT,"readfull %s (%s)", name(), dostrerror());
else if (i==0) throw FileEx(Ex_INIT,"readfull %s: unexpected EOF", name());
cur += i;
}
assert(cur == len);
}
ssize_t c_file::write(const void *data,size_t len){
size_t sent=0;
ssize_t i;
while (sent < len) {
i=dowrite((char*)data+sent, len-sent);
if (i <= 0)
throw FileEx(Ex_INIT,"write %s: %i!=%i (%s)", name(), sent, len, dostrerror());
sent += i;
}
assert(sent == len);
return sent;
}
void c_file::flush(int local){
// int i=0;
//###########3 dowrite(buffers..)
if (!local) {
int r=doflush();
if (r != 0) throw FileEx(Ex_INIT,"flush %s: %i (%s)", name(), r, dostrerror());
}
}
void c_file::close(void){
if (isopen()){
flush(1);
if (doclose() != 0)
throw FileEx(Ex_INIT,"close %s (%s)", name(), dostrerror());
}
if (rbuffer)rbuffer->clearbuf();
}
int c_file::close_noEx(void){
try {
close();
return 0;
} catch (FileEx &e) {
return -1;
}
}
void c_file::initrbuf(void){
if (!rbuffer){
rbuffer=new c_file_buffy(this);
}
};
c_file_fd::c_file_fd(int dfd, const char *name):c_file(name){
fd=::dup(dfd);
if (fd<0)
throw FileEx(Ex_INIT,"dup %s(%i) (%s)", name, dfd, strerror(errno));
}
c_file_fd::c_file_fd(const char *name,int flags, int mode):c_file(name){
fd=::open(name,flags,mode);
if (fd<0)
THROW_OPEN_ERROR("open %s (%s)", name, strerror(errno));
//throw FileEx(Ex_INIT,"open %s (%s)", name, strerror(errno));
}
int fopen2open(const char *mode){
int m = 0;
switch(mode[0]) {
case 'r': m = strchr(mode,'+')?O_RDWR:O_RDONLY; break;
case 'w': m = (strchr(mode,'+')?O_RDWR:O_WRONLY) | O_CREAT | O_TRUNC; break;
case 'a': m = (strchr(mode,'+')?O_RDWR:O_WRONLY) | O_CREAT | O_APPEND; break;
default:assert(0);
}
if (strchr(mode,'b')) m |= O_BINARY;
return m;
}
c_file_fd::c_file_fd(const char *name,const char *mode):c_file(name){
int flags=fopen2open(mode);
fd=::open(name,flags,PUBMODE);
if (fd<0)
THROW_OPEN_ERROR("open %s (%s)", name, strerror(errno));
}
const char *c_file_fd::dostrerror(void) {
return strerror(errno);
}
int c_file_fd::doflush(void){
#ifdef HAVE_FSYNC
if (fd>=0)
return fsync(fd);
#endif
return 0;
}
int c_file_fd::doclose(void){
int i=0;
i=::close(fd);
fd=-1;
return i;
}
int c_file_fd::isopen(void)const{
return (fd>=0);
}
ssize_t c_file_fd::dowrite(const void *data,size_t len){
return ::write(fd,(char*)data,len);
}
ssize_t c_file_fd::doread(void *data,size_t len){
return ::read(fd,data,len);
}
int c_file_fd::seek(int offset, int whence){
int r = lseek(fd, offset, whence);
if (r<0)
throw FileEx(Ex_INIT,"seek %s: %s", name(), dostrerror());
return r;
}
#ifdef USE_FILE_STREAM
int c_file_stream::c_file_stream(const char *name,const char * mode):c_file(name){
if (!(fs=fopen(name,mode)))
THROW_OPEN_ERROR("fopen %s (%s)", name, strerror(errno));
}
const char c_file_stream::*dostrerror(void) {
return strerror(errno);
}
int c_file_stream::doflush(void){
if (fs)
return fflush(fs);
return 0;
}
int c_file_stream::doclose(void){
int i=0;
i=fclose(fs);
fs=NULL;
return i;
}
int c_file_stream::isopen(void)const{
return (fs!=0);
}
ssize_t c_file_stream::dowrite(const void *data,size_t len){
return fwrite(data,1,len,fs);
}
ssize_t c_file_stream::doread(void *data,size_t len){
return fread(data,1,len,fs);
}
#endif
c_file_tcp::c_file_tcp(const char *host,const char * port):c_file(host){
if (m_name.find(':')<0){//this isn't quite right with ipv6 addrs, but its only for error messages so who cares ;)
m_name+=':';
m_name+=port;
}
try {
sock=make_connection(host,port);
} catch (FileEx &e) {
throw FileEx(Ex_INIT,"open %s (%s)", name(), e.getExStr());
}
}
const char *c_file_tcp::dostrerror(void) {
return sock_strerror(sock_errno);
}
int c_file_tcp::doflush(void){
#ifdef HAVE_FSYNC
if (sock_isvalid(sock))
return fsync(sock);
#endif
return 0;
}
int c_file_tcp::doclose(void){
int i=0;
i=sock_close(sock);
sock=SOCK_INVALID;
return i;
}
int c_file_tcp::isopen(void)const{
return sock_isvalid(sock);
}
ssize_t c_file_tcp::dowrite(const void *data,size_t len){
//don't need to use sock_write_ensured since c_file::write handles the looping.
return sock_write(sock,(char*)data, len);
}
ssize_t c_file_tcp::doread(void *data,size_t len){
return sock_read(sock,data,len);
}
bool c_file_tcp::datawaiting(void) const {
return sock_datawaiting(sock);
}
syntax highlighted by Code2HTML, v. 0.9.1