Logo Search packages:      
Sourcecode: parted version File versions

count.c

/*
    libparted
    Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    I can also be contacted at:

    Andrew Clausen
    18 Shaw St
    Ashwood, 3147
    Victoria, Australia

*/

#include "fat.h"
#include "traverse.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef DISCOVER_ONLY

#if 0
/* extremely ugly hack: stick everything that obviously isn't an unmovable file
 * in here.  Note: DAT is a bit dubious.  Unfortunately, it's used by the
 * registry, so it'll be all over the place :-(
 */
static char*      movable_extensions[] = {
      "",
      "1ST",
      "AVI",
      "BAK", "BAT", "BMP",
      "CFG", "COM", "CSS",
      "DAT", "DLL", "DOC", "DRV",
      "EXE",
      "FAQ", "FLT", "FON",
      "GID", "GIF",
      "HLP", "HTT", "HTM",
      "ICO", "INI",
      "JPG",
      "LNK", "LOG",
      "KBD",
      "ME", "MID", "MSG",
      "OCX", "OLD",
      "PIF", "PNG", "PRV",
      "RTF",
      "SCR", "SYS",
      "TMP", "TTF", "TXT",
      "URL",
      "WAV",
      "VBX", "VOC", "VXD",
      NULL
};

static char*
get_extension (char* file_name)
{
      char*       ext;

      ext = strrchr (file_name, '.');
      if (!ext)
            return "";
      if (strchr (ext, '\\'))
            return "";
      return ext + 1;
}

static int
is_movable_system_file (char* file_name)
{
      char*       ext = get_extension (file_name);
      int         i;

      for (i = 0; movable_extensions [i]; i++) {
            if (strcasecmp (ext, movable_extensions [i]) == 0)
                  return 1;
      }

      return 0;
}
#endif /* 0 */

/*
    prints out the sequence of clusters for a given file chain, beginning
    at start_cluster.
*/
static void
print_chain (PedFileSystem* fs, FatCluster start)
{
      FatSpecific*      fs_info = FAT_SPECIFIC (fs);
      FatCluster  clst;
      int         this_row;

      this_row = 0;
      for (clst = start; !fat_table_is_eof (fs_info->fat, clst);
           clst = fat_table_get (fs_info->fat, clst)) {
            printf ("  %d", (int) clst);
            if (++this_row == 7) {
                  printf ("\n");
                  this_row = 0;
            }
      }
      printf ("\n");
}

static PedSector
remainder_round_up (PedSector a, PedSector b)
{
      PedSector   result;

      result = a % b;
      if (!result)
            result = b;
      return result;
}

