aboutsummaryrefslogtreecommitdiff
path: root/winsup/cygwin/pathfinder.h
diff options
context:
space:
mode:
authorMichael Haubenwallner <michael.haubenwallner@ssi-schaefer.com>2016-08-31 20:07:06 +0200
committerCorinna Vinschen <corinna@vinschen.de>2016-09-08 13:36:29 +0200
commit97974e3076f26d4031a95722116eb45bc98b5571 (patch)
treee68d7303dc0bd0780de866c864df0d23f2050cb0 /winsup/cygwin/pathfinder.h
parent091a0ac120e2c220a7b2c102e2e23d9b4b543ff6 (diff)
downloadnewlib-97974e3076f26d4031a95722116eb45bc98b5571.zip
newlib-97974e3076f26d4031a95722116eb45bc98b5571.tar.gz
newlib-97974e3076f26d4031a95722116eb45bc98b5571.tar.bz2
dlopen: switch to new pathfinder class
Instead of find_exec, without changing behaviour use new pathfinder class with new allocator_interface around tmp_pathbuf and new vstrlist class. * pathfinder.h (pathfinder): New file. * vstrlist.h (allocator_interface, allocated_type, vstrlist): New file. * dlfcn.cc (dlopen): Avoid redundant GetModuleHandleExW with RTLD_NOLOAD and RTLD_NODELETE. Switch to new pathfinder class, using (tmp_pathbuf_allocator): New class. (get_full_path_of_dll): Drop.
Diffstat (limited to 'winsup/cygwin/pathfinder.h')
-rw-r--r--winsup/cygwin/pathfinder.h208
1 files changed, 208 insertions, 0 deletions
diff --git a/winsup/cygwin/pathfinder.h b/winsup/cygwin/pathfinder.h
new file mode 100644
index 0000000..bbba168
--- /dev/null
+++ b/winsup/cygwin/pathfinder.h
@@ -0,0 +1,208 @@
+/* pathfinder.h: find one of multiple file names in path list
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "vstrlist.h"
+
+#ifdef __cplusplus
+
+/* Search a list of directory names for first occurrence of a file,
+ which's file name matches one out of a list of file names. */
+class pathfinder
+{
+public:
+ typedef vstrlist searchdirlist;
+ typedef vstrlist basenamelist;
+
+private:
+ pathfinder ();
+ pathfinder (pathfinder const &);
+ pathfinder & operator = (pathfinder const &);
+
+ basenamelist basenames_;
+ size_t basenames_maxlen_;
+
+ /* Add to searchdirs_ with extra buffer for any basename we may search for.
+ This is an optimization for the loops in check_path_access method. */
+ searchdirlist searchdirs_;
+
+public:
+ ~pathfinder () {}
+
+ /* We need the basenames to search for first, to allow for optimized
+ memory allocation of each searchpath + longest basename combination.
+ The incoming list of basenames is emptied (ownership take over). */
+ pathfinder (allocator_interface & a, basenamelist & basenames)
+ : basenames_ (a)
+ , basenames_maxlen_ ()
+ , searchdirs_(a)
+ {
+ basenames_.swap(basenames);
+
+ for (basenamelist::buffer_iterator basename (basenames_.begin ());
+ basename != basenames_.end ();
+ ++ basename)
+ {
+ if (basenames_maxlen_ < basename->bufferlength ())
+ basenames_maxlen_ = basename->bufferlength ();
+ }
+ }
+
+ void add_searchdir (const char *dir, int dirlen)
+ {
+ if (dirlen < 0)
+ dirlen = strlen (dir);
+
+ if (!dirlen)
+ return;
+
+ searchdirs_.appendv (dir, dirlen, "/", 1 + basenames_maxlen_, NULL);
+ }
+
+ void add_searchpath (const char *path)
+ {
+ while (path && *path)
+ {
+ const char *next = strchr (path, ':');
+ add_searchdir (path, next ? next - path : -1);
+ path = next ? next + 1 : next;
+ }
+ }
+
+ void add_envsearchpath (const char *envpath)
+ {
+ add_searchpath (getenv (envpath));
+ }
+
+
+ /* 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_not_dir
+ Test if path_conv argument does exist and is not a directory. */
+ struct exists_and_not_dir
+ : public path_conv_criterion_interface
+ {
+ virtual char const * name () const { return "exists and not dir"; }
+
+ exists_and_not_dir (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)
+ {
+ char const * critname = criterion.name ();
+ for (basenamelist::iterator name = basenames_.begin ();
+ name != basenames_.end ();
+ ++name)
+ for (searchdirlist::iterator dir(searchdirs_.begin ());
+ dir != searchdirs_.end ();
+ ++dir)
+ 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 ("not (%s), skip %s%s", critname,
+ dir->string(), name->string ());
+ return false;
+ }
+};
+
+#endif /* __cplusplus */