nopen.c 6.16 KB
Newer Older
1
/* Network open functions (nopen and fnopen) and friends */
2 3 4 5 6

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
7
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *																			*
 * 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.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

22 23 24
#include "filewrap.h"
#include "sockwrap.h"
#include "sbbsdefs.h"
25
#include "nopen.h"
26 27

/****************************************************************************/
28 29 30 31
/* Network open function. Opens all files DENYALL, DENYWRITE, or DENYNONE	*/
/* depending on access, and retries LOOP_NOPEN number of times if the		*/
/* attempted file is already open or denying access  for some other reason. */
/* All files are opened in BINARY mode.										*/
32
/****************************************************************************/
rswindell's avatar
rswindell committed
33
int nopen(const char* str, int access)
34 35 36 37 38
{
	int file,share,count=0;

    if(access&O_DENYNONE) {
        share=SH_DENYNO;
39 40 41 42 43 44
        access&=~O_DENYNONE; 
	} 
	else if((access&~(O_TEXT|O_BINARY))==O_RDONLY) 
		share=SH_DENYWR;
    else 
		share=SH_DENYRW;
45 46

#if !defined(__unix__)	/* Basically, a no-op on Unix anyway */
47 48
	if(!(access&O_TEXT))
		access|=O_BINARY;
49
#endif
50
    while(((file=sopen(str,access,share,DEFFILEMODE))==-1)
51
        && (errno==EACCES || errno==EAGAIN || errno==EDEADLOCK) && count++<LOOP_NOPEN)
52 53 54 55
        if(count)
            mswait(100);
    return(file);
}
56

57 58 59 60
/****************************************************************************/
/* This function performs an nopen, but returns a file stream with a buffer */
/* allocated.																*/
/****************************************************************************/
rswindell's avatar
rswindell committed
61
FILE* fnopen(int* fd, const char* str, int access)
62
{
63
	char*	mode;
64 65
	int		file;
	FILE *	stream;
66

67 68 69 70 71 72 73
    if((file=nopen(str,access))==-1)
        return(NULL);

    if(fd!=NULL)
        *fd=file;

    if(access&O_APPEND) {
deuce's avatar
deuce committed
74
        if((access&O_RDWR)==O_RDWR)
75
            mode="a+";
76
        else
77
            mode="a"; 
78
	} else if(access&(O_TRUNC|O_WRONLY)) {
deuce's avatar
deuce committed
79
		if((access&O_RDWR)==O_RDWR)
80
			mode="w+";
81
		else
82
			mode="w";
83
	} else {
deuce's avatar
deuce committed
84
        if((access&O_RDWR)==O_RDWR)
85
            mode="r+";
86
        else
87
            mode="r"; 
88 89 90 91 92 93 94 95 96
	}
    stream=fdopen(file,mode);
    if(stream==NULL) {
        close(file);
        return(NULL); 
	}
    setvbuf(stream,NULL,_IOFBF,FNOPEN_BUF_SIZE);
    return(stream);
}
rswindell's avatar
rswindell committed
97 98 99 100

BOOL ftouch(const char* fname)
{
	int file;
101
	struct utimbuf ut;
rswindell's avatar
rswindell committed
102

103
	/* update the time stamp */
104 105
	ut.actime = ut.modtime = time(NULL);
	if(utime(fname, &ut)==0)
106
		return TRUE;
107 108 109

	/* create the file */
	if((file=nopen(fname,O_WRONLY|O_CREAT))<0)
110
		return FALSE;
111
	close(file);
112
	return TRUE;
rswindell's avatar
rswindell committed
113
}
114

115
BOOL fmutex(const char* fname, const char* text, long max_age)
116 117
{
	int file;
rswindell's avatar
rswindell committed
118
	time_t t;
119
#if !defined(NO_SOCKET_SUPPORT)
120
	char hostname[128];
121 122 123
	if(text==NULL && gethostname(hostname,sizeof(hostname))==0)
		text=hostname;
#endif
124

125 126
	if(max_age && (t=fdate(fname)) >= 0 && (time(NULL)-t) > max_age) {
		if(remove(fname)!=0)
127
			return FALSE;
128
	}
129
	if((file=open(fname,O_CREAT|O_WRONLY|O_EXCL,DEFFILEMODE))<0)
130
		return FALSE;
131 132 133
	if(text!=NULL)
		write(file,text,strlen(text));
	close(file);
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
	return TRUE;
}

BOOL fcompare(const char* fn1, const char* fn2)
{
	FILE*	fp1;
	FILE*	fp2;
	BOOL	success=TRUE;

	if(flength(fn1) != flength(fn2))
		return FALSE;
	if((fp1=fopen(fn1,"rb"))==NULL)
		return FALSE;
	if((fp2=fopen(fn2,"rb"))==NULL) {
		fclose(fp1);
		return FALSE;
	}

	while(!feof(fp1) && success) {
		if(fgetc(fp1) != fgetc(fp2))
			success=FALSE;
	}

	fclose(fp1);
	fclose(fp2);

	return(success);
}


/****************************************************************************/
/****************************************************************************/
BOOL backup(const char *fname, int backup_level, BOOL ren)
{
	char	oldname[MAX_PATH+1];
	char	newname[MAX_PATH+1];
	char*	ext;
	int		i;
	int		len;

	if(flength(fname) < 1)	/* no need to backup a 0-byte (or non-existent) file */
		return FALSE;

	if((ext=strrchr(fname,'.'))==NULL)
		ext="";

	len=strlen(fname)-strlen(ext);

	for(i=backup_level;i;i--) {
		safe_snprintf(newname,sizeof(newname),"%.*s.%d%s",len,fname,i-1,ext);
		if(i==backup_level)
			if(fexist(newname) && remove(newname)!=0)
				return FALSE;
		if(i==1) {
			if(ren == TRUE) {
				if(rename(fname,newname)!=0)
					return FALSE;
			} else {
				struct utimbuf ut;

				/* preserve the original time stamp */
				ut.modtime = fdate(fname);

197
				if(!CopyFile(fname, newname, /* failIfExists: */FALSE))
198 199 200 201 202 203 204 205 206 207 208 209 210
					return FALSE;

				ut.actime = time(NULL);
				utime(newname, &ut);
			}
			continue; 
		}
		safe_snprintf(oldname,sizeof(oldname),"%.*s.%d%s",len,fname,i-2,ext);
		if(fexist(oldname) && rename(oldname,newname)!=0)
			return FALSE;
	}

	return TRUE;
211
}
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242

/****************************************************************************/
/* Open a log file for append, supporting log rotation based on size		*/
/****************************************************************************/
FILE* fopenlog(scfg_t* cfg, const char* path)
{
	const int mode = O_WRONLY|O_CREAT|O_APPEND;
	FILE* fp;

	if((fp = fnopen(NULL, path, mode)) == NULL)
		return NULL;

	if(cfg->max_log_size && cfg->max_logs_kept && ftello(fp) >= (off_t)cfg->max_log_size) {
#ifdef _WIN32 // Can't rename an open file on Windows
		fclose(fp);
#endif
		backup(path, cfg->max_logs_kept, /* rename: */TRUE);
#ifndef _WIN32
		fclose(fp);
#endif
		if((fp = fnopen(NULL, path, mode)) == NULL)
			return NULL;
	}

	return fp;
}

void fcloselog(FILE* fp)
{
	fclose(fp);
}