/*
* File: io.c
*
* Author: Ulli Horlacher (framstag@rus.uni-stuttgart.de)
*
* History:
*
* 1995-08-11 Framstag initial version
* 1996-04-23 Framstag added file copying function
* 1996-05-02 Framstag corrected file creating bug in fcopy()
* 1996-06-24 Framstag enhanced fcopy() to copy to stdout
* 1997-02-02 Framstag improved reliability for fcopy() with NFS
* 1997-02-24 Framstag sprintf() -> snprintf()
* 1997-05-05 Framstag better IRIX support (blksize)
* 1997-12-09 Framstag added whereis()
* 2001-01-10 Framstag added rfopen()
* 2001-02-04 Framstag added mktmpdir() and rmtmpdir()
* 2001-02-16 Framstag fixed cleanup loop
*
* Socket read and write routines and file copy function of the
* sendfile package.
*
* Copyright © 1995-2001 Ulli Horlacher
* This file is covered by the GNU General Public License
*/
#include "config.h" /* various #defines */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "io.h" /* (socket) read/write */
#include "net.h" /* the network routines */
#include "string.h" /* extended string functions */
#include "message.h" /* information, warning and error messages */
#ifdef NEXT
#include <sys/uio.h>
#endif
#if defined(SOLARIS2)
#ifndef fileno
int fileno(FILE *);
#endif
#endif
/*
* readn - read n bytes from network socket
*
* INPUT: fd - socket file descriptor
* ptr - empty string
* nbytes - number of bytes to read
*
* RETURN: number of actual read bytes
*
* this function is derived from example code from
* "Unix Networking Programming" by W. R. Stevens
*/
int readn(int fd, char *ptr, int nbytes) {
int nleft, nread;
nleft=nbytes;
while (nleft>0) {
nread=read(fd, ptr, nleft);
if (nread<0)
return(nread);
else
if (nread==0) break;
nleft-=nread;
ptr+=nread;
}
return(nbytes-nleft);
}
/*
* writen - write n bytes to network socket
*
* INPUT: fd - socket file descriptor
* ptr - string to send
* nbytes - number of bytes to send
*
* RETURN: number of actual written bytes
*
* this function is derived from example code from
* "Unix Networking Programming" by W. R. Stevens
*/
int writen(int fd, char *ptr, int nbytes) {
int nleft, nwritten;
nleft=nbytes;
while (nleft>0) {
nwritten=write(fd, ptr, nleft);
if (nwritten<0) return(nwritten);
nleft-=nwritten;
ptr+=nwritten;
}
return(nbytes-nleft);
}
/*
* fcopy - copy a file (copy to stdout if there is no destination filename)
*
* INPUT: from - source file
* to - destination file
* mode - file protection mode
*
* RETURN: 0 if ok, -1 on failure
*
*/
int fcopy(const char *from, const char *to, mode_t mode) {
int fdin, fdout; /* file descriptor in/out */
int
rbytes, /* read bytes */
wbytes; /* written bytes */
char
tmp[MAXLEN], /* temporary string */
*buf; /* copy buffer */
struct stat finfo; /* information about a file */
off_t
fsize, /* original file size */
wtotal, /* total read bytes */
blksize; /* file system block size */
wtotal=0;
/* get the original file size */
if (stat(from,&finfo)<0) {
snprintf(MAXS(tmp),"cannot access '%s'",from);
message("",'E',tmp);
return(-1);
}
fsize=finfo.st_size;
/* open source file */
fdin=open(from,O_RDONLY,0);
if (fdin<0) {
snprintf(MAXS(tmp),"error opening '%s'",from);
message("",'E',tmp);
return(-1);
}
/* destination file specified? */
if (*to) {
/* open destination file */
fdout=creat(to,mode);
if (fdout<0) {
snprintf(MAXS(tmp),"error creating '%s'",to);
message("",'E',tmp);
close(fdin);
return(-1);
}
/* get file system block size for copy operation */
stat(to,&finfo);
#ifdef HAVE_ST_BLKSIZE
blksize=finfo.st_blksize;
#else
blksize=1024;
#endif
/* ANSI C can not dynamicly allocate with buf[blksize] */
buf=(char *)malloc(blksize);
if (!buf) message("",'F',"out of memory");
/* read until EOF */
while ((rbytes=read(fdin,buf,blksize)) > 0) {
/* write to destination file */
wbytes=write(fdout,buf,rbytes);
if (wbytes!=rbytes) {
/* write error */
close(fdin);
close(fdout);
free(buf);
snprintf(MAXS(tmp),"error writing '%s'",to);
message("",'E',tmp);
return(-1);
}
wtotal+=wbytes;
}
close(fdout);
}
else /* copy to stdout */ {
/* get file system block size for copy operation */
stat(from,&finfo);
#ifdef HAVE_ST_BLKSIZE
blksize=finfo.st_blksize;
#else
blksize=1024;
#endif
/* ANSI C can not dynamicly allocate with buf[blksize] */
buf=(char *)malloc(blksize);
if (!buf) message("",'F',"out of memory");
/* read until EOF */
while ((rbytes=read(fdin,buf,blksize)) > 0) {
/* write to stdout */
wbytes=write(fileno(stdout),buf,rbytes);
wtotal+=wbytes;
}
}
close(fdin);
free(buf);
/* read error? */
if (rbytes<0) {
snprintf(MAXS(tmp),"error reading '%s'",from);
message("",'E',tmp);
return(-1);
}
/* count mismatch or read/write errors? */
if (fsize!=wtotal) {
errno=0;
snprintf(MAXS(tmp),"wrong byte count for '%s'",from);
message("",'E',tmp);
return(-1);
}
return(0);
}
/*
* whereis - where is a program in the path
*
* INPUT: prg - program to look for
*
* RETURN: NULL if not found else path to file
*/
char *whereis(char *prg) {
int len;
static char filepath[MAXLEN]; /* file with path */
char *path; /* $PATH */
char *cp;
/* when file contains a / test directly */
if (strchr(prg,'/')) {
if (access(prg,X_OK)==0)
return(prg);
else
return(NULL);
}
len=strlen(prg);
path=getenv("PATH");
if (!path || !strchr(path,'/')) return(NULL);
while (*path==':') path++;
while (*path) {
snprintf(filepath,MAXLEN-2-len,"%s",path);
if ((cp=strchr(filepath,':'))) *cp=0;
strcat(filepath,"/");
strcat(filepath,prg);
if (access(filepath,X_OK)==0) return(filepath);
if ((cp=strchr(path,':')))
path=cp+1;
else
return(NULL);
}
return(NULL);
}
/*
* rfopen - open a regular file
*
* INPUT: file - file name (with path)
* mode - fopen mode
*
* RETURN: same like fopen(), but NULL if file is not a regular file
*/
FILE *rfopen(const char *file, const char *mode) {
struct stat finfo; /* information about a file */
/* what kind of file ist it and do we have access at all? */
if (stat(file,&finfo)<0) {
/* no such file ==> open it! (mode can be "w" or "a+") */
if (errno==ENOENT)
return(fopen(file,mode));
else
/* other error */
return(NULL);
} else {
/* regular file? */
if (finfo.st_mode&S_IFREG) {
return(fopen(file,mode));
} else {
errno=EIO;
return(NULL);
}
}
}
/*
* mktmpdir - create a new temporary directory
*
* INPUT: verbose - flag
*
* RETURN: full path of the temporary directory
*
* ENVIRONMENT: SF_TMPDIR, TMPDIR
*/
char *mktmpdir(int verbose) {
char *cp; /* a simple string pointer */
char tmp[MAXLEN]; /* temporary string */
static char tmpdir[FLEN]; /* directory for temporary files */
/* get tmpdir base */
if ((cp=getenv("SF_TMPDIR")))
snprintf(tmpdir,FLEN-30,"%s",cp);
else if ((cp=getenv("TMPDIR")))
snprintf(tmpdir,FLEN-30,"%s",cp);
else
strcpy(tmpdir,"/tmp");
snprintf(tmp,30,"/sf_%u.tmp",(unsigned int)(time(NULL)*getpid()));
strcat(tmpdir,tmp);
if (mkdir(tmpdir,S_IRWXU)<0 || chmod(tmpdir,S_IRWXU)<0) {
snprintf(MAXS(tmp),"cannot create tmpdir %s",tmpdir);
message("",'F',tmp);
}
if (verbose) {
snprintf(MAXS(tmp),"directory for temporary files is: %s",tmpdir);
message("",'I',tmp);
}
return(tmpdir);
}
/*
* rmtmpdir - delete the temporary directory
*
* INPUT: full path of the temporary directory
*/
void rmtmpdir(char *tmpdir) {
char cwd[FLEN]; /* current directory */
char tmp[MAXLEN]; /* temporary string */
struct dirent *dire; /* directory entry */
DIR *dp; /* directory pointer */
if (!tmpdir || !*tmpdir) return;
if (!getcwd(MAXS(cwd))) strcpy(cwd,"/tmp");
if (chdir(tmpdir) < 0) return;
/* open dir */
if (!(dp=opendir(tmpdir))) {
snprintf(MAXS(tmp),"cleanup: cannot open %s",tmpdir);
message("",'X',tmp);
}
while ((dire=readdir(dp))) {
/* skip . and .. */
if (strcmp(dire->d_name,".")==0 || strcmp(dire->d_name,"..")==0) continue;
/* delete file */
if (unlink(dire->d_name) < 0) {
snprintf(MAXS(tmp),"cannot remove %s/%s",tmpdir);
message("",'X',tmp);
}
}
chdir(cwd);
if (rmdir(tmpdir) < 0) {
snprintf(MAXS(tmp),"cannot remove %s",tmpdir);
message("",'X',tmp);
}
}
/*
int main(int argc, char *argv[]) {
char *filepath;
filepath=whereis(argv[1]);
if (filepath) {
printf("%s\n",filepath);
exit(0);
}
exit(1);
}
*/
syntax highlighted by Code2HTML, v. 0.9.1