diff --git a/winsup/cygwin/dlfcn.cc b/winsup/cygwin/dlfcn.cc index 46348bb..c2cd740 100644 --- a/winsup/cygwin/dlfcn.cc +++ b/winsup/cygwin/dlfcn.cc @@ -168,7 +168,9 @@ get_full_path_of_dll (const char* str, path_conv &real_filename) finder.add_lib_searchdir ("/usr/lib", -1); } - if (finder.check_path_access (real_filename)) + if (finder.find (pathfinder:: + exists_and_is_file (real_filename, + PC_SYM_FOLLOW | PC_POSIX))) return true; /* If nothing worked, create a relative path from the original incoming diff --git a/winsup/cygwin/pathfinder.h b/winsup/cygwin/pathfinder.h index 11bb5fd..c7e79eb 100644 --- a/winsup/cygwin/pathfinder.h +++ b/winsup/cygwin/pathfinder.h @@ -109,32 +109,130 @@ public: add_lib_searchpath (getenv (envpath)); } - /* Within each searchdir registered, try each registered basename to - find as executable. Returns found dir/basename in real_filename. - Returns true when found. */ - bool check_path_access (path_conv& real_filename) + + /* pathfinder::criterion_interface + Overload this test method when you need separate dir and basename. */ + struct criterion_interface + { + virtual char const * name () const { return NULL; } + + virtual bool test (searchdirlist::iterator dir, + basenamelist::iterator name) const = 0; + }; + + + /* pathfinder::simple_criterion_interface + Overload this test method when you need a single filename. */ + class simple_criterion_interface + : public criterion_interface + { + virtual bool test (searchdirlist::iterator dir, + basenamelist::iterator name) const + { + /* Complete the filename path to search for within dir, + We have allocated enough memory above. */ + searchdirlist::buffer_iterator dirbuf (dir); + memcpy (dirbuf->buffer () + dirbuf->stringlength (), + name->string (), name->stringlength () + 1); + bool ret = test (dirbuf->string ()); + /* reset original dir */ + dirbuf->buffer ()[dirbuf->stringlength ()] = '\0'; + return ret; + } + + public: + virtual bool test (const char * filename) const = 0; + }; + + + /* pathfinder::path_conv_criterion_interface + Overload this test method when you need a path_conv. */ + class path_conv_criterion_interface + : public simple_criterion_interface + { + path_conv mypc_; + path_conv & pc_; + unsigned opt_; + + /* simple_criterion_interface */ + virtual bool test (const char * filename) const + { + pc_.check (filename, opt_); + return test (pc_); + } + + public: + path_conv_criterion_interface (unsigned opt = PC_SYM_FOLLOW) + : mypc_ () + , pc_ (mypc_) + , opt_ (opt) + {} + + path_conv_criterion_interface (path_conv & ret, unsigned opt = PC_SYM_FOLLOW) + : mypc_ () + , pc_ (ret) + , opt_ (opt) + {} + + virtual bool test (path_conv & pc) const = 0; + }; + + + /* pathfinder::exists_and_is_file + Test if path_conv argument does exist and is not a directory. */ + struct exists_and_is_file + : public path_conv_criterion_interface + { + virtual char const * name () const { return "exists and is file"; } + + exists_and_is_file (path_conv & pc, unsigned opt = PC_SYM_FOLLOW) + : path_conv_criterion_interface (pc, opt) + {} + + /* path_conv_criterion_interface */ + virtual bool test (path_conv & pc) const + { + if (pc.exists () && !pc.isdir ()) + return true; + + pc.error = ENOENT; + return false; + } + }; + + + /* Find the single dir + basename that matches criterion. + + Calls criterion.test method for each registered dir + basename + until returning true: + Returns true with found_dir + found_basename set. + If criterion.test method never returns true: + Returns false, not modifying found_dir nor found_basename. */ + bool find (criterion_interface const & criterion, + searchdirlist::member const ** found_dir = NULL, + basenamelist::member const ** found_basename = NULL) { - for (searchdirlist::buffer_iterator dir(searchdirs_.begin ()); + char const * critname = criterion.name (); + for (searchdirlist::iterator dir(searchdirs_.begin ()); dir != searchdirs_.end (); ++dir) for (basenamelist::iterator name = basenames_.begin (); name != basenames_.end (); ++name) - { - /* Complete the filename path to search for. - We have allocated enough memory above. */ - memcpy (dir->buffer () + dir->stringlength (), - name->string (), name->stringlength () + 1); - real_filename.check (dir->string (), PC_SYM_FOLLOW | PC_POSIX); - if (real_filename.exists () && !real_filename.isdir ()) - { - debug_printf ("found %s", dir->buffer ()); - return true; - } - debug_printf ("no %s", dir->buffer ()); - } - real_filename.error = ENOENT; - return !real_filename.error; + if (criterion.test (dir, name)) + { + debug_printf ("(%s) take %s%s", critname, + dir->string(), name->string ()); + if (found_dir) + *found_dir = dir.operator -> (); + if (found_basename) + *found_basename = name.operator -> (); + return true; + } + else + debug_printf ("(%s) skip %s%s", critname, + dir->string(), name->string ()); + return false; } };