blob: be9d951a63d941f9ff0c54716a6cf7a8f6ae8cd7 [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 Lattner34d1f5a2007-02-08 19:08:49 +000040 StringMapEntry<DirectoryEntry *> &NamedDirEnt =
41 DirEntries.GetOrCreateValue(NameStart, NameEnd);
Chris Lattneraf653752006-10-30 03:06:54 +000042
Chris Lattner22eb9722006-06-18 05:43:12 +000043 // See if there is already an entry in the map.
Chris Lattner34d1f5a2007-02-08 19:08:49 +000044 if (NamedDirEnt.getValue())
45 return NamedDirEnt.getValue() == NON_EXISTANT_DIR
46 ? 0 : NamedDirEnt.getValue();
Chris Lattner22eb9722006-06-18 05:43:12 +000047
48 ++NumDirCacheMisses;
49
Chris Lattneraf653752006-10-30 03:06:54 +000050 // By default, initialize it to invalid.
Chris Lattner34d1f5a2007-02-08 19:08:49 +000051 NamedDirEnt.setValue(NON_EXISTANT_DIR);
Chris Lattner22eb9722006-06-18 05:43:12 +000052
Chris Lattner43fd42e2006-10-30 03:40:58 +000053 // Get the null-terminated directory name as stored as the key of the
54 // DirEntries map.
Chris Lattner34d1f5a2007-02-08 19:08:49 +000055 const char *InterndDirName = NamedDirEnt.getKeyData();
Chris Lattner43fd42e2006-10-30 03:40:58 +000056
Chris Lattneraf653752006-10-30 03:06:54 +000057 // Check to see if the directory exists.
Chris Lattner22eb9722006-06-18 05:43:12 +000058 struct stat StatBuf;
Chris Lattner43fd42e2006-10-30 03:40:58 +000059 if (stat(InterndDirName, &StatBuf) || // Error stat'ing.
60 !S_ISDIR(StatBuf.st_mode)) // Not a directory?
Chris Lattner22eb9722006-06-18 05:43:12 +000061 return 0;
62
63 // It exists. See if we have already opened a directory with the same inode.
64 // This occurs when one dir is symlinked to another, for example.
Chris Lattner8b1e8482006-10-30 02:45:16 +000065 DirectoryEntry &UDE =
Chris Lattner22eb9722006-06-18 05:43:12 +000066 UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)];
67
Chris Lattner34d1f5a2007-02-08 19:08:49 +000068 NamedDirEnt.setValue(&UDE);
69 if (UDE.getName()) // Already have an entry with this inode, return it.
70 return &UDE;
Chris Lattner22eb9722006-06-18 05:43:12 +000071
Chris Lattnera85cbe22006-10-30 03:11:40 +000072 // Otherwise, we don't have this directory yet, add it. We use the string
73 // key from the DirEntries map as the string.
Chris Lattner43fd42e2006-10-30 03:40:58 +000074 UDE.Name = InterndDirName;
Chris Lattner34d1f5a2007-02-08 19:08:49 +000075 return &UDE;
Chris Lattner22eb9722006-06-18 05:43:12 +000076}
77
Chris Lattner2f4a89a2006-10-30 03:55:17 +000078/// NON_EXISTANT_FILE - A special value distinct from null that is used to
79/// represent a filename that doesn't exist on the disk.
80#define NON_EXISTANT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1)
81
Chris Lattner22eb9722006-06-18 05:43:12 +000082/// getFile - Lookup, cache, and verify the specified file. This returns null
83/// if the file doesn't exist.
84///
Chris Lattner2f4a89a2006-10-30 03:55:17 +000085const FileEntry *FileManager::getFile(const char *NameStart,
86 const char *NameEnd) {
Chris Lattner22eb9722006-06-18 05:43:12 +000087 ++NumFileLookups;
88
89 // See if there is already an entry in the map.
Chris Lattner34d1f5a2007-02-08 19:08:49 +000090 StringMapEntry<FileEntry *> &NamedFileEnt =
91 FileEntries.GetOrCreateValue(NameStart, NameEnd);
Chris Lattner22eb9722006-06-18 05:43:12 +000092
Chris Lattner2f4a89a2006-10-30 03:55:17 +000093 // See if there is already an entry in the map.
Chris Lattner34d1f5a2007-02-08 19:08:49 +000094 if (NamedFileEnt.getValue())
95 return NamedFileEnt.getValue() == NON_EXISTANT_FILE
96 ? 0 : NamedFileEnt.getValue();
Chris Lattner2f4a89a2006-10-30 03:55:17 +000097
Chris Lattner22eb9722006-06-18 05:43:12 +000098 ++NumFileCacheMisses;
99
Chris Lattner2f4a89a2006-10-30 03:55:17 +0000100 // By default, initialize it to invalid.
Chris Lattner34d1f5a2007-02-08 19:08:49 +0000101 NamedFileEnt.setValue(NON_EXISTANT_FILE);
Chris Lattner22eb9722006-06-18 05:43:12 +0000102
Chris Lattner9c59bda2006-10-30 04:34:28 +0000103 // Figure out what directory it is in. If the string contains a / in it,
104 // strip off everything after it.
Chris Lattner22eb9722006-06-18 05:43:12 +0000105 // FIXME: this logic should be in sys::Path.
Chris Lattner2f4a89a2006-10-30 03:55:17 +0000106 const char *SlashPos = NameEnd-1;
107 while (SlashPos >= NameStart && SlashPos[0] != '/')
108 --SlashPos;
109
Chris Lattner9c59bda2006-10-30 04:34:28 +0000110 const DirectoryEntry *DirInfo;
Chris Lattner2f4a89a2006-10-30 03:55:17 +0000111 if (SlashPos < NameStart) {
112 // Use the current directory if file has no path component.
Chris Lattner9c59bda2006-10-30 04:34:28 +0000113 const char *Name = ".";
114 DirInfo = getDirectory(Name, Name+1);
Chris Lattner2f4a89a2006-10-30 03:55:17 +0000115 } else if (SlashPos == NameEnd-1)
Chris Lattner22eb9722006-06-18 05:43:12 +0000116 return 0; // If filename ends with a /, it's a directory.
117 else
Chris Lattner9c59bda2006-10-30 04:34:28 +0000118 DirInfo = getDirectory(NameStart, SlashPos);
119
Chris Lattner22eb9722006-06-18 05:43:12 +0000120 if (DirInfo == 0) // Directory doesn't exist, file can't exist.
121 return 0;
122
Chris Lattner2f4a89a2006-10-30 03:55:17 +0000123 // Get the null-terminated file name as stored as the key of the
124 // FileEntries map.
Chris Lattner34d1f5a2007-02-08 19:08:49 +0000125 const char *InterndFileName = NamedFileEnt.getKeyData();
Chris Lattner2f4a89a2006-10-30 03:55:17 +0000126
Chris Lattner22eb9722006-06-18 05:43:12 +0000127 // FIXME: Use the directory info to prune this, before doing the stat syscall.
128 // FIXME: This will reduce the # syscalls.
129
130 // Nope, there isn't. Check to see if the file exists.
131 struct stat StatBuf;
Chris Lattner81500bc2006-07-19 03:40:07 +0000132 //std::cerr << "STATING: " << Filename;
Chris Lattner2f4a89a2006-10-30 03:55:17 +0000133 if (stat(InterndFileName, &StatBuf) || // Error stat'ing.
Chris Lattner81500bc2006-07-19 03:40:07 +0000134 S_ISDIR(StatBuf.st_mode)) { // A directory?
135 // If this file doesn't exist, we leave a null in FileEntries for this path.
136 //std::cerr << ": Not existing\n";
Chris Lattner22eb9722006-06-18 05:43:12 +0000137 return 0;
Chris Lattner81500bc2006-07-19 03:40:07 +0000138 }
139 //std::cerr << ": exists\n";
Chris Lattner22eb9722006-06-18 05:43:12 +0000140
141 // It exists. See if we have already opened a directory with the same inode.
142 // This occurs when one dir is symlinked to another, for example.
Chris Lattner8b1e8482006-10-30 02:45:16 +0000143 FileEntry &UFE = UniqueFiles[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)];
Chris Lattner22eb9722006-06-18 05:43:12 +0000144
Chris Lattner34d1f5a2007-02-08 19:08:49 +0000145 NamedFileEnt.setValue(&UFE);
Chris Lattner2f4a89a2006-10-30 03:55:17 +0000146 if (UFE.getName()) // Already have an entry with this inode, return it.
Chris Lattner34d1f5a2007-02-08 19:08:49 +0000147 return &UFE;
Chris Lattner269c2322006-06-25 06:23:00 +0000148
Chris Lattner22eb9722006-06-18 05:43:12 +0000149 // Otherwise, we don't have this directory yet, add it.
Chris Lattner8b1e8482006-10-30 02:45:16 +0000150 // FIXME: Change the name to be a char* that points back to the 'FileEntries'
151 // key.
Chris Lattner2f4a89a2006-10-30 03:55:17 +0000152 UFE.Name = InterndFileName;
153 UFE.Size = StatBuf.st_size;
154 UFE.ModTime = StatBuf.st_mtime;
155 UFE.Dir = DirInfo;
156 UFE.UID = NextFileUID++;
Chris Lattner34d1f5a2007-02-08 19:08:49 +0000157 return &UFE;
Chris Lattner22eb9722006-06-18 05:43:12 +0000158}
159
160void FileManager::PrintStats() const {
161 std::cerr << "\n*** File Manager Stats:\n";
162 std::cerr << UniqueFiles.size() << " files found, "
163 << UniqueDirs.size() << " dirs found.\n";
164 std::cerr << NumDirLookups << " dir lookups, "
165 << NumDirCacheMisses << " dir cache misses.\n";
166 std::cerr << NumFileLookups << " file lookups, "
167 << NumFileCacheMisses << " file cache misses.\n";
168
169 //std::cerr << PagesMapped << BytesOfPagesMapped << FSLookups;
170}