1 /*
2 file.* - file io classes
3 Copyright (C) 1999-2004 Matthew Mueller <donut AT dakotacom.net>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 #include "file.h"
23 #include <stdarg.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include "sockstuff.h"
29 #include "strreps.h"
30 #include "path.h"
31
32
xxrename(const char * oldpath,const char * newpath)33 void xxrename(const char *oldpath, const char *newpath) {
34 #ifdef WIN32
35 //On windows rename will not replace an existing file, so check first and remove it.
36 if (fexists(newpath)) {
37 if (unlink(newpath))
38 throw FileEx(Ex_INIT, "rename: unlink %s: %s(%i)\n",newpath,strerror(errno),errno);
39 }
40 #endif
41 if (rename(oldpath, newpath))
42 throw FileEx(Ex_INIT, "rename %s > %s: %s(%i)\n",oldpath,newpath,strerror(errno),errno);
43 }
44
copyfile(c_file * of,c_file * nf)45 void copyfile(c_file *of, c_file *nf) {
46 char buf[4096];
47 int len;
48 while ((len=of->read(buf, 4096)) != 0)
49 nf->write(buf, len);
50 }
51
bfill(uchar * b,int l)52 int c_file_buffy::bfill(uchar *b,int l){
53 return fileptr->read(b,l);
54 }
55
c_file(const char * fname)56 c_file::c_file(const char *fname): m_name(fname){
57 rbuffer=NULL;
58 }
59
~c_file()60 c_file::~c_file(){
61 // close();//cant call it here, since doclose is already gone
62 delete rbuffer;
63 }
64
vputf(const char * buf,va_list ap)65 ssize_t c_file::vputf(const char *buf, va_list ap){
66 char *fpbuf;
67 int i,l;
68 l=vasprintf(&fpbuf,buf,ap);
69 try {
70 i=write(fpbuf,l);
71 } catch (...) {
72 free(fpbuf);
73 throw;
74 }
75 free(fpbuf);
76 return i;
77 }
putf(const char * data,...)78 ssize_t c_file::putf(const char *data,...){
79 va_list ap;
80 va_start(ap,data);
81 ssize_t r=vputf(data, ap);
82 va_end(ap);
83 return r;
84 }
read(void * data,size_t len)85 ssize_t c_file::read(void *data,size_t len){
86 ssize_t i=doread(data,len);
87 if (i<0) throw FileEx(Ex_INIT,"read %s (%s)", name(), dostrerror());
88 return i;
89 }
readfull(void * data,size_t len)90 void c_file::readfull(void *data,size_t len){
91 size_t cur=0;
92 ssize_t i;
93 while (cur < len) {
94 i=doread((char*)data+cur, len-cur);
95 if (i<0) throw FileEx(Ex_INIT,"readfull %s (%s)", name(), dostrerror());
96 else if (i==0) throw FileEx(Ex_INIT,"readfull %s: unexpected EOF", name());
97 cur += i;
98 }
99 assert(cur == len);
100 }
write(const void * data,size_t len)101 ssize_t c_file::write(const void *data,size_t len){
102 size_t sent=0;
103 ssize_t i;
104 while (sent < len) {
105 i=dowrite((char*)data+sent, len-sent);
106 if (i <= 0)
107 throw FileEx(Ex_INIT,"write %s: %i!=%i (%s)", name(), sent, len, dostrerror());
108 sent += i;
109 }
110 assert(sent == len);
111 return sent;
112 }
113
flush(int local)114 void c_file::flush(int local){
115 // int i=0;
116 //###########3 dowrite(buffers..)
117 if (!local) {
118 int r=doflush();
119 if (r != 0) throw FileEx(Ex_INIT,"flush %s: %i (%s)", name(), r, dostrerror());
120 }
121 }
close(void)122 void c_file::close(void){
123 if (isopen()){
124 flush(1);
125 if (doclose() != 0)
126 throw FileEx(Ex_INIT,"close %s (%s)", name(), dostrerror());
127 }
128 if (rbuffer)rbuffer->clearbuf();
129 }
close_noEx(void)130 int c_file::close_noEx(void){
131 try {
132 close();
133 return 0;
134 } catch (FileEx &e) {
135 return -1;
136 }
137 }
initrbuf(void)138 void c_file::initrbuf(void){
139 if (!rbuffer){
140 rbuffer=new c_file_buffy(this);
141 }
142 };
143
144
c_file_fd(int dfd,const char * name)145 c_file_fd::c_file_fd(int dfd, const char *name):c_file(name){
146 fd=::dup(dfd);
147 if (fd<0)
148 throw FileEx(Ex_INIT,"dup %s(%i) (%s)", name, dfd, strerror(errno));
149 }
150
c_file_fd(const char * name,int flags,int mode)151 c_file_fd::c_file_fd(const char *name,int flags, int mode):c_file(name){
152 fd=::open(name,flags,mode);
153 if (fd<0)
154 THROW_OPEN_ERROR("open %s (%s)", name, strerror(errno));
155 //throw FileEx(Ex_INIT,"open %s (%s)", name, strerror(errno));
156 }
fopen2open(const char * mode)157 int fopen2open(const char *mode){
158 int m = 0;
159 switch(mode[0]) {
160 case 'r': m = strchr(mode,'+')?O_RDWR:O_RDONLY; break;
161 case 'w': m = (strchr(mode,'+')?O_RDWR:O_WRONLY) | O_CREAT | O_TRUNC; break;
162 case 'a': m = (strchr(mode,'+')?O_RDWR:O_WRONLY) | O_CREAT | O_APPEND; break;
163 default:assert(0);
164 }
165 if (strchr(mode,'b')) m |= O_BINARY;
166 return m;
167 }
c_file_fd(const char * name,const char * mode)168 c_file_fd::c_file_fd(const char *name,const char *mode):c_file(name){
169 int flags=fopen2open(mode);
170 fd=::open(name,flags,PUBMODE);
171 if (fd<0)
172 THROW_OPEN_ERROR("open %s (%s)", name, strerror(errno));
173 }
dostrerror(void)174 const char *c_file_fd::dostrerror(void) {
175 return strerror(errno);
176 }
doflush(void)177 int c_file_fd::doflush(void){
178 #ifdef HAVE_FSYNC
179 if (fd>=0)
180 return fsync(fd);
181 #endif
182 return 0;
183 }
doclose(void)184 int c_file_fd::doclose(void){
185 int i=0;
186 i=::close(fd);
187 fd=-1;
188 return i;
189 }
isopen(void) const190 int c_file_fd::isopen(void)const{
191 return (fd>=0);
192 }
dowrite(const void * data,size_t len)193 ssize_t c_file_fd::dowrite(const void *data,size_t len){
194 return ::write(fd,(char*)data,len);
195 }
doread(void * data,size_t len)196 ssize_t c_file_fd::doread(void *data,size_t len){
197 return ::read(fd,data,len);
198 }
seek(int offset,int whence)199 int c_file_fd::seek(int offset, int whence){
200 int r = lseek(fd, offset, whence);
201 if (r<0)
202 throw FileEx(Ex_INIT,"seek %s: %s", name(), dostrerror());
203 return r;
204 }
205
206
207 #ifdef USE_FILE_STREAM
c_file_stream(const char * name,const char * mode)208 int c_file_stream::c_file_stream(const char *name,const char * mode):c_file(name){
209 if (!(fs=fopen(name,mode)))
210 THROW_OPEN_ERROR("fopen %s (%s)", name, strerror(errno));
211 }
dostrerror(void)212 const char c_file_stream::*dostrerror(void) {
213 return strerror(errno);
214 }
doflush(void)215 int c_file_stream::doflush(void){
216 if (fs)
217 return fflush(fs);
218 return 0;
219 }
doclose(void)220 int c_file_stream::doclose(void){
221 int i=0;
222 i=fclose(fs);
223 fs=NULL;
224 return i;
225 }
isopen(void) const226 int c_file_stream::isopen(void)const{
227 return (fs!=0);
228 }
dowrite(const void * data,size_t len)229 ssize_t c_file_stream::dowrite(const void *data,size_t len){
230 return fwrite(data,1,len,fs);
231 }
doread(void * data,size_t len)232 ssize_t c_file_stream::doread(void *data,size_t len){
233 return fread(data,1,len,fs);
234 }
235 #endif
236
237
c_file_tcp(const char * host,const char * port)238 c_file_tcp::c_file_tcp(const char *host,const char * port):c_file(host){
239 if (m_name.find(':')<0){//this isn't quite right with ipv6 addrs, but its only for error messages so who cares ;)
240 m_name+=':';
241 m_name+=port;
242 }
243 try {
244 sock=make_connection(host,port);
245 } catch (FileEx &e) {
246 throw FileEx(Ex_INIT,"open %s (%s)", name(), e.getExStr());
247 }
248 }
dostrerror(void)249 const char *c_file_tcp::dostrerror(void) {
250 return sock_strerror(sock_errno);
251 }
doflush(void)252 int c_file_tcp::doflush(void){
253 #ifdef HAVE_FSYNC
254 if (sock_isvalid(sock))
255 return fsync(sock);
256 #endif
257 return 0;
258 }
doclose(void)259 int c_file_tcp::doclose(void){
260 int i=0;
261 i=sock_close(sock);
262 sock=SOCK_INVALID;
263 return i;
264 }
isopen(void) const265 int c_file_tcp::isopen(void)const{
266 return sock_isvalid(sock);
267 }
dowrite(const void * data,size_t len)268 ssize_t c_file_tcp::dowrite(const void *data,size_t len){
269 //don't need to use sock_write_ensured since c_file::write handles the looping.
270 return sock_write(sock,(char*)data, len);
271 }
doread(void * data,size_t len)272 ssize_t c_file_tcp::doread(void *data,size_t len){
273 return sock_read(sock,data,len);
274 }
datawaiting(void) const275 bool c_file_tcp::datawaiting(void) const {
276 return sock_datawaiting(sock);
277 }
278