]> granicus.if.org Git - clang/commitdiff
change the 'is directory' indicator to be a null-or-not
authorChris Lattner <sabre@nondot.org>
Tue, 23 Nov 2010 21:17:56 +0000 (21:17 +0000)
committerChris Lattner <sabre@nondot.org>
Tue, 23 Nov 2010 21:17:56 +0000 (21:17 +0000)
pointer that is passed down through the APIs, and make
FileSystemStatCache::get be the one that filters out
directory lookups that hit files.  This also paves the
way to have stat queries be able to return opened files.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@120060 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/FileManager.h
include/clang/Basic/FileSystemStatCache.h
lib/Basic/FileManager.cpp
lib/Basic/FileSystemStatCache.cpp
lib/Frontend/CacheTokens.cpp
lib/Lex/PTHLexer.cpp
lib/Serialization/ASTReader.cpp

index 8e97062b44cc7914d2faf994201bb20cbd9b282e..a32f65a5984a4d2751b0c1e5e0aa31a45326f726 100644 (file)
@@ -131,7 +131,8 @@ class FileManager {
   // Caching.
   llvm::OwningPtr<FileSystemStatCache> StatCache;
 
-  bool getStatValue(const char *Path, struct stat &StatBuf, bool isForDir);
+  bool getStatValue(const char *Path, struct stat &StatBuf,
+                    int *FileDescriptor);
 public:
   FileManager(const FileSystemOptions &FileSystemOpts);
   ~FileManager();
index e9da8cf15c00618daea2bca835f978d58fab82ad..77828b3ecb8ad5b66194da7d768be435302ea7d3 100644 (file)
@@ -39,13 +39,15 @@ public:
   /// FileSystemStatCache::get - Get the 'stat' information for the specified
   /// path, using the cache to accellerate it if possible.  This returns true if
   /// the path does not exist or false if it exists.
-  static bool get(const char *Path, struct stat &StatBuf,
-                  FileSystemStatCache *Cache) {
-    if (Cache)
-      return Cache->getStat(Path, StatBuf) == CacheMissing;
-    
-    return ::stat(Path, &StatBuf) != 0;
-  }
+  ///
+  /// If FileDescriptor is non-null, then this lookup should only return success
+  /// for files (not directories).  If it is null this lookup should only return
+  /// success for directories (not files).  On a successful file lookup, the
+  /// implementation can optionally fill in FileDescriptor with a valid
+  /// descriptor and the client guarantees that it will close it.
+  static bool get(const char *Path, struct stat &StatBuf, int *FileDescriptor,
+                  FileSystemStatCache *Cache);
+  
   
   /// \brief Sets the next stat call cache in the chain of stat caches.
   /// Takes ownership of the given stat cache.
@@ -62,15 +64,17 @@ public:
   FileSystemStatCache *takeNextStatCache() { return NextStatCache.take(); }
   
 protected:
-  virtual LookupResult getStat(const char *Path, struct stat &StatBuf) = 0;
+  virtual LookupResult getStat(const char *Path, struct stat &StatBuf,
+                               int *FileDescriptor) = 0;
 
-  LookupResult statChained(const char *Path, struct stat &StatBuf) {
+  LookupResult statChained(const char *Path, struct stat &StatBuf,
+                           int *FileDescriptor) {
     if (FileSystemStatCache *Next = getNextStatCache())
-      return Next->getStat(Path, StatBuf);
+      return Next->getStat(Path, StatBuf, FileDescriptor);
     
     // If we hit the end of the list of stat caches to try, just compute and
     // return it without a cache.
-    return get(Path, StatBuf, 0) ? CacheMissing : CacheExists;
+    return get(Path, StatBuf, FileDescriptor, 0) ? CacheMissing : CacheExists;
   }
 };
 
@@ -88,7 +92,8 @@ public:
   iterator begin() const { return StatCalls.begin(); }
   iterator end() const { return StatCalls.end(); }
   
-  virtual LookupResult getStat(const char *Path, struct stat &StatBuf);
+  virtual LookupResult getStat(const char *Path, struct stat &StatBuf,
+                               int *FileDescriptor);
 };
 
 } // end namespace clang
index b56d96f21f66583de998a7c3d3353fb24633ab54..27a4dfe5446c8327e5c5d3478abff3b59ad2a75c 100644 (file)
@@ -33,10 +33,6 @@ using namespace clang;
 // FIXME: Enhance libsystem to support inode and other fields.
 #include <sys/stat.h>
 
