/* Copyright 1996 Acorn Computers Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* List files as specified in a selection. Revision History: 0.00 02-Jun-89 JSR Created from extracts of c.actionwind. 0.01 27-Jun-89 JSR Update to cope with arbitrary length file names. 0.02 29-Sep-89 JSR Use overflowing_ memory allocation routines. Add selection_summary. Add name_of_next_node. 0.03 17-Oct-89 JSR Upgrade next_nodename and next_filename to not prepend the directory if the directory is a nul string. */ #if 0 #define debuglist #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #ifndef __os_h #include "os.h" #endif #include "Options.h" #include "malloc+.h" #include "listfiles.h" #include "allerrs.h" #include "debug.h" #include "memmanage.h" #define Yes 1 #define No 0 #define Directory_Buffer_Size 20 #define Temp_DirBuffer_Size 640 #define Directory_File_Type 2 typedef struct { int load_address; int execution_address; int length; int attributes; int object_type; char *object_name; #ifdef PROGRESS_BAR void *chain_ref; #endif } directory_buffer_entry; typedef struct Search_Nest_Level { struct Search_Nest_Level *next_search_nest_level; int offset_to_next_item; int entries_in_buffer; int next_entry_to_return; directory_buffer_entry directory_buffer[ Directory_Buffer_Size ]; #ifdef PROGRESS_BAR int total_entries; int total_progress; int progress_per_object; #endif } search_nest_level; typedef struct File_Selection { struct File_Selection *next_file; char *selection_name; } file_selection; /* This enumerates the states for finding the next leaf to process. */ typedef enum { Next_Leaf, /* Find the next leaf at this level */ Process_Node, /* Process that found by Next_Leaf */ Read_Next_Cache_Full, /* Read another directory cache-full */ Nest_Into_Directory /* Start up into a nested directory */ } next_leaf_state; typedef struct search_context { search_nest_level *nested_filenames; char *directory; file_selection *selection; file_selection **last_selections_link; next_leaf_state action; unsigned int selections_size; unsigned int selections_reload; unsigned int selections_execute; unsigned int selections_attributes; unsigned int selections_objecttype; unsigned int recursive:1; unsigned int directories_first:1; unsigned int directories_last:1; unsigned int partitions_as_directories:1; #ifdef PROGRESS_BAR int total_entries; int total_progress; int progress_per_object; void *chain_ref; #endif } search_context; #ifdef PROGRESS_BAR #include "swis.h" #define SIZE 2048 static int count_objects_in_dir(char *dir) { os_error *e; char *buff[SIZE]; int chunk = 256, context = 0, c, num = 0, total = 0; while (context != -1) { if ((e = _swix(OS_GBPB, _INR(0,6) | _OUTR(3,4), 9, dir, buff, chunk, context, SIZE, 0, &num, &c)) == NULL) { if (c == context) { /* Broken archives cause context to never be updated ... not sure why the SWI does not return an error. */ DEBUG(("count_objects_in_dir: aborting\n")); return 0; } context = c; total += num; } else { DEBUG(("count_objects_in_dir: %s\n", e->errmess)); return 0; } } return total; } #undef SIZE #endif // PROGRESS_BAR /* This initialises an empty search context. The search will return a list of files or directories, which must be added to the context after it has been created. The context is created recursive. */ os_error *create_search_context( search_handle *handle ) { search_context *new_context; if ( ( new_context = overflowing_malloc( sizeof( search_context ))) != NULL ) { *handle = (search_handle)new_context; new_context->directory = NULL; new_context->nested_filenames = NULL; new_context->selection = NULL; new_context->last_selections_link = &new_context->selection; new_context->recursive = Yes; new_context->directories_first = No; new_context->directories_last = No; new_context->partitions_as_directories = Yes; new_context->action = Process_Node; #ifdef PROGRESS_BAR new_context->total_entries = 0; new_context->total_progress = PROGRESS_MAX; new_context->progress_per_object = 0; new_context->chain_ref = NULL; #endif return NULL; } else { return error( mb_malloc_failed ); } } static int is_a_directory( search_handle handle, int objecttype ) { if ( objecttype == ObjectType_Directory || (objecttype == (ObjectType_Directory | ObjectType_File) && handle->partitions_as_directories) ) { return Yes; } else { return No; } } /* Sets whether the search is recursive or not */ extern void recurse_search_context( search_handle handle, int recursive ) { /* Make sure when changing to recursive that the children of this directory get returned */ if ( !handle->recursive && recursive && is_a_directory( handle, objecttype_of_next_node( handle )) && handle->action == Next_Leaf ) { handle->action = Nest_Into_Directory; } handle->recursive = recursive != No; } /* Sets whether directories should be returned before their contents. This is relevant only when recursing. */ extern void return_directories_first( search_handle handle, int directories_first ) { ((search_context *)handle)->directories_first = directories_first != No; } /* Sets whether directories should be returned after their contents. This is relevant only when recursing. */ extern void return_directories_last( search_handle handle, int directories_last ) { handle->directories_last = directories_last != No; } /* Sets whether partitions should be treated the same as directories or not. This is relevant only when recursing. */ extern void treat_partitions_as_directories( search_handle handle, int partitions_are_directories ) { handle->partitions_as_directories = partitions_are_directories; } /* Changes the directory in which the search will take place */ os_error *set_directory( search_handle handle, char *directory ) { search_context *context = (search_context *)handle; if ( context->directory ) { overflowing_free( context->directory ); } if ( ( context->directory = overflowing_malloc( strlen( directory ) + 1 )) != NULL ) { strcpy( context->directory, directory ); return NULL; } else { return error( mb_malloc_failed ); } } /* frees the passed selection */ static void free_selection( file_selection *selection ) { overflowing_free( selection->selection_name ); overflowing_free( selection ); } /* Clears down a whole selection */ void clear_selection( search_handle handle ) { search_context *context = (search_context *)handle; file_selection *next_selection; file_selection *this_selection; /* Free the chain of selections */ for ( this_selection = context->selection; this_selection != NULL; this_selection = next_selection ) { next_selection = this_selection->next_file; free_selection( this_selection ); } /* close off the head of the list */ context->selection = NULL; context->last_selections_link = &context->selection; } /* Add a selection to an initialised search context. The search context will return found files in the order in which they were added. */ os_error *add_selection( search_handle handle, char *file_name, int wordlen ) { file_selection *new_selection; search_context *context = (search_context *)handle; /* These two if statements allocate the new selection structure and then some space for the file name. The mallocs are checked to work, and if they don't everything is tidied up and an error is returned. */ new_selection = overflowing_malloc( sizeof( file_selection )); if ( new_selection != NULL ) { new_selection->selection_name = overflowing_malloc( wordlen + 1 ); if ( new_selection->selection_name != NULL ) { /* Everything allocated OK, so copy the string and link the new selection onto the end of the list. */ *context->last_selections_link = new_selection; strncpy( new_selection->selection_name, file_name, wordlen ); new_selection->selection_name[ wordlen ] = '\0'; context->last_selections_link = &new_selection->next_file; new_selection->next_file = NULL; DEBUG(("context: %x new selection: %s\n", context, new_selection->selection_name)); #ifdef PROGRESS_BAR context->total_entries++; context->progress_per_object = context->total_progress / context->total_entries; #endif return NULL; } else { /* No room for selection name. Free up the selection structure and tidy up the ends */ overflowing_free( new_selection ); return error( mb_malloc_failed ); } } else { return error( mb_malloc_failed ); } } /* Free the abstract data type search_context. This is an equivalent to free(), but for this data type. It free all things hanging off it as well as the base structure. */ void dispose_search_context( search_handle handle ) { search_context *context = (search_context *)handle; search_nest_level *rover; search_nest_level *temp_rover; int i; /* Free the search nest level chain */ rover = context->nested_filenames; while( rover != NULL ) { temp_rover = rover; rover = rover->next_search_nest_level; for ( i = 0; i < Directory_Buffer_Size; i++ ) { overflowing_free( temp_rover->directory_buffer[ i ].object_name ); } overflowing_free( temp_rover ); } clear_selection( handle ); overflowing_free( context->directory ); overflowing_free( context ); } static int size_of_next_filename( search_context *context, search_nest_level *nesting ) { search_nest_level *nest_level = nesting; int returned_length = 0; if ( context->directory && context->selection && context->selection->selection_name ) { returned_length = strlen( context->directory ); /* Only Add one in if there's going to be a . in between dir and selection */ if ( returned_length ) returned_length++; returned_length += strlen( context->selection->selection_name ); if ( context->recursive ) { while ( nest_level != NULL ) { returned_length += 1 + strlen( nest_level-> directory_buffer[ nest_level->next_entry_to_return ]. object_name ); nest_level = nest_level->next_search_nest_level; } } } return returned_length; } /* Returns a pointer to the next filename in search_context This is a 'malloc'ed piece of memory, which should be 'free'ed when it is no longer needed. */ static os_error *next_filename( search_context *context, search_nest_level *nesting, char **hook_location ) { search_nest_level *nest_level = nesting; char *buffer = NULL; char *rover; int next_filename_size = size_of_next_filename( context, nesting ); int part_length; if ( next_filename_size > 0 ) { buffer = overflowing_malloc( next_filename_size + 1 ); if ( buffer == NULL ) { return error( mb_malloc_failed ); } } if ( buffer != NULL ) { if ( context->directory[0] ) { sprintf( buffer, "%s.%s", context->directory, context->selection->selection_name ); } else { sprintf( buffer, "%s", context->selection->selection_name ); } rover = buffer + next_filename_size; *rover = '\0'; while ( nest_level != NULL ) { part_length = strlen( nest_level-> directory_buffer[ nest_level->next_entry_to_return ]. object_name ); rover -= part_length + 1; rover[0] = '.'; memcpy( &rover[1], nest_level-> directory_buffer[ nest_level->next_entry_to_return ]. object_name, part_length ); nest_level = nest_level->next_search_nest_level; } } *hook_location = buffer; return NULL; } os_error *next_nodename( search_handle handle, char **hook_location ) { search_context *context = (search_context *)handle; return next_filename( context, context->nested_filenames, hook_location ); } os_error *selection_summary( search_handle handle, char **summary ) { search_context *context = (search_context *)handle; char *cont; if ( context->selection == NULL ) { cont = msgs_lookup("93"); // 'nothing' } else if ( context->selection->next_file == NULL ) { cont = context->selection->selection_name; } else { cont = msgs_lookup("92"); // 'many' } *summary = overflowing_malloc( strlen( context->directory ) + 1 + strlen( cont ) + 1 ); if ( *summary == NULL ) return error( mb_malloc_failed ); sprintf( *summary, "%s.%s", context->directory, cont ); return NULL; } /* Finds the degree by which mstring matches the current next node. It returns the next mismatching position, and other information concerning where the mismatch occured */ static char *first_position_not_matched( search_handle handle, search_nest_level *nl, char *mstring, search_nest_level **deepest_match, search_nest_level **shallowest_non_match ) { char *matched_position; char *ms; int dl; int sl; if ( nl == NULL ) { matched_position = mstring; dl = strlen( handle->directory ); if ( strncmp( handle->directory, matched_position, dl ) != 0 ) return NULL; matched_position += dl; if ( *matched_position != '.' ) return NULL; matched_position += 1; sl = strlen( handle->selection->selection_name ); if ( strncmp( handle->selection->selection_name, matched_position, sl ) != 0 ) return NULL; matched_position += sl; return matched_position; } else { matched_position = first_position_not_matched( handle, nl->next_search_nest_level, mstring, deepest_match, shallowest_non_match ); if ( matched_position == NULL ) return NULL; ms = nl->directory_buffer[ nl->next_entry_to_return ].object_name; sl = strlen( ms ); if ( *matched_position == '.' && strncmp( matched_position + 1, ms, sl ) == 0 ) { matched_position += 1 + sl; *deepest_match = nl; } else { if ( nl->next_search_nest_level == *deepest_match ) { *shallowest_non_match = nl; } } return matched_position; } } /* Informs that next node has been deleted */ void deleted_next_node( search_handle handle, char *deleted_node ) { if ( handle->nested_filenames && handle->selection ) { char *matched_position; search_nest_level *deepest_match = NULL; search_nest_level *shallowest_non_match = NULL; matched_position = first_position_not_matched( handle, handle->nested_filenames, deleted_node, &deepest_match, &shallowest_non_match ); if ( matched_position != NULL ) { /* Deleted node is before something in shallowest non-match */ if ( matched_position == strrchr( deleted_node, '.' ) && shallowest_non_match != NULL ) { shallowest_non_match->offset_to_next_item--; } /* Deleted is current node or a parent of it (gulp!) */ if ( *matched_position == '\0' && deepest_match != NULL ) { deepest_match->offset_to_next_item--; } } } } /* Read the parameters for the next node, don't update if an error occurs */ void read_next_node_parameters( search_handle handle ) { os_filestr fileplace; char *filename; os_error *err; err = next_nodename( handle, &filename ); if ( err ) return; fileplace.action = 5; /* read catalogue information */ fileplace.name = filename; err = os_file( &fileplace ); if ( err ) return; handle->selections_size = fileplace.start; handle->selections_reload = fileplace.loadaddr; handle->selections_execute = fileplace.execaddr; handle->selections_attributes = fileplace.end; } typedef enum { the_size, the_load_address, the_execute_address, the_attributes, the_type, the_name #ifdef PROGRESS_BAR , the_progress, the_ref_ptr #endif } which_thing; /* Returns one of the values associated with the next node. If the node doesn't exist the value not_found is returned. */ static unsigned int thing_of_next_node( search_handle handle, which_thing thing, int not_found ) { search_context *context = (search_context *)handle; search_nest_level *nf; if ( context->selection ) { if ( (nf = context->nested_filenames) == NULL ) { switch( thing ) { case the_size: return context->selections_size; case the_load_address: return context->selections_reload; case the_execute_address: return context->selections_execute; case the_attributes: return context->selections_attributes; case the_type: return context->selections_objecttype; case the_name: return (int)context->selection->selection_name; #ifdef PROGRESS_BAR case the_progress: if (context->selections_objecttype == ObjectType_Directory) { DEBUG(("ponn: selection: %08x\n", 0)); return 0; } else { DEBUG(("ponn: selection: %08x\n", context->progress_per_object)); return context->progress_per_object; } case the_ref_ptr: return (unsigned int) &context->chain_ref; #endif } // end switch } else { directory_buffer_entry *d; d = nf->directory_buffer + nf->next_entry_to_return; switch( thing ) { case the_size: return d->length; case the_load_address: return d->load_address; case the_execute_address: return d->execution_address; case the_attributes: return d->attributes; case the_type: return d->object_type; case the_name: return (int) d->object_name; #ifdef PROGRESS_BAR case the_progress: if (d->object_type == ObjectType_Directory) { DEBUG(("ponn: nested: %08x\n", 0)); return 0; } else { DEBUG(("ponn: nested: %08x\n", nf->progress_per_object)); return nf->progress_per_object; } case the_ref_ptr: return (int) &d->chain_ref; #endif } } } return not_found; } unsigned int size_of_next_node( search_handle handle ) { return thing_of_next_node( handle, the_size, -1 ); } unsigned int reload_of_next_node( search_handle handle ) { return thing_of_next_node( handle, the_load_address, -1 ); } unsigned int execute_of_next_node( search_handle handle ) { return thing_of_next_node( handle, the_execute_address, -1 ); } unsigned int attributes_of_next_node( search_handle handle ) { return thing_of_next_node( handle, the_attributes, -1 ); } unsigned int objecttype_of_next_node( search_handle handle ) { return thing_of_next_node( handle, the_type, ObjectType_NotFound ); } char *name_of_next_node( search_handle handle ) { return (char *)thing_of_next_node( handle, the_name, NULL ); } #ifdef PROGRESS_BAR unsigned int progress_of_next_node( search_handle handle ) { return thing_of_next_node( handle, the_progress, 0 ); } unsigned int chain_ref_ptr_of_next_node( search_handle handle ) { return thing_of_next_node( handle, the_ref_ptr, 0 ); } #endif /* Assuming a directory has just been found, return whether this return of this directory was before or after its contents. */ unsigned int directory_is_after_contents( search_handle handle ) { search_context *context = (search_context *)handle; return context->action == Next_Leaf; } /* Returns 0 if no more nodes Returns non-0 if more nodes */ unsigned int another_node( search_handle handle ) { return ((search_context *)handle)->selection != NULL; } /* When finding a selection fails call this to skip it. */ void skip_failed_selection( search_handle handle ) { search_context *context = (search_context *)handle; switch ( context->action ) { case Next_Leaf: /* Can't generate an error in this state */ break; case Process_Node: context->action = Next_Leaf; break; case Read_Next_Cache_Full: /* This forces un-nesting then continuing at the upper level */ context->nested_filenames->offset_to_next_item = -1; break; case Nest_Into_Directory: context->action = Next_Leaf; break; } } void skip_list_file( search_handle handle ) { search_context *context = (search_context *)handle; context->action = Next_Leaf; } os_error *step_to_next_node( search_handle handle, unsigned int *progress ) { search_context *context = (search_context *)handle; search_nest_level *temp_context; os_gbpbstr gbpbplace; os_filestr fileplace; char temp_directory_buffer[ Temp_DirBuffer_Size ]; int i; int pos; int resolved = No; os_error *err = NULL; file_selection *next_selection; int objecttype; DEBUG(("\nstep_to_next_node\n")); /* While the answer hasn't resolved itself and there's no error then try the next step of resolving the answer */ while( !resolved && !err ) { switch( context->action ) { case Next_Leaf: DEBUG(("Next_Leaf ")); /* Step to the next leaf at this nesting level */ if ( context->nested_filenames == NULL ) { /* Get next selection */ next_selection = context->selection->next_file; free_selection( context->selection ); context->selection = next_selection; DEBUG(("get next selection")); context->action = Process_Node; } else { /* Get next cached entry */ context->nested_filenames->next_entry_to_return++; if ( context->nested_filenames->next_entry_to_return >= context->nested_filenames->entries_in_buffer ) { /* We've run out of cached entries */ DEBUG(("cache empty ")); context->action = Read_Next_Cache_Full; } else { /* Found an entry in the cache, so let's process it */ DEBUG(("cache ok ")); context->action = Process_Node; } } break; case Process_Node: DEBUG(("Process_Node ")); /* Process the node as supplied by Next_Leaf */ if ( context->selection == NULL ) { /* No more entries in the selection, so we've resolved what happens next */ DEBUG(("resolved all ")); resolved = Yes; } else { DEBUG(("%s ", name_of_next_node(context))); /* Get type of node if needed */ if ( context->nested_filenames == NULL ) { fileplace.action = 17; err = next_filename( context, context->nested_filenames, &fileplace.name ); DEBUG(("%s ", fileplace.name)); if ( err ) { DEBUG(("err\n")); continue; } err = os_file( &fileplace ); if ( err ) { overflowing_free( fileplace.name ); DEBUG((" error\n")); continue; } /* Didn't find a selection - generate an error. */ if ( fileplace.action == ObjectType_NotFound ) { fileplace.loadaddr = fileplace.action; fileplace.action = 19; err = os_file( &fileplace ); overflowing_free( fileplace.name ); DEBUG((" not found\n")); continue; } overflowing_free( fileplace.name ); context->selections_objecttype = fileplace.action; context->selections_size = fileplace.start; context->selections_reload = fileplace.loadaddr; context->selections_execute = fileplace.execaddr; context->selections_attributes = fileplace.end; } // end if (nested_filenames == NULL) objecttype = objecttype_of_next_node( (search_handle)context ); if ( objecttype == ObjectType_NotFound ) { /* Didn't find that, so go around for another time - nothing to do here */ DEBUG(("not found ")); context->action = Next_Leaf; } else if ( context->recursive && is_a_directory( context, objecttype ) ) { /* If we are returning directories first, then we have resolved it at this level */ DEBUG(("directory ")); resolved = context->directories_first; context->action = Nest_Into_Directory; } else { /* Found a file or we found a directory when not recursing, in which case we've found something worth while and so we've resolved things. */ resolved = Yes; context->action = Next_Leaf; DEBUG(("resolved ")); } } break; case Read_Next_Cache_Full: DEBUG(("Read_Next_Cache_Full ")); /* If run out of entries in this directory */ if ( context->nested_filenames->offset_to_next_item == -1 ) { search_nest_level *nf = context->nested_filenames; // for legibility #ifdef PROGRESS_BAR unsigned int p = 0; /* Compensate for rounding errors by adding the 'spare' progress Isn't totally accurate if copying, as the actual progress values used will have been halved. */ p = nf->total_progress - (nf->total_entries * nf->progress_per_object); if (p > 0) *progress += p; DEBUG(("finished %d entries (total %08x) extra progress +%08x", nf->total_entries, nf->total_progress, p)); #endif /* Down down one level */ temp_context = context->nested_filenames->next_search_nest_level; for ( i = 0; i < Directory_Buffer_Size; i++ ) { overflowing_free( context->nested_filenames->directory_buffer[ i ].object_name ); } overflowing_free( context->nested_filenames ); context->nested_filenames = temp_context; /* Return the directory after all the files in it */ resolved = context->directories_last; context->action = Next_Leaf; } else { char **filename_store; /* Read more of this directory */ gbpbplace.action = 10; err = next_filename( context, context->nested_filenames->next_search_nest_level, (char **)&gbpbplace.file_handle ); if ( err ) continue; DEBUG(("%s ", (char *)gbpbplace.file_handle)); #ifdef PROGRESS_BAR search_nest_level *nf = context->nested_filenames; // for legibility if (nf->total_entries == -1) { nf->total_entries = count_objects_in_dir((char *)gbpbplace.file_handle); if (nf->total_entries > 0) { nf->progress_per_object = nf->total_progress / nf->total_entries; } else { void *ref; /* Modify progress values so that half the progress for the dir is added when the dir is finished (in the rounding process above) and the other half when written. We have to do this now as when the dir was added to the chain, we didn't know it was empty. Of course if the dir is not in the chain, we are not copying, and so we add all the progress for this dir at once. */ if (nf->next_search_nest_level == NULL) { /* top level */ ref = context->chain_ref; } else { int i = nf->next_search_nest_level->next_entry_to_return; ref = nf->next_search_nest_level->directory_buffer[i].chain_ref; } if (ref != NULL) { nf->total_progress /= 2; nf->progress_per_object = 0; modify_chain_file_progress(ref, nf->total_progress); } } // end if (total_entries > 0) DEBUG(("%d entries %08x total progress %08x per object ", nf->total_entries, nf->total_progress, nf->progress_per_object)); } // end if (total_entries == -1) #endif // PROGRESS_BAR gbpbplace.data_addr = &temp_directory_buffer; gbpbplace.number = Directory_Buffer_Size; gbpbplace.seq_point = context->nested_filenames->offset_to_next_item; gbpbplace.buf_len = Temp_DirBuffer_Size; gbpbplace.wild_fld = "*"; err = os_gbpb( &gbpbplace ); overflowing_free( (void *)gbpbplace.file_handle ); if ( err ) { if ( (err->errnum & FileError_Mask) == ErrorNumber_NotFound ) { /* Cancel the error */ err = NULL; /* Down down one level */ temp_context = context->nested_filenames->next_search_nest_level; for ( i = 0; i < Directory_Buffer_Size; i++ ) { overflowing_free( context->nested_filenames->directory_buffer[ i ].object_name ); } overflowing_free( context->nested_filenames ); context->nested_filenames = temp_context; /* Don't return the directory, as it doesn't exist! */ context->action = Next_Leaf; } continue; } for ( i = 0, pos = 0; i < gbpbplace.number; i++ ) { context->nested_filenames->directory_buffer[ i ].load_address = *(int *)&temp_directory_buffer[ pos ]; pos += 4; context->nested_filenames->directory_buffer[ i ].execution_address = *(int *)&temp_directory_buffer[ pos ]; pos += 4; context->nested_filenames->directory_buffer[ i ].length = *(int *)&temp_directory_buffer[ pos ]; pos += 4; context->nested_filenames->directory_buffer[ i ].attributes = *(int *)&temp_directory_buffer[ pos ]; pos += 4; context->nested_filenames->directory_buffer[ i ].object_type = *(int *)&temp_directory_buffer[ pos ]; pos += 4; /* Free the filename if there's one there */ filename_store = &context->nested_filenames->directory_buffer[ i ].object_name; if ( *filename_store ) { overflowing_free ( *filename_store ); *filename_store = NULL; } /* Allocate some space for the file name */ if ( ( *filename_store = overflowing_malloc( strlen( &temp_directory_buffer[ pos ] ) + 1 ) ) == NULL ) { /* If the allocation failed, free everything up */ int j; for ( j = 0; j < i; j++ ) { overflowing_free( context->nested_filenames->directory_buffer[ j ].object_name ); context->nested_filenames->directory_buffer[ j ].object_name = NULL; } err = error( mb_malloc_failed ); break; } strcpy( *filename_store, &temp_directory_buffer[ pos ] ); pos += strlen( &temp_directory_buffer[ pos ] ) + 1; /* round pos up to a word boundary */ pos = (( pos + 3 ) / 4 ) * 4; } if ( err ) break; context->nested_filenames->offset_to_next_item = gbpbplace.seq_point; context->nested_filenames->entries_in_buffer = gbpbplace.number; context->nested_filenames->next_entry_to_return = -1; context->action = Next_Leaf; } break; case Nest_Into_Directory: DEBUG(("Nest_Into_Directory ")); /* Go down into the next nesting level */ temp_context = context->nested_filenames; context->nested_filenames = overflowing_malloc( sizeof( search_nest_level )); if ( context->nested_filenames == NULL ) { context->nested_filenames = temp_context; err = error( mb_malloc_failed ); continue; } context->nested_filenames->next_search_nest_level = temp_context; context->nested_filenames->offset_to_next_item = 0; context->nested_filenames->entries_in_buffer = 0; context->nested_filenames->next_entry_to_return = -1; #ifdef PROGRESS_BAR if (temp_context != NULL) { context->nested_filenames->total_progress = temp_context->progress_per_object; } else { context->nested_filenames->total_progress = context->progress_per_object; } /* Default values, will be overwitten if this object is a dir */ context->nested_filenames->progress_per_object = 0; context->nested_filenames->total_entries = -1; #endif for ( i = 0; i < Directory_Buffer_Size; i++ ) { context->nested_filenames->directory_buffer[ i ].object_name = NULL; #ifdef PROGRESS_BAR context->nested_filenames->directory_buffer[ i ].chain_ref = NULL; #endif } context->action = Next_Leaf; break; default: /* disaster!!!!! */ err = error( mb_unexpected_state ); break; } // end switch DEBUG(("\n")); } // end while return err; } #ifdef PROGRESS_BAR void listfiles_convert_to_copymove(search_handle handle) { search_context *context = (search_context *)handle; if (context == NULL) return; context->total_progress /= 2; } #endif