|
Packit |
fd8b60 |
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* prof_file.c ---- routines that manipulate an individual profile file.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include "prof_int.h"
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include <stdio.h>
|
|
Packit |
fd8b60 |
#ifdef HAVE_STDLIB_H
|
|
Packit |
fd8b60 |
#include <stdlib.h>
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
#ifdef HAVE_UNISTD_H
|
|
Packit |
fd8b60 |
#include <unistd.h>
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
#include <string.h>
|
|
Packit |
fd8b60 |
#include <stddef.h>
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include <sys/types.h>
|
|
Packit |
fd8b60 |
#include <sys/stat.h>
|
|
Packit |
fd8b60 |
#include <errno.h>
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#ifdef HAVE_PWD_H
|
|
Packit |
fd8b60 |
#include <pwd.h>
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#if defined(_WIN32)
|
|
Packit |
fd8b60 |
#include <io.h>
|
|
Packit |
fd8b60 |
#define HAVE_STAT
|
|
Packit |
fd8b60 |
#define stat _stat
|
|
Packit |
fd8b60 |
#ifndef S_ISDIR
|
|
Packit |
fd8b60 |
#define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include "k5-platform.h"
|
|
rpm-build |
c4c9c6 |
#include "k5-label.h"
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
struct global_shared_profile_data {
|
|
Packit |
fd8b60 |
/* This is the head of the global list of shared trees */
|
|
Packit |
fd8b60 |
prf_data_t trees;
|
|
Packit |
fd8b60 |
/* Lock for above list. */
|
|
Packit |
fd8b60 |
k5_mutex_t mutex;
|
|
Packit |
fd8b60 |
};
|
|
Packit |
fd8b60 |
#define g_shared_trees (krb5int_profile_shared_data.trees)
|
|
Packit |
fd8b60 |
#define g_shared_trees_mutex (krb5int_profile_shared_data.mutex)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static struct global_shared_profile_data krb5int_profile_shared_data = {
|
|
Packit |
fd8b60 |
0,
|
|
Packit |
fd8b60 |
K5_MUTEX_PARTIAL_INITIALIZER
|
|
Packit |
fd8b60 |
};
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
MAKE_INIT_FUNCTION(profile_library_initializer);
|
|
Packit |
fd8b60 |
MAKE_FINI_FUNCTION(profile_library_finalizer);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
int profile_library_initializer(void)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
#ifdef SHOW_INITFINI_FUNCS
|
|
Packit |
fd8b60 |
printf("profile_library_initializer\n");
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
add_error_table(&et_prof_error_table);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
return k5_mutex_finish_init(&g_shared_trees_mutex);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
void profile_library_finalizer(void)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
if (! INITIALIZER_RAN(profile_library_initializer) || PROGRAM_EXITING()) {
|
|
Packit |
fd8b60 |
#ifdef SHOW_INITFINI_FUNCS
|
|
Packit |
fd8b60 |
printf("profile_library_finalizer: skipping\n");
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
#ifdef SHOW_INITFINI_FUNCS
|
|
Packit |
fd8b60 |
printf("profile_library_finalizer\n");
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
k5_mutex_destroy(&g_shared_trees_mutex);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
remove_error_table(&et_prof_error_table);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static void profile_free_file_data(prf_data_t);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static int rw_access(const_profile_filespec_t filespec)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
#ifdef HAVE_ACCESS
|
|
Packit |
fd8b60 |
if (access(filespec, W_OK) == 0)
|
|
Packit |
fd8b60 |
return 1;
|
|
Packit |
fd8b60 |
else
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
#else
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* We're on a substandard OS that doesn't support access. So
|
|
Packit |
fd8b60 |
* we kludge a test using stdio routines, and hope fopen
|
|
Packit |
fd8b60 |
* checks the r/w permissions.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
FILE *f;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
f = fopen(filespec, "r+");
|
|
Packit |
fd8b60 |
if (f) {
|
|
Packit |
fd8b60 |
fclose(f);
|
|
Packit |
fd8b60 |
return 1;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static int r_access(const_profile_filespec_t filespec)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
#ifdef HAVE_ACCESS
|
|
Packit |
fd8b60 |
if (access(filespec, R_OK) == 0)
|
|
Packit |
fd8b60 |
return 1;
|
|
Packit |
fd8b60 |
else
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
#else
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* We're on a substandard OS that doesn't support access. So
|
|
Packit |
fd8b60 |
* we kludge a test using stdio routines, and hope fopen
|
|
Packit |
fd8b60 |
* checks the r/w permissions.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
FILE *f;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
f = fopen(filespec, "r");
|
|
Packit |
fd8b60 |
if (f) {
|
|
Packit |
fd8b60 |
fclose(f);
|
|
Packit |
fd8b60 |
return 1;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
int profile_file_is_writable(prf_file_t profile)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
if (profile && profile->data) {
|
|
Packit |
fd8b60 |
return rw_access(profile->data->filespec);
|
|
Packit |
fd8b60 |
} else {
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
prf_data_t
|
|
Packit |
fd8b60 |
profile_make_prf_data(const char *filename)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
prf_data_t d;
|
|
Packit |
fd8b60 |
size_t len, flen, slen;
|
|
Packit |
fd8b60 |
char *fcopy;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
flen = strlen(filename);
|
|
Packit |
fd8b60 |
slen = offsetof(struct _prf_data_t, filespec);
|
|
Packit |
fd8b60 |
len = slen + flen + 1;
|
|
Packit |
fd8b60 |
if (len < sizeof(struct _prf_data_t))
|
|
Packit |
fd8b60 |
len = sizeof(struct _prf_data_t);
|
|
Packit |
fd8b60 |
d = malloc(len);
|
|
Packit |
fd8b60 |
if (d == NULL)
|
|
Packit |
fd8b60 |
return NULL;
|
|
Packit |
fd8b60 |
memset(d, 0, len);
|
|
Packit |
fd8b60 |
fcopy = (char *) d + slen;
|
|
Packit |
fd8b60 |
assert(fcopy == d->filespec);
|
|
Packit |
fd8b60 |
strlcpy(fcopy, filename, flen + 1);
|
|
Packit |
fd8b60 |
d->refcount = 1;
|
|
Packit |
fd8b60 |
d->magic = PROF_MAGIC_FILE_DATA;
|
|
Packit |
fd8b60 |
d->root = NULL;
|
|
Packit |
fd8b60 |
d->next = NULL;
|
|
Packit |
fd8b60 |
d->fslen = flen;
|
|
Packit |
fd8b60 |
return d;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
errcode_t profile_open_file(const_profile_filespec_t filespec,
|
|
Packit |
fd8b60 |
prf_file_t *ret_prof, char **ret_modspec)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
prf_file_t prf;
|
|
Packit |
fd8b60 |
errcode_t retval;
|
|
Packit |
fd8b60 |
char *home_env = 0;
|
|
Packit |
fd8b60 |
prf_data_t data;
|
|
Packit |
fd8b60 |
char *expanded_filename;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = CALL_INIT_FUNCTION(profile_library_initializer);
|
|
Packit |
fd8b60 |
if (retval)
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
prf = malloc(sizeof(struct _prf_file_t));
|
|
Packit |
fd8b60 |
if (!prf)
|
|
Packit |
fd8b60 |
return ENOMEM;
|
|
Packit |
fd8b60 |
memset(prf, 0, sizeof(struct _prf_file_t));
|
|
Packit |
fd8b60 |
prf->magic = PROF_MAGIC_FILE;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (filespec[0] == '~' && filespec[1] == '/') {
|
|
Packit |
fd8b60 |
home_env = secure_getenv("HOME");
|
|
Packit |
fd8b60 |
#ifdef HAVE_PWD_H
|
|
Packit |
fd8b60 |
if (home_env == NULL) {
|
|
Packit |
fd8b60 |
uid_t uid;
|
|
Packit |
fd8b60 |
struct passwd *pw, pwx;
|
|
Packit |
fd8b60 |
char pwbuf[BUFSIZ];
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
uid = getuid();
|
|
Packit |
fd8b60 |
if (!k5_getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf), &pw)
|
|
Packit |
fd8b60 |
&& pw != NULL && pw->pw_dir[0] != 0)
|
|
Packit |
fd8b60 |
home_env = pw->pw_dir;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (home_env) {
|
|
Packit |
fd8b60 |
if (asprintf(&expanded_filename, "%s%s", home_env,
|
|
Packit |
fd8b60 |
filespec + 1) < 0)
|
|
Packit |
fd8b60 |
expanded_filename = 0;
|
|
Packit |
fd8b60 |
} else
|
|
Packit |
fd8b60 |
expanded_filename = strdup(filespec);
|
|
Packit |
fd8b60 |
if (expanded_filename == 0) {
|
|
Packit |
fd8b60 |
free(prf);
|
|
Packit |
fd8b60 |
return ENOMEM;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
k5_mutex_lock(&g_shared_trees_mutex);
|
|
Packit |
fd8b60 |
for (data = g_shared_trees; data; data = data->next) {
|
|
Packit |
fd8b60 |
if (!strcmp(data->filespec, expanded_filename)
|
|
Packit |
fd8b60 |
/* Check that current uid has read access. */
|
|
Packit |
fd8b60 |
&& r_access(data->filespec))
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (data) {
|
|
Packit |
fd8b60 |
data->refcount++;
|
|
Packit |
fd8b60 |
data->last_stat = 0; /* Make sure to stat when updating. */
|
|
Packit |
fd8b60 |
k5_mutex_unlock(&g_shared_trees_mutex);
|
|
Packit |
fd8b60 |
retval = profile_update_file_data(data, NULL);
|
|
Packit |
fd8b60 |
free(expanded_filename);
|
|
Packit |
fd8b60 |
if (retval) {
|
|
Packit |
fd8b60 |
profile_dereference_data(data);
|
|
Packit |
fd8b60 |
free(prf);
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
prf->data = data;
|
|
Packit |
fd8b60 |
*ret_prof = prf;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
k5_mutex_unlock(&g_shared_trees_mutex);
|
|
Packit |
fd8b60 |
data = profile_make_prf_data(expanded_filename);
|
|
Packit |
fd8b60 |
if (data == NULL) {
|
|
Packit |
fd8b60 |
free(prf);
|
|
Packit |
fd8b60 |
free(expanded_filename);
|
|
Packit |
fd8b60 |
return ENOMEM;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
free(expanded_filename);
|
|
Packit |
fd8b60 |
prf->data = data;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = k5_mutex_init(&data->lock);
|
|
Packit |
fd8b60 |
if (retval) {
|
|
Packit |
fd8b60 |
free(data);
|
|
Packit |
fd8b60 |
free(prf);
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = profile_update_file(prf, ret_modspec);
|
|
Packit |
fd8b60 |
if (retval) {
|
|
Packit |
fd8b60 |
profile_close_file(prf);
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
k5_mutex_lock(&g_shared_trees_mutex);
|
|
Packit |
fd8b60 |
data->flags |= PROFILE_FILE_SHARED;
|
|
Packit |
fd8b60 |
data->next = g_shared_trees;
|
|
Packit |
fd8b60 |
g_shared_trees = data;
|
|
Packit |
fd8b60 |
k5_mutex_unlock(&g_shared_trees_mutex);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*ret_prof = prf;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
errcode_t profile_update_file_data_locked(prf_data_t data, char **ret_modspec)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
errcode_t retval;
|
|
Packit |
fd8b60 |
#ifdef HAVE_STAT
|
|
Packit |
fd8b60 |
struct stat st;
|
|
Packit |
fd8b60 |
unsigned long frac;
|
|
Packit |
fd8b60 |
time_t now;
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
FILE *f;
|
|
Packit |
fd8b60 |
int isdir = 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if ((data->flags & PROFILE_FILE_NO_RELOAD) && data->root != NULL)
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#ifdef HAVE_STAT
|
|
Packit |
fd8b60 |
now = time(0);
|
|
Packit |
fd8b60 |
if (now == data->last_stat && data->root != NULL) {
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (stat(data->filespec, &st)) {
|
|
Packit |
fd8b60 |
return errno;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
data->last_stat = now;
|
|
Packit |
fd8b60 |
#if defined HAVE_STRUCT_STAT_ST_MTIMENSEC
|
|
Packit |
fd8b60 |
frac = st.st_mtimensec;
|
|
Packit |
fd8b60 |
#elif defined HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
|
|
Packit |
fd8b60 |
frac = st.st_mtimespec.tv_nsec;
|
|
Packit |
fd8b60 |
#elif defined HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
|
|
Packit |
fd8b60 |
frac = st.st_mtim.tv_nsec;
|
|
Packit |
fd8b60 |
#else
|
|
Packit |
fd8b60 |
frac = 0;
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
if (st.st_mtime == data->timestamp
|
|
Packit |
fd8b60 |
&& frac == data->frac_ts
|
|
Packit |
fd8b60 |
&& data->root != NULL) {
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (data->root) {
|
|
Packit |
fd8b60 |
profile_free_node(data->root);
|
|
Packit |
fd8b60 |
data->root = 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Only try to reload regular files, not devices such as pipes. */
|
|
Packit |
fd8b60 |
if ((st.st_mode & S_IFMT) != S_IFREG)
|
|
Packit |
fd8b60 |
data->flags |= PROFILE_FILE_NO_RELOAD;
|
|
Packit |
fd8b60 |
#else
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* If we don't have the stat() call, assume that our in-core
|
|
Packit |
fd8b60 |
* memory image is correct. That is, we won't reread the
|
|
Packit |
fd8b60 |
* profile file if it changes.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
if (data->root) {
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#ifdef HAVE_STAT
|
|
Packit |
fd8b60 |
isdir = S_ISDIR(st.st_mode);
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
if (!isdir) {
|
|
Packit |
fd8b60 |
errno = 0;
|
|
Packit |
fd8b60 |
f = fopen(data->filespec, "r");
|
|
Packit |
fd8b60 |
if (f == NULL)
|
|
Packit |
fd8b60 |
return (errno != 0) ? errno : ENOENT;
|
|
Packit |
fd8b60 |
set_cloexec_file(f);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
data->upd_serial++;
|
|
Packit |
fd8b60 |
data->flags &= ~PROFILE_FILE_DIRTY;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (isdir) {
|
|
Packit |
fd8b60 |
retval = profile_process_directory(data->filespec, &data->root);
|
|
Packit |
fd8b60 |
} else {
|
|
Packit |
fd8b60 |
retval = profile_parse_file(f, &data->root, ret_modspec);
|
|
Packit |
fd8b60 |
(void)fclose(f);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (retval) {
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
assert(data->root != NULL);
|
|
Packit |
fd8b60 |
#ifdef HAVE_STAT
|
|
Packit |
fd8b60 |
data->timestamp = st.st_mtime;
|
|
Packit |
fd8b60 |
data->frac_ts = frac;
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
errcode_t profile_update_file_data(prf_data_t data, char **ret_modspec)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
errcode_t retval;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
k5_mutex_lock(&data->lock);
|
|
Packit |
fd8b60 |
retval = profile_update_file_data_locked(data, ret_modspec);
|
|
Packit |
fd8b60 |
k5_mutex_unlock(&data->lock);
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static int
|
|
Packit |
fd8b60 |
make_hard_link(const char *oldpath, const char *newpath)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
#ifdef _WIN32
|
|
Packit |
fd8b60 |
return -1;
|
|
Packit |
fd8b60 |
#else
|
|
Packit |
fd8b60 |
return link(oldpath, newpath);
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static errcode_t write_data_to_file(prf_data_t data, const char *outfile,
|
|
Packit |
fd8b60 |
int can_create)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
FILE *f;
|
|
Packit |
fd8b60 |
profile_filespec_t new_file;
|
|
Packit |
fd8b60 |
profile_filespec_t old_file;
|
|
Packit |
fd8b60 |
errcode_t retval = 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = ENOMEM;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
new_file = old_file = 0;
|
|
Packit |
fd8b60 |
if (asprintf(&new_file, "%s.$$$", outfile) < 0) {
|
|
Packit |
fd8b60 |
new_file = NULL;
|
|
Packit |
fd8b60 |
goto errout;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (asprintf(&old_file, "%s.bak", outfile) < 0) {
|
|
Packit |
fd8b60 |
old_file = NULL;
|
|
Packit |
fd8b60 |
goto errout;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
errno = 0;
|
|
Packit |
fd8b60 |
|
|
rpm-build |
c4c9c6 |
f = WRITABLEFOPEN(new_file, "w");
|
|
Packit |
fd8b60 |
if (!f) {
|
|
Packit |
fd8b60 |
retval = errno;
|
|
Packit |
fd8b60 |
if (retval == 0)
|
|
Packit |
fd8b60 |
retval = PROF_FAIL_OPEN;
|
|
Packit |
fd8b60 |
goto errout;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
set_cloexec_file(f);
|
|
Packit |
fd8b60 |
profile_write_tree_file(data->root, f);
|
|
Packit |
fd8b60 |
if (fclose(f) != 0) {
|
|
Packit |
fd8b60 |
retval = errno;
|
|
Packit |
fd8b60 |
goto errout;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
unlink(old_file);
|
|
Packit |
fd8b60 |
if (make_hard_link(outfile, old_file) == 0) {
|
|
Packit |
fd8b60 |
/* Okay, got the hard link. Yay. Now we've got our
|
|
Packit |
fd8b60 |
backup version, so just put the new version in
|
|
Packit |
fd8b60 |
place. */
|
|
Packit |
fd8b60 |
if (rename(new_file, outfile)) {
|
|
Packit |
fd8b60 |
/* Weird, the rename didn't work. But the old version
|
|
Packit |
fd8b60 |
should still be in place, so no special cleanup is
|
|
Packit |
fd8b60 |
needed. */
|
|
Packit |
fd8b60 |
retval = errno;
|
|
Packit |
fd8b60 |
goto errout;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
} else if (errno == ENOENT && can_create) {
|
|
Packit |
fd8b60 |
if (rename(new_file, outfile)) {
|
|
Packit |
fd8b60 |
retval = errno;
|
|
Packit |
fd8b60 |
goto errout;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
} else {
|
|
Packit |
fd8b60 |
/* Couldn't make the hard link, so there's going to be a
|
|
Packit |
fd8b60 |
small window where data->filespec does not refer to
|
|
Packit |
fd8b60 |
either version. */
|
|
Packit |
fd8b60 |
#ifndef _WIN32
|
|
Packit |
fd8b60 |
sync();
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
if (rename(outfile, old_file)) {
|
|
Packit |
fd8b60 |
retval = errno;
|
|
Packit |
fd8b60 |
goto errout;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (rename(new_file, outfile)) {
|
|
Packit |
fd8b60 |
retval = errno;
|
|
Packit |
fd8b60 |
rename(old_file, outfile); /* back out... */
|
|
Packit |
fd8b60 |
goto errout;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
errout:
|
|
Packit |
fd8b60 |
if (new_file)
|
|
Packit |
fd8b60 |
free(new_file);
|
|
Packit |
fd8b60 |
if (old_file)
|
|
Packit |
fd8b60 |
free(old_file);
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
errcode_t profile_flush_file_data_to_buffer (prf_data_t data, char **bufp)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
errcode_t retval;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
k5_mutex_lock(&data->lock);
|
|
Packit |
fd8b60 |
retval = profile_write_tree_to_buffer(data->root, bufp);
|
|
Packit |
fd8b60 |
k5_mutex_unlock(&data->lock);
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
errcode_t profile_flush_file_data(prf_data_t data)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
errcode_t retval = 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (!data || data->magic != PROF_MAGIC_FILE_DATA)
|
|
Packit |
fd8b60 |
return PROF_MAGIC_FILE_DATA;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
k5_mutex_lock(&data->lock);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if ((data->flags & PROFILE_FILE_DIRTY) == 0) {
|
|
Packit |
fd8b60 |
k5_mutex_unlock(&data->lock);
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = write_data_to_file(data, data->filespec, 0);
|
|
Packit |
fd8b60 |
data->flags &= ~PROFILE_FILE_DIRTY;
|
|
Packit |
fd8b60 |
k5_mutex_unlock(&data->lock);
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
errcode_t profile_flush_file_data_to_file(prf_data_t data, const char *outfile)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
errcode_t retval = 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (!data || data->magic != PROF_MAGIC_FILE_DATA)
|
|
Packit |
fd8b60 |
return PROF_MAGIC_FILE_DATA;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
k5_mutex_lock(&data->lock);
|
|
Packit |
fd8b60 |
retval = write_data_to_file(data, outfile, 1);
|
|
Packit |
fd8b60 |
k5_mutex_unlock(&data->lock);
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
void profile_dereference_data(prf_data_t data)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
k5_mutex_lock(&g_shared_trees_mutex);
|
|
Packit |
fd8b60 |
profile_dereference_data_locked(data);
|
|
Packit |
fd8b60 |
k5_mutex_unlock(&g_shared_trees_mutex);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
void profile_dereference_data_locked(prf_data_t data)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
data->refcount--;
|
|
Packit |
fd8b60 |
if (data->refcount == 0)
|
|
Packit |
fd8b60 |
profile_free_file_data(data);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
void profile_lock_global()
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
k5_mutex_lock(&g_shared_trees_mutex);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
void profile_unlock_global()
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
k5_mutex_unlock(&g_shared_trees_mutex);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
void profile_free_file(prf_file_t prf)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
profile_dereference_data(prf->data);
|
|
Packit |
fd8b60 |
free(prf);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Call with mutex locked! */
|
|
Packit |
fd8b60 |
static void profile_free_file_data(prf_data_t data)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
if (data->flags & PROFILE_FILE_SHARED) {
|
|
Packit |
fd8b60 |
/* Remove from linked list. */
|
|
Packit |
fd8b60 |
if (g_shared_trees == data)
|
|
Packit |
fd8b60 |
g_shared_trees = data->next;
|
|
Packit |
fd8b60 |
else {
|
|
Packit |
fd8b60 |
prf_data_t prev, next;
|
|
Packit |
fd8b60 |
prev = g_shared_trees;
|
|
Packit |
fd8b60 |
next = prev->next;
|
|
Packit |
fd8b60 |
while (next) {
|
|
Packit |
fd8b60 |
if (next == data) {
|
|
Packit |
fd8b60 |
prev->next = next->next;
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
prev = next;
|
|
Packit |
fd8b60 |
next = next->next;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (data->root)
|
|
Packit |
fd8b60 |
profile_free_node(data->root);
|
|
Packit |
fd8b60 |
data->magic = 0;
|
|
Packit |
fd8b60 |
k5_mutex_destroy(&data->lock);
|
|
Packit |
fd8b60 |
free(data);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
errcode_t profile_close_file(prf_file_t prf)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
errcode_t retval;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = profile_flush_file(prf);
|
|
Packit |
fd8b60 |
if (retval)
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
profile_free_file(prf);
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|