1 /*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2011-2017, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7 #include "FileManager.h"
8
9 #include <new>
10
11 #include <AutoDeleter.h>
12 #include <AutoLocker.h>
13
14 #include "LocatableDirectory.h"
15 #include "LocatableFile.h"
16 #include "SourceFile.h"
17 #include "TeamFileManagerSettings.h"
18
19
20 // #pragma mark - EntryPath
21
22
23 struct FileManager::EntryPath {
24 const char* directory;
25 const char* name;
26
EntryPathFileManager::EntryPath27 EntryPath(const char* directory, const char* name)
28 :
29 directory(directory),
30 name(name)
31 {
32 }
33
EntryPathFileManager::EntryPath34 EntryPath(const BString& directory, const BString& name)
35 :
36 directory(directory.Length() > 0 ? directory.String() : NULL),
37 name(name.String())
38 {
39 }
40
EntryPathFileManager::EntryPath41 EntryPath(const LocatableEntry* entry)
42 :
43 directory(NULL),
44 name(entry->Name())
45 {
46 LocatableDirectory* parent = entry->Parent();
47 if (parent != NULL && strlen(parent->Path()) > 0)
48 directory = parent->Path();
49 }
50
EntryPathFileManager::EntryPath51 EntryPath(const EntryPath& other)
52 :
53 directory(other.directory),
54 name(other.name)
55 {
56 }
57
HashValueFileManager::EntryPath58 size_t HashValue() const
59 {
60 return BString::HashValue(directory)
61 ^ BString::HashValue(name);
62 }
63
operator ==FileManager::EntryPath64 bool operator==(const EntryPath& other) const
65 {
66 if (directory != other.directory
67 && (directory == NULL || other.directory == NULL
68 || strcmp(directory, other.directory) != 0)) {
69 return false;
70 }
71
72 return strcmp(name, other.name) == 0;
73 }
74 };
75
76
77 // #pragma mark - EntryHashDefinition
78
79
80 struct FileManager::EntryHashDefinition {
81 typedef EntryPath KeyType;
82 typedef LocatableEntry ValueType;
83
HashKeyFileManager::EntryHashDefinition84 size_t HashKey(const EntryPath& key) const
85 {
86 return key.HashValue();
87 }
88
HashFileManager::EntryHashDefinition89 size_t Hash(const LocatableEntry* value) const
90 {
91 return HashKey(EntryPath(value));
92 }
93
CompareFileManager::EntryHashDefinition94 bool Compare(const EntryPath& key, const LocatableEntry* value) const
95 {
96 return EntryPath(value) == key;
97 }
98
GetLinkFileManager::EntryHashDefinition99 LocatableEntry*& GetLink(LocatableEntry* value) const
100 {
101 return value->fNext;
102 }
103 };
104
105
106 // #pragma mark - Domain
107
108
109 class FileManager::Domain : private LocatableEntryOwner {
110 public:
Domain(FileManager * manager,bool isLocal)111 Domain(FileManager* manager, bool isLocal)
112 :
113 fManager(manager),
114 fIsLocal(isLocal)
115 {
116 }
117
~Domain()118 ~Domain()
119 {
120 LocatableEntry* entry = fEntries.Clear(true);
121 while (entry != NULL) {
122 LocatableEntry* next = entry->fNext;
123 entry->ReleaseReference();
124 entry = next;
125 }
126 }
127
Init()128 status_t Init()
129 {
130 status_t error = fEntries.Init();
131 if (error != B_OK)
132 return error;
133
134 return B_OK;
135 }
136
GetFile(const BString & directoryPath,const BString & relativePath)137 LocatableFile* GetFile(const BString& directoryPath,
138 const BString& relativePath)
139 {
140 if (directoryPath.Length() == 0 || relativePath[0] == '/')
141 return GetFile(relativePath);
142 return GetFile(BString(directoryPath) << '/' << relativePath);
143 }
144
GetFile(const BString & path)145 LocatableFile* GetFile(const BString& path)
146 {
147 BString directoryPath;
148 BString name;
149 _SplitPath(path, directoryPath, name);
150 LocatableFile* file = _GetFile(directoryPath, name);
151 if (file == NULL)
152 return NULL;
153
154 // try to auto-locate the file
155 if (LocatableDirectory* directory = file->Parent()) {
156 if (directory->State() == LOCATABLE_ENTRY_UNLOCATED) {
157 // parent not yet located -- try locate with the entry's path
158 BString path;
159 file->GetPath(path);
160 _LocateEntry(file, path, true, true);
161 } else {
162 // parent already located -- locate the entry in the parent
163 BString locatedDirectoryPath;
164 if (directory->GetLocatedPath(locatedDirectoryPath))
165 _LocateEntryInParentDir(file, locatedDirectoryPath, true);
166 }
167 }
168
169 return file;
170 }
171
EntryLocated(const BString & path,const BString & locatedPath)172 void EntryLocated(const BString& path, const BString& locatedPath)
173 {
174 BString directory;
175 BString name;
176 _SplitPath(path, directory, name);
177
178 LocatableEntry* entry = _LookupEntry(EntryPath(directory, name));
179 if (entry == NULL)
180 return;
181
182 _LocateEntry(entry, locatedPath, false, true);
183 }
184
185 private:
Lock()186 virtual bool Lock()
187 {
188 return fManager->Lock();
189 }
190
Unlock()191 virtual void Unlock()
192 {
193 fManager->Unlock();
194 }
195
LocatableEntryUnused(LocatableEntry * entry)196 virtual void LocatableEntryUnused(LocatableEntry* entry)
197 {
198 AutoLocker<FileManager> lock(fManager);
199 if (fEntries.Lookup(EntryPath(entry)) == entry)
200 fEntries.Remove(entry);
201
202 LocatableDirectory* parent = entry->Parent();
203 if (parent != NULL)
204 parent->RemoveEntry(entry);
205 }
206
_LocateDirectory(LocatableDirectory * directory,const BString & locatedPath,bool implicit)207 bool _LocateDirectory(LocatableDirectory* directory,
208 const BString& locatedPath, bool implicit)
209 {
210 if (directory == NULL
211 || directory->State() != LOCATABLE_ENTRY_UNLOCATED) {
212 return false;
213 }
214
215 if (!_LocateEntry(directory, locatedPath, implicit, true))
216 return false;
217
218 _LocateEntries(directory, locatedPath, implicit);
219
220 return true;
221 }
222
_LocateEntry(LocatableEntry * entry,const BString & locatedPath,bool implicit,bool locateAncestors)223 bool _LocateEntry(LocatableEntry* entry, const BString& locatedPath,
224 bool implicit, bool locateAncestors)
225 {
226 if (implicit && entry->State() == LOCATABLE_ENTRY_LOCATED_EXPLICITLY)
227 return false;
228
229 struct stat st;
230 if (stat(locatedPath, &st) != 0)
231 return false;
232
233 if (S_ISDIR(st.st_mode)) {
234 LocatableDirectory* directory
235 = dynamic_cast<LocatableDirectory*>(entry);
236 if (directory == NULL)
237 return false;
238 entry->SetLocatedPath(locatedPath, implicit);
239 } else if (S_ISREG(st.st_mode)) {
240 LocatableFile* file = dynamic_cast<LocatableFile*>(entry);
241 if (file == NULL)
242 return false;
243 entry->SetLocatedPath(locatedPath, implicit);
244 }
245
246 // locate the ancestor directories, if requested
247 if (locateAncestors) {
248 BString locatedDirectory;
249 BString locatedName;
250 _SplitPath(locatedPath, locatedDirectory, locatedName);
251 if (locatedName == entry->Name())
252 _LocateDirectory(entry->Parent(), locatedDirectory, implicit);
253 }
254
255 return true;
256 }
257
_LocateEntryInParentDir(LocatableEntry * entry,const BString & locatedDirectoryPath,bool implicit)258 bool _LocateEntryInParentDir(LocatableEntry* entry,
259 const BString& locatedDirectoryPath, bool implicit)
260 {
261 // construct the located entry path
262 BString locatedEntryPath(locatedDirectoryPath);
263 int32 pathLength = locatedEntryPath.Length();
264 if (pathLength >= 1 && locatedEntryPath[pathLength - 1] != '/')
265 locatedEntryPath << '/';
266 locatedEntryPath << entry->Name();
267
268 return _LocateEntry(entry, locatedEntryPath, implicit, false);
269 }
270
_LocateEntries(LocatableDirectory * directory,const BString & locatedPath,bool implicit)271 void _LocateEntries(LocatableDirectory* directory,
272 const BString& locatedPath, bool implicit)
273 {
274 for (LocatableEntryList::ConstIterator it
275 = directory->Entries().GetIterator();
276 LocatableEntry* entry = it.Next();) {
277 if (entry->State() == LOCATABLE_ENTRY_LOCATED_EXPLICITLY)
278 continue;
279
280 if (_LocateEntryInParentDir(entry, locatedPath, implicit)) {
281 // recurse for directories
282 if (LocatableDirectory* subDir
283 = dynamic_cast<LocatableDirectory*>(entry)) {
284 BString locatedEntryPath;
285 if (subDir->GetLocatedPath(locatedEntryPath))
286 _LocateEntries(subDir, locatedEntryPath, implicit);
287 }
288 }
289 }
290 }
291
_GetFile(const BString & directoryPath,const BString & name)292 LocatableFile* _GetFile(const BString& directoryPath, const BString& name)
293 {
294 BString normalizedDirPath;
295 _NormalizePath(directoryPath, normalizedDirPath);
296
297 // if already known return the file
298 LocatableEntry* entry = _LookupEntry(EntryPath(normalizedDirPath, name));
299 if (entry != NULL) {
300 LocatableFile* file = dynamic_cast<LocatableFile*>(entry);
301 if (file == NULL)
302 return NULL;
303
304 if (file->AcquireReference() == 0)
305 fEntries.Remove(file);
306 else
307 return file;
308 }
309
310 // no such file yet -- create it
311 LocatableDirectory* directory = _GetDirectory(normalizedDirPath);
312 if (directory == NULL)
313 return NULL;
314
315 LocatableFile* file = new(std::nothrow) LocatableFile(this, directory,
316 name);
317 if (file == NULL) {
318 directory->ReleaseReference();
319 return NULL;
320 }
321
322 directory->AddEntry(file);
323
324 fEntries.Insert(file);
325
326 return file;
327 }
328
_GetDirectory(const BString & path)329 LocatableDirectory* _GetDirectory(const BString& path)
330 {
331 BString directoryPath;
332 BString fileName;
333 _SplitNormalizedPath(path, directoryPath, fileName);
334
335 // if already know return the directory
336 LocatableEntry* entry
337 = _LookupEntry(EntryPath(directoryPath, fileName));
338 if (entry != NULL) {
339 LocatableDirectory* directory
340 = dynamic_cast<LocatableDirectory*>(entry);
341 if (directory == NULL)
342 return NULL;
343 directory->AcquireReference();
344 return directory;
345 }
346
347 // get the parent directory
348 LocatableDirectory* parentDirectory = NULL;
349 if (directoryPath.Length() > 0) {
350 parentDirectory = _GetDirectory(directoryPath);
351 if (parentDirectory == NULL)
352 return NULL;
353 }
354
355 // create a new directory
356 LocatableDirectory* directory = new(std::nothrow) LocatableDirectory(
357 this, parentDirectory, path);
358 if (directory == NULL) {
359 parentDirectory->ReleaseReference();
360 return NULL;
361 }
362
363 // auto-locate, if possible
364 if (fIsLocal) {
365 BString dirPath;
366 directory->GetPath(dirPath);
367 directory->SetLocatedPath(dirPath, false);
368 } else if (parentDirectory != NULL
369 && parentDirectory->State() != LOCATABLE_ENTRY_UNLOCATED) {
370 BString locatedDirectoryPath;
371 if (parentDirectory->GetLocatedPath(locatedDirectoryPath))
372 _LocateEntryInParentDir(directory, locatedDirectoryPath, true);
373 }
374
375 if (parentDirectory != NULL)
376 parentDirectory->AddEntry(directory);
377
378 fEntries.Insert(directory);
379 return directory;
380 }
381
_LookupEntry(const EntryPath & entryPath)382 LocatableEntry* _LookupEntry(const EntryPath& entryPath)
383 {
384 LocatableEntry* entry = fEntries.Lookup(entryPath);
385 if (entry == NULL)
386 return NULL;
387
388 // if already unreferenced, remove it
389 if (entry->CountReferences() == 0) {
390 fEntries.Remove(entry);
391 return NULL;
392 }
393
394 return entry;
395 }
396
_NormalizePath(const BString & path,BString & _normalizedPath)397 void _NormalizePath(const BString& path, BString& _normalizedPath)
398 {
399 BString normalizedPath;
400 char* buffer = normalizedPath.LockBuffer(path.Length());
401 int32 outIndex = 0;
402 const char* remaining = path.String();
403
404 while (*remaining != '\0') {
405 // collapse repeated slashes
406 if (*remaining == '/') {
407 buffer[outIndex++] = '/';
408 remaining++;
409 while (*remaining == '/')
410 remaining++;
411 }
412
413 if (*remaining == '\0') {
414 // remove trailing slash (unless it's "/" only)
415 if (outIndex > 1)
416 outIndex--;
417 break;
418 }
419
420 // skip "." components
421 if (*remaining == '.') {
422 if (remaining[1] == '\0')
423 break;
424
425 if (remaining[1] == '/') {
426 remaining += 2;
427 while (*remaining == '/')
428 remaining++;
429 continue;
430 }
431 }
432
433 // copy path component
434 while (*remaining != '\0' && *remaining != '/')
435 buffer[outIndex++] = *(remaining++);
436 }
437
438 // If the path didn't change, use the original path (BString's copy on
439 // write mechanism) rather than the new string.
440 if (outIndex == path.Length()) {
441 _normalizedPath = path;
442 } else {
443 normalizedPath.UnlockBuffer(outIndex);
444 _normalizedPath = normalizedPath;
445 }
446 }
447
_SplitPath(const BString & path,BString & _directory,BString & _name)448 void _SplitPath(const BString& path, BString& _directory, BString& _name)
449 {
450 BString normalized;
451 _NormalizePath(path, normalized);
452 _SplitNormalizedPath(normalized, _directory, _name);
453 }
454
_SplitNormalizedPath(const BString & path,BString & _directory,BString & _name)455 void _SplitNormalizedPath(const BString& path, BString& _directory,
456 BString& _name)
457 {
458 // handle single component (including root dir) cases
459 int32 lastSlash = path.FindLast('/');
460 if (lastSlash < 0 || path.Length() == 1) {
461 _directory = (const char*)NULL;
462 _name = path;
463 return;
464 }
465
466 // handle root dir + one component and multi component cases
467 if (lastSlash == 0)
468 _directory = "/";
469 else
470 _directory.SetTo(path, lastSlash);
471 _name = path.String() + (lastSlash + 1);
472 }
473
474 private:
475 FileManager* fManager;
476 LocatableEntryTable fEntries;
477 bool fIsLocal;
478 };
479
480
481 // #pragma mark - SourceFileEntry
482
483
484 struct FileManager::SourceFileEntry : public SourceFileOwner {
485
486 FileManager* manager;
487 BString path;
488 SourceFile* file;
489 SourceFileEntry* next;
490
SourceFileEntryFileManager::SourceFileEntry491 SourceFileEntry(FileManager* manager, const BString& path)
492 :
493 manager(manager),
494 path(path),
495 file(NULL)
496 {
497 }
498
SourceFileUnusedFileManager::SourceFileEntry499 virtual void SourceFileUnused(SourceFile* sourceFile)
500 {
501 manager->_SourceFileUnused(this);
502 }
503
SourceFileDeletedFileManager::SourceFileEntry504 virtual void SourceFileDeleted(SourceFile* sourceFile)
505 {
506 // We have already been removed from the table, so commit suicide.
507 delete this;
508 }
509 };
510
511
512 // #pragma mark - SourceFileHashDefinition
513
514
515 struct FileManager::SourceFileHashDefinition {
516 typedef BString KeyType;
517 typedef SourceFileEntry ValueType;
518
HashKeyFileManager::SourceFileHashDefinition519 size_t HashKey(const BString& key) const
520 {
521 return key.HashValue();
522 }
523
HashFileManager::SourceFileHashDefinition524 size_t Hash(const SourceFileEntry* value) const
525 {
526 return HashKey(value->path);
527 }
528
CompareFileManager::SourceFileHashDefinition529 bool Compare(const BString& key, const SourceFileEntry* value) const
530 {
531 return value->path == key;
532 }
533
GetLinkFileManager::SourceFileHashDefinition534 SourceFileEntry*& GetLink(SourceFileEntry* value) const
535 {
536 return value->next;
537 }
538 };
539
540
541 // #pragma mark - FileManager
542
543
FileManager()544 FileManager::FileManager()
545 :
546 fLock("file manager"),
547 fTargetDomain(NULL),
548 fSourceDomain(NULL),
549 fSourceFiles(NULL)
550 {
551 }
552
553
~FileManager()554 FileManager::~FileManager()
555 {
556 delete fTargetDomain;
557 delete fSourceDomain;
558
559 SourceFileEntry* entry = fSourceFiles->Clear();
560 while (entry != NULL) {
561 SourceFileEntry* next = entry->next;
562 delete entry;
563 entry = next;
564 }
565 delete fSourceFiles;
566 }
567
568
569 status_t
Init(bool targetIsLocal)570 FileManager::Init(bool targetIsLocal)
571 {
572 status_t error = fLock.InitCheck();
573 if (error != B_OK)
574 return error;
575
576 // create target domain
577 fTargetDomain = new(std::nothrow) Domain(this, targetIsLocal);
578 if (fTargetDomain == NULL)
579 return B_NO_MEMORY;
580
581 error = fTargetDomain->Init();
582 if (error != B_OK)
583 return error;
584
585 // create source domain
586 fSourceDomain = new(std::nothrow) Domain(this, false);
587 if (fSourceDomain == NULL)
588 return B_NO_MEMORY;
589
590 error = fSourceDomain->Init();
591 if (error != B_OK)
592 return error;
593
594 // create source file table
595 fSourceFiles = new(std::nothrow) SourceFileTable;
596 if (fSourceFiles == NULL)
597 return B_NO_MEMORY;
598
599 error = fSourceFiles->Init();
600 if (error != B_OK)
601 return error;
602
603 return B_OK;
604 }
605
606
607 LocatableFile*
GetTargetFile(const BString & directory,const BString & relativePath)608 FileManager::GetTargetFile(const BString& directory,
609 const BString& relativePath)
610 {
611 AutoLocker<FileManager> locker(this);
612 return fTargetDomain->GetFile(directory, relativePath);
613 }
614
615
616 LocatableFile*
GetTargetFile(const BString & path)617 FileManager::GetTargetFile(const BString& path)
618 {
619 AutoLocker<FileManager> locker(this);
620 return fTargetDomain->GetFile(path);
621 }
622
623
624 void
TargetEntryLocated(const BString & path,const BString & locatedPath)625 FileManager::TargetEntryLocated(const BString& path,
626 const BString& locatedPath)
627 {
628 AutoLocker<FileManager> locker(this);
629 fTargetDomain->EntryLocated(path, locatedPath);
630 }
631
632
633 LocatableFile*
GetSourceFile(const BString & directory,const BString & relativePath)634 FileManager::GetSourceFile(const BString& directory,
635 const BString& relativePath)
636 {
637 AutoLocker<FileManager> locker(this);
638 LocatableFile* file = fSourceDomain->GetFile(directory, relativePath);
639
640 return file;
641 }
642
643
644 LocatableFile*
GetSourceFile(const BString & path)645 FileManager::GetSourceFile(const BString& path)
646 {
647 AutoLocker<FileManager> locker(this);
648 LocatableFile* file = fSourceDomain->GetFile(path);
649
650 return file;
651 }
652
653
654 status_t
SourceEntryLocated(const BString & path,const BString & locatedPath)655 FileManager::SourceEntryLocated(const BString& path,
656 const BString& locatedPath)
657 {
658 AutoLocker<FileManager> locker(this);
659
660 // check if we already have this path mapped. If so,
661 // first clear the mapping, as the user may be attempting
662 // to correct an existing entry.
663 SourceFileEntry* entry = _LookupSourceFile(path);
664 if (entry != NULL)
665 _SourceFileUnused(entry);
666
667 fSourceDomain->EntryLocated(path, locatedPath);
668
669 try {
670 fSourceLocationMappings[path] = locatedPath;
671 } catch (...) {
672 return B_NO_MEMORY;
673 }
674
675 return B_OK;
676 }
677
678
679 status_t
LoadSourceFile(LocatableFile * file,SourceFile * & _sourceFile)680 FileManager::LoadSourceFile(LocatableFile* file, SourceFile*& _sourceFile)
681 {
682 AutoLocker<FileManager> locker(this);
683
684 // get the path
685 BString path;
686 BString originalPath;
687 file->GetPath(originalPath);
688 if (!file->GetLocatedPath(path)) {
689 // see if this is a file we have a lazy mapping for.
690 if (!_LocateFileIfMapped(originalPath, file)
691 || !file->GetLocatedPath(path)) {
692 return B_ENTRY_NOT_FOUND;
693 }
694 }
695
696 // we might already know the source file
697 SourceFileEntry* entry = _LookupSourceFile(originalPath);
698 if (entry != NULL) {
699 entry->file->AcquireReference();
700 _sourceFile = entry->file;
701 return B_OK;
702 }
703
704 // create the hash table entry
705 entry = new(std::nothrow) SourceFileEntry(this, originalPath);
706 if (entry == NULL)
707 return B_NO_MEMORY;
708
709 // load the file
710 SourceFile* sourceFile = new(std::nothrow) SourceFile(entry);
711 if (sourceFile == NULL) {
712 delete entry;
713 return B_NO_MEMORY;
714 }
715 ObjectDeleter<SourceFile> sourceFileDeleter(sourceFile);
716
717 entry->file = sourceFile;
718
719 status_t error = sourceFile->Init(path);
720 if (error != B_OK)
721 return error;
722
723 fSourceFiles->Insert(entry);
724
725 _sourceFile = sourceFileDeleter.Detach();
726 return B_OK;
727 }
728
729
730 status_t
LoadLocationMappings(TeamFileManagerSettings * settings)731 FileManager::LoadLocationMappings(TeamFileManagerSettings* settings)
732 {
733 AutoLocker<FileManager> locker(this);
734 for (int32 i = 0; i < settings->CountSourceMappings(); i++) {
735 BString sourcePath;
736 BString locatedPath;
737
738 if (settings->GetSourceMappingAt(i, sourcePath, locatedPath) != B_OK)
739 return B_NO_MEMORY;
740
741 try {
742 fSourceLocationMappings[sourcePath] = locatedPath;
743 } catch (...) {
744 return B_NO_MEMORY;
745 }
746 }
747
748 return B_OK;
749 }
750
751
752 status_t
SaveLocationMappings(TeamFileManagerSettings * settings)753 FileManager::SaveLocationMappings(TeamFileManagerSettings* settings)
754 {
755 AutoLocker<FileManager> locker(this);
756
757 for (LocatedFileMap::const_iterator it = fSourceLocationMappings.begin();
758 it != fSourceLocationMappings.end(); ++it) {
759 status_t error = settings->AddSourceMapping(it->first, it->second);
760 if (error != B_OK)
761 return error;
762 }
763
764 return B_OK;
765 }
766
767
768 FileManager::SourceFileEntry*
_LookupSourceFile(const BString & path)769 FileManager::_LookupSourceFile(const BString& path)
770 {
771 SourceFileEntry* entry = fSourceFiles->Lookup(path);
772 if (entry == NULL)
773 return NULL;
774
775 // the entry might be unused already -- in that case remove it
776 if (entry->file->CountReferences() == 0) {
777 fSourceFiles->Remove(entry);
778 return NULL;
779 }
780
781 return entry;
782 }
783
784
785 void
_SourceFileUnused(SourceFileEntry * entry)786 FileManager::_SourceFileUnused(SourceFileEntry* entry)
787 {
788 AutoLocker<FileManager> locker(this);
789
790 SourceFileEntry* otherEntry = fSourceFiles->Lookup(entry->path);
791 if (otherEntry == entry)
792 fSourceFiles->Remove(entry);
793 }
794
795
796 bool
_LocateFileIfMapped(const BString & sourcePath,LocatableFile * file)797 FileManager::_LocateFileIfMapped(const BString& sourcePath,
798 LocatableFile* file)
799 {
800 // called with lock held
801
802 LocatedFileMap::const_iterator it = fSourceLocationMappings.find(
803 sourcePath);
804 if (it != fSourceLocationMappings.end()
805 && file->State() != LOCATABLE_ENTRY_LOCATED_EXPLICITLY
806 && file->State() != LOCATABLE_ENTRY_LOCATED_IMPLICITLY) {
807 fSourceDomain->EntryLocated(it->first, it->second);
808 return true;
809 }
810
811 return false;
812 }
813