nopen.c 6.59 KB
Newer Older
1 2
/* nopen.c */

3
/* Network open functions (nopen and fnopen) and friends */
4

5
/* $Id: nopen.c,v 1.30 2018/11/23 17:08:42 rswindell Exp $ */
6 7 8 9 10

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
11
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
 *																			*
 * 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										*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include "sbbs.h"
#include "crc32.h"

/****************************************************************************/
42 43 44 45
/* 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.										*/
46
/****************************************************************************/
rswindell's avatar
rswindell committed
47
int nopen(const char* str, int access)
48 49 50 51 52
{
	int file,share,count=0;

    if(access&O_DENYNONE) {
        share=SH_DENYNO;
53 54 55 56 57 58
        access&=~O_DENYNONE; 
	} 
	else if((access&~(O_TEXT|O_BINARY))==O_RDONLY) 
		share=SH_DENYWR;
    else 
		share=SH_DENYRW;
59 60

#if !defined(__unix__)	/* Basically, a no-op on Unix anyway */
61 62
	if(!(access&O_TEXT))
		access|=O_BINARY;
63
#endif
64
    while(((file=sopen(str,access,share,DEFFILEMODE))==-1)
65
        && (errno==EACCES || errno==EAGAIN || errno==EDEADLOCK) && count++<LOOP_NOPEN)
66 67 68 69
        if(count)
            mswait(100);
    return(file);
}
70

71 72 73 74
/****************************************************************************/
/* This function performs an nopen, but returns a file stream with a buffer */
/* allocated.																*/
/****************************************************************************/
rswindell's avatar
rswindell committed
75
FILE* fnopen(int* fd, const char* str, int access)
76
{
77
	char*	mode;
78 79
	int		file;
	FILE *	stream;
80

81 82 83 84 85 86 87
    if((file=nopen(str,access))==-1)
        return(NULL);

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

    if(access&O_APPEND) {
deuce's avatar
deuce committed
88
        if((access&O_RDWR)==O_RDWR)
89
            mode="a+";
90
        else
91
            mode="a"; 
92
	} else if(access&(O_TRUNC|O_WRONLY)) {
deuce's avatar
deuce committed
93
		if((access&O_RDWR)==O_RDWR)
94
			mode="w+";
95
		else
96
			mode="w";
97
	} else {
deuce's avatar
deuce committed
98
        if((access&O_RDWR)==O_RDWR)
99
            mode="r+";
100
        else
101
            mode="r"; 
102 103 104 105 106 107 108 109 110
	}
    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
111 112 113 114

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

117
	/* update the time stamp */
118 119
	ut.actime = ut.modtime = time(NULL);
	if(utime(fname, &ut)==0)
120
		return TRUE;
121 122 123

	/* create the file */
	if((file=nopen(fname,O_WRONLY|O_CREAT))<0)
124
		return FALSE;
125
	close(file);
126
	return TRUE;
rswindell's avatar
rswindell committed
127
}
128

129
BOOL fmutex(const char* fname, const char* text, long max_age)
130 131
{
	int file;
rswindell's avatar
rswindell committed
132
	time_t t;
133
#if !defined(NO_SOCKET_SUPPORT)
134
	char hostname[128];
135 136 137
	if(text==NULL && gethostname(hostname,sizeof(hostname))==0)
		text=hostname;
#endif
138

139 140
	if(max_age && (t=fdate(fname)) >= 0 && (time(NULL)-t) > max_age) {
		if(remove(fname)!=0)
141
			return FALSE;
142
	}
143
	if((file=open(fname,O_CREAT|O_WRONLY|O_EXCL,DEFFILEMODE))<0)
144
		return FALSE;
145 146 147
	if(text!=NULL)
		write(file,text,strlen(text));
	close(file);
148 149 150 151 152
	return TRUE;
}

BOOL fcopy(const char* src, const char* dest)
{
153
	uint8_t	buf[256 * 1024];
154 155 156 157 158 159 160 161 162 163 164 165 166
	ulong	count=0;
	FILE*	in;
	FILE*	out;
	BOOL	success=TRUE;

	if((in=fopen(src,"rb"))==NULL)
		return FALSE;
	if((out=fopen(dest,"wb"))==NULL) {
		fclose(in);
		return FALSE;
	}

	while(!feof(in)) {
167 168
		size_t rd = fread(buf, sizeof(uint8_t), sizeof(buf), in);
		if(rd < 1)
169
			break;
170 171
		if(fwrite(buf, sizeof(uint8_t), rd, out) != rd) {
			success = FALSE;
172 173
			break;
		}
174
		MAYBE_YIELD();
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 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 243 244 245 246 247 248 249 250 251 252 253 254 255 256
	}

	fclose(in);
	fclose(out);

	return(success);
}

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);

				if(!fcopy(fname,newname))
					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;
257
}