-#if defined(_MSC_VER)
-#define S_ISDIR(s) (_S_IFDIR & s)
-#endif
-
 /// NON_EXISTENT_DIR - A special value distinct from null that is used to
 /// represent a dir name that doesn't exist on the disk.
 #define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1)
@@ -248,7 +244,7 @@ const DirectoryEntry *FileManager::getDirectory(llvm::StringRef Filename) {
 
   // Check to see if the directory exists.
   struct stat StatBuf;
-  if (getStatValue(InterndDirName, StatBuf, true))
+  if (getStatValue(InterndDirName, StatBuf, 0/*directory lookup*/))
     return 0;
 
   // It exists.  See if we have already opened a directory with the same inode.
@@ -304,8 +300,9 @@ const FileEntry *FileManager::getFile(llvm::StringRef Filename) {
   // FIXME: This will reduce the # syscalls.
 
   // Nope, there isn't.  Check to see if the file exists.
+  int FileDescriptor = -1;
   struct stat StatBuf;
-  if (getStatValue(InterndFileName, StatBuf, false))
+  if (getStatValue(InterndFileName, StatBuf, &FileDescriptor))
     return 0;
 
   // It exists.  See if we have already opened a file with the same inode.
@@ -313,8 +310,13 @@ const FileEntry *FileManager::getFile(llvm::StringRef Filename) {
   FileEntry &UFE = UniqueFiles.getFile(InterndFileName, StatBuf);
 
   NamedFileEnt.setValue(&UFE);
-  if (UFE.getName())  // Already have an entry with this inode, return it.
+  if (UFE.getName()) { // Already have an entry with this inode, return it.
+    // If the stat process opened the file, close it to avoid a FD leak.
+    if (FileDescriptor != -1)
+      close(FileDescriptor);
+    
     return &UFE;
+  }
 
   // Otherwise, we don't have this directory yet, add it.
   // FIXME: Change the name to be a char* that points back to the 'FileEntries'
@@ -324,6 +326,7 @@ const FileEntry *FileManager::getFile(llvm::StringRef Filename) {
   UFE.ModTime = StatBuf.st_mtime;
   UFE.Dir     = DirInfo;
   UFE.UID     = NextFileUID++;
+  UFE.FD      = FileDescriptor;
   return &UFE;
 }
 
@@ -366,10 +369,12 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
   
   // If this virtual file resolves to a file, also map that file to the 
   // newly-created file entry.
+  int FileDescriptor = -1;
   struct stat StatBuf;
-  if (getStatValue(InterndFileName, StatBuf, false))
+  if (getStatValue(InterndFileName, StatBuf, &FileDescriptor))
     return UFE;
-    
+  
+  UFE->FD = FileDescriptor;
   llvm::sys::Path FilePath(UFE->Name);
   FilePath.makeAbsolute();
   FileEntries[FilePath.str()] = UFE;
@@ -414,18 +419,18 @@ getBufferForFile(llvm::StringRef Filename, std::string *ErrorStr) {
 /// The isForDir member indicates whether this is a directory lookup or not.
 /// This will return failure if the lookup isn't the expected kind.
 bool FileManager::getStatValue(const char *Path, struct stat &StatBuf,
-                               bool isForDir) {
+                               int *FileDescriptor) {
   // FIXME: FileSystemOpts shouldn't be passed in here, all paths should be
   // absolute!
   if (FileSystemOpts.WorkingDir.empty())
-    return FileSystemStatCache::get(Path, StatBuf, StatCache.get()) ||
-           S_ISDIR(StatBuf.st_mode) != isForDir;
+    return FileSystemStatCache::get(Path, StatBuf, FileDescriptor,
+                                    StatCache.get());
   
   llvm::sys::Path FilePath(Path);
   FixupRelativePath(FilePath, FileSystemOpts);
 
-  return FileSystemStatCache::get(FilePath.c_str(), StatBuf, StatCache.get()) ||
-         S_ISDIR(StatBuf.st_mode) != isForDir;
+  return FileSystemStatCache::get(FilePath.c_str(), StatBuf, FileDescriptor,
+                                  StatCache.get());
 }
 
 
index 6457414df98da7c7cfff5d333bc3039e1fc7903e..b2d43e474479b1e458c610f486cc762d20660e6d 100644 (file)
@@ -19,9 +19,35 @@ using namespace clang;
 #define S_ISDIR(s) (_S_IFDIR & s)
 #endif
 
+/// FileSystemStatCache::get - Get the 'stat' information for the specified
+/// path, using the cache to accellerate it if possible.  This returns true if
+/// the path does not exist or false if it exists.
+///
+/// If FileDescriptor is non-null, then this lookup should only return success
+/// for files (not directories).  If it is null this lookup should only return
+/// success for directories (not files).  On a successful file lookup, the
+/// implementation can optionally fill in FileDescriptor with a valid
+/// descriptor and the client guarantees that it will close it.
+bool FileSystemStatCache::get(const char *Path, struct stat &StatBuf,
+                              int *FileDescriptor, FileSystemStatCache *Cache) {
+  LookupResult R;
+  
+  if (Cache)
+    R = Cache->getStat(Path, StatBuf, FileDescriptor);
+  else
+    R = ::stat(Path, &StatBuf) != 0 ? CacheMissing : CacheExists;
+
+  if (R == CacheMissing) return true;
+  
+  bool isForDir = FileDescriptor == 0;
+  return S_ISDIR(StatBuf.st_mode) != isForDir;
+}
+
+
 MemorizeStatCalls::LookupResult
-MemorizeStatCalls::getStat(const char *Path, struct stat &StatBuf) {
-  LookupResult Result = statChained(Path, StatBuf);
+MemorizeStatCalls::getStat(const char *Path, struct stat &StatBuf,
+                           int *FileDescriptor) {
+  LookupResult Result = statChained(Path, StatBuf, FileDescriptor);
   
   // Do not cache failed stats, it is easy to construct common inconsistent
   // situations if we do, and they are not important for PCH performance (which
index 2a7af8a8c352f53b963175d3a9a0f1dd4f500142..ae4cdb5063ae30f98ff7c8b00e693eb1b23e3f90 100644 (file)
@@ -517,8 +517,9 @@ public:
   StatListener(PTHMap &pm) : PM(pm) {}
   ~StatListener() {}
 
-  LookupResult getStat(const char *Path, struct stat &StatBuf) {
-    LookupResult Result = statChained(Path, StatBuf);
+  LookupResult getStat(const char *Path, struct stat &StatBuf,
+                       int *FileDescriptor) {
+    LookupResult Result = statChained(Path, StatBuf, FileDescriptor);
 
     if (Result == CacheMissing) // Failed 'stat'.
       PM.insert(PTHEntryKeyVariant(Path), PTHEntry());
index ed068675fe323a8d0b23d0dcc8ed9c4925dfed4a..b6bc7ce48874eba85937ddd5b51fb7d24a394f2d 100644 (file)
@@ -678,13 +678,14 @@ public:
 
   ~PTHStatCache() {}
 
-  LookupResult getStat(const char *Path, struct stat &StatBuf) {
+  LookupResult getStat(const char *Path, struct stat &StatBuf,
+                       int *FileDescriptor) {
     // Do the lookup for the file's data in the PTH file.
     CacheTy::iterator I = Cache.find(Path);
 
     // If we don't get a hit in the PTH file just forward to 'stat'.
     if (I == Cache.end())
-      return statChained(Path, StatBuf);
+      return statChained(Path, StatBuf, FileDescriptor);
 
     const PTHStatData &Data = *I;
 
index dc719a1f938a3e7f6490cd5fb94386ec99d7017e..4994b4944e21c912cf8729b731d8509514620a64 100644 (file)
@@ -1074,14 +1074,15 @@ public:
 
   ~ASTStatCache() { delete Cache; }
 
-  LookupResult getStat(const char *Path, struct stat &StatBuf) {
+  LookupResult getStat(const char *Path, struct stat &StatBuf,
+                       int *FileDescriptor) {
     // Do the lookup for the file's data in the AST file.
     CacheTy::iterator I = Cache->find(Path);
 
     // If we don't get a hit in the AST file just forward to 'stat'.
     if (I == Cache->end()) {
       ++NumStatMisses;
-      return statChained(Path, StatBuf);
+      return statChained(Path, StatBuf, FileDescriptor);
     }
 
     ++NumStatHits;