[svlug] auto-fit files on CDs

Tim tim at tetro.net
Sun Oct 20 12:38:21 PDT 2002


On Sun, Oct 20, 2002 at 07:32:49PM +0200, Ira Abramov wrote:
> I have a question that needs a difficult algorithem for the solution, I
> wonder if someone already coded that wheel to save me from redoing it.
> 
> We have a product update to burn on CD-Rs and send once in a few weeks.
> the update includes many RPMs and other files of various sizes and can
> run up to a few gigs. the question of packing them for best-fit on the
> several CD-Rs they will take up is not a simple one, but doesn't need a
> perfect solution that will run an up-to-the-megabyte optimization over a
> few hours, since the slack "allocation unit" is 640/700 megs afterall :)
> 
> So, did anyone invent this wheel already?

Maybe..
I wrote this script to simply recurse a directory and output a list of
files to file(s) that can be used with mkisofs's -path-list option
(-graft-points needed too).  It doesn't try to find a best-fit, it just
opens a new list file when the tallied up number of bytes exceeds the
configured MAX_ISO_SIZE.

Here is an example usage of it:

# mkisolist.pl /home home-backup 
 ---Output omitted---
# ls home-backup*
home-backup00.list  home-backup01.list  home-backup02.list
# for LIST in home-backup*.list; do \
 mkisofs -R -J -o ${LIST%.*}.iso -graft-points -path-list $LIST; done
 ---Output omitted---

Of course you probably want -r instead of -R if your going to send it to
someone, but -R is good for backups where the permissions, uids, and
gids need to be preserved.

Here is the script:


#!/usr/bin/perl -w

#-------- Config Variables ---------
my $MAX_ISO_SIZE = 736100352;  # 702 MB
#----- End of Config Variables -----


my ( $source_dir,  # dir which has files to be listed
     $list_name,   # prefix to be used in the list filename(s)
     $list_num,    # the current list filename number (starting at zero)
     $totalsize    # current total size of filenames in current list
   );

# main
processArgs();
makeLists();
exit(0);


########################################################################
#
#  processArgs  -  Process command line arguments
#
#    Global variables used:
#      $list_name
#      $source_dir
#
########################################################################
sub processArgs
{
  if($#ARGV != 1)  # last index
  {
    print("Usage:\n"                       .
          "       $0 <dir> <list_name>\n" );
    exit(1);
  }

  $source_dir = $ARGV[0];
  $source_dir =~ s,/$,,;  # get rid of trailing slash
  $list_name  = $ARGV[1];
}


########################################################################
#
#  makeLists  -  Make mkisofs path-list files from files in $source_dir
#
#    Global variables used:
#      $list_num
#      $source_dir
#      $totalsize
#      LISTFILE
#
########################################################################
sub makeLists
{
  local ( $listfilename );

  # prepare first list file
  $list_num = 0;
  $totalsize = 0;
  openListFile();

  # start processing files, recursing dirs
  recurseDir($source_dir);

  print("*** CD " . ($list_num+1) .
        " (last CD) size: $totalsize (Max: $MAX_ISO_SIZE)\n");

  # clean up
  close(LISTFILE);
}


########################################################################
#
#  recurseDir  -  Recursively processes all files under given directory 
#                 and add them to the current LISTFILE.
#
#    Parameters:
#      $_[0]   Given directory.
#
#    Global variables used:
#      $list_num
#      $source_dir
#      $totalsize
#      LISTFILE
#
########################################################################
sub recurseDir
{
  local ( $dir, $filesize, $filecount, $graft_path );
  $dir = $_[0];

  print("*** Adding $dir/\n");

  if ( !opendir(local $dirhandle, "$dir") ) {
    print("$0: $dir: $!\n");
    return;
  }

  $filecount = 0;
  foreach $file (sort readdir($dirhandle)) {
    if ( "$file" eq "." || "$file" eq ".." ) {
      next; }
    elsif ( -d "$dir/$file" ) {
      recurseDir("$dir/$file"); }
    else {
      $filesize   = (-s "$dir/$file");
      $totalsize += $filesize;
      if($totalsize > $MAX_ISO_SIZE) {
        $list_num++;
        print("*** Filled CD $list_num. Size: " . 
              ($totalsize - $filesize) . " (Max: $MAX_ISO_SIZE)\n");
        $totalsize = $filesize;
        close(LISTFILE);
        openListFile();
      }

      # cut off $source_dir/ 
      $graft_path = "$dir/$file";
      $graft_path =~ s,^$source_dir/,,;
      print(LISTFILE "$graft_path=$dir/$file\n");
    }
    $filecount++;
  }

  # handle empty directories
  if($filecount == 0) {
    # cut off $source_dir/ 
    $graft_path = $dir;
    $graft_path =~ s,^$source_dir/,,;
    print(LISTFILE "$graft_path=$dir\n");
  }

  closedir($dirhandle);
}


########################################################################
#
#  openListFile  -  Open list file based on $list_name and $list_num
#
#    Global variables used:
#      $list_name
#      $list_num
#      LISTFILE
#
########################################################################
sub openListFile
{
  local ( $listfilename );

  $listfilename = sprintf("$list_name%02d.list", $list_num);
  if(-e $listfilename) {
    print("$0: $listfilename: List file already exists.\n");
    exit(1);
  }

  if(!open(LISTFILE, ">$listfilename")) {
    print("$0: $listfilename: $!\n");
    exit(1);
  }
}



More information about the svlug mailing list