static errcode_t rw_setup(profile_t profile) { prf_file_t file; errcode_t retval = 0; if (!profile) return PROF_NO_PROFILE; if (profile->magic != PROF_MAGIC_PROFILE) return PROF_MAGIC_PROFILE; file = profile->first_file; retval = profile_lock_global(); if (retval) return retval; /* Don't update the file if we've already made modifications */ if (file->data->flags & PROFILE_FILE_DIRTY) { profile_unlock_global(); return 0; } if ((file->data->flags & PROFILE_FILE_SHARED) != 0) { prf_data_t new_data; new_data = profile_make_prf_data(file->data->filespec); if (new_data == NULL) { retval = ENOMEM; } else { retval = k5_mutex_init(&new_data->lock); if (retval == 0) { new_data->root = NULL; new_data->flags = file->data->flags & ~PROFILE_FILE_SHARED; new_data->timestamp = 0; new_data->upd_serial = file->data->upd_serial; } } if (retval != 0) { profile_unlock_global(); free(new_data); return retval; } profile_dereference_data_locked(file->data); file->data = new_data; } profile_unlock_global(); retval = profile_update_file(file); return retval; }
errcode_t profile_open_file(const_profile_filespec_t filespec, prf_file_t *ret_prof) { prf_file_t prf; errcode_t retval; char *home_env = 0; prf_data_t data; char *expanded_filename; retval = CALL_INIT_FUNCTION(profile_library_initializer); if (retval) return retval; scan_shared_trees_unlocked(); prf = malloc(sizeof(struct _prf_file_t)); if (!prf) return ENOMEM; memset(prf, 0, sizeof(struct _prf_file_t)); prf->magic = PROF_MAGIC_FILE; if (filespec[0] == '~' && filespec[1] == '/') { home_env = getenv("HOME"); #ifdef HAVE_PWD_H if (home_env == NULL) { uid_t uid; struct passwd *pw, pwx; char pwbuf[BUFSIZ]; uid = getuid(); if (!k5_getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf), &pw) && pw != NULL && pw->pw_dir[0] != 0) home_env = pw->pw_dir; } #endif } if (home_env) { if (asprintf(&expanded_filename, "%s%s", home_env, filespec + 1) < 0) expanded_filename = 0; } else expanded_filename = strdup(filespec); if (expanded_filename == 0) { free(prf); return ENOMEM; } retval = k5_mutex_lock(&g_shared_trees_mutex); if (retval) { free(expanded_filename); free(prf); scan_shared_trees_unlocked(); return retval; } scan_shared_trees_locked(); for (data = g_shared_trees; data; data = data->next) { if (!strcmp(data->filespec, expanded_filename) /* Check that current uid has read access. */ && r_access(data->filespec)) break; } if (data) { data->refcount++; (void) k5_mutex_unlock(&g_shared_trees_mutex); retval = profile_update_file_data(data); free(expanded_filename); prf->data = data; *ret_prof = prf; scan_shared_trees_unlocked(); return retval; } (void) k5_mutex_unlock(&g_shared_trees_mutex); data = profile_make_prf_data(expanded_filename); if (data == NULL) { free(prf); free(expanded_filename); return ENOMEM; } free(expanded_filename); prf->data = data; retval = k5_mutex_init(&data->lock); if (retval) { free(data); free(prf); return retval; } retval = profile_update_file(prf); if (retval) { profile_close_file(prf); return retval; } retval = k5_mutex_lock(&g_shared_trees_mutex); if (retval) { profile_close_file(prf); scan_shared_trees_unlocked(); return retval; } scan_shared_trees_locked(); data->flags |= PROFILE_FILE_SHARED; data->next = g_shared_trees; g_shared_trees = data; scan_shared_trees_locked(); (void) k5_mutex_unlock(&g_shared_trees_mutex); *ret_prof = prf; return 0; }