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