qBittorrent
Utils::Fs Namespace Reference

Functions

QString toNativePath (const QString &path)
 
QString toUniformPath (const QString &path)
 
QString resolvePath (const QString &relativePath, const QString &basePath)
 
QString fileExtension (const QString &filename)
 
QString fileName (const QString &filePath)
 
QString folderName (const QString &filePath)
 
qint64 computePathSize (const QString &path)
 
bool sameFiles (const QString &path1, const QString &path2)
 
QString toValidFileSystemName (const QString &name, bool allowSeparators=false, const QString &pad=QLatin1String(" "))
 
bool isValidFileSystemName (const QString &name, bool allowSeparators=false)
 
qint64 freeDiskSpaceOnPath (const QString &path)
 
QString branchPath (const QString &filePath, QString *removed=nullptr)
 
bool sameFileNames (const QString &first, const QString &second)
 
QString expandPath (const QString &path)
 
QString expandPathAbs (const QString &path)
 
bool isRegularFile (const QString &path)
 
bool smartRemoveEmptyFolderTree (const QString &path)
 
bool forceRemove (const QString &filePath)
 
void removeDirRecursive (const QString &path)
 
QString tempPath ()
 
QString findRootFolder (const QStringList &filePaths)
 
void stripRootFolder (QStringList &filePaths)
 
void addRootFolder (QStringList &filePaths, const QString &name)
 
bool isNetworkFileSystem (const QString &path)
 

Detailed Description

Utility functions related to file system.

Function Documentation

◆ addRootFolder()

void Utils::Fs::addRootFolder ( QStringList &  filePaths,
const QString &  name 
)

Definition at line 432 of file fs.cpp.

433 {
434  Q_ASSERT(!rootFolder.isEmpty());
435 
436  for (QString &filePath : filePaths)
437  filePath = rootFolder + QLatin1Char('/') + filePath;
438 }

Referenced by BitTorrent::applyContentLayout().

Here is the caller graph for this function:

◆ branchPath()

QString Utils::Fs::branchPath ( const QString &  filePath,
QString *  removed = nullptr 
)

Definition at line 276 of file fs.cpp.

277 {
278  QString ret = toUniformPath(filePath);
279  if (ret.endsWith('/'))
280  ret.chop(1);
281  const int slashIndex = ret.lastIndexOf('/');
282  if (slashIndex >= 0)
283  {
284  if (removed)
285  *removed = ret.mid(slashIndex + 1);
286  ret = ret.left(slashIndex);
287  }
288  return ret;
289 }
QString toUniformPath(const QString &path)
Definition: fs.cpp:69

References toUniformPath().

Referenced by FileLogger::deleteOld(), TorrentCreatorDialog::handleCreationSuccess(), TorrentCreatorDialog::onCreateButtonClicked(), BitTorrent::TorrentCreatorThread::run(), and BitTorrent::TorrentImpl::TorrentImpl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ computePathSize()

qint64 Utils::Fs::computePathSize ( const QString &  path)

Returns the size of a file. If the file is a folder, it will compute its size based on its content.

Returns -1 in case of error.

Definition at line 199 of file fs.cpp.

200 {
201  // Check if it is a file
202  const QFileInfo fi(path);
203  if (!fi.exists()) return -1;
204  if (fi.isFile()) return fi.size();
205 
206  // Compute folder size based on its content
207  qint64 size = 0;
208  QDirIterator iter(path, QDir::Files | QDir::Hidden | QDir::NoSymLinks, QDirIterator::Subdirectories);
209  while (iter.hasNext())
210  {
211  iter.next();
212  size += iter.fileInfo().size();
213  }
214  return size;
215 }

◆ expandPath()

QString Utils::Fs::expandPath ( const QString &  path)

Definition at line 300 of file fs.cpp.

301 {
302  const QString ret = path.trimmed();
303  if (ret.isEmpty())
304  return ret;
305 
306  return QDir::cleanPath(ret);
307 }

Referenced by expandPathAbs(), and PropertiesWidget::getFullPath().

Here is the caller graph for this function:

◆ expandPathAbs()

◆ fileExtension()

QString Utils::Fs::fileExtension ( const QString &  filename)

Returns the file extension part of a file name.