/*
    traverse the FAT for a file/directory, marking each entry's flag
    to "flag".
*/
static int
flag_traverse_fat (PedFileSystem* fs, const char* chain_name, FatCluster start,
               FatClusterFlag flag, PedSector size)
{
      FatSpecific*      fs_info = FAT_SPECIFIC (fs);
      FatCluster  clst;
      FatCluster  prev_clst;
      int         last_cluster_usage;
      FatCluster  chain_length = 0;

      if (fat_table_is_eof (fs_info->fat, start)) {
            if (ped_exception_throw (
                  PED_EXCEPTION_ERROR,
                  PED_EXCEPTION_IGNORE_CANCEL,
                  _("Bad directory entry for %s: first cluster is the "
                    "end of file marker."),
                  chain_name)
                        != PED_EXCEPTION_IGNORE)
                  return 0;
      }

      for (prev_clst = clst = start; !fat_table_is_eof (fs_info->fat, clst);
           prev_clst = clst, clst = fat_table_get (fs_info->fat, clst)) {
            chain_length++;
            if (!clst) {
                  ped_exception_throw (PED_EXCEPTION_FATAL,
                        PED_EXCEPTION_CANCEL,
                        _("Bad FAT: unterminated chain for %s.  You "
                          "should run dosfsck or scandisk."),
                        chain_name);
                  return 0;
            }

            if (clst >= fs_info->fat->cluster_count + 2) {
                  ped_exception_throw (PED_EXCEPTION_FATAL,
                        PED_EXCEPTION_CANCEL,
                        _("Bad FAT: cluster %d outside filesystem "
                          "in chain for %s.  You should run dosfsck "
                          "or scandisk."),
                        (int) clst, chain_name);
                  return 0;
            }

            if (fs_info->cluster_info [clst].flag != FAT_FLAG_FREE ) {
                  ped_exception_throw (PED_EXCEPTION_FATAL,
                        PED_EXCEPTION_CANCEL,
                        _("Bad FAT: cluster %d is cross-linked for "
                          "%s.  You should run dosfsck or scandisk."),
                        (int) clst, chain_name);
                  return 0;
            }

            if (flag == FAT_FLAG_DIRECTORY)
                  fs_info->total_dir_clusters++;

            fs_info->cluster_info [clst].flag = flag;
            fs_info->cluster_info [clst].units_used = 64;
      }

      if (size
          && chain_length
                  != ped_div_round_up (size, fs_info->cluster_sectors)) {
            if (ped_exception_throw (
                  PED_EXCEPTION_ERROR,
                  PED_EXCEPTION_IGNORE_CANCEL,
                  _("%s is %dk, but it has %d clusters (%dk)."),
                  chain_name,
                  (int) size / 2,
                  (int) chain_length,
                  (int) chain_length * fs_info->cluster_sectors / 2)
                        != PED_EXCEPTION_IGNORE)
                  return 0;
      }

      last_cluster_usage
            = ped_div_round_up (64 * remainder_round_up (size,
                                    fs_info->cluster_sectors),
                        fs_info->cluster_sectors);

      fs_info->cluster_info [prev_clst].units_used = last_cluster_usage;

      return 1;
}

/*
    recursively traverses a directory, flagging all clusters in the process.
    It frees the traverse_info structure before returning.
*/
static int
flag_traverse_dir (FatTraverseInfo* trav_info) {
      PedFileSystem*          fs = trav_info->fs;
      FatDirEntry*            this_entry;
      FatTraverseInfo*  subdir_trav_info;
      char              file_name [512];
      char*             file_name_start;
      FatCluster        first_cluster;
      PedSector         size;
      PedExceptionOption      ex_status;

      PED_ASSERT (trav_info != NULL, return 0);

      strcpy (file_name, trav_info->dir_name);
      file_name_start = file_name + strlen (file_name);

      while ( (this_entry = fat_traverse_next_dir_entry (trav_info)) ) {
            if (fat_dir_entry_is_null_term (this_entry))
                  break;
            if (!fat_dir_entry_has_first_cluster (this_entry, fs))
                  continue;
            if (this_entry->name [0] == '.')
                  continue;   /* skip . and .. entries */

            fat_dir_entry_get_name (this_entry, file_name_start);
            first_cluster = fat_dir_entry_get_first_cluster(this_entry, fs);
            size = ped_div_round_up (fat_dir_entry_get_length (this_entry),
                               512);

#ifdef PED_VERBOSE
            printf ("%s: ", file_name);
            print_chain (fs, first_cluster);
#endif

#if 0
            if (fat_dir_entry_is_system_file (this_entry)
                && !is_movable_system_file (file_name)) {
                  ex_status = ped_exception_throw (
                        PED_EXCEPTION_WARNING,
                        PED_EXCEPTION_IGNORE_CANCEL,
                        _("The file %s is marked as a system file.  "
                        "This means moving it could cause some "
                        "programs to stop working."),
                        file_name);

                  switch (ex_status) {
                        case PED_EXCEPTION_CANCEL:
                              return 0;

                        case PED_EXCEPTION_UNHANDLED:
                              ped_exception_catch ();
                        case PED_EXCEPTION_IGNORE:
                  }
            }
#endif /* 0 */

            if (fat_dir_entry_is_directory (this_entry)) {
                  if (!flag_traverse_fat (fs, file_name, first_cluster,
                                    FAT_FLAG_DIRECTORY, size))
                        return 0;

                  subdir_trav_info = fat_traverse_directory (trav_info,
                                                   this_entry);
                  if (!subdir_trav_info)
                        return 0;
                  if (!flag_traverse_dir (subdir_trav_info))
                        return 0;
            } else if (fat_dir_entry_is_file (this_entry)) {
                  if (!flag_traverse_fat (fs, file_name, first_cluster,
                                    FAT_FLAG_FILE, size)) 
                        return 0;
            }
      }

      fat_traverse_complete (trav_info);
      return 1;
}

