source: rtems-tools/rtemstoolkit/rld-path.cpp @ 562e98c

5
Last change on this file since 562e98c was f7d303f, checked in by Chris Johns <chrisj@…>, on 05/08/18 at 05:09:45

rtemstoolkit/path: Fix crash when going above the root directory.

  • Property mode set to 100644
File size: 5.7 KB
Line 
1/*
2 * Copyright (c) 2011-2014, Chris Johns <chrisj@rtems.org>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#if HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#include <errno.h>
22#include <string.h>
23#include <sys/stat.h>
24#include <unistd.h>
25
26#include <rld.h>
27
28namespace rld
29{
30  namespace path
31  {
32    const std::string
33    basename (const std::string& name)
34    {
35      size_t b = name.find_last_of (RLD_PATH_SEPARATOR);
36      if (b != std::string::npos)
37        return name.substr (b + 1);
38      return name;
39    }
40
41    const std::string
42    dirname (const std::string& name)
43    {
44      size_t b = name.find_last_of (RLD_PATH_SEPARATOR);
45      if (b != std::string::npos)
46        return name.substr (0, b);
47      return name;
48    }
49
50    const std::string
51    extension (const std::string& name)
52    {
53      size_t b = name.find_last_of ('.');
54      if (b != std::string::npos)
55        return name.substr (b);
56      return name;
57    }
58
59    void
60    path_split (const std::string& path, paths& paths)
61    {
62      strings ps;
63      rld::split (ps, path, RLD_PATHSTR_SEPARATOR);
64      if (ps.size ())
65      {
66        for (strings::iterator psi = ps.begin ();
67             psi != ps.end ();
68             ++psi)
69        {
70          if (check_directory (*psi))
71            paths.push_back (*psi);
72        }
73      }
74    }
75
76    void
77    path_join (const std::string& base, const std::string& part, std::string& joined)
78    {
79      if ((base[base.size () - 1] != RLD_PATH_SEPARATOR) &&
80          (part[0] != RLD_PATH_SEPARATOR))
81        joined = base + RLD_PATH_SEPARATOR + part;
82      else if ((base[base.size () - 1] == RLD_PATH_SEPARATOR) &&
83               (part[0] == RLD_PATH_SEPARATOR))
84        joined = base + &part[1];
85      else
86        joined = base + part;
87    }
88
89    void
90    path_join (const std::string& base, const paths& parts, std::string& joined)
91    {
92      joined = base;
93      for (paths::const_iterator pi = parts.begin ();
94           pi != parts.end ();
95           ++pi)
96      {
97        path_join (joined, *pi, joined);
98      }
99    }
100
101    const std::string
102    path_abs (const std::string& path)
103    {
104      std::string apath;
105
106      if (path[0] == RLD_PATH_SEPARATOR)
107      {
108        apath = path;
109      }
110      else
111      {
112        char* buf = 0;
113        try
114        {
115          buf = new char[32 * 1024];
116          if (!::getcwd (buf, 32 * 1024))
117          {
118            delete [] buf;
119            throw rld::error (::strerror (errno), "get current working directory");
120          }
121          path_join (buf, path, apath);
122          delete [] buf;
123        }
124        catch (...)
125        {
126          delete [] buf;
127          throw;
128        }
129      }
130
131      strings ps;
132      strings aps;
133
134      rld::split (ps, apath, RLD_PATH_SEPARATOR);
135
136      for (strings::iterator psi = ps.begin ();
137           psi != ps.end ();
138           ++psi)
139      {
140        const std::string& dir = *psi;
141
142        if (dir.empty () || dir == ".")
143        {
144          /* do nothing */
145        }
146        else if (dir == "..")
147        {
148          /*
149           * If the path goes above the root of where we are there is nothing
150           * that can be done so return the path passed in.
151           */
152          aps.pop_back ();
153          if (aps.empty ())
154            return path;
155        }
156        else
157        {
158          aps.push_back (dir);
159        }
160      }
161
162      return RLD_PATH_SEPARATOR + rld::join (aps, RLD_PATH_SEPARATOR_STR);
163    }
164
165    bool
166    check_file (const std::string& path)
167    {
168      struct stat sb;
169      if (::stat (path.c_str (), &sb) == 0)
170        if (S_ISREG (sb.st_mode))
171          return true;
172      return false;
173    }
174
175    bool
176    check_directory (const std::string& path)
177    {
178      struct stat sb;
179      if (::stat (path.c_str (), &sb) == 0)
180        if (S_ISDIR (sb.st_mode))
181          return true;
182      return false;
183    }
184
185    void
186    find_file (std::string& path, const std::string& name, paths& search_paths)
187    {
188      for (paths::iterator pi = search_paths.begin ();
189           pi != search_paths.end ();
190           ++pi)
191      {
192        path_join (*pi, name, path);
193        if (check_file (path))
194          return;
195      }
196      path.clear ();
197    }
198
199    void
200    unlink (const std::string& path, bool not_present_error)
201    {
202      struct stat sb;
203      if (::stat (path.c_str (), &sb) >= 0)
204      {
205        if (!S_ISREG (sb.st_mode))
206            throw rld::error ("Not a regular file", "unlinking: " + path);
207
208        int r;
209#if _WIN32
210        r = ::remove(path.c_str ());
211#else
212        r = ::unlink (path.c_str ());
213#endif
214        if (r < 0)
215          throw rld::error (::strerror (errno), "unlinking: " + path);
216      }
217      else
218      {
219        if (not_present_error)
220          throw rld::error ("Not found", "unlinking: " + path);
221      }
222    }
223
224    void
225    get_system_path (paths& paths)
226    {
227      const char* path = ::getenv ("PATH");
228      strings     ps;
229      rld::split (ps, path, RLD_PATHSTR_SEPARATOR);
230      if (ps.size ())
231      {
232        for (strings::iterator psi = ps.begin ();
233             psi != ps.end ();
234             ++psi)
235        {
236          if (check_directory (*psi))
237            paths.push_back (*psi);
238        }
239      }
240    }
241  }
242}
Note: See TracBrowser for help on using the repository browser.