Definition at line 82 of file fs.cpp.

83 {
84  return QMimeDatabase().suffixForFileName(filename);
85 }

Referenced by AutoExpandableDialog::getText(), Utils::Misc::isPreviewable(), and anonymous_namespace{torrentcontentlayout.cpp}::removeExtension().

Here is the caller graph for this function:

◆ fileName()

◆ findRootFolder()

QString Utils::Fs::findRootFolder ( const QStringList &  filePaths)

Definition at line 403 of file fs.cpp.

404 {
405  QString rootFolder;
406  for (const QString &filePath : filePaths)
407  {
408  const auto filePathElements = QStringView(filePath).split(u'/');
409  // if at least one file has no root folder, no common root folder exists
410  if (filePathElements.count() <= 1)
411  return {};
412 
413  if (rootFolder.isEmpty())
414  rootFolder = filePathElements.at(0).toString();
415  else if (rootFolder != filePathElements.at(0))
416  return {};
417  }
418 
419  return rootFolder;
420 }

Referenced by BitTorrent::Session::addTorrent_impl(), BitTorrent::applyContentLayout(), AddNewTorrentDialog::contentLayoutChanged(), BitTorrent::detectContentLayout(), BitTorrent::TorrentInfo::rootFolder(), AddNewTorrentDialog::setupTreeview(), and stripRootFolder().

Here is the caller graph for this function:

◆ folderName()

QString Utils::Fs::folderName ( const QString &  filePath)

Definition at line 96 of file fs.cpp.

97 {
98  const QString path = toUniformPath(filePath);
99  const int slashIndex = path.lastIndexOf('/');
100  if (slashIndex == -1)
101  return {};
102  return path.left(slashIndex);
103 }

References toUniformPath().

Referenced by OptionsDialog::on_addWatchedFolderButton_clicked().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ forceRemove()

bool Utils::Fs::forceRemove ( const QString &  filePath)

Removes the file with the given filePath.

This function will try to fix the file permissions before removing it.

Definition at line 173 of file fs.cpp.

174 {
175  QFile f(filePath);
176  if (!f.exists())
177  return true;
178  // Make sure we have read/write permissions
179  f.setPermissions(f.permissions() | QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser | QFile::WriteUser);
180  // Remove the file
181  return f.remove();
182 }
void f()
Definition: test2.c:1

References f().

Referenced by RSS::Feed::cleanup(), anonymous_namespace{searchpluginmanager.cpp}::clearPythonCache(), FileLogger::deleteOld(), TrackerFiltersList::handleFavicoDownloadFinished(), PluginSelectDialog::iconDownloadFinished(), SearchPluginManager::installPlugin_impl(), SearchPluginManager::pluginDownloadFinished(), TorrentFilesWatcher::Worker::processFailedTorrents(), TorrentFilesWatcher::Worker::processFolder(), anonymous_namespace{settingsstorage.cpp}::TransactionalSettings::read(), BitTorrent::BencodeResumeDataStorage::Worker::remove(), smartRemoveEmptyFolderTree(), BitTorrent::Session::startUpTorrents(), SearchPluginManager::uninstallPlugin(), SearchPluginManager::updateNova(), anonymous_namespace{settingsstorage.cpp}::TransactionalSettings::write(), FileGuard::~FileGuard(), and TrackerFiltersList::~TrackerFiltersList().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ freeDiskSpaceOnPath()

qint64 Utils::Fs::freeDiskSpaceOnPath ( const QString &  path)

Definition at line 271 of file fs.cpp.

272 {
273  return QStorageInfo(path).bytesAvailable();
274 }

Referenced by FreeDiskSpaceChecker::check(), and AddNewTorrentDialog::updateDiskSpaceLabel().

Here is the caller graph for this function:

◆ isNetworkFileSystem()

bool Utils::Fs::isNetworkFileSystem ( const QString &  path)

Definition at line 337 of file fs.cpp.

