static int examine_log(my_string file_name, char **table_names) { uint command,result,files_open; ulong access_time,length; my_off_t filepos; int lock_command,mi_result; char isam_file_name[FN_REFLEN],llbuff[21],llbuff2[21]; uchar head[20]; gptr buff; struct test_if_open_param open_param; IO_CACHE cache; File file; FILE *write_file; enum ha_extra_function extra_command; TREE tree; struct file_info file_info,*curr_file_info; DBUG_ENTER("examine_log"); if ((file=my_open(file_name,O_RDONLY,MYF(MY_WME))) < 0) DBUG_RETURN(1); write_file=0; if (write_filename) { if (!(write_file=my_fopen(write_filename,O_WRONLY,MYF(MY_WME)))) { my_close(file,MYF(0)); DBUG_RETURN(1); } } init_io_cache(&cache,file,0,READ_CACHE,start_offset,0,MYF(0)); bzero((gptr) com_count,sizeof(com_count)); init_tree(&tree,0,0,sizeof(file_info),(qsort_cmp2) file_info_compare,1, (tree_element_free) file_info_free, NULL); VOID(init_key_cache(KEY_CACHE_SIZE)); files_open=0; access_time=0; while (access_time++ != number_of_commands && !my_b_read(&cache,(byte*) head,9)) { isamlog_filepos=my_b_tell(&cache)-9L; file_info.filenr= mi_uint2korr(head+1); isamlog_process=file_info.process=(long) mi_uint4korr(head+3); if (!opt_processes) file_info.process=0; result= mi_uint2korr(head+7); if ((curr_file_info=(struct file_info*) tree_search(&tree,&file_info))) { curr_file_info->accessed=access_time; if (update && curr_file_info->used && curr_file_info->closed) { if (reopen_closed_file(&tree,curr_file_info)) { command=sizeof(com_count)/sizeof(com_count[0][0])/3; result=0; goto com_err; } } } command=(uint) head[0]; if (command < sizeof(com_count)/sizeof(com_count[0][0])/3 && (!table_names[0] || (curr_file_info && curr_file_info->used))) { com_count[command][0]++; if (result) com_count[command][1]++; } switch ((enum myisam_log_commands) command) { case MI_LOG_OPEN: if (!table_names[0]) { com_count[command][0]--; /* Must be counted explicite */ if (result) com_count[command][1]--; } if (curr_file_info) printf("\nWarning: %s is opened with same process and filenumber\nMaybe you should use the -P option ?\n", curr_file_info->show_name); if (my_b_read(&cache,(byte*) head,2)) goto err; file_info.name=0; file_info.show_name=0; file_info.record=0; if (read_string(&cache,(gptr*) &file_info.name, (uint) mi_uint2korr(head))) goto err; { uint i; char *pos,*to; /* Fix if old DOS files to new format */ for (pos=file_info.name; (pos=strchr(pos,'\\')) ; pos++) *pos= '/'; pos=file_info.name; for (i=0 ; i < prefix_remove ; i++) { char *next; if (!(next=strchr(pos,'/'))) break; pos=next+1; } to=isam_file_name; if (filepath) to=convert_dirname(isam_file_name,filepath,NullS); strmov(to,pos); fn_ext(isam_file_name)[0]=0; /* Remove extension */ } open_param.name=file_info.name; open_param.max_id=0; VOID(tree_walk(&tree,(tree_walk_action) test_if_open,(void*) &open_param, left_root_right)); file_info.id=open_param.max_id+1; /* * In the line below +10 is added to accomodate '<' and '>' chars * plus '\0' at the end, so that there is place for 7 digits. * It is improbable that same table can have that many entries in * the table cache. * The additional space is needed for the sprintf commands two lines * below. */ file_info.show_name=my_memdup(isam_file_name, (uint) strlen(isam_file_name)+10, MYF(MY_WME)); if (file_info.id > 1) sprintf(strend(file_info.show_name),"<%d>",file_info.id); file_info.closed=1; file_info.accessed=access_time; file_info.used=1; if (table_names[0]) { char **name; file_info.used=0; for (name=table_names ; *name ; name++) { if (!strcmp(*name,isam_file_name)) file_info.used=1; /* Update/log only this */ } } if (update && file_info.used) { if (files_open >= max_files) { if (close_some_file(&tree)) goto com_err; files_open--; } if (!(file_info.isam= mi_open(isam_file_name,O_RDWR, HA_OPEN_WAIT_IF_LOCKED))) goto com_err; if (!(file_info.record=my_malloc(file_info.isam->s->base.reclength, MYF(MY_WME)))) goto end; files_open++; file_info.closed=0; if (opt_myisam_with_debug) file_info.isam->s->rnd= 0; else file_info.isam->s->rnd= isamlog_process; } VOID(tree_insert(&tree,(gptr) &file_info,0)); if (file_info.used) { if (verbose && !record_pos_file) printf_log("%s: open -> %d",file_info.show_name, file_info.filenr); com_count[command][0]++; if (result) com_count[command][1]++; } break; case MI_LOG_CLOSE: if (verbose && !record_pos_file && (!table_names[0] || (curr_file_info && curr_file_info->used))) printf_log("%s: %s -> %d",FILENAME(curr_file_info), command_name[command],result); if (curr_file_info) { if (!curr_file_info->closed) files_open--; VOID(tree_delete(&tree,(gptr) curr_file_info)); } break; case MI_LOG_EXTRA: if (my_b_read(&cache,(byte*) head,1)) goto err; extra_command=(enum ha_extra_function) head[0]; if (verbose && !record_pos_file && (!table_names[0] || (curr_file_info && curr_file_info->used))) printf_log("%s: %s(%d) -> %d",FILENAME(curr_file_info), command_name[command], (int) extra_command,result); if (update && curr_file_info && !curr_file_info->closed) { if (mi_extra(curr_file_info->isam, extra_command, 0) != (int) result) { fflush(stdout); VOID(fprintf(stderr, "Warning: error %d, expected %d on command %s at %s\n", my_errno,result,command_name[command], llstr(isamlog_filepos,llbuff))); fflush(stderr); } } break; case MI_LOG_DELETE: if (my_b_read(&cache,(byte*) head,8)) goto err; filepos=mi_sizekorr(head); if (verbose && (!record_pos_file || ((record_pos == filepos || record_pos == NO_FILEPOS) && !cmp_filename(curr_file_info,record_pos_file))) && (!table_names[0] || (curr_file_info && curr_file_info->used))) printf_log("%s: %s at %ld -> %d",FILENAME(curr_file_info), command_name[command],(long) filepos,result); if (update && curr_file_info && !curr_file_info->closed) { if (mi_rrnd(curr_file_info->isam,curr_file_info->record,filepos)) { if (!recover) goto com_err; if (verbose) printf_log("error: Didn't find row to delete with mi_rrnd"); com_count[command][2]++; /* Mark error */ } mi_result=mi_delete(curr_file_info->isam,curr_file_info->record); if ((mi_result == 0 && result) || (mi_result && (uint) my_errno != result)) { if (!recover) goto com_err; if (mi_result) com_count[command][2]++; /* Mark error */ if (verbose) printf_log("error: Got result %d from mi_delete instead of %d", mi_result, result); } } break; case MI_LOG_WRITE: case MI_LOG_UPDATE: if (my_b_read(&cache,(byte*) head,12)) goto err; filepos=mi_sizekorr(head); length=mi_uint4korr(head+8); buff=0; if (read_string(&cache,&buff,(uint) length)) goto err; if ((!record_pos_file || ((record_pos == filepos || record_pos == NO_FILEPOS) && !cmp_filename(curr_file_info,record_pos_file))) && (!table_names[0] || (curr_file_info && curr_file_info->used))) { if (write_file && (my_fwrite(write_file,buff,length,MYF(MY_WAIT_IF_FULL | MY_NABP)))) goto end; if (verbose) printf_log("%s: %s at %ld, length=%ld -> %d", FILENAME(curr_file_info), command_name[command], filepos,length,result); } if (update && curr_file_info && !curr_file_info->closed) { if (curr_file_info->isam->s->base.blobs) fix_blob_pointers(curr_file_info->isam,buff); if ((enum myisam_log_commands) command == MI_LOG_UPDATE) { if (mi_rrnd(curr_file_info->isam,curr_file_info->record,filepos)) { if (!recover) { result=0; goto com_err; } if (verbose) printf_log("error: Didn't find row to update with mi_rrnd"); if (recover == 1 || result || find_record_with_key(curr_file_info,buff)) { com_count[command][2]++; /* Mark error */ break; } } mi_result=mi_update(curr_file_info->isam,curr_file_info->record, buff); if ((mi_result == 0 && result) || (mi_result && (uint) my_errno != result)) { if (!recover) goto com_err; if (verbose) printf_log("error: Got result %d from mi_update instead of %d", mi_result, result); if (mi_result) com_count[command][2]++; /* Mark error */ } } else { mi_result=mi_write(curr_file_info->isam,buff); if ((mi_result == 0 && result) || (mi_result && (uint) my_errno != result)) { if (!recover) goto com_err; if (verbose) printf_log("error: Got result %d from mi_write instead of %d", mi_result, result); if (mi_result) com_count[command][2]++; /* Mark error */ } if (!recover && filepos != curr_file_info->isam->lastpos) { printf("error: Wrote at position: %s, should have been %s", llstr(curr_file_info->isam->lastpos,llbuff), llstr(filepos,llbuff2)); goto end; } } } my_free(buff,MYF(0)); break; case MI_LOG_LOCK: if (my_b_read(&cache,(byte*) head,sizeof(lock_command))) goto err; memcpy_fixed(&lock_command,head,sizeof(lock_command)); if (verbose && !record_pos_file && (!table_names[0] || (curr_file_info && curr_file_info->used))) printf_log("%s: %s(%d) -> %d\n",FILENAME(curr_file_info), command_name[command],lock_command,result); if (update && curr_file_info && !curr_file_info->closed) { if (mi_lock_database(curr_file_info->isam,lock_command) != (int) result) goto com_err; } break; case MI_LOG_DELETE_ALL: if (verbose && !record_pos_file && (!table_names[0] || (curr_file_info && curr_file_info->used))) printf_log("%s: %s -> %d\n",FILENAME(curr_file_info), command_name[command],result); break; default: fflush(stdout); VOID(fprintf(stderr, "Error: found unknown command %d in logfile, aborted\n", command)); fflush(stderr); goto end; } } end_key_cache(); delete_tree(&tree); VOID(end_io_cache(&cache)); VOID(my_close(file,MYF(0))); if (write_file && my_fclose(write_file,MYF(MY_WME))) DBUG_RETURN(1); DBUG_RETURN(0); err: fflush(stdout); VOID(fprintf(stderr,"Got error %d when reading from logfile\n",my_errno)); fflush(stderr); goto end; com_err: fflush(stdout); VOID(fprintf(stderr,"Got error %d, expected %d on command %s at %s\n", my_errno,result,command_name[command], llstr(isamlog_filepos,llbuff))); fflush(stderr); end: end_key_cache(); delete_tree(&tree); VOID(end_io_cache(&cache)); VOID(my_close(file,MYF(0))); if (write_file) VOID(my_fclose(write_file,MYF(MY_WME))); DBUG_RETURN(1); }
/** * Finds a named file/directory * * Starting at the root directory, this function * searches file tables to find required subdirectories and * eventually to find the required file table entry. * * @param[in] fs_handle : filesystem handle obtained from wicedfs_init() * @param[in] filename : the path of the file table entry (e.g. a file or directory) * @param[out] curr_dir : Receives the directory header of the item found. * @param[out] file_hnd : Receives the file table entry of the item found. * @param[out] curr_dir_addr : Receives the hardware address of the content data for the item found. * * @return The WICEDFS_TYPE (e.g. DIR, FILE, etc) or negative on error */ static int find_item( /*@in@*/ const wiced_filesystem_t* fs_handle, /*@in@*/ const char* filename, /*@out@*/ wicedfs_dir_header_t* curr_dir, /*@out@*/ wicedfs_file_header_t* file_hnd, /*@out@*/ wicedfs_usize_t* curr_dir_addr ) { uint32_t cmp_bytes; char* slash_offset; uint32_t file_num; wicedfs_usize_t curr_file_table_addr; /* Start at the root directory */ *curr_dir_addr = fs_handle->root_dir_addr; file_hnd->type_flags_permissions = WICEDFS_TYPE_DIR; /* Each interation of this loop descends one subdirectory */ while ( 1 == 1 ) { wicedfs_usize_t bytes_read; int cmp_val = -1; /* Skip the first character if it is a directory separator */ if ( filename[0] == WICEDFS_DIRECTORY_SEPARATOR ) { filename++; } /* Read the header of the current directory from the hardware */ bytes_read = fs_handle->read_func( fs_handle->user_param, curr_dir, (wicedfs_usize_t) sizeof(wicedfs_dir_header_t), *curr_dir_addr ); if ( bytes_read != sizeof(wicedfs_dir_header_t) ) { /* Error reading hardware device */ return -1; } /* If the filename has been reduced to nothing, then the * caller requested a directory name, and it has been found. */ if ( filename[ 0 ] == '\x00' ) { /* Return the file table entry-type */ return (int) ( file_hnd->type_flags_permissions & WICEDFS_TYPE_MASK ); } /* Look for a directory separator character */ if ( ( slash_offset = strchr( filename, WICEDFS_DIRECTORY_SEPARATOR ) ) != NULL ) { /* A directory separator was found. * Calculate the length of the name comparison that should be performed */ cmp_bytes = (uint32_t)( slash_offset - filename ); } else { /* No directory separator. Compare entire name */ cmp_bytes = strlen( filename ); } /* Set up loop variables */ file_num = 0; curr_file_table_addr = (wicedfs_usize_t)( (wicedfs_ssize_t) *curr_dir_addr + curr_dir->file_table_offset ); /* Loop over each file table entry * For each: read the entry from hardware, then compare the entry name to the given filename */ while ( ( ( bytes_read = fs_handle->read_func( fs_handle->user_param, file_hnd, (wicedfs_usize_t) sizeof(wicedfs_file_header_t), curr_file_table_addr + file_num * curr_dir->file_header_size ) ) == (wicedfs_usize_t) sizeof(wicedfs_file_header_t) ) && ( 1 == ( cmp_val = cmp_filename( fs_handle, curr_file_table_addr + file_num * curr_dir->file_header_size + sizeof(wicedfs_file_header_t), filename, cmp_bytes, curr_dir->filename_size ) ) ) ) { /* Not found yet - increment file table position */ file_num++; /* Check if position has passed the end of the file table */ if ( file_num >= curr_dir->num_files ) { /* Table position has passed the end of the * file table without finding a match. * * i.e. file not found */ return -2; } } if ( ( bytes_read != (wicedfs_usize_t) sizeof(wicedfs_file_header_t) ) || ( cmp_val < 0 ) ) { /* error reading hardware device */ return -3; } /* Prepare current directory pointer to descend into next directory */ *curr_dir_addr = (wicedfs_usize_t) ((wicedfs_ssize_t) curr_file_table_addr + file_hnd->offset + (wicedfs_ssize_t)( file_num * curr_dir->file_header_size )); /* Strip off the part of the filename that was found */ filename += cmp_bytes; } /* No return needed here due to the while(1) */ /*@-noret@*/ }