Esempio n. 1
0
// ////////////////////////////////////////////////////////////////////////////
std::string CoreDumperBase::ResolveBaseName(const char *file_name_base,
	bool is_full_name, MLB::Utility::ProcessId process_id,
	const std::string &host_name, const MLB::Utility::TimeT &time_stamp)
{
	if ((file_name_base == NULL) || (!(*file_name_base)))
		return(MLB::Utility::CanonicalizePathNameSlashes(
			GetDefaultCoreDir() + MLB::Utility::PathNameSeparatorCanonical_String +
			DecorateBaseName(NULL, process_id, host_name, time_stamp)));

	if (!is_full_name)
		return(MLB::Utility::CanonicalizePathNameSlashes(GetDefaultCoreDir() +
			MLB::Utility::PathNameSeparatorCanonical_String +
			DecorateBaseName(file_name_base, process_id, host_name, time_stamp)));

	std::string tmp_base(MLB::Utility::GetFileNamePortion(file_name_base));
	std::string dir_part(MLB::Utility::GetDirNamePortion(file_name_base));

	if (tmp_base.empty())
		tmp_base = DecorateBaseName(NULL, process_id, host_name, time_stamp);

	if (dir_part.empty())
		dir_part = GetDefaultCoreDir();

	MLB::Utility::ResolveDirectoryPath(dir_part, "", true);

	return(MLB::Utility::CanonicalizePathNameSlashes(dir_part +
		MLB::Utility::PathNameSeparatorCanonical_String + tmp_base));
}
Esempio n. 2
0
void LibraryWatcher::ScanSubdirectory(const QString& path,
                                      const Subdirectory& subdir,
                                      ScanTransaction* t,
                                      bool force_noincremental) {
  QFileInfo path_info(path);
  QDir      path_dir(path);

  // Do not scan symlinked dirs that are already in collection
  if (path_info.isSymLink()) {
    QString real_path = path_info.symLinkTarget();
    for (const Directory& dir : watched_dirs_) {
      if (real_path.startsWith(dir.path)) {
        t->AddToProgress(1);
        return;
      }
    }
  }

  // Do not scan directories containing a .nomedia or .nomusic file
  if (path_dir.exists(kNoMediaFile) ||
      path_dir.exists(kNoMusicFile)) {
    t->AddToProgress(1);
    return;
  }

  if (!t->ignores_mtime() && !force_noincremental && t->is_incremental() &&
      subdir.mtime == path_info.lastModified().toTime_t()) {
    // The directory hasn't changed since last time
    t->AddToProgress(1);
    return;
  }

  QMap<QString, QStringList> album_art;
  QStringList files_on_disk;
  SubdirectoryList my_new_subdirs;

  // If a directory is moved then only its parent gets a changed notification,
  // so we need to look and see if any of our children don't exist any more.
  // If one has been removed, "rescan" it to get the deleted songs
  SubdirectoryList previous_subdirs = t->GetImmediateSubdirs(path);
  for (const Subdirectory& subdir : previous_subdirs) {
    if (!QFile::exists(subdir.path) && subdir.path != path) {
      t->AddToProgressMax(1);
      ScanSubdirectory(subdir.path, subdir, t, true);
    }
  }

  // First we "quickly" get a list of the files in the directory that we
  // think might be music.  While we're here, we also look for new
  // subdirectories
  // and possible album artwork.
  QDirIterator it(
      path, QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot);
  while (it.hasNext()) {
    if (stop_requested_) return;

    QString child(it.next());
    QFileInfo child_info(child);

    if (child_info.isDir()) {
      if (!child_info.isHidden() && !t->HasSeenSubdir(child)) {
        // We haven't seen this subdirectory before - add it to a list and
        // later we'll tell the backend about it and scan it.
        Subdirectory new_subdir;
        new_subdir.directory_id = -1;
        new_subdir.path = child;
        new_subdir.mtime = child_info.lastModified().toTime_t();
        my_new_subdirs << new_subdir;
      }
    } else {
      QString ext_part(ExtensionPart(child));
      QString dir_part(DirectoryPart(child));

      if (sValidImages.contains(ext_part))
        album_art[dir_part] << child;
      else if (!child_info.isHidden())
        files_on_disk << child;
    }
  }

  if (stop_requested_) return;

  // Ask the database for a list of files in this directory
  SongList songs_in_db = t->FindSongsInSubdirectory(path);

  QSet<QString> cues_processed;

  // Now compare the list from the database with the list of files on disk
  for (const QString& file : files_on_disk) {
    if (stop_requested_) return;

    // associated cue
    QString matching_cue = NoExtensionPart(file) + ".cue";

    Song matching_song;
    if (FindSongByPath(songs_in_db, file, &matching_song)) {
      uint matching_cue_mtime = GetMtimeForCue(matching_cue);

      // The song is in the database and still on disk.
      // Check the mtime to see if it's been changed since it was added.
      QFileInfo file_info(file);

      if (!file_info.exists()) {
        // Partially fixes race condition - if file was removed between being
        // added to the list and now.
        files_on_disk.removeAll(file);
        continue;
      }

      // cue sheet's path from library (if any)
      QString song_cue = matching_song.cue_path();
      uint song_cue_mtime = GetMtimeForCue(song_cue);

      bool cue_deleted = song_cue_mtime == 0 && matching_song.has_cue();
      bool cue_added = matching_cue_mtime != 0 && !matching_song.has_cue();

      // watch out for cue songs which have their mtime equal to
      // qMax(media_file_mtime, cue_sheet_mtime)
      bool changed =
          (matching_song.mtime() !=
           qMax(file_info.lastModified().toTime_t(), song_cue_mtime)) ||
          cue_deleted || cue_added;

      // Also want to look to see whether the album art has changed
      QString image = ImageForSong(file, album_art);
      if ((matching_song.art_automatic().isEmpty() && !image.isEmpty()) ||
          (!matching_song.art_automatic().isEmpty() &&
           !matching_song.has_embedded_cover() &&
           !QFile::exists(matching_song.art_automatic()))) {
        changed = true;
      }

      // the song's changed - reread the metadata from file
      if (t->ignores_mtime() || changed) {
        qLog(Debug) << file << "changed";

        // if cue associated...
        if (!cue_deleted && (matching_song.has_cue() || cue_added)) {
          UpdateCueAssociatedSongs(file, path, matching_cue, image, t);
          // if no cue or it's about to lose it...
        } else {
          UpdateNonCueAssociatedSong(file, matching_song, image, cue_deleted,
                                     t);
        }
      }

      // nothing has changed - mark the song available without re-scanning
      if (matching_song.is_unavailable()) t->readded_songs << matching_song;

    } else {
      // The song is on disk but not in the DB
      SongList song_list =
          ScanNewFile(file, path, matching_cue, &cues_processed);

      if (song_list.isEmpty()) {
        continue;
      }

      qLog(Debug) << file << "created";
      // choose an image for the song(s)
      QString image = ImageForSong(file, album_art);

      for (Song song : song_list) {
        song.set_directory_id(t->dir());
        if (song.art_automatic().isEmpty()) song.set_art_automatic(image);

        t->new_songs << song;
      }
    }
  }

  // Look for deleted songs
  for (const Song& song : songs_in_db) {
    if (!song.is_unavailable() &&
        !files_on_disk.contains(song.url().toLocalFile())) {
      qLog(Debug) << "Song deleted from disk:" << song.url().toLocalFile();
      t->deleted_songs << song;
    }
  }

  // Add this subdir to the new or touched list
  Subdirectory updated_subdir;
  updated_subdir.directory_id = t->dir();
  updated_subdir.mtime =
      path_info.exists() ? path_info.lastModified().toTime_t() : 0;
  updated_subdir.path = path;

  if (subdir.directory_id == -1)
    t->new_subdirs << updated_subdir;
  else
    t->touched_subdirs << updated_subdir;

  t->AddToProgress(1);

  // Recurse into the new subdirs that we found
  t->AddToProgressMax(my_new_subdirs.count());
  for (const Subdirectory& my_new_subdir : my_new_subdirs) {
    if (stop_requested_) return;
    ScanSubdirectory(my_new_subdir.path, my_new_subdir, t, true);
  }
}