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