blob: 3ca9c8cbde8f2f3507df1399842ba952520b7091 [file] [log] [blame]
Chris Lattner22eb9722006-06-18 05:43:12 +00001//===--- FileManager.cpp - File System Probing and Caching ----------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Chris Lattner and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the FileManager interface.
11//
12//===----------------------------------------------------------------------===//
13//
14// TODO: This should index all interesting directories with dirent calls.
15// getdirentries ?
16// opendir/readdir_r/closedir ?
17//
18//===----------------------------------------------------------------------===//
19
20#include "clang/Basic/FileManager.h"
Chris Lattner2f4a89a2006-10-30 03:55:17 +000021#include "llvm/ADT/SmallString.h"
Chris Lattner22eb9722006-06-18 05:43:12 +000022#include <iostream>
23using namespace llvm;
24using namespace clang;
25
26// FIXME: Enhance libsystem to support inode and other fields.
27#include <sys/stat.h>
28
Chris Lattneraf653752006-10-30 03:06:54 +000029
30/// NON_EXISTANT_DIR - A special value distinct from null that is used to
31/// represent a dir name that doesn't exist on the disk.
32#define NON_EXISTANT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1)
33
Chris Lattner22eb9722006-06-18 05:43:12 +000034/// getDirectory - Lookup, cache, and verify the specified directory. This
35/// returns null if the directory doesn't exist.
36///
Chris Lattner2f4a89a2006-10-30 03:55:17 +000037const DirectoryEntry *FileManager::getDirectory(const char *NameStart,
38 const char *NameEnd) {
Chris Lattner22eb9722006-06-18 05:43:12 +000039 ++NumDirLookups;
Chris Lattner2f4a89a2006-10-30 03:55:17 +000040 DirectoryEntry *&NamedDirEnt =DirEntries.GetOrCreateValue(NameStart, NameEnd);
Chris Lattneraf653752006-10-30 03:06:54 +000041
Chris Lattner22eb9722006-06-18 05:43:12 +000042 // See if there is already an entry in the map.
Chris Lattneraf653752006-10-30 03:06:54 +000043 if (NamedDirEnt)
44 return NamedDirEnt == NON_EXISTANT_DIR ? 0 : NamedDirEnt;
Chris Lattner22eb9722006-06-18 05:43:12 +000045
46 ++NumDirCacheMisses;
47
Chris Lattneraf653752006-10-30 03:06:54 +000048 // By default, initialize it to invalid.
49 NamedDirEnt = NON_EXISTANT_DIR;
Chris Lattner22eb9722006-06-18 05:43:12 +000050
Chris Lattner43fd42e2006-10-30 03:40:58 +000051 // Get the null-terminated directory name as stored as the key of the
52 // DirEntries map.
53 const char *InterndDirName = DirEntries.GetKeyForValueInMap(NamedDirEnt);
54
Chris Lattneraf653752006-10-30 03:06:54 +000055 // Check to see if the directory exists.
Chris Lattner22eb9722006-06-18 05:43:12 +000056 struct stat StatBuf;
Chris Lattner43fd42e2006-10-30 03:40:58 +000057 if (stat(InterndDirName, &StatBuf) || // Error stat'ing.
58 !S_ISDIR(StatBuf.st_mode)) // Not a directory?
Chris Lattner22eb9722006-06-18 05:43:12 +000059 return 0;
60
61 // It exists. See if we have already opened a directory with the same inode.
62 // This occurs when one dir is symlinked to another, for example.
Chris Lattner8b1e8482006-10-30 02:45:16 +000063 DirectoryEntry &UDE =
Chris Lattner22eb9722006-06-18 05:43:12 +000064 UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)];
65
Chris Lattnera85cbe22006-10-30 03:11:40 +000066 if (UDE.getName()) // Already have an entry with this inode, return it.
Chris Lattneraf653752006-10-30 03:06:54 +000067 return NamedDirEnt = &UDE;
Chris Lattner22eb9722006-06-18 05:43:12 +000068
Chris Lattnera85cbe22006-10-30 03:11:40 +000069 // Otherwise, we don't have this directory yet, add it. We use the string
70 // key from the DirEntries map as the string.
Chris Lattner43fd42e2006-10-30 03:40:58 +000071 UDE.Name = InterndDirName;
Chris Lattneraf653752006-10-30 03:06:54 +000072 return NamedDirEnt = &UDE;
Chris Lattner22eb9722006-06-18 05:43:12 +000073}
74
Chris Lattner2f4a89a2006-10-30 03:55:17 +000075/// NON_EXISTANT_FILE - A special value distinct from null that is used to
76/// represent a filename that doesn't exist on the disk.
77#define NON_EXISTANT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1)
78
Chris Lattner22eb9722006-06-18 05:43:12 +000079/// getFile - Lookup, cache, and verify the specified file. This returns null
80/// if the file doesn't exist.
81///
Chris Lattner2f4a89a2006-10-30 03:55:17 +000082const FileEntry *FileManager::getFile(const char *NameStart,
83 const char *NameEnd) {
Chris Lattner22eb9722006-06-18 05:43:12 +000084 ++NumFileLookups;
85
86 // See if there is already an entry in the map.
Chris Lattner2f4a89a2006-10-30 03:55:17 +000087 FileEntry *&NamedFileEnt = FileEntries.GetOrCreateValue(NameStart, NameEnd);
Chris Lattner22eb9722006-06-18 05:43:12 +000088
Chris Lattner2f4a89a2006-10-30 03:55:17 +000089 // See if there is already an entry in the map.
90 if (NamedFileEnt)
91 return NamedFileEnt == NON_EXISTANT_FILE ? 0 : NamedFileEnt;
92
Chris Lattner22eb9722006-06-18 05:43:12 +000093 ++NumFileCacheMisses;
94
Chris Lattner2f4a89a2006-10-30 03:55:17 +000095 // By default, initialize it to invalid.
96 NamedFileEnt = NON_EXISTANT_FILE;
Chris Lattner22eb9722006-06-18 05:43:12 +000097
Chris Lattner9c59bda2006-10-30 04:34:28 +000098 // Figure out what directory it is in. If the string contains a / in it,
99 // strip off everything after it.
Chris Lattner22eb9722006-06-18 05:43:12 +0000100 // FIXME: this logic should be in sys::Path.
Chris Lattner2f4a89a2006-10-30 03:55:17 +0000101 const char *SlashPos = NameEnd-1;
102 while (SlashPos >= NameStart && SlashPos[0] != '/')
103 --SlashPos;
104
Chris Lattner9c59bda2006-10-30 04:34:28 +0000105 const DirectoryEntry *DirInfo;
Chris Lattner2f4a89a2006-10-30 03:55:17 +0000106 if (SlashPos < NameStart) {
107 // Use the current directory if file has no path component.
Chris Lattner9c59bda2006-10-30 04:34:28 +0000108 const char *Name = ".";
109 DirInfo = getDirectory(Name, Name+1);
Chris Lattner2f4a89a2006-10-30 03:55:17 +0000110 } else if (SlashPos == NameEnd-1)
Chris Lattner22eb9722006-06-18 05:43:12 +0000111 return 0; // If filename ends with a /, it's a directory.
112 else
Chris Lattner9c59bda2006-10-30 04:34:28 +0000113 DirInfo = getDirectory(NameStart, SlashPos);
114
Chris Lattner22eb9722006-06-18 05:43:12 +0000115 if (DirInfo == 0) // Directory doesn't exist, file can't exist.
116 return 0;
117
Chris Lattner2f4a89a2006-10-30 03:55:17 +0000118 // Get the null-terminated file name as stored as the key of the
119 // FileEntries map.
120 const char *InterndFileName = FileEntries.GetKeyForValueInMap(NamedFileEnt);
121
Chris Lattner22eb9722006-06-18 05:43:12 +0000122 // FIXME: Use the directory info to prune this, before doing the stat syscall.
123 // FIXME: This will reduce the # syscalls.
124
125 // Nope, there isn't. Check to see if the file exists.
126 struct stat StatBuf;
Chris Lattner81500bc2006-07-19 03:40:07 +0000127 //std::cerr << "STATING: " << Filename;
Chris Lattner2f4a89a2006-10-30 03:55:17 +0000128 if (stat(InterndFileName, &StatBuf) || // Error stat'ing.
Chris Lattner81500bc2006-07-19 03:40:07 +0000129 S_ISDIR(StatBuf.st_mode)) { // A directory?
130 // If this file doesn't exist, we leave a null in FileEntries for this path.
131 //std::cerr << ": Not existing\n";
Chris Lattner22eb9722006-06-18 05:43:12 +0000132 return 0;
Chris Lattner81500bc2006-07-19 03:40:07 +0000133 }
134 //std::cerr << ": exists\n";
Chris Lattner22eb9722006-06-18 05:43:12 +0000135
136 // It exists. See if we have already opened a directory with the same inode.
137 // This occurs when one dir is symlinked to another, for example.
Chris Lattner8b1e8482006-10-30 02:45:16 +0000138 FileEntry &UFE = UniqueFiles[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)];
Chris Lattner22eb9722006-06-18 05:43:12 +0000139
Chris Lattner2f4a89a2006-10-30 03:55:17 +0000140 if (UFE.getName()) // Already have an entry with this inode, return it.
141 return NamedFileEnt = &UFE;
Chris Lattner269c2322006-06-25 06:23:00 +0000142
Chris Lattner22eb9722006-06-18 05:43:12 +0000143 // Otherwise, we don't have this directory yet, add it.
Chris Lattner8b1e8482006-10-30 02:45:16 +0000144 // FIXME: Change the name to be a char* that points back to the 'FileEntries'
145 // key.
Chris Lattner2f4a89a2006-10-30 03:55:17 +0000146 UFE.Name = InterndFileName;
147 UFE.Size = StatBuf.st_size;
148 UFE.ModTime = StatBuf.st_mtime;
149 UFE.Dir = DirInfo;
150 UFE.UID = NextFileUID++;
151 return NamedFileEnt = &UFE;
Chris Lattner22eb9722006-06-18 05:43:12 +0000152}
153
154void FileManager::PrintStats() const {
155 std::cerr << "\n*** File Manager Stats:\n";
156 std::cerr << UniqueFiles.size() << " files found, "
157 << UniqueDirs.size() << " dirs found.\n";
158 std::cerr << NumDirLookups << " dir lookups, "
159 << NumDirCacheMisses << " dir cache misses.\n";
160 std::cerr << NumFileLookups << " file lookups, "
161 << NumFileCacheMisses << " file cache misses.\n";
162
163 //std::cerr << PagesMapped << BytesOfPagesMapped << FSLookups;
164}