Logo Search packages:      
Sourcecode: jigdo version File versions

int JigdoDesc::makeImage ( JigdoCache cache,
const string &  imageFile,
const string &  imageTmpFile,
const string &  templFile,
bistream *  templ,
const bool  optForce,
ProgressReporter pr = noReport,
size_t  readAmnt = 128U*1024,
const bool  optMkImageCheck = true 
) [static, inherited]

Create image file from template and files (via JigdoCache)

Definition at line 725 of file mkimage.cc.

References JigdoCache::begin(), JigdoCache::end(), JigdoDesc::ProgressReporter::error(), JigdoDescVec::get(), JigdoDesc::ProgressReporter::info(), JigdoDesc::MatchedFile::md5(), JigdoDesc::MatchedFile::size(), and MD5::toString().

                                                         {

  Task task = CREATE_TMP;

  if (imageFile == "-" || imageTmpFile.empty()) task = SINGLE_PASS;
  //____________________

  // Read info from template
  JigdoDescVec files;
  readTemplate(files, templFile, templ);
  //____________________

  // Do we need to add new stuff to an existing tmp file?
  bfstream* img = 0; // Non-null => tmp file exists
  auto_ptr<bfstream> imgDel(img);
  struct stat fileInfo;
  if (task != SINGLE_PASS && stat(imageTmpFile.c_str(), &fileInfo) == 0) {
    /* A tmp file already exists. We'll only reuse it if the DESC
       entries match exactly. Otherwise, if --force enabled, overwrite
       it, else error. */
    const char* wontReuse = 0; // non-NULL means: will not reuse tmp file
    JigdoDescVec filesTmp;
    imgDel.reset(new bfstream(imageTmpFile.c_str(),
                              ios::binary|ios::in|ios::out));
    img = imgDel.get();
    if (!*img)
      wontReuse = strerror(errno);
    else
      wontReuse = readTmpFile(*img, filesTmp, files);

    if (wontReuse != 0) {
      // Print out message
      string msg = subst(_("Will not reuse existing temporary file `%1' - "
                           "%2"), imageTmpFile, wontReuse);
      // Return error if not allowed to overwrite tmp file
      if (!optForce) {
        reporter.error(msg);
        throw Error(_("Delete/rename the file or use --force"));
      }
      // Open a new tmp file later (imgDel will close() this one for us)
      reporter.info(msg);
      img = 0;
      Paranoid(task == CREATE_TMP);
    } else {
      // Reuse temporary file
      task = MERGE_TMP;
      files.swap(filesTmp);
      Assert(!filesTmp.empty() && img != 0);
    }
  } // endif (tmp file exists)

  Paranoid((task == MERGE_TMP) == (img != 0));
  //____________________

  /* Variables now in use:
     enum task:
             Mode of operation (CREATE_TMP/MERGE_TMP/SINGLE_PASS)
     JigdoDescVec files:
             Contents of image, maybe with some WrittenFiles if MERGEing
     istream* templ: Template data (stream pointer at end of file)
     fstream* img: Temporary file if MERGE_TMP, else null
  */

  /* Create queue of files that need to be copied to the image. Later
     on, we will be pop()ing to get to the actual filenames in order.
     Referenced FileParts are owned by the JigdoCache - never delete
     them. */
  queue<FilePart*> toCopy;
  int missing = 0; // Nr of files that were not found
  JigdoCache::iterator ci, ce = cache->end();
  uint64 totalBytes = 0; // Total amount of data to be written, for "x% done"

  for (vector<JigdoDesc*>::iterator i = files.begin(), e = files.end();
       i != e; ++i) {
    // Need this extra test because we do *not* want the WrittenFiles
    if ((*i)->type() != MATCHED_FILE) continue;
    MatchedFile* m = dynamic_cast<MatchedFile*>(*i);
    Paranoid(m != 0);
    //totalBytes += m->size();

    // Search for file with matching MD5 sum
    ci = cache->begin();
    bool found = false;
    while (ci != ce) {
      // The call to getMD5Sum() may cause the whole file to be read!
      const MD5Sum* md = ci->getMD5Sum(cache);
      if (md != 0 && *md == m->md5()) {
        toCopy.push(&*ci); // Found matching file
        totalBytes += m->size();
        debug("%1 found, pushed %2", m->md5().toString(), &*ci);
        found = true;
        break;
      }
      ++ci;
    }
    if (!found) ++missing;

  }
  //____________________

  debug("JigdoDesc::mkImage: %1 missing, %2 found for copying to image, "
        "%3 entries in template", missing, toCopy.size(), files.size());

  // Files appearing >1 times are counted >1 times for the message
  string missingInfo = subst(
      _("Found %1 of the %2 files required by the template"),
      toCopy.size(), toCopy.size() + missing);
  reporter.info(missingInfo);
  //____________________

  /* There used to be the following here:
     | If possible (i.e. all files present, tmp file not yet created),
     | avoid creating any tmp file at all.
     | if (task == CREATE_TMP && missing == 0) task = SINGLE_PASS;
     We do not do this because even though it says "missing==0" *now*,
     there could be a read error from one of the files when we
     actually access it, in which case we should be able to ignore the
     error for the moment, and leave behind a partially complete .tmp
     file. */

  /* Do nothing at all if a) no tmp file created yet, and b) *none* of
     the supplied files matched one of the missing parts, and c) the
     template actually contains at least one MatchedFile (i.e. *do*
     write if template consists entirely of UnmatchedData). */
# ifndef MKIMAGE_ALWAYS_CREATE_TMPFILE
  if (task == CREATE_TMP && toCopy.size() == 0 && missing != 0) {
    const char* m = _("Will not create image or temporary file - try again "
                      "with different input files");
    reporter.info(m);
    return 1; // Return value: "Soft failure - may retry with more files"
  }

  // Give error if unable to create image in one pass
  if (task == SINGLE_PASS && missing > 0) {
    reporter.error(_("Cannot create image because of missing files"));
    return 3; // Permanent failure
  }
# endif
  //____________________

  if (task == MERGE_TMP) { // If MERGEing, img was already set up above
    int result = writeMerge(files, toCopy, missing, readAmount, img,
                            imageTmpFile, optMkImageCheck, reporter, cache,
                            totalBytes);
    if (missing != 0 && result < 3)
      info_NeedMoreFiles(reporter, imageTmpFile);
    if (result == 0) {
      if (compat_rename(imageTmpFile.c_str(), imageFile.c_str()) != 0)
        return error_CouldntRename(reporter, imageTmpFile.c_str(),
                                   imageFile.c_str());
      string info = subst(_("Successfully created `%1'"), imageFile);
      reporter.info(info);
    }
    return result;
  }

  // task == CREATE_TMP || task == SINGLE_PASS

  // Assign a stream to img which we're going to write image data to
  // If necessary, create a new temporary/output file
  const char* name;
  const char* finalName = 0;
  if (task == CREATE_TMP) { // CREATE new tmp file
    name = imageTmpFile.c_str();
    finalName = imageFile.c_str();
    imgDel.reset(new bfstream(name, ios::binary|ios::out|ios::trunc));
    img = imgDel.get();
  } else if (imageFile != "-") { // SINGLE_PASS; create output file
    name = imageFile.c_str();
    imgDel.reset(new bfstream(name, ios::binary|ios::out|ios::trunc));
    img = imgDel.get();
  } else { // SINGLE_PASS, outputting to stdout
    name = "-";
    imgDel.reset(0);
    img = 0; // Cannot do "img = &cout", so img==0 is special case: stdout
  }
  if (img != 0 && !*img) {
    string err = subst(_("Could not open `%1' for output: %2"),
                       name, strerror(errno));
    reporter.error(err);
    return 3; // Permanent failure
  }

  /* Above, totalBytes was calculated for the case of a MERGE_TMP. If
     we're not merging, we need to write everything. */
  Assert(files.back()->type() == IMAGE_INFO);
  uint64 imageSize = files.back()->size();
  totalBytes = imageSize;
# if 0 /* # if WINDOWS */
  /* The C++ STL of the MinGW 1.1 gcc port for Windows doesn't support
     files >2GB. Fail early and with a clear error message... */
  if (imageSize >= (1U<<31))
    throw Error(_("Sorry, at the moment the Windows port of jigdo cannot "
                  "create files bigger than 2 GB. Use the Linux version."));
# endif

  int result = writeAll(task, files, toCopy, templ, readAmount, img, name,
                        optMkImageCheck, reporter, cache, totalBytes);
  if (result >= 3) return result;

  if (task == CREATE_TMP && result == 1) {
    info_NeedMoreFiles(reporter, imageTmpFile);
  } else if (result == 0) {
    if (img != 0)
      img->close(); // Necessary on Windows before renaming is possible
    if (finalName != 0 && compat_rename(name, finalName) != 0)
      return error_CouldntRename(reporter, name, finalName);
    string info = subst(_("Successfully created `%1'"), imageFile);
    reporter.info(info);
  }
  return result;
}


Generated by  Doxygen 1.6.0   Back to index