1f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines//===- PathV3.inc ---------------------------------------------------------===//
2f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines//
3f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines//                     The MCLinker Project
4f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines//
5f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines// This file is distributed under the University of Illinois Open Source
6f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines// License. See LICENSE.TXT for details.
7f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines//
8f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines//===----------------------------------------------------------------------===//
937b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include "mcld/Support/Path.h"
1037b74a387bb3993387029859c2d9d051c41c724eStephen Hines
11f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines#include <stack>
12f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
1337b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include <sys/stat.h>
1437b74a387bb3993387029859c2d9d051c41c724eStephen Hines#include <sys/types.h>
1537b74a387bb3993387029859c2d9d051c41c724eStephen Hines
1637b74a387bb3993387029859c2d9d051c41c724eStephen Hinesnamespace mcld {
1737b74a387bb3993387029859c2d9d051c41c724eStephen Hinesnamespace sys {
1837b74a387bb3993387029859c2d9d051c41c724eStephen Hinesnamespace fs {
19f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
20f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines//===----------------------------------------------------------------------===//
21f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines// mcld::sys::fs::detail
22f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines//===----------------------------------------------------------------------===//
2337b74a387bb3993387029859c2d9d051c41c724eStephen Hinesnamespace detail {
24f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
25f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines// return the last charactor being handled.
2637b74a387bb3993387029859c2d9d051c41c724eStephen Hinessize_t canonicalize(std::string& pathname) {
27f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // Variable Index //
28f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // SepTable - stack of result separators
29f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // LR(1) Algorithm //
30f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  // traverse pPathName
31f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  //   if we meet '//', '///', '////', ...
32f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  //     -> ignore it
33f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  //     -> push current into stack
34f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  //     -> jump to the next not '/'
35f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  //   if we meet '/./'
36f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  //     -> ignore
37f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  //     -> jump to the next not '/'
38f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  //   if we meet '/../'
39f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  //     -> pop previous position of '/' P
40f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  //     -> erase P+1 to now
41f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  //   if we meet other else
42f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  //     -> go go go
43f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  //   if we meet '/.../', '/..../', ... -> illegal
44f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (pathname.empty())
45f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    return 0;
46f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
47f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  size_t handler = 0;
48f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  std::stack<size_t> slash_stack;
49f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  slash_stack.push(-1);
50f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  while (handler < pathname.size()) {
5137b74a387bb3993387029859c2d9d051c41c724eStephen Hines    if (separator == pathname[handler]) {  // handler = 1st '/'
52f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      size_t next = handler + 1;
53f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      if (next >= pathname.size())
54f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        return handler;
5537b74a387bb3993387029859c2d9d051c41c724eStephen Hines      switch (pathname[next]) {  // next = handler + 1;
5637b74a387bb3993387029859c2d9d051c41c724eStephen Hines        case separator: {        // '//'
57f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          while (next < pathname.size() && separator == pathname[next])
58f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines            ++next;
59f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          // next is the last not '/'
60f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          pathname.erase(handler, next - handler - 1);
61f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          // handler is the first '/'
62f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          slash_stack.push(handler);
63f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          break;
64f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        }
6537b74a387bb3993387029859c2d9d051c41c724eStephen Hines        case '.': {                     // '/.'
6637b74a387bb3993387029859c2d9d051c41c724eStephen Hines          ++next;                       // next = handler + 2
6737b74a387bb3993387029859c2d9d051c41c724eStephen Hines          if (next >= pathname.size())  // '/.'
68f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines            return handler;
69f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          switch (pathname[next]) {
7037b74a387bb3993387029859c2d9d051c41c724eStephen Hines            case separator: {  // '/./'
71f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines              pathname.erase(handler, 2);
72f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines              break;
73f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines            }
7437b74a387bb3993387029859c2d9d051c41c724eStephen Hines            case '.': {                     // '/..'
7537b74a387bb3993387029859c2d9d051c41c724eStephen Hines              ++next;                       // next = handler + 3;
7637b74a387bb3993387029859c2d9d051c41c724eStephen Hines              if (next >= pathname.size())  // '/..?'
77f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                return handler;
7837b74a387bb3993387029859c2d9d051c41c724eStephen Hines              switch (pathname[next]) {
7937b74a387bb3993387029859c2d9d051c41c724eStephen Hines                case separator: {  // '/../'
80f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                  handler = slash_stack.top();
81f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                  slash_stack.pop();
8237b74a387bb3993387029859c2d9d051c41c724eStephen Hines                  pathname.erase(handler + 1, next - handler);
83f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                  if (static_cast<size_t>(-1) == handler) {
84f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                    slash_stack.push(-1);
85f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                    handler = pathname.find_first_of(separator, handler);
86f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                  }
87f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                  break;
88f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                }
8937b74a387bb3993387029859c2d9d051c41c724eStephen Hines                case '.': {  // '/...', illegal
90f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                  return handler;
91f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                  break;
92f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                }
9337b74a387bb3993387029859c2d9d051c41c724eStephen Hines                default: {  // '/..a'
94f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                  slash_stack.push(handler);
9537b74a387bb3993387029859c2d9d051c41c724eStephen Hines                  handler = pathname.find_first_of(separator, handler + 3);
96f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                  break;
97f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                }
98f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines              }
99f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines              break;
100f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines            }
10137b74a387bb3993387029859c2d9d051c41c724eStephen Hines            default: {  // '/.a'
102f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines              slash_stack.push(handler);
10337b74a387bb3993387029859c2d9d051c41c724eStephen Hines              handler = pathname.find_first_of(separator, handler + 2);
104f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines              break;
105f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines            }
106f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          }
107f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          break;
108f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        }
10937b74a387bb3993387029859c2d9d051c41c724eStephen Hines        default: {  // '/a
110f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          slash_stack.push(handler);
11137b74a387bb3993387029859c2d9d051c41c724eStephen Hines          handler = pathname.find_first_of(separator, handler + 1);
112f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          break;
113f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        }
114f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      }
11537b74a387bb3993387029859c2d9d051c41c724eStephen Hines    } else {
116f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      handler = pathname.find_first_of(separator, handler);
117f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    }
118f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  }
119f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  return handler;
120f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines}
121f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
12237b74a387bb3993387029859c2d9d051c41c724eStephen Hinesbool not_found_error(int perrno) {
123f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  return perrno == ENOENT || perrno == ENOTDIR;
124f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines}
125f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
12637b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid status(const Path& p, FileStatus& pFileStatus) {
127f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  struct ::_stat path_stat;
12837b74a387bb3993387029859c2d9d051c41c724eStephen Hines  if (::_stat(p.c_str(), &path_stat) != 0) {
12937b74a387bb3993387029859c2d9d051c41c724eStephen Hines    if (not_found_error(errno)) {
130f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      pFileStatus.setType(FileNotFound);
13137b74a387bb3993387029859c2d9d051c41c724eStephen Hines    } else
132f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      pFileStatus.setType(StatusError);
13337b74a387bb3993387029859c2d9d051c41c724eStephen Hines  } else if (S_ISDIR(path_stat.st_mode))
134f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    pFileStatus.setType(DirectoryFile);
13537b74a387bb3993387029859c2d9d051c41c724eStephen Hines  else if (S_ISREG(path_stat.st_mode))
136f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    pFileStatus.setType(RegularFile);
13737b74a387bb3993387029859c2d9d051c41c724eStephen Hines  else if (S_ISBLK(path_stat.st_mode))
138f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    pFileStatus.setType(BlockFile);
13937b74a387bb3993387029859c2d9d051c41c724eStephen Hines  else if (S_ISCHR(path_stat.st_mode))
140f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    pFileStatus.setType(CharacterFile);
14137b74a387bb3993387029859c2d9d051c41c724eStephen Hines  else if (S_ISFIFO(path_stat.st_mode))
142f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    pFileStatus.setType(FifoFile);
143f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  else
144f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    pFileStatus.setType(TypeUnknown);
145f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines}
146f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
14737b74a387bb3993387029859c2d9d051c41c724eStephen Hinesvoid symlink_status(const Path& p, FileStatus& pFileStatus) {
148f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  pFileStatus.setType(FileNotFound);
149f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines}
150f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
151f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines/// directory_iterator_increment - increment function implementation
152f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines//
153f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines//  iterator will call this function in two situations:
154f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines//  1. All elements have been put into cache, and iterator stays at the end
155f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines//     of cache. (a real end)
156f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines//  2. Some but not all elements had beed put into cache, and we stoped.
157f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines//     An iterator now is staying at the end of cache. (a temporal end)
15837b74a387bb3993387029859c2d9d051c41c724eStephen Hinesmcld::sys::fs::PathCache::entry_type* bring_one_into_cache(DirIterator& pIter) {
159f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  mcld::sys::fs::PathCache::entry_type* entry = 0;
160f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  fs::Path file_filter(pIter.m_pParent->m_Path);
161f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  file_filter.append("*");
162f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
163f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  WIN32_FIND_DATA FindFileData;
164f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  if (FindNextFile(reinterpret_cast<HANDLE>(pIter.m_pParent->m_Handler),
165f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                   &FindFileData)) {
166f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    // read one
167f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    bool exist = false;
168f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    std::string path(pIter.m_pParent->m_Path.native());
169f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    path += separator;
170f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    path += std::string(FindFileData.cFileName);
171f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    entry = pIter.m_pParent->m_Cache.insert(path, exist);
172f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    if (!exist)
173f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      entry->setValue(path);
17437b74a387bb3993387029859c2d9d051c41c724eStephen Hines  } else if (ERROR_NO_MORE_FILES == GetLastError()) {
175f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    // meet real end
176f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines    pIter.m_pParent->m_CacheFull = true;
17737b74a387bb3993387029859c2d9d051c41c724eStephen Hines  } else {
17837b74a387bb3993387029859c2d9d051c41c724eStephen Hines    llvm::report_fatal_error(std::string("Can't read directory: ") +
179f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines                             pIter.m_pParent->path().native());
180f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  }
181f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
182f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  return entry;
183f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines}
184f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines
18537b74a387bb3993387029859c2d9d051c41c724eStephen Hines}  // namespace detail
18637b74a387bb3993387029859c2d9d051c41c724eStephen Hines}  // namespace fs
18737b74a387bb3993387029859c2d9d051c41c724eStephen Hines}  // namespace sys
18837b74a387bb3993387029859c2d9d051c41c724eStephen Hines}  // namespace mcld
189