338 {
339 #if defined(Q_OS_WIN)
340  const std::wstring pathW {path.toStdWString()};
341  auto volumePath = std::make_unique<wchar_t[]>(path.length() + 1);
342  if (!::GetVolumePathNameW(pathW.c_str(), volumePath.get(), (path.length() + 1)))
343  return false;
344  return (::GetDriveTypeW(volumePath.get()) == DRIVE_REMOTE);
345 #else
346  QString file = path;
347  if (!file.endsWith('/'))
348  file += '/';
349  file += '.';
350 
351  struct statfs buf {};
352  if (statfs(file.toLocal8Bit().constData(), &buf) != 0)
353  return false;
354 
355 #if defined(Q_OS_OPENBSD)
356  return ((strncmp(buf.f_fstypename, "cifs", sizeof(buf.f_fstypename)) == 0)
357  || (strncmp(buf.f_fstypename, "nfs", sizeof(buf.f_fstypename)) == 0)
358  || (strncmp(buf.f_fstypename, "smbfs", sizeof(buf.f_fstypename)) == 0));
359 #else
360  // Magic number reference:
361  // https://github.com/coreutils/coreutils/blob/master/src/stat.c
362  switch (static_cast<quint32>(buf.f_type))
363  {
364  case 0x0000517B: // SMB
365  case 0x0000564C: // NCP
366  case 0x00006969: // NFS
367  case 0x00C36400: // CEPH
368  case 0x01161970: // GFS
369  case 0x013111A8: // IBRIX
370  case 0x0BD00BD0: // LUSTRE
371  case 0x19830326: // FHGFS
372  case 0x47504653: // GPFS
373  case 0x50495045: // PIPEFS
374  case 0x5346414F: // AFS
375  case 0x61636673: // ACFS
376  case 0x61756673: // AUFS
377  case 0x65735543: // FUSECTL
378  case 0x65735546: // FUSEBLK
379  case 0x6B414653: // KAFS
380  case 0x6E667364: // NFSD
381  case 0x73757245: // CODA
382  case 0x7461636F: // OCFS2
383  case 0x786F4256: // VBOXSF
384  case 0x794C7630: // OVERLAYFS
385  case 0x7C7C6673: // PRL_FS
386  case 0xA501FCF5: // VXFS
387  case 0xAAD7AAEA: // OVERLAYFS
388  case 0xBACBACBC: // VMHGFS
389  case 0xBEEFDEAD: // SNFS
390  case 0xFE534D42: // SMB2
391  case 0xFF534D42: // CIFS
392  return true;
393  default:
394  break;
395  }
396 
397  return false;
398 #endif
399 #endif
400 }
file(GLOB QBT_TS_FILES "${qBittorrent_SOURCE_DIR}/src/lang/*.ts") set_source_files_properties($
Definition: CMakeLists.txt:5

References file().

Referenced by TorrentFilesWatcher::Worker::addWatchedFolder(), and TorrentFilesWatcher::Worker::updateWatchedFolder().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ isRegularFile()

bool Utils::Fs::isRegularFile ( const QString &  path)

Definition at line 321 of file fs.cpp.

322 {
323  struct ::stat st;
324  if (::stat(path.toUtf8().constData(), &st) != 0)
325  {
326  // analyse erno and log the error
327  const auto err = errno;
328  qDebug("Could not get file stats for path '%s'. Error: %s"
329  , qUtf8Printable(path), qUtf8Printable(strerror(err)));
330  return false;
331  }
332 
333  return (st.st_mode & S_IFMT) == S_IFREG;
334 }

Referenced by WebApplication::sendWebUIFile().

Here is the caller graph for this function:

◆ isValidFileSystemName()

bool Utils::Fs::isValidFileSystemName ( const QString &  name,
bool  allowSeparators = false 
)

Definition at line 248 of file fs.cpp.

249 {
250  if (name.isEmpty()) return false;
251 
252 #if defined(Q_OS_WIN)
253  const QRegularExpression regex
254  {allowSeparators
255  ? QLatin1String("[:?\"*<>|]")
256  : QLatin1String("[\\\\/:?\"*<>|]")};
257 #elif defined(Q_OS_MACOS)
258  const QRegularExpression regex
259  {allowSeparators
260  ? QLatin1String("[\\0:]")
261  : QLatin1String("[\\0/:]")};
262 #else
263  const QRegularExpression regex
264  {allowSeparators
265  ? QLatin1String("[\\0]")
266  : QLatin1String("[\\0/]")};
267 #endif
268  return !name.contains(regex);
269 }

Referenced by BitTorrent::AbstractFileStorage::renameFile(), and BitTorrent::AbstractFileStorage::renameFolder().

Here is the caller graph for this function:

◆ removeDirRecursive()

void Utils::Fs::removeDirRecursive ( const QString &  path)

Removes directory and its content recursively.

Definition at line 187 of file fs.cpp.

188 {
189  if (!path.isEmpty())
190  QDir(path).removeRecursively();
191 }

Referenced by Application::cleanup(), and anonymous_namespace{searchpluginmanager.cpp}::clearPythonCache().

Here is the caller graph for this function:

◆ resolvePath()

QString Utils::Fs::resolvePath ( const QString &  relativePath,
const QString &  basePath 
)

If path is relative then resolves it againstbasePath, otherwise returns thepath` itself

Definition at line 74 of file fs.cpp.

75 {
76  Q_ASSERT(QDir::isRelativePath(relativePath));
77  Q_ASSERT(QDir::isAbsolutePath(basePath));
78 
79  return (relativePath.isEmpty() ? basePath : QDir(basePath).absoluteFilePath(relativePath));
80 }

Referenced by BitTorrent::Session::categoryDownloadPath(), TorrentCategoryDialog::categoryNameChanged(), BitTorrent::Session::categorySavePath(), BitTorrent::Session::initLoadTorrentParams(), BitTorrent::Session::setDownloadPath(), BitTorrent::TorrentImpl::setDownloadPath(), BitTorrent::Session::setSavePath(), BitTorrent::TorrentImpl::setSavePath(), and TorrentCategoryDialog::useDownloadPathChanged().

Here is the caller graph for this function:

◆ sameFileNames()

bool Utils::Fs::sameFileNames ( const QString &  first,
const QString &  second 
)

Definition at line 291 of file fs.cpp.

292 {
293 #if defined(Q_OS_UNIX) || defined(Q_WS_QWS)
294  return QString::compare(first, second, Qt::CaseSensitive) == 0;
295 #else
296  return QString::compare(first, second, Qt::CaseInsensitive) == 0;
297 #endif
298 }

◆ sameFiles()

bool Utils::Fs::sameFiles ( const QString &  path1,
const QString &  path2 
)

Makes deep comparison of two files to make sure they are identical.

Definition at line 220 of file fs.cpp.

221 {
222  QFile f1(path1), f2(path2);
223  if (!f1.exists() || !f2.exists()) return false;
224  if (f1.size() != f2.size()) return false;
225  if (!f1.open(QIODevice::ReadOnly)) return false;
226  if (!f2.open(QIODevice::ReadOnly)) return false;
227 
228  const int readSize = 1024 * 1024; // 1 MiB
229  while (!f1.atEnd() && !f2.atEnd())
230  {
231  if (f1.read(readSize) != f2.read(readSize))
232  return false;
233  }
234  return true;
235 }
void f1(struct fred_t *p)
Definition: clang.c:1
void f2()
Definition: clang.c:10

References f1(), and f2().

Here is the call graph for this function:

◆ smartRemoveEmptyFolderTree()

bool Utils::Fs::smartRemoveEmptyFolderTree ( const QString &  path)

This function will first check if there are only system cache files, e.g. Thumbs.db, .DS_Store and/or only temp files that end with '~', e.g. filename~. If they are the only files it will try to remove them and delete the folder. This action will be performed for each subfolder starting from the deepest folder. There is an inherent race condition here. A file might appear after it is checked that only the above mentioned "useless" files exist but before the whole folder is removed. In this case, the folder will not be removed but the "useless" files will be deleted.

Definition at line 114 of file fs.cpp.

115 {
116  if (path.isEmpty() || !QDir(path).exists())
117  return true;
118 
119  const QStringList deleteFilesList =
120  {
121  // Windows
122  QLatin1String("Thumbs.db"),
123  QLatin1String("desktop.ini"),
124  // Linux
125  QLatin1String(".directory"),
126  // Mac OS
127  QLatin1String(".DS_Store")
128  };
129 
130  // travel from the deepest folder and remove anything unwanted on the way out.
131  QStringList dirList(path + '/'); // get all sub directories paths
132  QDirIterator iter(path, (QDir::AllDirs | QDir::NoDotAndDotDot), QDirIterator::Subdirectories);
133  while (iter.hasNext())
134  dirList << iter.next() + '/';
135  // sort descending by directory depth
136  std::sort(dirList.begin(), dirList.end()
137  , [](const QString &l, const QString &r) { return l.count('/') > r.count('/'); });
138 
139  for (const QString &p : asConst(dirList))
140  {
141  const QDir dir(p);
142  // A deeper folder may have not been removed in the previous iteration
143  // so don't remove anything from this folder either.
144  if (!dir.isEmpty(QDir::Dirs | QDir::NoDotAndDotDot))
145  continue;
146 
147  const QStringList tmpFileList = dir.entryList(QDir::Files);
148 
149  // deleteFilesList contains unwanted files, usually created by the OS
150  // temp files on linux usually end with '~', e.g. `filename~`
151  const bool hasOtherFiles = std::any_of(tmpFileList.cbegin(), tmpFileList.cend(), [&deleteFilesList](const QString &f)
152  {
153  return (!f.endsWith('~') && !deleteFilesList.contains(f, Qt::CaseInsensitive));
154  });
155  if (hasOtherFiles)
156  continue;
157 
158  for (const QString &f : tmpFileList)
159  forceRemove(p + f);
160 
161  // remove directory if empty
162  dir.rmdir(p);
163  }
164 
165  return QDir(path).exists();
166 }
constexpr std::add_const_t< T > & asConst(T &t) noexcept
Definition: global.h:42
bool forceRemove(const QString &filePath)
Definition: fs.cpp:173

References asConst(), f(), and forceRemove().

Referenced by BitTorrent::Session::handleTorrentDeletedAlert(), and BitTorrent::Session::handleTorrentDeleteFailedAlert().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ stripRootFolder()

void Utils::Fs::stripRootFolder ( QStringList &  filePaths)

Definition at line 422 of file fs.cpp.

423 {
424  const QString commonRootFolder = findRootFolder(filePaths);
425  if (commonRootFolder.isEmpty())
426  return;
427 
428  for (QString &filePath : filePaths)
429  filePath = filePath.mid(commonRootFolder.size() + 1);
430 }
QString findRootFolder(const QStringList &filePaths)
Definition: fs.cpp:403

References findRootFolder().

Referenced by BitTorrent::applyContentLayout().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ tempPath()

QString Utils::Fs::tempPath ( )

Definition at line 314 of file fs.cpp.

315 {
316  static const QString path = QDir::tempPath() + "/.qBittorrent/";
317  QDir().mkdir(path);
318  return path;
319 }
QString tempPath()
Definition: fs.cpp:314

Referenced by Application::cleanup(), BitTorrent::Session::downloadMetadata(), UIThemeManager::getIconPath(), and anonymous_namespace{downloadhandlerimpl.cpp}::saveToTempFile().

Here is the caller graph for this function:

◆ toNativePath()

QString Utils::Fs::toNativePath ( const QString &  path)

Converts a path to a string suitable for display. This function makes sure the directory separator used is consistent with the OS being run.

Definition at line 64 of file fs.cpp.

65 {
66  return QDir::toNativeSeparators(path);
67 }

Referenced by FileSystemPathComboEdit::addItem(), BitTorrent::Session::addMoveTorrentStorageJob(), BitTorrent::Session::addTorrent_impl(), TorrentFilesWatcher::Worker::addWatchedFolder(), BitTorrent::BencodeResumeDataStorage::BencodeResumeDataStorage(), FileSystemPathEdit::FileSystemPathEditPrivate::browseActionTriggered(), BitTorrent::TorrentCreatorThread::calculateTotalPieces(), AddNewTorrentDialog::categoryChanged(), WatchedFoldersModel::data(), TransferListModel::displayValue(), BitTorrent::Session::downloadMetadata(), BitTorrent::TorrentImpl::endReceivedMetadataHandling(), anonymous_namespace{upgrade.cpp}::exportWebUIHttpsFiles(), BitTorrent::Session::fileSearchFinished(), TorrentOptionsDialog::handleCategoryChanged(), TorrentCreatorDialog::handleCreationSuccess(), TorrentOptionsDialog::handleTMMChanged(), BitTorrent::Session::handleTorrentFinished(), FileSystemPathComboEdit::insertItem(), TransferListModel::internalValue(), OptionsDialog::loadOptions(), AddNewTorrentDialog::loadTorrentFile(), BitTorrent::TorrentImpl::moveStorage(), OptionsDialog::on_addWatchedFolderButton_clicked(), WatchedFolderOptionsDialog::onCategoryChanged(), Utils::Gui::openFolderSelect(), Utils::Gui::openPath(), AppController::preferencesAction(), PreviewSelectDialog::previewButtonClicked(), TorrentsController::propertiesAction(), anonymous_namespace{settingsstorage.cpp}::TransactionalSettings::read(), BitTorrent::Session::recursiveTorrentDownload(), BitTorrent::TorrentImpl::renameFile(), BitTorrent::TorrentCreatorThread::run(), Application::runExternalProgram(), SearchDownloadHandler::SearchDownloadHandler(), SearchHandler::SearchHandler(), serialize(), TorrentsController::setLocationAction(), FileSystemPathEdit::setSelectedPath(), SearchPluginManager::update(), TorrentCreatorDialog::updateInputPath(), AutomatedRssDownloader::updateRuleDefinitionBox(), and PropertiesWidget::updateSavePath().

Here is the caller graph for this function:

◆ toUniformPath()

QString Utils::Fs::toUniformPath ( const QString &  path)

Converts a path to a string suitable for processing. This function makes sure the directory separator used is independent from the OS being run so it is the same on all supported platforms. Slash ('/') is used as "uniform" directory separator.

Definition at line 69 of file fs.cpp.

70 {
71  return QDir::fromNativeSeparators(path);
72 }

Referenced by BitTorrent::TorrentImpl::actualStorageLocation(), branchPath(), RSS::Feed::Feed(), fileName(), BitTorrent::TorrentInfo::filePath(), TorrentsController::filesAction(), BitTorrent::Session::finishedTorrentExportDirectory(), folderName(), Preferences::getScanDirsLastPath(), BitTorrent::TorrentImpl::handleFileRenamedAlert(), PluginSelectDialog::iconDownloadFinished(), BitTorrent::Session::IPFilterFile(), FileSystemPathComboEdit::item(), Preferences::lastLocationPath(), BitTorrent::DBResumeDataStorage::load(), BitTorrent::BencodeResumeDataStorage::loadTorrentResumeData(), MainWindow::on_actionOpen_triggered(), TorrentCreatorDialog::onCreateButtonClicked(), Utils::Gui::openFolderSelect(), Utils::Gui::openPath(), SearchPluginManager::pluginDownloadFinished(), BitTorrent::AbstractFileStorage::renameFile(), BitTorrent::AbstractFileStorage::renameFolder(), FileSystemPathEdit::selectedPath(), BitTorrent::Session::setFinishedTorrentExportDirectory(), BitTorrent::Session::setIPFilterFile(), Preferences::setLastLocationPath(), RSS::AutoDownloadRule::setSavePath(), Preferences::setScanDirsLastPath(), BitTorrent::Session::setTorrentExportDirectory(), TorrentContentModel::setupModelData(), BitTorrent::Session::torrentExportDirectory(), and BitTorrent::TorrentImpl::TorrentImpl().

Here is the caller graph for this function:

◆ toValidFileSystemName()

QString Utils::Fs::toValidFileSystemName ( const QString &  name,
bool  allowSeparators = false,
const QString &  pad = QLatin1String(" ") 
)

Definition at line 237 of file fs.cpp.

238 {
239  const QRegularExpression regex(allowSeparators ? "[:?\"*<>|]+" : "[\\\\/:?\"*<>|]+");
240 
241  QString validName = name.trimmed();
242  validName.replace(regex, pad);
243  qDebug() << "toValidFileSystemName:" << name << "=>" << validName;
244 
245  return validName;
246 }

Referenced by BitTorrent::Session::categoryDownloadPath(), TorrentCategoryDialog::categoryNameChanged(), BitTorrent::Session::categorySavePath(), BitTorrent::Session::exportTorrentFile(), RSS::Feed::Feed(), and TorrentCategoryDialog::useDownloadPathChanged().

Here is the caller graph for this function: