Blame src/util/profile/prof_file.c

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 8f6511
#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 8f6511
    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
}