diff --git a/include/clang/AST/ASTImporter.h b/include/clang/AST/ASTImporter.h
index a1c4d5399ec9ad297c87354d8a0a56608842b852..1ad33990f2e5b2a563adacf4067c593544aa1cbd 100644
--- a/include/clang/AST/ASTImporter.h
+++ b/include/clang/AST/ASTImporter.h
@@ -28,6 +28,7 @@ namespace clang {
   class Diagnostic;
   class Expr;
   class FileManager;
+  class FileSystemOptions;
   class IdentifierInfo;
   class NestedNameSpecifier;
   class Stmt;
@@ -45,6 +46,8 @@ namespace clang {
     
     /// \brief The file managers we're importing to and from.
     FileManager &ToFileManager, &FromFileManager;
+
+    const FileSystemOptions &ToFileSystemOpts, &FromFileSystemOpts;
     
     /// \brief The diagnostics object that we should use to emit diagnostics.
     Diagnostic &Diags;
@@ -76,7 +79,9 @@ namespace clang {
   public:
     ASTImporter(Diagnostic &Diags,
                 ASTContext &ToContext, FileManager &ToFileManager,
-                ASTContext &FromContext, FileManager &FromFileManager);
+                const FileSystemOptions &ToFileSystemOpts,
+                ASTContext &FromContext, FileManager &FromFileManager,
+                const FileSystemOptions &FromFileSystemOpts);
     
     virtual ~ASTImporter();
     
diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h
index e71f51a0e7001bdc448d0f9ddbe03a5802f22cbe..44a7079edd24cf6de62df7f1db0fa648dbe58db5 100644
--- a/include/clang/Basic/FileManager.h
+++ b/include/clang/Basic/FileManager.h
@@ -24,8 +24,16 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
+namespace llvm {
+class MemoryBuffer;
+namespace sys {
+class Path;
+}
+}
+
 namespace clang {
 class FileManager;
+class FileSystemOptions;
 
 /// DirectoryEntry - Cached information about one directory on the disk.
 ///
@@ -162,9 +170,8 @@ class FileManager {
   // Caching.
   llvm::OwningPtr<StatSysCallCache> StatCache;
 
-  int stat_cached(const char* path, struct stat* buf) {
-    return StatCache.get() ? StatCache->stat(path, buf) : stat(path, buf);
-  }
+  int stat_cached(const char* path, struct stat* buf,
+                  const FileSystemOptions &FileSystemOpts);
 
 public:
   FileManager();
@@ -189,25 +196,61 @@ public:
   /// getDirectory - Lookup, cache, and verify the specified directory.  This
   /// returns null if the directory doesn't exist.
   ///
-  const DirectoryEntry *getDirectory(llvm::StringRef Filename) {
-    return getDirectory(Filename.begin(), Filename.end());
+  const DirectoryEntry *getDirectory(llvm::StringRef Filename,
+                                     const FileSystemOptions &FileSystemOpts) {
+    return getDirectory(Filename.begin(), Filename.end(), FileSystemOpts);
   }
-  const DirectoryEntry *getDirectory(const char *FileStart,const char *FileEnd);
+  const DirectoryEntry *getDirectory(const char *FileStart,const char *FileEnd,
+                                     const FileSystemOptions &FileSystemOpts);
 
   /// getFile - Lookup, cache, and verify the specified file.  This returns null
   /// if the file doesn't exist.
   ///
-  const FileEntry *getFile(llvm::StringRef Filename) {
-    return getFile(Filename.begin(), Filename.end());
+  const FileEntry *getFile(llvm::StringRef Filename,
+                           const FileSystemOptions &FileSystemOpts) {
+    return getFile(Filename.begin(), Filename.end(), FileSystemOpts);
   }
   const FileEntry *getFile(const char *FilenameStart,
-                           const char *FilenameEnd);
+                           const char *FilenameEnd,
+                           const FileSystemOptions &FileSystemOpts);
 
   /// \brief Retrieve a file entry for a "virtual" file that acts as
   /// if there were a file with the given name on disk. The file
   /// itself is not accessed.
   const FileEntry *getVirtualFile(llvm::StringRef Filename, off_t Size,
-                                  time_t ModificationTime);
+                                  time_t ModificationTime,
+                                  const FileSystemOptions &FileSystemOpts);
+
+  /// \brief Open the specified file as a MemoryBuffer, returning a new
+  /// MemoryBuffer if successful, otherwise returning null.
+  llvm::MemoryBuffer *getBufferForFile(const FileEntry *Entry,
+                                       const FileSystemOptions &FileSystemOpts,
+                                       std::string *ErrorStr = 0,
+                                       struct stat *FileInfo = 0) {
+    return getBufferForFile(Entry->getName(), FileSystemOpts,
+                            ErrorStr, Entry->getSize(), FileInfo);
+  }
+  llvm::MemoryBuffer *getBufferForFile(llvm::StringRef Filename,
+                                       const FileSystemOptions &FileSystemOpts,
+                                       std::string *ErrorStr = 0,
+                                       int64_t FileSize = -1,
+                                       struct stat *FileInfo = 0) {
+    return getBufferForFile(Filename.begin(), Filename.end(), FileSystemOpts,
+                            ErrorStr, FileSize, FileInfo);
+  }
+  llvm::MemoryBuffer *getBufferForFile(const char *FilenameStart,
+                                       const char *FilenameEnd,
+                                       const FileSystemOptions &FileSystemOpts,
+                                       std::string *ErrorStr = 0,
+                                       int64_t FileSize = -1,
+                                       struct stat *FileInfo = 0);
+
+  /// \brief If path is not absolute and FileSystemOptions set the working
+  /// directory, the path is modified to be relative to the given
+  /// working directory.
+  static void FixupRelativePath(llvm::sys::Path &path,
+                                const FileSystemOptions &FSOpts);
+
   void PrintStats() const;
 };
 
diff --git a/include/clang/Basic/FileSystemOptions.h b/include/clang/Basic/FileSystemOptions.h
new file mode 100644
index 0000000000000000000000000000000000000000..4f3c2ae03df01227e3a0f06be8636daff442aa6e
--- /dev/null
+++ b/include/clang/Basic/FileSystemOptions.h
@@ -0,0 +1,29 @@
+//===--- FileSystemOptions.h - File System Options --------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the FileSystemOptions interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_FILESYSTEMOPTIONS_H
+#define LLVM_CLANG_BASIC_FILESYSTEMOPTIONS_H
+
+namespace clang {
+
+/// \brief Keeps track of options that affect how file operations are performed.
+class FileSystemOptions {
+public:
+  /// \brief If set, paths are resolved as if the working directory was
+  /// set to the value of WorkingDir.
+  std::string WorkingDir;
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index 2098698400c79fd8e311bdd5afd97d468394d530..4f5c17344d1d687052ca8d49dffbebfe6b340548 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -33,6 +33,7 @@ namespace clang {
 class Diagnostic;
 class SourceManager;
 class FileManager;
+class FileSystemOptions;
 class FileEntry;
 class LineTableInfo;
   
@@ -369,7 +370,10 @@ public:
 class SourceManager {
   /// \brief Diagnostic object.
   Diagnostic &Diag;
-  
+
+  FileManager &FileMgr;
+  const FileSystemOptions &FileSystemOpts;
+
   mutable llvm::BumpPtrAllocator ContentCacheAlloc;
 
   /// FileInfos - Memoized information about all of the files tracked by this
@@ -427,8 +431,10 @@ class SourceManager {
   explicit SourceManager(const SourceManager&);
   void operator=(const SourceManager&);
 public:
-  SourceManager(Diagnostic &Diag)
-    : Diag(Diag), ExternalSLocEntries(0), LineTable(0), NumLinearScans(0),
+  SourceManager(Diagnostic &Diag, FileManager &FileMgr,
+                const FileSystemOptions &FSOpts)
+    : Diag(Diag), FileMgr(FileMgr), FileSystemOpts(FSOpts),
+      ExternalSLocEntries(0), LineTable(0), NumLinearScans(0),
       NumBinaryProbes(0) {
     clearIDTables();
   }
@@ -438,6 +444,9 @@ public:
 
   Diagnostic &getDiagnostics() const { return Diag; }
 
+  FileManager &getFileManager() const { return FileMgr; }
+  const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; }
+
   //===--------------------------------------------------------------------===//
   // MainFileID creation and querying methods.
   //===--------------------------------------------------------------------===//
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 8a967d033a399835e861fb0d123defa442f39265..dee123ddd49686bd851a1460ef0b627f90d4ccba 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -366,6 +366,11 @@ def create_module : Flag<"-create-module">,
 def import_module : Separate<"-import-module">,
   HelpText<"Import a module definition file">;
 
+def working_directory : JoinedOrSeparate<"-working-directory">,
+  HelpText<"Resolve file paths relative to the specified directory">;
+def working_directory_EQ : Joined<"-working-directory=">,
+  Alias<working_directory>;
+
 def relocatable_pch : Flag<"-relocatable-pch">,
   HelpText<"Whether to build a relocatable precompiled header">;
 def chained_pch : Flag<"-chained-pch">,
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index da762becb64401f2ae34e51a6f88a9dd689d64b2..907639f58b5d83c1cf4be67637f99ed48a298adf 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -624,6 +624,11 @@ def x : JoinedOrSeparate<"-x">, Flags<[DriverOption]>,
   MetaVarName<"<language>">;
 def y : Joined<"-y">;
 
+def working_directory : Separate<"-working-directory">,
+  HelpText<"Resolve file paths relative to the specified directory">;
+def working_directory_EQ : Joined<"-working-directory=">,
+  Alias<working_directory>;
+
 // Double dash options, which are usually an alias for one of the previous
 // options.
 
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 45f771763d534f5ce421838cba7ea8b2d76f911f..980cd54cb314933f3fd39082fe6d695a48f24929 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -21,6 +21,7 @@
 #include "clang/Lex/PreprocessingRecord.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
 #include "clang-c/Index.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/OwningPtr.h"
@@ -68,7 +69,9 @@ private:
   llvm::OwningPtr<TargetInfo>       Target;
   llvm::OwningPtr<Preprocessor>     PP;
   llvm::OwningPtr<ASTContext>       Ctx;
-  
+
+  FileSystemOptions FileSystemOpts;
+
   /// \brief The AST consumer that received information about the translation
   /// unit as it was parsed or loaded.
   llvm::OwningPtr<ASTConsumer> Consumer;
@@ -359,6 +362,8 @@ public:
   const FileManager &getFileManager() const { return *FileMgr; }
         FileManager &getFileManager()       { return *FileMgr; }
 
+  const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; }
+
   const std::string &getOriginalSourceFileName();
   const std::string &getASTFileName();
 
@@ -452,7 +457,12 @@ public:
   unsigned cached_completion_size() const { 
     return CachedCompletionResults.size(); 
   }
-  
+
+  llvm::MemoryBuffer *getBufferForFile(llvm::StringRef Filename,
+                                       std::string *ErrorStr = 0,
+                                       int64_t FileSize = -1,
+                                       struct stat *FileInfo = 0);
+
   /// \brief Whether this AST represents a complete translation unit.
   ///
   /// If false, this AST is only a partial translation unit, e.g., one
@@ -473,6 +483,7 @@ public:
   /// \returns - The initialized ASTUnit or null if the AST failed to load.
   static ASTUnit *LoadFromASTFile(const std::string &Filename,
                                   llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
+                                  const FileSystemOptions &FileSystemOpts,
                                   bool OnlyLocalDecls = false,
                                   RemappedFile *RemappedFiles = 0,
                                   unsigned NumRemappedFiles = 0,
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index e5121e1bf9d1295ac6c4a980590ad9b09f7d4f8d..3db6077029110ab312db6dc2bf0d9e1326ca20ed 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -220,6 +220,10 @@ public:
     return Invocation->getDiagnosticOpts();
   }
 
+  const FileSystemOptions &getFileSystemOpts() const {
+    return Invocation->getFileSystemOpts();
+  }
+
   FrontendOptions &getFrontendOpts() {
     return Invocation->getFrontendOpts();
   }
@@ -499,7 +503,8 @@ public:
   void createFileManager();
 
   /// Create the source manager and replace any existing one with it.
-  void createSourceManager();
+  void createSourceManager(FileManager &FileMgr,
+                           const FileSystemOptions &FSOpts);
 
   /// Create the preprocessor, using the invocation, file, and source managers,
   /// and replace any existing one with it.
@@ -517,6 +522,7 @@ public:
                                           const DependencyOutputOptions &,
                                           const TargetInfo &,
                                           const FrontendOptions &,
+                                          const FileSystemOptions &,
                                           SourceManager &, FileManager &);
 
   /// Create the AST context.
@@ -617,6 +623,7 @@ public:
   static bool InitializeSourceManager(llvm::StringRef InputFile,
                                       Diagnostic &Diags,
                                       FileManager &FileMgr,
+                                      const FileSystemOptions &FSOpts,
                                       SourceManager &SourceMgr,
                                       const FrontendOptions &Opts);
 
diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h
index aef02448f0997437dd933315ee115331e3b18103..641c5f6650ebfe9d365597fdbabfefd915e13aeb 100644
--- a/include/clang/Frontend/CompilerInvocation.h
+++ b/include/clang/Frontend/CompilerInvocation.h
@@ -12,6 +12,7 @@
 
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/TargetOptions.h"
+#include "clang/Basic/FileSystemOptions.h"
 #include "clang/Frontend/AnalyzerOptions.h"
 #include "clang/Frontend/CodeGenOptions.h"
 #include "clang/Frontend/DependencyOutputOptions.h"
@@ -52,6 +53,9 @@ class CompilerInvocation {
   /// Options controlling the diagnostic engine.
   DiagnosticOptions DiagnosticOpts;
 
+  /// Options controlling file system operations.
+  FileSystemOptions FileSystemOpts;
+
   /// Options controlling the frontend itself.
   FrontendOptions FrontendOpts;
 
@@ -126,6 +130,11 @@ public:
   DiagnosticOptions &getDiagnosticOpts() { return DiagnosticOpts; }
   const DiagnosticOptions &getDiagnosticOpts() const { return DiagnosticOpts; }
 
+  FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; }
+  const FileSystemOptions &getFileSystemOpts() const {
+    return FileSystemOpts;
+  }
+
   HeaderSearchOptions &getHeaderSearchOpts() { return HeaderSearchOpts; }
   const HeaderSearchOptions &getHeaderSearchOpts() const {
     return HeaderSearchOpts;
diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h
index fe722db381d0106b1379f3872fb45f7a7f90dc1f..ff075445b49fee9d9c7626eb7be886b6b9a79eaf 100644
--- a/include/clang/Frontend/Utils.h
+++ b/include/clang/Frontend/Utils.h
@@ -39,6 +39,7 @@ class SourceManager;
 class Stmt;
 class TargetInfo;
 class FrontendOptions;
+class FileSystemOptions;
 
 /// Normalize \arg File for use in a user defined #include directive (in the
 /// predefines buffer).
@@ -53,6 +54,7 @@ void ApplyHeaderSearchOptions(HeaderSearch &HS,
 /// InitializePreprocessor - Initialize the preprocessor getting it and the
 /// environment ready to process a single file.
 void InitializePreprocessor(Preprocessor &PP,
+                            const FileSystemOptions &FSOpts,
                             const PreprocessorOptions &PPOpts,
                             const HeaderSearchOptions &HSOpts,
                             const FrontendOptions &FEOpts);
diff --git a/include/clang/Lex/HeaderMap.h b/include/clang/Lex/HeaderMap.h
index 9837e296535f1345df14c40aa64b8ab4ba3b7685..4f17ae3ec3bd1dfda8c4da876231c7ee986363ed 100644
--- a/include/clang/Lex/HeaderMap.h
+++ b/include/clang/Lex/HeaderMap.h
@@ -21,6 +21,7 @@ namespace llvm {
 namespace clang {
   class FileEntry;
   class FileManager;
+  class FileSystemOptions;
   struct HMapBucket;
   struct HMapHeader;
 
@@ -43,11 +44,13 @@ public:
 
   /// HeaderMap::Create - This attempts to load the specified file as a header
   /// map.  If it doesn't look like a HeaderMap, it gives up and returns null.
-  static const HeaderMap *Create(const FileEntry *FE);
+  static const HeaderMap *Create(const FileEntry *FE, FileManager &FM,
+                                 const FileSystemOptions &FSOpts);
 
   /// LookupFile - Check to see if the specified relative filename is located in
   /// this HeaderMap.  If so, open it and return its FileEntry.
-  const FileEntry *LookupFile(llvm::StringRef Filename, FileManager &FM) const;
+  const FileEntry *LookupFile(llvm::StringRef Filename, FileManager &FM,
+                              const FileSystemOptions &FileSystemOpts) const;
 
   /// getFileName - Return the filename of the headermap.
   const char *getFileName() const;
diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h
index 80b38dee06afa40b190dcc85086d232b33b3d681..7d467a56800bf376fcb4a7d3e3bea740d979e7a2 100644
--- a/include/clang/Lex/HeaderSearch.h
+++ b/include/clang/Lex/HeaderSearch.h
@@ -23,6 +23,7 @@ namespace clang {
 class ExternalIdentifierLookup;
 class FileEntry;
 class FileManager;
+class FileSystemOptions;
 class IdentifierInfo;
 
 /// HeaderFileInfo - The preprocessor keeps track of this information for each
@@ -71,6 +72,7 @@ struct HeaderFileInfo {
 /// file referenced by a #include or #include_next, (sub-)framework lookup, etc.
 class HeaderSearch {
   FileManager &FileMgr;
+  const FileSystemOptions &FileSystemOpts;
 
   /// #include search path information.  Requests for #include "x" search the
   /// directory of the #including file first, then each directory in SearchDirs
@@ -118,10 +120,11 @@ class HeaderSearch {
   explicit HeaderSearch(const HeaderSearch&);
   void operator=(const HeaderSearch&);
 public:
-  HeaderSearch(FileManager &FM);
+  HeaderSearch(FileManager &FM, const FileSystemOptions &FSOpts);
   ~HeaderSearch();
 
   FileManager &getFileMgr() const { return FileMgr; }
+  const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; }
 
   /// SetSearchPaths - Interface for setting the file search paths.
   ///
diff --git a/include/clang/Lex/PTHManager.h b/include/clang/Lex/PTHManager.h
index 5e8a4f144c96d0310aaccc06769e42bfa81efdbc..a3787e3ffef12c71f22ccae6357de417360f484b 100644
--- a/include/clang/Lex/PTHManager.h
+++ b/include/clang/Lex/PTHManager.h
@@ -119,7 +119,9 @@ public:
 
   /// Create - This method creates PTHManager objects.  The 'file' argument
   ///  is the name of the PTH file.  This method returns NULL upon failure.
-  static PTHManager *Create(const std::string& file, Diagnostic &Diags);
+  static PTHManager *Create(const std::string& file, FileManager &FileMgr,
+                            const FileSystemOptions &FSOpts,
+                            Diagnostic &Diags);
 
   void setPreprocessor(Preprocessor *pp) { PP = pp; }
 
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 7b138884e0bb5758fb7a56c32f0df7f91fa9ef12..b45f47bf117e1a3dd2aa3b4a9bf76f188a823fba 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -35,6 +35,7 @@ namespace clang {
 class SourceManager;
 class ExternalPreprocessorSource;
 class FileManager;
+class FileSystemOptions;
 class FileEntry;
 class HeaderSearch;
 class PragmaNamespace;
@@ -57,6 +58,7 @@ class Preprocessor {
   LangOptions        Features;
   const TargetInfo  &Target;
   FileManager       &FileMgr;
+  const FileSystemOptions &FileSystemOpts;
   SourceManager     &SourceMgr;
   ScratchBuffer     *ScratchBuf;
   HeaderSearch      &HeaderInfo;
@@ -279,6 +281,7 @@ public:
   const LangOptions &getLangOptions() const { return Features; }
   const TargetInfo &getTargetInfo() const { return Target; }
   FileManager &getFileManager() const { return FileMgr; }
+  const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; }
   SourceManager &getSourceManager() const { return SourceMgr; }
   HeaderSearch &getHeaderSearchInfo() const { return HeaderInfo; }
 
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 9ac7c3185290c0f95f95e5833ee157c1161fb355..420197c260693d70c9875e716335b5089059de66 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -67,6 +67,7 @@ class ASTDeclReader;
 class ASTStmtReader;
 class ASTIdentifierLookupTrait;
 class TypeLocReader;
+class FileSystemOptions;
 struct HeaderFileInfo;
 
 struct PCHPredefinesBlock {
@@ -193,6 +194,7 @@ private:
 
   SourceManager &SourceMgr;
   FileManager &FileMgr;
+  const FileSystemOptions &FileSystemOpts;
   Diagnostic &Diags;
 
   /// \brief The semantic analysis object that will be processing the
@@ -802,7 +804,8 @@ public:
   /// \param DisableValidation If true, the AST reader will suppress most
   /// of its regular consistency checking, allowing the use of precompiled
   /// headers that cannot be determined to be compatible.
-      ASTReader(SourceManager &SourceMgr, FileManager &FileMgr,
+  ASTReader(SourceManager &SourceMgr, FileManager &FileMgr,
+            const FileSystemOptions &FileSystemOpts,
             Diagnostic &Diags, const char *isysroot = 0,
             bool DisableValidation = false);
   ~ASTReader();
@@ -834,6 +837,8 @@ public:
   /// \brief Retrieve the name of the original source file name directly from
   /// the AST file, without actually loading the AST file.
   static std::string getOriginalSourceFile(const std::string &ASTFileName,
+                                           FileManager &FileMgr,
+                                           const FileSystemOptions &FSOpts,
                                            Diagnostic &Diags);
 
   /// \brief Returns the suggested contents of the predefines buffer,
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index a8cb1c5bed5962aced00c0ee112d2155a3b8950f..7747e617e3a50bbfe72f4f1a442efe7215843d0e 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -2980,9 +2980,12 @@ Expr *ASTNodeImporter::VisitCStyleCastExpr(CStyleCastExpr *E) {
 
 ASTImporter::ASTImporter(Diagnostic &Diags,
                          ASTContext &ToContext, FileManager &ToFileManager,
-                         ASTContext &FromContext, FileManager &FromFileManager)
+                         const FileSystemOptions &ToFileSystemOpts,
+                         ASTContext &FromContext, FileManager &FromFileManager,
+                         const FileSystemOptions &FromFileSystemOpts)
   : ToContext(ToContext), FromContext(FromContext),
     ToFileManager(ToFileManager), FromFileManager(FromFileManager),
+    ToFileSystemOpts(ToFileSystemOpts), FromFileSystemOpts(FromFileSystemOpts),
     Diags(Diags) {
   ImportedDecls[FromContext.getTranslationUnitDecl()]
     = ToContext.getTranslationUnitDecl();
@@ -3153,7 +3156,8 @@ FileID ASTImporter::Import(FileID FromID) {
     // disk again
     // FIXME: We definitely want to re-use the existing MemoryBuffer, rather
     // than mmap the files several times.
-    const FileEntry *Entry = ToFileManager.getFile(Cache->Entry->getName());
+    const FileEntry *Entry = ToFileManager.getFile(Cache->Entry->getName(),
+                                                   ToFileSystemOpts);
     ToID = ToSM.createFileID(Entry, ToIncludeLoc, 
                              FromSLoc.getFile().getFileCharacteristic());
   } else {
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index 565f8a61dee67310c3645987cff060b883757fe1..247ba1b752b32561c0c86438e7ab3cd783d2e857 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -18,8 +18,10 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/System/Path.h"
 #include "llvm/Config/config.h"
@@ -197,7 +199,8 @@ void FileManager::removeStatCache(StatSysCallCache *statCache) {
 /// \brief Retrieve the directory that the given file name resides in.
 static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
                                                   const char *NameStart,
-                                                  const char *NameEnd) {
+                                                  const char *NameEnd,
+                                      const FileSystemOptions &FileSystemOpts) {
   // Figure out what directory it is in.   If the string contains a / in it,
   // strip off everything after it.
   // FIXME: this logic should be in sys::Path.
@@ -211,18 +214,19 @@ static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
   if (SlashPos < NameStart) {
     // Use the current directory if file has no path component.
     const char *Name = ".";
-    return FileMgr.getDirectory(Name, Name+1);
+    return FileMgr.getDirectory(Name, Name+1, FileSystemOpts);
   } else if (SlashPos == NameEnd-1)
     return 0;       // If filename ends with a /, it's a directory.
   else
-    return FileMgr.getDirectory(NameStart, SlashPos);
+    return FileMgr.getDirectory(NameStart, SlashPos, FileSystemOpts);
 }
 
 /// getDirectory - Lookup, cache, and verify the specified directory.  This
 /// returns null if the directory doesn't exist.
 ///
 const DirectoryEntry *FileManager::getDirectory(const char *NameStart,
-                                                const char *NameEnd) {
+                                                const char *NameEnd,
+                                      const FileSystemOptions &FileSystemOpts) {
   // stat doesn't like trailing separators (at least on Windows).
   if (((NameEnd - NameStart) > 1) &&
       ((*(NameEnd - 1) == '/') || (*(NameEnd - 1) == '\\')))
@@ -248,7 +252,7 @@ const DirectoryEntry *FileManager::getDirectory(const char *NameStart,
 
   // Check to see if the directory exists.
   struct stat StatBuf;
-  if (stat_cached(InterndDirName, &StatBuf) ||   // Error stat'ing.
+  if (stat_cached(InterndDirName, &StatBuf, FileSystemOpts) ||   // Error stat'ing.
       !S_ISDIR(StatBuf.st_mode))          // Not a directory?
     return 0;
 
@@ -274,7 +278,8 @@ const DirectoryEntry *FileManager::getDirectory(const char *NameStart,
 /// if the file doesn't exist.
 ///
 const FileEntry *FileManager::getFile(const char *NameStart,
-                                      const char *NameEnd) {
+                                      const char *NameEnd,
+                                      const FileSystemOptions &FileSystemOpts) {
   ++NumFileLookups;
 
   // See if there is already an entry in the map.
@@ -297,7 +302,7 @@ const FileEntry *FileManager::getFile(const char *NameStart,
   const char *InterndFileName = NamedFileEnt.getKeyData();
 
   const DirectoryEntry *DirInfo
-    = getDirectoryFromFile(*this, NameStart, NameEnd);
+    = getDirectoryFromFile(*this, NameStart, NameEnd, FileSystemOpts);
   if (DirInfo == 0)  // Directory doesn't exist, file can't exist.
     return 0;
 
@@ -307,7 +312,7 @@ const FileEntry *FileManager::getFile(const char *NameStart,
   // Nope, there isn't.  Check to see if the file exists.
   struct stat StatBuf;
   //llvm::errs() << "STATING: " << Filename;
-  if (stat_cached(InterndFileName, &StatBuf) ||   // Error stat'ing.
+  if (stat_cached(InterndFileName, &StatBuf, FileSystemOpts) ||   // Error stat'ing.
         S_ISDIR(StatBuf.st_mode)) {           // A directory?
     // If this file doesn't exist, we leave a null in FileEntries for this path.
     //llvm::errs() << ": Not existing\n";
@@ -336,7 +341,8 @@ const FileEntry *FileManager::getFile(const char *NameStart,
 
 const FileEntry *
 FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
-                            time_t ModificationTime) {
+                            time_t ModificationTime,
+                            const FileSystemOptions &FileSystemOpts) {
   const char *NameStart = Filename.begin(), *NameEnd = Filename.end();
 
   ++NumFileLookups;
@@ -356,7 +362,7 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
   NamedFileEnt.setValue(NON_EXISTENT_FILE);
 
   const DirectoryEntry *DirInfo
-    = getDirectoryFromFile(*this, NameStart, NameEnd);
+    = getDirectoryFromFile(*this, NameStart, NameEnd, FileSystemOpts);
   if (DirInfo == 0)  // Directory doesn't exist, file can't exist.
     return 0;
 
@@ -374,7 +380,7 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
   // newly-created file entry.
   const char *InterndFileName = NamedFileEnt.getKeyData();
   struct stat StatBuf;
-  if (!stat_cached(InterndFileName, &StatBuf) &&
+  if (!stat_cached(InterndFileName, &StatBuf, FileSystemOpts) &&
       !S_ISDIR(StatBuf.st_mode)) {
     llvm::sys::Path FilePath(InterndFileName);
     FilePath.makeAbsolute();
@@ -384,6 +390,38 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
   return UFE;
 }
 
+llvm::MemoryBuffer *FileManager::getBufferForFile(const char *FilenameStart,
+                                     const char *FilenameEnd,
+                                     const FileSystemOptions &FileSystemOpts,
+                                     std::string *ErrorStr,
+                                     int64_t FileSize,
+                                     struct stat *FileInfo) {
+  llvm::sys::Path FilePath(llvm::StringRef(FilenameStart,
+                                           FilenameEnd-FilenameStart));
+  FixupRelativePath(FilePath, FileSystemOpts);
+
+  return llvm::MemoryBuffer::getFile(FilePath.c_str(), ErrorStr,
+                                     FileSize, FileInfo);
+}
+
+int FileManager::stat_cached(const char* path, struct stat* buf,
+                             const FileSystemOptions &FileSystemOpts) {
+  llvm::sys::Path FilePath(path);
+  FixupRelativePath(FilePath, FileSystemOpts);
+
+  return StatCache.get() ? StatCache->stat(FilePath.c_str(), buf)
+                         : stat(FilePath.c_str(), buf);
+}
+
+void FileManager::FixupRelativePath(llvm::sys::Path &path,
+                                    const FileSystemOptions &FSOpts) {
+  if (!FSOpts.WorkingDir.empty() && !path.isAbsolute()) {
+    llvm::sys::Path NewPath(FSOpts.WorkingDir);
+    NewPath.appendComponent(path.str());
+    path = NewPath;
+  }
+}
+
 void FileManager::PrintStats() const {
   llvm::errs() << "\n*** File Manager Stats:\n";
   llvm::errs() << UniqueFiles.size() << " files found, "
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 7127e80018655b005f3771bbe661f910f5652037..97af0d6fe36fdfbe92e19890a0f8294379990762 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -73,9 +73,10 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag,
   if (!Buffer.getPointer() && Entry) {
     std::string ErrorStr;
     struct stat FileInfo;
-    Buffer.setPointer(MemoryBuffer::getFile(Entry->getName(), &ErrorStr,
-                                            Entry->getSize(), &FileInfo));
-    
+    Buffer.setPointer(SM.getFileManager().getBufferForFile(Entry,
+                                                         SM.getFileSystemOpts(),
+                                                         &ErrorStr, &FileInfo));
+
     // If we were unable to open the file, then we are in an inconsistent
     // situation where the content cache referenced a file which no longer
     // exists. Most likely, we were using a stat cache with an invalid entry but
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 135520606592b651f63ebe05d30dbf9317850ca4..c7a74348374db2d3b30eb52cbd4675c84e4149cc 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -753,10 +753,19 @@ void Driver::BuildActions(const ToolChain &TC, const ArgList &Args,
       }
 
       // Check that the file exists, if enabled.
-      if (CheckInputsExist && memcmp(Value, "-", 2) != 0 &&
-          !llvm::sys::Path(Value).exists())
-        Diag(clang::diag::err_drv_no_such_file) << A->getValue(Args);
-      else
+      if (CheckInputsExist && memcmp(Value, "-", 2) != 0) {
+        llvm::sys::Path Path(Value);
+        if (Arg *WorkDir = Args.getLastArg(options::OPT_working_directory))
+          if (!Path.isAbsolute()) {
+            Path = WorkDir->getValue(Args);
+            Path.appendComponent(Value);
+          }
+
+        if (!Path.exists())
+          Diag(clang::diag::err_drv_no_such_file) << Path.str();
+        else
+          Inputs.push_back(std::make_pair(Ty, A));
+      } else
         Inputs.push_back(std::make_pair(Ty, A));
 
     } else if (A->getOption().isLinkerInput()) {
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 7ba1dc8be7eda96fe7fc678048c0f05a720c5046..744b0ae661f81a0ae192d178a75760b8e12cf701 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1073,6 +1073,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   CmdArgs.push_back("-resource-dir");
   CmdArgs.push_back(D.ResourceDir.c_str());
 
+  Args.AddLastArg(CmdArgs, options::OPT_working_directory);
+
   // Add preprocessing options like -I, -D, etc. if we are using the
   // preprocessor.
   //
diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp
index b46212fedaf47c91cb65936e46db2b8971e4fd69..f2708463430533dbdc610a241535d190426afa7d 100644
--- a/lib/Frontend/ASTMerge.cpp
+++ b/lib/Frontend/ASTMerge.cpp
@@ -40,7 +40,8 @@ void ASTMergeAction::ExecuteAction() {
                                        &CI.getASTContext());
   llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics());
   for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) {
-    ASTUnit *Unit = ASTUnit::LoadFromASTFile(ASTFiles[I], Diags, false);
+    ASTUnit *Unit = ASTUnit::LoadFromASTFile(ASTFiles[I], Diags,
+                                             CI.getFileSystemOpts(), false);
     if (!Unit)
       continue;
 
@@ -53,8 +54,10 @@ void ASTMergeAction::ExecuteAction() {
     ASTImporter Importer(CI.getDiagnostics(),
                          CI.getASTContext(), 
                          CI.getFileManager(),
+                         CI.getFileSystemOpts(),
                          Unit->getASTContext(), 
-                         Unit->getFileManager());
+                         Unit->getFileManager(),
+                         Unit->getFileSystemOpts());
 
     TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
     for (DeclContext::decl_iterator D = TU->decls_begin(), 
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index b07ed12f757db679842e46ab729bfc0aa7970e5b..bbee11ba7c98a3104c2a62bf4b49ded8fc201355 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -449,8 +449,17 @@ const std::string &ASTUnit::getASTFileName() {
   return static_cast<ASTReader *>(Ctx->getExternalSource())->getFileName();
 }
 
+llvm::MemoryBuffer *ASTUnit::getBufferForFile(llvm::StringRef Filename,
+                                              std::string *ErrorStr,
+                                              int64_t FileSize,
+                                              struct stat *FileInfo) {
+  return FileMgr->getBufferForFile(Filename, FileSystemOpts,
+                                   ErrorStr, FileSize, FileInfo);
+}
+
 ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
                                   llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
+                                  const FileSystemOptions &FileSystemOpts,
                                   bool OnlyLocalDecls,
                                   RemappedFile *RemappedFiles,
                                   unsigned NumRemappedFiles,
@@ -467,9 +476,13 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
   AST->CaptureDiagnostics = CaptureDiagnostics;
   AST->OnlyLocalDecls = OnlyLocalDecls;
   AST->Diagnostics = Diags;
+  AST->FileSystemOpts = FileSystemOpts;
   AST->FileMgr.reset(new FileManager);
-  AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics()));
-  AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
+  AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics(),
+                                         AST->getFileManager(),
+                                         AST->getFileSystemOpts()));
+  AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager(),
+                                         AST->getFileSystemOpts()));
   
   // If requested, capture diagnostics in the ASTUnit.
   CaptureDroppedDiagnostics Capture(CaptureDiagnostics, AST->getDiagnostics(),
@@ -480,7 +493,8 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
     const FileEntry *FromFile
       = AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
                                     RemappedFiles[I].second->getBufferSize(),
-                                             0);
+                                             0,
+                                             AST->getFileSystemOpts());
     if (!FromFile) {
       AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file)
         << RemappedFiles[I].first;
@@ -505,7 +519,7 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
   llvm::OwningPtr<ASTReader> Reader;
 
   Reader.reset(new ASTReader(AST->getSourceManager(), AST->getFileManager(),
-                             AST->getDiagnostics()));
+                             AST->getFileSystemOpts(), AST->getDiagnostics()));
   Reader->setListener(new ASTInfoCollector(LangInfo, HeaderInfo, TargetTriple,
                                            Predefines, Counter));
 
@@ -732,7 +746,8 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
   // Configure the various subsystems.
   // FIXME: Should we retain the previous file manager?
   FileMgr.reset(new FileManager);
-  SourceMgr.reset(new SourceManager(getDiagnostics()));
+  FileSystemOpts = Clang.getFileSystemOpts();
+  SourceMgr.reset(new SourceManager(getDiagnostics(), *FileMgr, FileSystemOpts));
   TheSema.reset();
   Ctx.reset();
   PP.reset();
@@ -908,7 +923,7 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
             CreatedBuffer = false;
           }
           
-          Buffer = llvm::MemoryBuffer::getFile(M->second);
+          Buffer = getBufferForFile(M->second);
           if (!Buffer)
             return std::make_pair((llvm::MemoryBuffer*)0, 
                                   std::make_pair(0, true));
@@ -941,7 +956,7 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation,
   
   // If the main source file was not remapped, load it now.
   if (!Buffer) {
-    Buffer = llvm::MemoryBuffer::getFile(FrontendOpts.Inputs[0].second);
+    Buffer = getBufferForFile(FrontendOpts.Inputs[0].second);
     if (!Buffer)
       return std::make_pair((llvm::MemoryBuffer*)0, std::make_pair(0, true));    
     
@@ -1240,7 +1255,9 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
   Clang.setFileManager(new FileManager);
   
   // Create the source manager.
-  Clang.setSourceManager(new SourceManager(getDiagnostics()));
+  Clang.setSourceManager(new SourceManager(getDiagnostics(),
+                                           Clang.getFileManager(),
+                                           Clang.getFileSystemOpts()));
   
   llvm::OwningPtr<PrecompilePreambleAction> Act;
   Act.reset(new PrecompilePreambleAction(*this));
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 95d417f63347dda8d0195cf0e3ba6842ae08afe4..c5e5d7f90a0131f8ecd78d3c230f8ebebfbec389 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -148,8 +148,9 @@ void CompilerInstance::createFileManager() {
 
 // Source Manager
 
-void CompilerInstance::createSourceManager() {
-  SourceMgr.reset(new SourceManager(getDiagnostics()));
+void CompilerInstance::createSourceManager(FileManager &FileMgr,
+                                           const FileSystemOptions &FSOpts) {
+  SourceMgr.reset(new SourceManager(getDiagnostics(), FileMgr, FSOpts));
 }
 
 // Preprocessor
@@ -158,8 +159,8 @@ void CompilerInstance::createPreprocessor() {
   PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(),
                               getPreprocessorOpts(), getHeaderSearchOpts(),
                               getDependencyOutputOpts(), getTarget(),
-                              getFrontendOpts(), getSourceManager(),
-                              getFileManager()));
+                              getFrontendOpts(), getFileSystemOpts(),
+                              getSourceManager(), getFileManager()));
 }
 
 Preprocessor *
@@ -170,15 +171,16 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
                                      const DependencyOutputOptions &DepOpts,
                                      const TargetInfo &Target,
                                      const FrontendOptions &FEOpts,
+                                     const FileSystemOptions &FSOpts,
                                      SourceManager &SourceMgr,
                                      FileManager &FileMgr) {
   // Create a PTH manager if we are using some form of a token cache.
   PTHManager *PTHMgr = 0;
   if (!PPOpts.TokenCache.empty())
-    PTHMgr = PTHManager::Create(PPOpts.TokenCache, Diags);
+    PTHMgr = PTHManager::Create(PPOpts.TokenCache, FileMgr, FSOpts, Diags);
 
   // Create the Preprocessor.
-  HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr);
+  HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr, FSOpts);
   Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target,
                                       SourceMgr, *HeaderInfo, PTHMgr,
                                       /*OwnsHeaderSearch=*/true);
@@ -194,7 +196,7 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
   if (PPOpts.DetailedRecord)
     PP->createPreprocessingRecord();
   
-  InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts);
+  InitializePreprocessor(*PP, FSOpts, PPOpts, HSOpts, FEOpts);
 
   // Handle generating dependencies, if requested.
   if (!DepOpts.OutputFile.empty())
@@ -271,7 +273,8 @@ static bool EnableCodeCompletion(Preprocessor &PP,
                                  unsigned Column) {
   // Tell the source manager to chop off the given file at a specific
   // line and column.
-  const FileEntry *Entry = PP.getFileManager().getFile(Filename);
+  const FileEntry *Entry = PP.getFileManager().getFile(Filename,
+                                                       PP.getFileSystemOpts());
   if (!Entry) {
     PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file)
       << Filename;
@@ -352,7 +355,11 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) {
         TempPath.eraseFromDisk();
       else {
         std::string Error;
-        if (TempPath.renamePathOnDisk(llvm::sys::Path(it->Filename), &Error)) {
+        llvm::sys::Path NewOutFile(it->Filename);
+        // If '-working-directory' was passed, the output filename should be
+        // relative to that.
+        FileManager::FixupRelativePath(NewOutFile, getFileSystemOpts());
+        if (TempPath.renamePathOnDisk(NewOutFile, &Error)) {
           getDiagnostics().Report(diag::err_fe_unable_to_rename_temp)
             << it->TempFilename << it->Filename << Error;
           TempPath.eraseFromDisk();
@@ -457,17 +464,19 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
 
 bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile) {
   return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(),
+                                 getFileSystemOpts(),
                                  getSourceManager(), getFrontendOpts());
 }
 
 bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile,
                                                Diagnostic &Diags,
                                                FileManager &FileMgr,
+                                               const FileSystemOptions &FSOpts,
                                                SourceManager &SourceMgr,
                                                const FrontendOptions &Opts) {
   // Figure out where to get and map in the main file.
   if (InputFile != "-") {
-    const FileEntry *File = FileMgr.getFile(InputFile);
+    const FileEntry *File = FileMgr.getFile(InputFile, FSOpts);
     if (!File) {
       Diags.Report(diag::err_fe_error_reading) << InputFile;
       return false;
@@ -480,7 +489,8 @@ bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile,
       return false;
     }
     const FileEntry *File = FileMgr.getVirtualFile(SB->getBufferIdentifier(),
-                                                   SB->getBufferSize(), 0);
+                                                   SB->getBufferSize(), 0,
+                                                   FSOpts);
     SourceMgr.createMainFileID(File);
     SourceMgr.overrideFileContents(File, SB);
   }
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 561555ad1f67d13194b24ee1631c40af14e965a1..b20520bbeead6cd2a240174f510d232b8dace962 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -10,6 +10,7 @@
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/Version.h"
+#include "clang/Basic/FileManager.h"
 #include "clang/Driver/Arg.h"
 #include "clang/Driver/ArgList.h"
 #include "clang/Driver/CC1Options.h"
@@ -351,6 +352,14 @@ static const char *getActionName(frontend::ActionKind Kind) {
   return 0;
 }
 
+static void FileSystemOptsToArgs(const FileSystemOptions &Opts,
+                                 std::vector<std::string> &Res) {
+  if (!Opts.WorkingDir.empty()) {
+    Res.push_back("-working-directory");
+    Res.push_back(Opts.WorkingDir);
+  }
+}
+
 static void FrontendOptsToArgs(const FrontendOptions &Opts,
                                std::vector<std::string> &Res) {
   if (Opts.DisableFree)
@@ -743,6 +752,7 @@ void CompilerInvocation::toArgs(std::vector<std::string> &Res) {
   CodeGenOptsToArgs(getCodeGenOpts(), Res);
   DependencyOutputOptsToArgs(getDependencyOutputOpts(), Res);
   DiagnosticOptsToArgs(getDiagnosticOpts(), Res);
+  FileSystemOptsToArgs(getFileSystemOpts(), Res);
   FrontendOptsToArgs(getFrontendOpts(), Res);
   HeaderSearchOptsToArgs(getHeaderSearchOpts(), Res);
   LangOptsToArgs(getLangOpts(), Res);
@@ -979,6 +989,10 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
   Opts.Warnings = Args.getAllArgValues(OPT_W);
 }
 
+static void ParseFileSystemArgs(FileSystemOptions &Opts, ArgList &Args) {
+  Opts.WorkingDir = Args.getLastArgValue(OPT_working_directory);
+}
+
 static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
                                    Diagnostic &Diags) {
   using namespace cc1options;
@@ -1402,6 +1416,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
 }
 
 static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
+                                  FileManager &FileMgr,
+                                  const FileSystemOptions &FSOpts,
                                   Diagnostic &Diags) {
   using namespace cc1options;
   Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch);
@@ -1456,7 +1472,8 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
     // PCH is handled specially, we need to extra the original include path.
     if (A->getOption().matches(OPT_include_pch)) {
       std::string OriginalFile =
-        ASTReader::getOriginalSourceFile(A->getValue(Args), Diags);
+        ASTReader::getOriginalSourceFile(A->getValue(Args), FileMgr, FSOpts,
+                                         Diags);
       if (OriginalFile.empty())
         continue;
 
@@ -1535,11 +1552,18 @@ void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
   ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, Diags);
   ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args);
   ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, Diags);
+  ParseFileSystemArgs(Res.getFileSystemOpts(), *Args);
   InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags);
   ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args);
   if (DashX != IK_AST && DashX != IK_LLVM_IR)
     ParseLangArgs(Res.getLangOpts(), *Args, DashX, Diags);
-  ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, Diags);
+  // FIXME: ParsePreprocessorArgs uses the FileManager to read the contents of
+  // PCH file and find the original header name. Remove the need to do that in
+  // ParsePreprocessorArgs and remove the FileManager & FileSystemOptions
+  // parameters from the function and the "FileManager.h" #include.
+  FileManager FileMgr;
+  ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args,
+                        FileMgr, Res.getFileSystemOpts(), Diags);
   ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args);
   ParseTargetArgs(Res.getTargetOpts(), *Args);
 }
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index 48f115fd3e3a214f6de62eb17b4726568752b05c..cfa0b6dbd3f232534029474b81c9b9618dbbd252 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -103,7 +103,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
 
     llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics());
     std::string Error;
-    ASTUnit *AST = ASTUnit::LoadFromASTFile(Filename, Diags);
+    ASTUnit *AST = ASTUnit::LoadFromASTFile(Filename, Diags,
+                                            CI.getFileSystemOpts());
     if (!AST)
       goto failure;
 
@@ -132,7 +133,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
   if (!CI.hasFileManager())
     CI.createFileManager();
   if (!CI.hasSourceManager())
-    CI.createSourceManager();
+    CI.createSourceManager(CI.getFileManager(), CI.getFileSystemOpts());
 
   // IR files bypass the rest of initialization.
   if (InputKind == IK_LLVM_IR) {
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 5bc6506e1fd9499e9e5f8219b365f40d586425a3..9ef1ca64d740c3e3ca966e563ecb9ea841cfe316 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -207,7 +207,10 @@ void PrintPreambleAction::ExecuteAction() {
     return;
   }
   
-  llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getFile(getCurrentFile());
+  CompilerInstance &CI = getCompilerInstance();
+  llvm::MemoryBuffer *Buffer
+      = CI.getFileManager().getBufferForFile(getCurrentFile(),
+                                             CI.getFileSystemOpts());
   if (Buffer) {
     unsigned Preamble = Lexer::ComputePreamble(Buffer).first;
     llvm::outs().write(Buffer->getBufferStart(), Preamble);
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 97157b3615d0bfc11a64360a5480264572e25e1a..e47381e39d3714b032cfa03b8b2029e66352d39e 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -99,6 +99,7 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path,
                                bool IgnoreSysRoot) {
   assert(!Path.isTriviallyEmpty() && "can't handle empty path here");
   FileManager &FM = Headers.getFileMgr();
+  const FileSystemOptions &FSOpts = Headers.getFileSystemOpts();
 
   // Compute the actual path, taking into consideration -isysroot.
   llvm::SmallString<256> MappedPathStr;
@@ -125,7 +126,7 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path,
 
 
   // If the directory exists, add it.
-  if (const DirectoryEntry *DE = FM.getDirectory(MappedPath.str())) {
+  if (const DirectoryEntry *DE = FM.getDirectory(MappedPath.str(), FSOpts)) {
     IncludeGroup[Group].push_back(DirectoryLookup(DE, Type, isUserSupplied,
                                                   isFramework));
     return;
@@ -134,7 +135,7 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path,
   // Check to see if this is an apple-style headermap (which are not allowed to
   // be frameworks).
   if (!isFramework) {
-    if (const FileEntry *FE = FM.getFile(MappedPath.str())) {
+    if (const FileEntry *FE = FM.getFile(MappedPath.str(), FSOpts)) {
       if (const HeaderMap *HM = Headers.CreateHeaderMap(FE)) {
         // It is a headermap, add it to the search path.
         IncludeGroup[Group].push_back(DirectoryLookup(HM, Type,isUserSupplied));
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 181f671025691b032aadb0c029c04510eda92160..7275733bbb06f015fe6d87e872e35d2c8395b935 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -478,6 +478,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
 static void InitializeFileRemapping(Diagnostic &Diags,
                                     SourceManager &SourceMgr,
                                     FileManager &FileMgr,
+                                    const FileSystemOptions &FSOpts,
                                     const PreprocessorOptions &InitOpts) {
   // Remap files in the source manager (with buffers).
   for (PreprocessorOptions::const_remapped_file_buffer_iterator
@@ -488,7 +489,7 @@ static void InitializeFileRemapping(Diagnostic &Diags,
     // Create the file entry for the file that we're mapping from.
     const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first,
                                                 Remap->second->getBufferSize(),
-                                                       0);
+                                                       0, FSOpts);
     if (!FromFile) {
       Diags.Report(diag::err_fe_remap_missing_from_file)
         << Remap->first;
@@ -510,7 +511,7 @@ static void InitializeFileRemapping(Diagnostic &Diags,
        Remap != RemapEnd;
        ++Remap) {
     // Find the file that we're mapping to.
-    const FileEntry *ToFile = FileMgr.getFile(Remap->second);
+    const FileEntry *ToFile = FileMgr.getFile(Remap->second, FSOpts);
     if (!ToFile) {
       Diags.Report(diag::err_fe_remap_missing_to_file)
       << Remap->first << Remap->second;
@@ -520,7 +521,7 @@ static void InitializeFileRemapping(Diagnostic &Diags,
     // Create the file entry for the file that we're mapping from.
     const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first,
                                                        ToFile->getSize(),
-                                                       0);
+                                                       0, FSOpts);
     if (!FromFile) {
       Diags.Report(diag::err_fe_remap_missing_from_file)
       << Remap->first;
@@ -530,7 +531,7 @@ static void InitializeFileRemapping(Diagnostic &Diags,
     // Load the contents of the file we're mapping to.
     std::string ErrorStr;
     const llvm::MemoryBuffer *Buffer
-    = llvm::MemoryBuffer::getFile(ToFile->getName(), &ErrorStr);
+    = FileMgr.getBufferForFile(ToFile->getName(), FSOpts, &ErrorStr);
     if (!Buffer) {
       Diags.Report(diag::err_fe_error_opening)
         << Remap->second << ErrorStr;
@@ -547,6 +548,7 @@ static void InitializeFileRemapping(Diagnostic &Diags,
 /// environment ready to process a single file. This returns true on error.
 ///
 void clang::InitializePreprocessor(Preprocessor &PP,
+                                   const FileSystemOptions &FSOpts,
                                    const PreprocessorOptions &InitOpts,
                                    const HeaderSearchOptions &HSOpts,
                                    const FrontendOptions &FEOpts) {
@@ -556,7 +558,7 @@ void clang::InitializePreprocessor(Preprocessor &PP,
   MacroBuilder Builder(Predefines);
 
   InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(),
-                          PP.getFileManager(), InitOpts);
+                          PP.getFileManager(), FSOpts, InitOpts);
 
   // Emit line markers for various builtin sections of the file.  We don't do
   // this in asm preprocessor mode, because "# 4" is not a line marker directive
diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp
index 4010d613ac24267051df1905b12aaee0667a940b..5d9b218a7d8abc18b54a69a67ffb0c2c7c596324 100644
--- a/lib/Lex/HeaderMap.cpp
+++ b/lib/Lex/HeaderMap.cpp
@@ -75,13 +75,14 @@ static inline unsigned HashHMapKey(llvm::StringRef Str) {
 /// map.  If it doesn't look like a HeaderMap, it gives up and returns null.
 /// If it looks like a HeaderMap but is obviously corrupted, it puts a reason
 /// into the string error argument and returns null.
-const HeaderMap *HeaderMap::Create(const FileEntry *FE) {
+const HeaderMap *HeaderMap::Create(const FileEntry *FE, FileManager &FM,
+                                   const FileSystemOptions &FSOpts) {
   // If the file is too small to be a header map, ignore it.
   unsigned FileSize = FE->getSize();
   if (FileSize <= sizeof(HMapHeader)) return 0;
 
   llvm::OwningPtr<const llvm::MemoryBuffer> FileBuffer(
-    llvm::MemoryBuffer::getFile(FE->getName(), 0, FE->getSize()));
+    FM.getBufferForFile(FE, FSOpts));
   if (FileBuffer == 0) return 0;  // Unreadable file?
   const char *FileStart = FileBuffer->getBufferStart();
 
@@ -200,7 +201,8 @@ void HeaderMap::dump() const {
 /// LookupFile - Check to see if the specified relative filename is located in
 /// this HeaderMap.  If so, open it and return its FileEntry.
 const FileEntry *HeaderMap::LookupFile(llvm::StringRef Filename,
-                                       FileManager &FM) const {
+                                       FileManager &FM,
+                                const FileSystemOptions &FileSystemOpts) const {
   const HMapHeader &Hdr = getHeader();
   unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets);
 
@@ -223,6 +225,6 @@ const FileEntry *HeaderMap::LookupFile(llvm::StringRef Filename,
     llvm::SmallString<1024> DestPath;
     DestPath += getString(B.Prefix);
     DestPath += getString(B.Suffix);
-    return FM.getFile(DestPath.begin(), DestPath.end());
+    return FM.getFile(DestPath.begin(), DestPath.end(), FileSystemOpts);
   }
 }
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index 4554ababf76d4aedd3d4af1bc43234e538abd29c..5a11652fc1d654e77d96fecc7d249e8bda041c97 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -32,7 +32,8 @@ HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) {
   return ControllingMacro;
 }
 
-HeaderSearch::HeaderSearch(FileManager &FM) : FileMgr(FM), FrameworkMap(64) {
+HeaderSearch::HeaderSearch(FileManager &FM, const FileSystemOptions &FSOpts)
+    : FileMgr(FM), FileSystemOpts(FSOpts), FrameworkMap(64) {
   SystemDirIdx = 0;
   NoCurDirSearch = false;
 
@@ -83,7 +84,7 @@ const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) {
         return HeaderMaps[i].second;
   }
 
-  if (const HeaderMap *HM = HeaderMap::Create(FE)) {
+  if (const HeaderMap *HM = HeaderMap::Create(FE, FileMgr, FileSystemOpts)) {
     HeaderMaps.push_back(std::make_pair(FE, HM));
     return HM;
   }
@@ -118,14 +119,16 @@ const FileEntry *DirectoryLookup::LookupFile(llvm::StringRef Filename,
     TmpDir += getDir()->getName();
     TmpDir.push_back('/');
     TmpDir.append(Filename.begin(), Filename.end());
-    return HS.getFileMgr().getFile(TmpDir.begin(), TmpDir.end());
+    return HS.getFileMgr().getFile(TmpDir.begin(), TmpDir.end(),
+                                   HS.getFileSystemOpts());
   }
 
   if (isFramework())
     return DoFrameworkLookup(Filename, HS);
 
   assert(isHeaderMap() && "Unknown directory lookup");
-  return getHeaderMap()->LookupFile(Filename, HS.getFileMgr());
+  return getHeaderMap()->LookupFile(Filename, HS.getFileMgr(),
+                                    HS.getFileSystemOpts());
 }
 
 
@@ -134,6 +137,7 @@ const FileEntry *DirectoryLookup::LookupFile(llvm::StringRef Filename,
 const FileEntry *DirectoryLookup::DoFrameworkLookup(llvm::StringRef Filename,
                                                     HeaderSearch &HS) const {
   FileManager &FileMgr = HS.getFileMgr();
+  const FileSystemOptions &FileSystemOpts = HS.getFileSystemOpts();
 
   // Framework names must have a '/' in the filename.
   size_t SlashPos = Filename.find('/');
@@ -184,7 +188,8 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(llvm::StringRef Filename,
   FrameworkName += "Headers/";
   FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end());
   if (const FileEntry *FE = FileMgr.getFile(FrameworkName.begin(),
-                                            FrameworkName.end())) {
+                                            FrameworkName.end(),
+                                            FileSystemOpts)) {
     return FE;
   }
 
@@ -192,7 +197,8 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(llvm::StringRef Filename,
   const char *Private = "Private";
   FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
                        Private+strlen(Private));
-  return FileMgr.getFile(FrameworkName.begin(), FrameworkName.end());
+  return FileMgr.getFile(FrameworkName.begin(), FrameworkName.end(),
+                         FileSystemOpts);
 }
 
 
@@ -219,7 +225,7 @@ const FileEntry *HeaderSearch::LookupFile(llvm::StringRef Filename,
     if (FromDir) return 0;
 
     // Otherwise, just return the file.
-    return FileMgr.getFile(Filename);
+    return FileMgr.getFile(Filename, FileSystemOpts);
   }
 
   // Step #0, unless disabled, check to see if the file is in the #includer's
@@ -234,7 +240,7 @@ const FileEntry *HeaderSearch::LookupFile(llvm::StringRef Filename,
     TmpDir += CurFileEnt->getDir()->getName();
     TmpDir.push_back('/');
     TmpDir.append(Filename.begin(), Filename.end());
-    if (const FileEntry *FE = FileMgr.getFile(TmpDir.str())) {
+    if (const FileEntry *FE = FileMgr.getFile(TmpDir.str(), FileSystemOpts)) {
       // Leave CurDir unset.
       // This file is a system header or C++ unfriendly if the old file is.
       //
@@ -344,7 +350,8 @@ LookupSubframeworkHeader(llvm::StringRef Filename,
 
     // If the framework dir doesn't exist, we fail.
     const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName.begin(),
-                                                     FrameworkName.end());
+                                                     FrameworkName.end(),
+                                                     FileSystemOpts);
     if (Dir == 0) return 0;
 
     // Otherwise, if it does, remember that this is the right direntry for this
@@ -359,13 +366,14 @@ LookupSubframeworkHeader(llvm::StringRef Filename,
   HeadersFilename += "Headers/";
   HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
   if (!(FE = FileMgr.getFile(HeadersFilename.begin(),
-                             HeadersFilename.end()))) {
+                             HeadersFilename.end(), FileSystemOpts))) {
 
     // Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
     HeadersFilename = FrameworkName;
     HeadersFilename += "PrivateHeaders/";
     HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
-    if (!(FE = FileMgr.getFile(HeadersFilename.begin(), HeadersFilename.end())))
+    if (!(FE = FileMgr.getFile(HeadersFilename.begin(), HeadersFilename.end(),
+                               FileSystemOpts)))
       return 0;
   }
 
diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp
index 63b4823cf19eac8c09fea2aa1e0c2055497248b0..3d52159fa3beb1e784d6d45bb95c75220fcdd2ff 100644
--- a/lib/Lex/PTHLexer.cpp
+++ b/lib/Lex/PTHLexer.cpp
@@ -434,10 +434,12 @@ static void InvalidPTH(Diagnostic &Diags, const char *Msg) {
   Diags.Report(Diags.getCustomDiagID(Diagnostic::Error, Msg));
 }
 
-PTHManager* PTHManager::Create(const std::string& file, Diagnostic &Diags) {
+PTHManager* PTHManager::Create(const std::string& file, FileManager &FileMgr,
+                               const FileSystemOptions &FSOpts,
+                               Diagnostic &Diags) {
   // Memory map the PTH file.
   llvm::OwningPtr<llvm::MemoryBuffer>
-  File(llvm::MemoryBuffer::getFile(file.c_str()));
+  File(FileMgr.getBufferForFile(file, FSOpts));
 
   if (!File) {
     Diags.Report(diag::err_invalid_pth_file) << file;
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 1be22df6b1cbc329f9657f0e736dc41a409f45de..ff18c3f32456f4195faec4d67cdfb1d7705d8c38 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -53,7 +53,8 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
                            IdentifierInfoLookup* IILookup,
                            bool OwnsHeaders)
   : Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()),
-    SourceMgr(SM), HeaderInfo(Headers), ExternalSource(0),
+    FileSystemOpts(Headers.getFileSystemOpts()), SourceMgr(SM),
+    HeaderInfo(Headers), ExternalSource(0),
     Identifiers(opts, IILookup), BuiltinInfo(Target), CodeComplete(0),
     CodeCompletionFile(0), SkipMainFilePreamble(0, true), CurPPLexer(0), 
     CurDirLookup(0), Callbacks(0), MacroArgCache(0), Record(0), MIChainHead(0),
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 5c947bc6395b5e4b31307f6604a4fdd4dc05f5f3..b90203b477b0dae2d12704fd6b03548a4cd0717c 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -1234,7 +1234,7 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(unsigned ID) {
   case SM_SLOC_FILE_ENTRY: {
     std::string Filename(BlobStart, BlobStart + BlobLen);
     MaybeAddSystemRootToFilename(Filename);
-    const FileEntry *File = FileMgr.getFile(Filename);
+    const FileEntry *File = FileMgr.getFile(Filename, FileSystemOpts);
     if (File == 0) {
       std::string ErrorStr = "could not find file '";
       ErrorStr += Filename;
@@ -1549,7 +1549,8 @@ void ASTReader::ReadMacroRecord(PerFileData &F, uint64_t Offset) {
       const char *FullFileNameStart = BlobStart + Record[3];
       const FileEntry *File
         = PP->getFileManager().getFile(FullFileNameStart,
-                                     FullFileNameStart + (BlobLen - Record[3]));
+                                     FullFileNameStart + (BlobLen - Record[3]),
+                                     FileSystemOpts);
 
       // FIXME: Stable encoding
       InclusionDirective::InclusionKind Kind
@@ -2257,7 +2258,10 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(llvm::StringRef FileName,
   //
   // FIXME: This shouldn't be here, we should just take a raw_ostream.
   std::string ErrStr;
-  F.Buffer.reset(llvm::MemoryBuffer::getFileOrSTDIN(FileName, &ErrStr));
+  if (FileName == "-")
+    F.Buffer.reset(llvm::MemoryBuffer::getSTDIN(&ErrStr));
+  else
+    F.Buffer.reset(FileMgr.getBufferForFile(FileName, FileSystemOpts, &ErrStr));
   if (!F.Buffer) {
     Error(ErrStr.c_str());
     return IgnorePCH;
@@ -2459,11 +2463,13 @@ void ASTReader::InitializeContext(ASTContext &Ctx) {
 /// directly from the AST file, without actually loading the AST
 /// file.
 std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
+                                             FileManager &FileMgr,
+                                             const FileSystemOptions &FSOpts,
                                              Diagnostic &Diags) {
   // Open the AST file.
   std::string ErrStr;
   llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
-  Buffer.reset(llvm::MemoryBuffer::getFile(ASTFileName.c_str(), &ErrStr));
+  Buffer.reset(FileMgr.getBufferForFile(ASTFileName, FSOpts, &ErrStr));
   if (!Buffer) {
     Diags.Report(diag::err_fe_unable_to_read_pch_file) << ErrStr;
     return std::string();
@@ -4477,6 +4483,7 @@ ASTReader::ASTReader(Preprocessor &PP, ASTContext *Context,
                      const char *isysroot, bool DisableValidation)
   : Listener(new PCHValidator(PP, *this)), DeserializationListener(0),
     SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()),
+    FileSystemOpts(PP.getFileSystemOpts()),
     Diags(PP.getDiagnostics()), SemaObj(0), PP(&PP), Context(Context),
     Consumer(0), isysroot(isysroot), DisableValidation(DisableValidation),
     NumStatHits(0), NumStatMisses(0), NumSLocEntriesRead(0),
@@ -4490,9 +4497,11 @@ ASTReader::ASTReader(Preprocessor &PP, ASTContext *Context,
 }
 
 ASTReader::ASTReader(SourceManager &SourceMgr, FileManager &FileMgr,
+                     const FileSystemOptions &FileSystemOpts,
                      Diagnostic &Diags, const char *isysroot,
                      bool DisableValidation)
   : DeserializationListener(0), SourceMgr(SourceMgr), FileMgr(FileMgr),
+    FileSystemOpts(FileSystemOpts),
     Diags(Diags), SemaObj(0), PP(0), Context(0), Consumer(0),
     isysroot(isysroot), DisableValidation(DisableValidation), NumStatHits(0),
     NumStatMisses(0), NumSLocEntriesRead(0), TotalNumSLocEntries(0),
diff --git a/test/Misc/Inputs/working-directory.h b/test/Misc/Inputs/working-directory.h
new file mode 100644
index 0000000000000000000000000000000000000000..061df629d6ade67b86ddf363be3b9421bb816fcf
--- /dev/null
+++ b/test/Misc/Inputs/working-directory.h
@@ -0,0 +1 @@
+typedef int Foo;
diff --git a/test/Misc/working-directory.c b/test/Misc/working-directory.c
new file mode 100644
index 0000000000000000000000000000000000000000..5c71d9f3f323bb6d86b929e0a5b391ac521a7ca4
--- /dev/null
+++ b/test/Misc/working-directory.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -working-directory %S working-directory.c -IInputs -fsyntax-only
+
+#include "working-directory.h"
+
+Foo bar;
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index ac57a6941c34a8534a9e6af432a294158d71b0b1..3afe3007ea0e31302e6357794977350065a4ea15 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -1977,9 +1977,11 @@ CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx,
     return 0;
 
   CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
+  FileSystemOptions FileSystemOpts;
+  FileSystemOpts.WorkingDir = CXXIdx->getWorkingDirectory();
 
   llvm::IntrusiveRefCntPtr<Diagnostic> Diags;
-  return ASTUnit::LoadFromASTFile(ast_filename, Diags,
+  return ASTUnit::LoadFromASTFile(ast_filename, Diags, FileSystemOpts,
                                   CXXIdx->getOnlyLocalDecls(),
                                   0, 0, true);
 }
@@ -2405,7 +2407,8 @@ CXFile clang_getFile(CXTranslationUnit tu, const char *file_name) {
   ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu);
 
   FileManager &FMgr = CXXUnit->getFileManager();
-  const FileEntry *File = FMgr.getFile(file_name, file_name+strlen(file_name));
+  const FileEntry *File = FMgr.getFile(file_name, file_name+strlen(file_name),
+                                       CXXUnit->getFileSystemOpts());
   return const_cast<FileEntry *>(File);
 }
 
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index d42e9eacd0ad12c1be0bc82bac10b11e9ee3247b..c92e2afaf3c219fc64619f60cb15fc38276a9988 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -232,12 +232,14 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
   
   /// \brief Language options used to adjust source locations.
   LangOptions LangOpts;
-
-  /// \brief Source manager, used for diagnostics.
-  SourceManager SourceMgr;
   
   /// \brief File manager, used for diagnostics.
   FileManager FileMgr;
+
+  FileSystemOptions FileSystemOpts;
+
+  /// \brief Source manager, used for diagnostics.
+  SourceManager SourceMgr;
   
   /// \brief Temporary files that should be removed once we have finished
   /// with the code-completion results.
@@ -248,7 +250,8 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
 };
 
 AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults() 
-  : CXCodeCompleteResults(), Diag(new Diagnostic), SourceMgr(*Diag) { }
+  : CXCodeCompleteResults(), Diag(new Diagnostic),
+    SourceMgr(*Diag, FileMgr, FileSystemOpts) { }
   
 AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
   for (unsigned I = 0, N = NumResults; I != N; ++I)
diff --git a/tools/libclang/CIndexer.h b/tools/libclang/CIndexer.h
index 89b098728dc0893ed798bf4736509b8a114e34a0..1fcb964c6efeb5ad80e2639d31b1e8ff69db98a4 100644
--- a/tools/libclang/CIndexer.h
+++ b/tools/libclang/CIndexer.h
@@ -32,7 +32,8 @@ class CIndexer {
   bool DisplayDiagnostics;
 
   llvm::sys::Path ResourcesPath;
-  
+  std::string WorkingDir;
+
 public:
  CIndexer() : OnlyLocalDecls(false), DisplayDiagnostics(false) { }
   
@@ -49,6 +50,9 @@ public:
 
   /// \brief Get the path of the clang resource files.
   std::string getClangResourcesPath();
+
+  const std::string &getWorkingDirectory() const { return WorkingDir; }
+  void setWorkingDirectory(const std::string &Dir) { WorkingDir = Dir; }
 };
 
 namespace clang {