#include #include /* Directory information */ #include #include #include #include #include /* for unlink(), etc. */ #include #include /* for malloc(), free(), etc. */ #include "../global.h" #include "shared_cs_util.h" #include "shared_strtrm.h" #include "shared_file_util.h" #include "shared_user_index.h" /* for typedefs */ static void unlock_user_index (const char *users_path) { char lkfile[MAX_PATH + 1]; snprintf (lkfile, MAX_PATH + 1, "%s%s", TMP_PATH, USER_INDEX_LOCKFILE); unlink (lkfile); } /* the user index is locked using a lockfile ** Can't use flock() since some functions ** will need to entirely re-create the index file **/ static void lock_user_index(const char *users_path) { #define STALE_SECS 120 /* a lock file older than this #seconds has been abandoned */ char lkfile[MAX_PATH + 1]; int i; int fd; extern int errno; struct stat buf; time_t now; snprintf (lkfile, MAX_PATH + 1, "%s%s", TMP_PATH, USER_INDEX_LOCKFILE); /* check for an abandoned lock file ** if it exists, and was modified more than STALE_SECS ago, ** then the file is probably abandoned and can be deleted */ if(!stat(lkfile, &buf)) { now = time(NULL); if( (now - buf.st_mtime) > STALE_SECS) unlink(lkfile); } /* now create the lock file */ for (i = 1; i <= MAX_LOCK_ATTEMPTS; i++) { fd = open (lkfile, O_WRONLY | O_CREAT | O_EXCL, 0644); if ((fd < 0) && (errno == EEXIST)) sleep (3); else if (fd < 0) cs_critical_error (ERR_ERROR_CHECKING_INDEX_LOCKFILE, ""); else { close (fd); change_mkstemp_permission(lkfile); /* shared_file_util.c */ return; } } cs_critical_error (ERR_CANT_LOCK_USER_INDEX, ""); #undef STALE_SECS } static void add_index_data(const char *users_directory, const char *letter_directory, const char *username, FILE *index_fp) { char id_path[MAX_PATH + 1]; FILE *id_fp; char id[100]; char realname[100]; snprintf(id_path, MAX_PATH, "%s/%s/%s/%s", users_directory, letter_directory, username,ID_FNAME); id_fp = fopen(id_path, "r"); if(!id_fp) { return; } if(!fgets(id,100,id_fp) || !fgets(realname,100,id_fp)) { unlock_user_index (users_directory); cs_critical_error(ERR_ERROR_READING_ID_FILE_X, id_path); } fclose(id_fp); strtrm(id); /* shared_strtrm.c */ strtrm(realname); fprintf(index_fp,"%s:%s:%s\n",username,id,realname); } static void process_letter_directory(const char *users_directory, const char *letter_directory, FILE *fp) { char dir_path[MAX_PATH + 1]; DIR *dir_p; struct dirent *dir_entry_p; snprintf(dir_path, MAX_PATH + 1, "%s/%s" , users_directory, letter_directory); dir_p = opendir (dir_path); if (!dir_p) return; while (NULL != (dir_entry_p = readdir (dir_p))) { if(*(dir_entry_p->d_name) != '.') add_index_data(users_directory, letter_directory, dir_entry_p->d_name, fp); } closedir (dir_p); } static void do_reindex(const char *users_directory, FILE *fp) { DIR *dir_p; struct dirent *dir_entry_p; dir_p = opendir (users_directory); if (!dir_p) { unlock_user_index(users_directory); cs_critical_error (ERR_CANT_OPEN_USERS_DIR_X, users_directory); } while (NULL != (dir_entry_p = readdir (dir_p))) { if( (*(dir_entry_p->d_name) != '.') && strcmp(dir_entry_p->d_name, "keys") && strcmp(dir_entry_p->d_name,USER_INDEX_FNAME) && strcmp(dir_entry_p->d_name, USER_INDEX_LOCKFILE) ) { process_letter_directory(users_directory, dir_entry_p->d_name,fp); } } closedir (dir_p); } void reindex_users(const char *users_path) { FILE *fp = 0; char index_path[MAX_PATH + 1]; lock_user_index(users_path); snprintf(index_path, MAX_PATH + 1, "%s/%s",users_path,USER_INDEX_FNAME); fp = fopen(index_path, "w"); if(!fp) { unlock_user_index(users_path); cs_critical_error(ERR_FOPEN_WRITE_FAILED, ""); } do_reindex(users_path,fp); fclose(fp); unlock_user_index(users_path); } int add_to_user_index(const char *users_path, const char *username, const char *realname, const char *id) { char index_path[MAX_PATH + 1]; FILE *fp; lock_user_index(users_path); snprintf(index_path, MAX_PATH + 1, "%s/%s",users_path,USER_INDEX_FNAME); fp = fopen(index_path, "a"); if(!fp) { unlock_user_index(users_path); return 0; } fprintf(fp,"%s:%s:%s\n",username,id,realname); fclose(fp); unlock_user_index(users_path); return 1; } /* reads entire index.txt file into buffer */ void buffer_index ( char **buffer ) { FILE *fp; struct stat statbuf; char users_path[MAX_PATH + 1]; char index_path[MAX_PATH + 1]; *buffer = (char *) 0; snprintf(users_path, MAX_PATH + 1, "../%s",USERS_DIR); snprintf(index_path, MAX_PATH + 1, "%s/%s", users_path, USER_INDEX_FNAME); lock_user_index(users_path); if (stat (index_path, &statbuf)) /* then index file doesn't exist - return a null string */ { unlock_user_index(users_path); *buffer = (char *) malloc(1 * sizeof(char)); **buffer = '\0'; return; } *buffer = (char *) malloc((statbuf.st_size + 1) * sizeof(char)); if(!*buffer) { unlock_user_index(users_path); cs_critical_error (ERR_MALLOC_FAILED, ""); } fp = fopen(index_path, "r"); if(!fp) { unlock_user_index(users_path); cs_critical_error(ERR_FOPEN_READ_FAILED , ""); } if(fread(*buffer,statbuf.st_size,1,fp) != 1) { unlock_user_index(users_path); /* empty index.txt */ *buffer = (char *) malloc(1 * sizeof(char)); **buffer = '\0'; return; } unlock_user_index(users_path); fclose(fp); *(*buffer + statbuf.st_size) = '\0'; } /*** searches buffer for a record represented by id *** if found, returns username and realname from the same record *** upon return an empty username means id wasn't found or an error occurred **/ void index_get_names(char *buffer, const char *id, char *username, char *realname) { char *ptr, *search_start; int id_len; int found = 0; char *tmp; *username = '\0'; *realname = '\0'; id_len = strlen(id); if(!id_len) return; if(!buffer || !*buffer) return; search_start = buffer; while(!found) { ptr = strstr(search_start, id); if(ptr) { found = (ptr != buffer) && (*(ptr - 1) == ':') && (*(ptr + id_len) == ':'); if(!found) search_start = ptr + 1; } else break; } if(found) { /* copy the username field */ tmp = ptr - 1; *tmp = '\0'; ptr = strrchr(buffer,'\n'); if(ptr) ptr++; else ptr = buffer; strncpy(username, ptr, MAX_USERNAME + 1); *tmp = ':'; /* copy the realname field */ ptr = strchr(ptr, ':'); if(!ptr) { *username = '\0'; return; } ptr++; ptr = strchr(ptr, ':'); if(!ptr) { *username = '\0'; return; } ptr++; tmp = strchr(ptr,'\n'); if(!tmp) { *username = '\0'; return; } *tmp = '\0'; strncpy(realname, ptr, MAX_NAME + 1); *(realname + MAX_NAME) = '\0'; *tmp = '\n'; } } static void parse_index_line(char *line, char *username, char *id, char *realname) { char temp[200]; char *ptr, *ptr2; strncpy(temp, line, 200); ptr = strchr(temp, ':'); if(!ptr) cs_critical_error(ERR_INDEX_FILE_FORMAT_ERROR, ""); *ptr = '\0'; ptr++; strncpy(username, temp, MAX_USERNAME +1); ptr2 = ptr; ptr = strchr(ptr2, ':'); if(!ptr) cs_critical_error(ERR_INDEX_FILE_FORMAT_ERROR, ""); *ptr = '\0'; ptr++; strncpy(id, ptr2, MAX_ID +1); strncpy(realname, ptr, MAX_NAME +1); } INDEX_USER_LIST * add_to_index_list(INDEX_USER_LIST *list, const char *username, const char *id, const char *realname) { if(!list->head) { list->head = (INDEX_USER*)malloc(sizeof(INDEX_USER)); list->head->next =0; list->current = list->head; strncpy(list->head->username, username, MAX_USERNAME+1); strncpy(list->head->id, id, MAX_ID+1); strncpy(list->head->realname, realname, MAX_NAME+1); } else { list->current->next =(INDEX_USER*)malloc(sizeof(INDEX_USER)); list->current = list->current->next; list->current->next =0; strncpy(list->current->username, username, MAX_USERNAME+1); strncpy(list->current->id, id, MAX_ID+1); strncpy(list->current->realname, realname, MAX_NAME+1); } return list; } INDEX_USER_LIST * build_index_user_list(INDEX_USER_LIST *list) { FILE *fp; char line[200]; char username[MAX_USERNAME +1]; char id[MAX_ID +1]; char realname[MAX_NAME +1]; char users_path[MAX_PATH + 1]; char index_path[MAX_PATH + 1]; snprintf(users_path, MAX_PATH + 1, "../%s",USERS_DIR); snprintf(index_path, MAX_PATH + 1, "%s/%s", users_path, USER_INDEX_FNAME); lock_user_index(users_path); fp = fopen(index_path, "r"); if(!fp) { unlock_user_index(users_path); return list; } while(fgets(line, 200, fp)) { strtrm(line); parse_index_line(line, username, id, realname); list = add_to_index_list(list,username, id, realname); } fclose(fp); unlock_user_index(users_path); return list; } void free_index_user_list(INDEX_USER_LIST *list) { INDEX_USER *ptr; while(list->head) { ptr = list->head->next; free(list->head); list->head = ptr; } }