PathV3.inc revision 37b74a387bb3993387029859c2d9d051c41c724e
1//===- PathV3.inc ---------------------------------------------------------===//
2//
3//                     The MCLinker Project
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9#include "mcld/Support/Path.h"
10
11#include <stack>
12
13#include <sys/stat.h>
14#include <sys/types.h>
15
16namespace mcld {
17namespace sys {
18namespace fs {
19
20//===----------------------------------------------------------------------===//
21// mcld::sys::fs::detail
22//===----------------------------------------------------------------------===//
23namespace detail {
24
25// return the last charactor being handled.
26size_t canonicalize(std::string& pathname) {
27  // Variable Index //
28  // SepTable - stack of result separators
29  // LR(1) Algorithm //
30  // traverse pPathName
31  //   if we meet '//', '///', '////', ...
32  //     -> ignore it
33  //     -> push current into stack
34  //     -> jump to the next not '/'
35  //   if we meet '/./'
36  //     -> ignore
37  //     -> jump to the next not '/'
38  //   if we meet '/../'
39  //     -> pop previous position of '/' P
40  //     -> erase P+1 to now
41  //   if we meet other else
42  //     -> go go go
43  //   if we meet '/.../', '/..../', ... -> illegal
44  if (pathname.empty())
45    return 0;
46
47  size_t handler = 0;
48  std::stack<size_t> slash_stack;
49  slash_stack.push(-1);
50  while (handler < pathname.size()) {
51    if (separator == pathname[handler]) {  // handler = 1st '/'
52      size_t next = handler + 1;
53      if (next >= pathname.size())
54        return handler;
55      switch (pathname[next]) {  // next = handler + 1;
56        case separator: {        // '//'
57          while (next < pathname.size() && separator == pathname[next])
58            ++next;
59          // next is the last not '/'
60          pathname.erase(handler, next - handler - 1);
61          // handler is the first '/'
62          slash_stack.push(handler);
63          break;
64        }
65        case '.': {                     // '/.'
66          ++next;                       // next = handler + 2
67          if (next >= pathname.size())  // '/.'
68            return handler;
69          switch (pathname[next]) {
70            case separator: {  // '/./'
71              pathname.erase(handler, 2);
72              break;
73            }
74            case '.': {                     // '/..'
75              ++next;                       // next = handler + 3;
76              if (next >= pathname.size())  // '/..?'
77                return handler;
78              switch (pathname[next]) {
79                case separator: {  // '/../'
80                  handler = slash_stack.top();
81                  slash_stack.pop();
82                  pathname.erase(handler + 1, next - handler);
83                  if (static_cast<size_t>(-1) == handler) {
84                    slash_stack.push(-1);
85                    handler = pathname.find_first_of(separator, handler);
86                  }
87                  break;
88                }
89                case '.': {  // '/...', illegal
90                  return handler;
91                  break;
92                }
93                default: {  // '/..a'
94                  slash_stack.push(handler);
95                  handler = pathname.find_first_of(separator, handler + 3);
96                  break;
97                }
98              }
99              break;
100            }
101            default: {  // '/.a'
102              slash_stack.push(handler);
103              handler = pathname.find_first_of(separator, handler + 2);
104              break;
105            }
106          }
107          break;
108        }
109        default: {  // '/a
110          slash_stack.push(handler);
111          handler = pathname.find_first_of(separator, handler + 1);
112          break;
113        }
114      }
115    } else {
116      handler = pathname.find_first_of(separator, handler);
117    }
118  }
119  return handler;
120}
121
122bool not_found_error(int perrno) {
123  return perrno == ENOENT || perrno == ENOTDIR;
124}
125
126void status(const Path& p, FileStatus& pFileStatus) {
127  struct ::_stat path_stat;
128  if (::_stat(p.c_str(), &path_stat) != 0) {
129    if (not_found_error(errno)) {
130      pFileStatus.setType(FileNotFound);
131    } else
132      pFileStatus.setType(StatusError);
133  } else if (S_ISDIR(path_stat.st_mode))
134    pFileStatus.setType(DirectoryFile);
135  else if (S_ISREG(path_stat.st_mode))
136    pFileStatus.setType(RegularFile);
137  else if (S_ISBLK(path_stat.st_mode))
138    pFileStatus.setType(BlockFile);
139  else if (S_ISCHR(path_stat.st_mode))
140    pFileStatus.setType(CharacterFile);
141  else if (S_ISFIFO(path_stat.st_mode))
142    pFileStatus.setType(FifoFile);
143  else
144    pFileStatus.setType(TypeUnknown);
145}
146
147void symlink_status(const Path& p, FileStatus& pFileStatus) {
148  pFileStatus.setType(FileNotFound);
149}
150
151/// directory_iterator_increment - increment function implementation
152//
153//  iterator will call this function in two situations:
154//  1. All elements have been put into cache, and iterator stays at the end
155//     of cache. (a real end)
156//  2. Some but not all elements had beed put into cache, and we stoped.
157//     An iterator now is staying at the end of cache. (a temporal end)
158mcld::sys::fs::PathCache::entry_type* bring_one_into_cache(DirIterator& pIter) {
159  mcld::sys::fs::PathCache::entry_type* entry = 0;
160  fs::Path file_filter(pIter.m_pParent->m_Path);
161  file_filter.append("*");
162
163  WIN32_FIND_DATA FindFileData;
164  if (FindNextFile(reinterpret_cast<HANDLE>(pIter.m_pParent->m_Handler),
165                   &FindFileData)) {
166    // read one
167    bool exist = false;
168    std::string path(pIter.m_pParent->m_Path.native());
169    path += separator;
170    path += std::string(FindFileData.cFileName);
171    entry = pIter.m_pParent->m_Cache.insert(path, exist);
172    if (!exist)
173      entry->setValue(path);
174  } else if (ERROR_NO_MORE_FILES == GetLastError()) {
175    // meet real end
176    pIter.m_pParent->m_CacheFull = true;
177  } else {
178    llvm::report_fatal_error(std::string("Can't read directory: ") +
179                             pIter.m_pParent->path().native());
180  }
181
182  return entry;
183}
184
185}  // namespace detail
186}  // namespace fs
187}  // namespace sys
188}  // namespace mcld
189