/
oscam-files.c
148 lines (138 loc) · 4.03 KB
/
oscam-files.c
1
2
3
4
5
6
7
8
9
10
11
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#define MODULE_LOG_PREFIX "files"
#include "globals.h"
#include "oscam-files.h"
#include "oscam-lock.h"
#include "oscam-string.h"
extern CS_MUTEX_LOCK readdir_lock;
extern char cs_tmpdir[200];
/* Gets the tmp dir */
char *get_tmp_dir(void)
{
if(cs_tmpdir[0])
{ return cs_tmpdir; }
#if defined(__CYGWIN__)
char *d = getenv("TMPDIR");
if(!d || !d[0])
{ d = getenv("TMP"); }
if(!d || !d[0])
{ d = getenv("TEMP"); }
if(!d || !d[0])
{ getcwd(cs_tmpdir, sizeof(cs_tmpdir) - 1); }
cs_strncpy(cs_tmpdir, d, sizeof(cs_tmpdir));
char *p = cs_tmpdir;
while(*p) { p++; }
p--;
if(*p != '/' && *p != '\\')
{ strcat(cs_tmpdir, "/"); }
strcat(cs_tmpdir, "_oscam");
#else
cs_strncpy(cs_tmpdir, "/tmp/.oscam", sizeof(cs_tmpdir));
#endif
mkdir(cs_tmpdir, S_IRWXU);
return cs_tmpdir;
}
char *get_tmp_dir_filename(char *dest, size_t destlen, const char *filename)
{
char *tmp_dir = get_tmp_dir();
const char *slash = "/";
if(tmp_dir[strlen(tmp_dir) - 1] == '/') { slash = ""; }
snprintf(dest, destlen, "%s%s%s", tmp_dir, slash, filename);
return dest;
}
/* Drop-in replacement for readdir_r as some plattforms strip the function from their libc.
Furthermore, there are some security issues, see http://womble.decadent.org.uk/readdir_r-advisory.html */
int32_t cs_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
{
/* According to POSIX the buffer readdir uses is not shared between directory streams.
However readdir is not guaranteed to be thread-safe and some implementations may use global state.
Thus we use a lock as we have many plattforms... */
int32_t rc;
cs_writelock(__func__, &readdir_lock);
errno = 0;
*result = readdir(dirp);
rc = errno;
if(errno == 0 && *result != NULL)
{
memcpy(entry, *result, sizeof(struct dirent));
*result = entry;
}
cs_writeunlock(__func__, &readdir_lock);
return rc;
}
/* Return 1 if the file exists, else 0 */
bool file_exists(const char *filename)
{
return access(filename, R_OK) == 0;
}
/* Copies a file from srcfile to destfile. If an error occured before writing, -1 is returned, else -2. On success, 0 is returned.*/
int32_t file_copy(char *srcfile, char *destfile)
{
FILE *src, *dest;
int32_t ch;
src = fopen(srcfile, "r");
if(!src)
{
cs_log("Error opening file %s for reading (errno=%d %s)!", srcfile, errno, strerror(errno));
return -1;
}
dest = fopen(destfile, "w");
if(!dest)
{
cs_log("Error opening file %s for writing (errno=%d %s)!", destfile, errno, strerror(errno));
fclose(src);
return -1;
}
while(1)
{
ch = fgetc(src);
if(ch == EOF)
{
break;
}
else
{
fputc(ch, dest);
if(ferror(dest))
{
cs_log("Error while writing to file %s (errno=%d %s)!", destfile, errno, strerror(errno));
fclose(src);
fclose(dest);
return -2;
}
}
}
fclose(src);
fclose(dest);
return (0);
}
/* Overwrites destfile with temp_file. If forceBakOverWrite = 0, the bakfile will not be overwritten if it exists, else it will be.*/
int32_t safe_overwrite_with_bak(char *destfile, char *temp_file, char *bakfile, int32_t forceBakOverWrite)
{
int32_t rc;
if(file_exists(destfile))
{
if(forceBakOverWrite != 0 || !file_exists(bakfile))
{
if(file_copy(destfile, bakfile) < 0)
{
cs_log("Error copying original config file %s to %s. The original config will be left untouched!", destfile, bakfile);
if(unlink(temp_file) < 0)
{ cs_log("Error removing temp config file %s (errno=%d %s)!", temp_file, errno, strerror(errno)); }
return 1;
}
}
}
rc = file_copy(temp_file, destfile);
if(rc < 0)
{
cs_log("An error occured while writing the new config file %s.", destfile);
if(rc == -2)
{ cs_log("The config will be missing or only partly filled upon next startup as this is a non-recoverable error! Please restore from backup or try again."); }
if(unlink(temp_file) < 0)
{ cs_log("Error removing temp config file %s (errno=%d %s)!", temp_file, errno, strerror(errno)); }
return 1;
}
if(unlink(temp_file) < 0)
{ cs_log("Error removing temp config file %s (errno=%d %s)!", temp_file, errno, strerror(errno)); }
return 0;
}