221 lines
5.0 KiB
C
221 lines
5.0 KiB
C
#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 != '\\')
|
|
{
|
|
cs_strncat(cs_tmpdir, "/", sizeof(cs_tmpdir));
|
|
}
|
|
cs_strncat(cs_tmpdir, "_oscam", sizeof(cs_tmpdir));
|
|
#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[cs_strlen(tmp_dir) - 1] == '/')
|
|
{
|
|
slash = "";
|
|
}
|
|
snprintf(dest, destlen, "%s%s%s", tmp_dir, slash, filename);
|
|
return dest;
|
|
}
|
|
|
|
/* Return 1 if the file exists, else 0 */
|
|
bool file_exists(const char *filename)
|
|
{
|
|
return access(filename, R_OK) == 0;
|
|
}
|
|
|
|
/* Finds a file in the system PATH.
|
|
Returns a newly allocated string with the full path, or NULL if not found.
|
|
Caller must free() the returned string. */
|
|
char *find_in_path(const char *filename)
|
|
{
|
|
// If filename already has '/', don't search PATH
|
|
if (strchr(filename, '/')) {
|
|
return strdup(filename);
|
|
}
|
|
|
|
char *paths; const char *path = getenv("PATH"); if (!path || !(paths = strdup(path))) return NULL;
|
|
|
|
char *saveptr = NULL;
|
|
char *dir = strtok_r(paths, ":", &saveptr);
|
|
char fullpath[PATH_MAX];
|
|
char *result = NULL;
|
|
|
|
while (dir) {
|
|
if (*dir == '\0') dir = ".";
|
|
snprintf(fullpath, sizeof(fullpath), "%s/%s", dir, filename);
|
|
if (file_exists(fullpath)) {
|
|
result = strdup(fullpath);
|
|
break;
|
|
}
|
|
dir = strtok_r(NULL, ":", &saveptr);
|
|
}
|
|
|
|
free(paths);
|
|
return result;
|
|
}
|
|
|
|
/* 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);
|
|
if(fsync(fileno(dest)) == -1) // Dodano fsync, aby wymusić zapis na dysk
|
|
{
|
|
cs_log("ERROR: file_copy - fsync failed for %s (errno=%d %s)!", destfile, errno, strerror(errno));
|
|
}
|
|
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: safe_overwrite_with_bak - 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: safe_overwrite_with_bak - 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("ERROR: safe_overwrite_with_bak - An error occured while writing the new config file %s. Return code: %d, errno: %d (%s).", destfile, rc, errno, strerror(errno));
|
|
if(rc == -2)
|
|
{
|
|
cs_log("ERROR: safe_overwrite_with_bak - 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: safe_overwrite_with_bak - Error removing temp config file %s (errno=%d %s)!", temp_file, errno, strerror(errno));
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
if(unlink(temp_file) < 0)
|
|
{
|
|
cs_log("ERROR: safe_overwrite_with_bak - Error removing temp config file %s (errno=%d %s)!", temp_file, errno, strerror(errno));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#ifdef MODULE_GBOX
|
|
char *get_gbox_filename(char *dest, size_t destlen, const char *filename)
|
|
{
|
|
char *tmp_dir = get_tmp_dir();
|
|
const char *slash = "/";
|
|
|
|
if(cfg.gbox_tmp_dir != NULL)
|
|
{
|
|
if(cfg.gbox_tmp_dir[cs_strlen(cfg.gbox_tmp_dir) - 1] == '/')
|
|
{
|
|
slash = "";
|
|
}
|
|
snprintf(dest, destlen, "%s%s%s", cfg.gbox_tmp_dir, slash, filename);
|
|
}
|
|
else
|
|
{
|
|
if(tmp_dir[cs_strlen(tmp_dir) - 1] == '/') { slash = ""; }
|
|
snprintf(dest, destlen, "%s%s%s", tmp_dir, slash, filename);
|
|
}
|
|
return dest;
|
|
}
|
|
#endif
|