static void
_mark_bad_clusters (PedFileSystem* fs)
{
      FatSpecific*      fs_info = FAT_SPECIFIC (fs);
      FatCluster  cluster;
      FatFragment frag;

      for (cluster = 2; cluster < fs_info->cluster_count + 2; cluster++) {
            if (fat_table_is_bad (fs_info->fat, cluster))
                  fs_info->cluster_info [cluster].flag = FAT_FLAG_BAD;
      }
}

/*  
    fills in cluster_info.  Each FAT entry (= cluster) is flagged as either
    FAT_FLAG_FREE, FAT_FLAG_FILE or FAT_FLAG_DIRECTORY.

    Also, the fraction of each cluster (x/64) is recorded
*/
int
fat_collect_cluster_info (PedFileSystem* fs) {
      FatSpecific*            fs_info = FAT_SPECIFIC (fs);
      FatTraverseInfo*  trav_info;
    
      /* set all clusters to unused as a default */
      memset (fs_info->cluster_info, 0, fs_info->fat->cluster_count + 2);
      fs_info->total_dir_clusters = 0;

      if (fs_info->fat_type == FAT_TYPE_FAT32) {
            trav_info = fat_traverse_begin (fs, fs_info->root_cluster,
                                    "\\");
            if (!flag_traverse_dir (trav_info))
                  return 0;
            if (!flag_traverse_fat (fs, "\\", fs_info->root_cluster,
                                        FAT_FLAG_DIRECTORY, 0))
                  return 0;
      } else {
            trav_info = fat_traverse_begin (fs, FAT_ROOT, "\\");
            if (!flag_traverse_dir (trav_info))
                  return 0;
      }

      _mark_bad_clusters (fs);
      return 1;
}

FatClusterFlag
fat_get_cluster_flag (PedFileSystem* fs, FatCluster cluster)
{
      FatSpecific*            fs_info = FAT_SPECIFIC (fs);

      return fs_info->cluster_info [cluster].flag;
}

PedSector
fat_get_cluster_usage (PedFileSystem* fs, FatCluster cluster)
{
      FatSpecific*            fs_info = FAT_SPECIFIC (fs);
      int               fraction;

      if (fs_info->cluster_info [cluster].flag == FAT_FLAG_FREE)
            return 0;

      fraction = fs_info->cluster_info [cluster].units_used;
      if (fraction == 0)
            fraction = 64;

      return fraction * fs_info->cluster_sectors / 64;
}

FatClusterFlag
fat_get_fragment_flag (PedFileSystem* fs, FatFragment frag)
{
      FatSpecific*      fs_info = FAT_SPECIFIC (fs);
      FatCluster  cluster = fat_frag_to_cluster (fs, frag);
      FatFragment offset = frag % fs_info->cluster_frags;
      FatFragment last_frag_used;
      FatClusterFlag    flag;

      PED_ASSERT (cluster >= 2 && cluster < fs_info->cluster_count + 2,
                return 0);

      flag = fat_get_cluster_flag (fs, cluster);
      if (flag != FAT_FLAG_FILE && flag != FAT_FLAG_DIRECTORY)
            return flag;
      last_frag_used = (fat_get_cluster_usage (fs, cluster) - 1)
                        / fs_info->frag_sectors;
      if (offset > last_frag_used)
            return FAT_FLAG_FREE;
      else
            return flag;
}

int
fat_is_fragment_active (PedFileSystem* fs, FatFragment frag)
{
      switch (fat_get_fragment_flag (fs, frag)) {
            case FAT_FLAG_FREE:
            case FAT_FLAG_BAD:
                  return 0;

            case FAT_FLAG_FILE:
            case FAT_FLAG_DIRECTORY:
                  return 1;
      }
      return 0;
}

#endif /* !DISCOVER_ONLY */


Generated by  Doxygen 1.6.0   Back to index