| Index: chrome/browser/extensions/api/file_system/file_system_api.cc | 
| diff --git a/chrome/browser/extensions/api/file_system/file_system_api.cc b/chrome/browser/extensions/api/file_system/file_system_api.cc | 
| index 43c69a19a22a655502bb8bf03ab46282c2b4a3ef..4e3de965185b8f5a73a35631c784fb2e00f5f2ff 100644 | 
| --- a/chrome/browser/extensions/api/file_system/file_system_api.cc | 
| +++ b/chrome/browser/extensions/api/file_system/file_system_api.cc | 
| @@ -60,6 +60,8 @@ const char kUserCancelled[] = "User cancelled"; | 
| const char kWritableFileErrorFormat[] = "Error opening %s"; | 
| const char kRequiresFileSystemWriteError[] = | 
| "Operation requires fileSystem.write permission"; | 
| +const char kRequiresFileSystemDirectoryError[] = | 
| +    "Operation requires fileSystem.directory permission"; | 
| const char kMultipleUnsupportedError[] = | 
| "acceptsMultiple: true is not supported for 'saveFile'"; | 
| const char kUnknownIdError[] = "Unknown id"; | 
| @@ -304,6 +306,7 @@ bool FileSystemGetDisplayPathFunction::RunImpl() { | 
|  | 
| FileSystemEntryFunction::FileSystemEntryFunction() | 
| : multiple_(false), | 
| +      is_directory_(false), | 
| response_(NULL) {} | 
|  | 
| void FileSystemEntryFunction::CheckWritableFiles( | 
| @@ -312,6 +315,7 @@ void FileSystemEntryFunction::CheckWritableFiles( | 
| app_file_handler_util::CheckWritableFiles( | 
| paths, | 
| profile_, | 
| +      is_directory_, | 
| base::Bind(&FileSystemEntryFunction::RegisterFileSystemsAndSendResponse, | 
| this, | 
| paths), | 
| @@ -348,7 +352,8 @@ void FileSystemEntryFunction::AddEntryToResponse( | 
| profile(), | 
| GetExtension(), | 
| render_view_host_->GetProcess()->GetID(), | 
| -          path); | 
| +          path, | 
| +          is_directory_); | 
| base::ListValue* entries; | 
| bool success = response_->GetList("entries", &entries); | 
| DCHECK(success); | 
| @@ -360,6 +365,7 @@ void FileSystemEntryFunction::AddEntryToResponse( | 
| entry->SetString("id", file_entry.id); | 
| else | 
| entry->SetString("id", id_override); | 
| +  entry->SetBoolean("isDirectory", is_directory_); | 
| entries->Append(entry); | 
| } | 
|  | 
| @@ -382,15 +388,39 @@ bool FileSystemGetWritableEntryFunction::RunImpl() { | 
| return false; | 
| } | 
|  | 
| -  base::FilePath path; | 
| if (!ValidateFileEntryAndGetPath(filesystem_name, filesystem_path, | 
| -                                   render_view_host_, &path, &error_)) | 
| +                                   render_view_host_, &path_, &error_)) | 
| return false; | 
|  | 
| +  content::BrowserThread::PostTaskAndReply( | 
| +      content::BrowserThread::FILE, | 
| +      FROM_HERE, | 
| +      base::Bind( | 
| +          &FileSystemGetWritableEntryFunction::SetIsDirectoryOnFileThread, | 
| +          this), | 
| +      base::Bind( | 
| +          &FileSystemGetWritableEntryFunction::CheckPermissionAndSendResponse, | 
| +          this)); | 
| +  return true; | 
| +} | 
| + | 
| +void FileSystemGetWritableEntryFunction::CheckPermissionAndSendResponse() { | 
| +  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 
| +  if (is_directory_ && | 
| +      !extension_->HasAPIPermission(APIPermission::kFileSystemDirectory)) { | 
| +    error_ = kRequiresFileSystemDirectoryError; | 
| +    SendResponse(false); | 
| +  } | 
| std::vector<base::FilePath> paths; | 
| -  paths.push_back(path); | 
| +  paths.push_back(path_); | 
| CheckWritableFiles(paths); | 
| -  return true; | 
| +} | 
| + | 
| +void FileSystemGetWritableEntryFunction::SetIsDirectoryOnFileThread() { | 
| +  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | 
| +  if (base::DirectoryExists(path_)) { | 
| +    is_directory_ = true; | 
| +  } | 
| } | 
|  | 
| bool FileSystemIsWritableEntryFunction::RunImpl() { | 
| @@ -627,8 +657,15 @@ void FileSystemChooseEntryFunction::SetInitialPathOnFileThread( | 
| void FileSystemChooseEntryFunction::FilesSelected( | 
| const std::vector<base::FilePath>& paths) { | 
| DCHECK(!paths.empty()); | 
| -  file_system_api::SetLastChooseEntryDirectory( | 
| -      ExtensionPrefs::Get(profile()), GetExtension()->id(), paths[0].DirName()); | 
| +  base::FilePath last_choose_directory; | 
| +  if (is_directory_) { | 
| +    last_choose_directory = paths[0]; | 
| +  } else { | 
| +    last_choose_directory = paths[0].DirName(); | 
| +  } | 
| +  file_system_api::SetLastChooseEntryDirectory(ExtensionPrefs::Get(profile()), | 
| +                                               GetExtension()->id(), | 
| +                                               last_choose_directory); | 
| if (app_file_handler_util::HasFileSystemWritePermission(extension_)) { | 
| CheckWritableFiles(paths); | 
| return; | 
| @@ -732,6 +769,17 @@ bool FileSystemChooseEntryFunction::RunImpl() { | 
| return false; | 
| } | 
| picker_type = ui::SelectFileDialog::SELECT_SAVEAS_FILE; | 
| +    } else if (options->type == file_system::CHOOSE_ENTRY_TYPE_OPENDIRECTORY) { | 
| +      is_directory_ = true; | 
| +      if (!extension_->HasAPIPermission(APIPermission::kFileSystemDirectory)) { | 
| +        error_ = kRequiresFileSystemDirectoryError; | 
| +        return false; | 
| +      } | 
| +      if (multiple_) { | 
| +        error_ = kMultipleUnsupportedError; | 
| +        return false; | 
| +      } | 
| +      picker_type = ui::SelectFileDialog::SELECT_FOLDER; | 
| } | 
|  | 
| base::FilePath::StringType suggested_extension; | 
| @@ -767,32 +815,47 @@ bool FileSystemRetainEntryFunction::RunImpl() { | 
| EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &entry_id)); | 
| SavedFilesService* saved_files_service = SavedFilesService::Get(profile()); | 
| // Add the file to the retain list if it is not already on there. | 
| -  if (!saved_files_service->IsRegistered(extension_->id(), entry_id) && | 
| -      !RetainFileEntry(entry_id)) { | 
| -    return false; | 
| +  if (!saved_files_service->IsRegistered(extension_->id(), entry_id)) { | 
| +    std::string filesystem_name; | 
| +    std::string filesystem_path; | 
| +    EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_name)); | 
| +    EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &filesystem_path)); | 
| +    if (!ValidateFileEntryAndGetPath(filesystem_name, | 
| +                                     filesystem_path, | 
| +                                     render_view_host_, | 
| +                                     &path_, | 
| +                                     &error_)) { | 
| +      return false; | 
| +    } | 
| + | 
| +    content::BrowserThread::PostTaskAndReply( | 
| +        content::BrowserThread::FILE, | 
| +        FROM_HERE, | 
| +        base::Bind(&FileSystemRetainEntryFunction::SetIsDirectoryOnFileThread, | 
| +                   this), | 
| +        base::Bind( | 
| +            &FileSystemRetainEntryFunction::RetainFileEntry, this, entry_id)); | 
| +    return true; | 
| } | 
| + | 
| saved_files_service->EnqueueFileEntry(extension_->id(), entry_id); | 
| +  SendResponse(true); | 
| return true; | 
| } | 
|  | 
| -bool FileSystemRetainEntryFunction::RetainFileEntry( | 
| +void FileSystemRetainEntryFunction::RetainFileEntry( | 
| const std::string& entry_id) { | 
| -  std::string filesystem_name; | 
| -  std::string filesystem_path; | 
| -  EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &filesystem_name)); | 
| -  EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &filesystem_path)); | 
| -  base::FilePath path; | 
| -  if (!ValidateFileEntryAndGetPath(filesystem_name, | 
| -                                   filesystem_path, | 
| -                                   render_view_host_, | 
| -                                   &path, | 
| -                                   &error_)) { | 
| -    return false; | 
| -  } | 
| +  SavedFilesService* saved_files_service = SavedFilesService::Get(profile()); | 
| +  saved_files_service->RegisterFileEntry( | 
| +      extension_->id(), entry_id, path_, is_directory_); | 
| +  saved_files_service->EnqueueFileEntry(extension_->id(), entry_id); | 
| +  SendResponse(true); | 
| +} | 
|  | 
| -  SavedFilesService::Get(profile())->RegisterFileEntry( | 
| -      extension_->id(), entry_id, path); | 
| -  return true; | 
| +void FileSystemRetainEntryFunction::SetIsDirectoryOnFileThread() { | 
| +  if (base::DirectoryExists(path_)) { | 
| +    is_directory_ = true; | 
| +  } | 
| } | 
|  | 
| bool FileSystemIsRestorableFunction::RunImpl() { | 
| @@ -822,6 +885,7 @@ bool FileSystemRestoreEntryFunction::RunImpl() { | 
| // |needs_new_entry| will be false if the renderer already has an Entry for | 
| // |entry_id|. | 
| if (needs_new_entry) { | 
| +    is_directory_ = file_entry->is_directory; | 
| CreateResponse(); | 
| AddEntryToResponse(file_entry->path, file_entry->id); | 
| } | 
|  |