Logo Search packages:      
Sourcecode: fatsort version File versions  Download package

entrylist.c

/*
      FATSort, utility for sorting FAT directory structures
      Copyright (C) 2004 Boris Leidner <fatsort(at)formenos.de>

      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.
*/

/*
      This file contains/describes some ADOs which are used to
      represent the structures of FAT directory entries and entry lists.
*/

#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>

#include "entrylist.h"
#include "options.h"
#include "errors.h"
#include "natstrcmp.h"

// random number
u_int32_t irand( u_int32_t b, u_int32_t e)
{
    double r = e - b + 1;
    return b + (u_int32_t)(r * rand()/(RAND_MAX+1.0));
}

// List functions

struct sDirEntryList * newDirEntryList(void) {
/*
      create new dir entry list
*/
      struct sDirEntryList *tmp;

      if ((tmp=malloc(sizeof(struct sDirEntryList)))==NULL) {
            stderror();
            return NULL;
      }
      memset(tmp, 0, sizeof(struct sDirEntryList));
      return tmp;
}

struct sDirEntryList *
      newDirEntry(char *sname, char *lname, struct sShortDirEntry *sde, struct sLongDirEntryList *ldel, u_int32_t entries) {
/*
      create a new directory entry holder
*/
      assert(sname != NULL);
      assert(lname != NULL);
      assert(sde != NULL);
      
      struct sDirEntryList *tmp;

      if ((tmp=malloc(sizeof(struct sDirEntryList)))==NULL) {
            stderror();
            return NULL;
      }
      if ((tmp->sname=malloc(strlen(sname)+1))==NULL) {
            stderror();
            return NULL;
      }
      strcpy(tmp->sname, sname);
      if ((tmp->lname=malloc(strlen(lname)+1))==NULL) {
            stderror();
            return NULL;
      }
      strcpy(tmp->lname, lname);

      if ((tmp->sde=malloc(sizeof(struct sShortDirEntry)))==NULL) {
            stderror();
            return NULL;
      }
      memcpy(tmp->sde, sde, DIR_ENTRY_SIZE);
      tmp->ldel=ldel;
      tmp->entries=entries;
      tmp->next = NULL;
      return tmp;
}

struct sLongDirEntryList *
      insertLongDirEntryList(struct sLongDirEntry *lde, struct sLongDirEntryList *list) {
/*
      insert a long directory entry to list
*/

      assert(lde != NULL);

      struct sLongDirEntryList *tmp, *new;

      if ((new=malloc(sizeof(struct sLongDirEntryList)))==NULL) {
            stderror();
            return NULL;
      }
      if ((new->lde=malloc(sizeof(struct sLongDirEntry)))==NULL) {
            stderror();
            return NULL;
      }
      memcpy(new->lde, lde, DIR_ENTRY_SIZE);
      new->next=NULL;

      if (list != NULL) {
            tmp=list;
            while(tmp->next != NULL) {
                  tmp=tmp->next;
            }
            tmp->next=new;
            return list;
      } else {
            return new;
      }
}

int32_t cmpEntries(struct sDirEntryList *de1, struct sDirEntryList *de2) {
/*
      compare two directory entries
*/

      assert(de1 != NULL);
      assert(de2 != NULL);

      // the volume label must always remain at the beginning of the (root) directory
      if ((de1->sde->DIR_Atrr & (ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID | ATTR_DIRECTORY)) == ATTR_VOLUME_ID) {
            return(-1);
      } else if ((de2->sde->DIR_Atrr & (ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID | ATTR_DIRECTORY)) == ATTR_VOLUME_ID) {
            return(1);
      // the special "." and ".." directories must always remain at the beginning of directories, in this order
      } else if (strcmp(de1->sname, ".") == 0) {
            return(-1);
      } else if (strcmp(de2->sname, ".") == 0) {
            return(1);
      } else if (strcmp(de1->sname, "..") == 0) {
            return(-1);
      } else if (strcmp(de2->sname, "..") == 0) {
            return(1);
      // deleted entries should be moved to the end of the directory
      } else if (de1->sname[0] == DE_FREE) {
            return(1);
      } else if (de2->sname[0] == DE_FREE) {
            return(-1);
      }

      char *s1,*s2;

      if ((de1->lname != NULL) && (de1->lname[0] != '\0')) {
            s1=de1->lname;
      } else {
            s1=de1->sname;
      }
      if ((de2->lname != NULL) && (de2->lname[0] != '\0')) {
            s2=de2->lname;
      } else {
            s2=de2->sname;
      }

      // directories will be put above normal files
      if (OPT_ORDER == 0) {
            if ((de1->sde->DIR_Atrr & ATTR_DIRECTORY) &&
               !(de2->sde->DIR_Atrr & ATTR_DIRECTORY)) {
                  return -1;
            } else if (!(de1->sde->DIR_Atrr & ATTR_DIRECTORY) &&
                      (de2->sde->DIR_Atrr & ATTR_DIRECTORY)) {
                  return 1;
            }
      } else if (OPT_ORDER == 1) {
            if ((de1->sde->DIR_Atrr & ATTR_DIRECTORY) &&
               !(de2->sde->DIR_Atrr & ATTR_DIRECTORY)) {
                  return 1;
            } else if (!(de1->sde->DIR_Atrr & ATTR_DIRECTORY) &&
                      (de2->sde->DIR_Atrr & ATTR_DIRECTORY)) {
                  return -1;
            }
      }

      if (OPT_LIST) return 0;

      if (OPT_NATURAL_SORT) {
            if (OPT_IGNORE_CASE) {
                  return natstrcasecmp(s1, s2) * OPT_REVERSE;
            } else {
                  return natstrcmp(s1, s2) * OPT_REVERSE;
            } 
      } else {
            if (OPT_IGNORE_CASE) {
                  return strcasecmp(s1, s2) * OPT_REVERSE;
            } else {
                  return strcmp(s1, s2) * OPT_REVERSE;
            }
      }
}

void insertDirEntryList(struct sDirEntryList *new, struct sDirEntryList *list) {
/*
      insert a directory entry into list
*/

      assert(new != NULL);
      assert(list != NULL);

      struct sDirEntryList *tmp, *dummy;

      tmp=list;
      
      // comparison is unnecessary for randomization and listing
      if (!OPT_LIST && !OPT_RANDOM) {
            while ((tmp->next != NULL) &&
            (cmpEntries(new, tmp->next) >= 0)) {
                  tmp=tmp->next;
            }
      }
      
      dummy=tmp->next;
      tmp->next=new;
      new->next=dummy;
}

void freeDirEntryList(struct sDirEntryList *list) {
/*
      free dir entry list
*/

      assert(list != NULL);

      struct sDirEntryList *tmp, *next;
      
      for (tmp = list; tmp; tmp = next) {
            next = tmp -> next;
            free (tmp);
      }
}

void randomizeDirEntryList(struct sDirEntryList *list, u_int32_t entries) {
/*
      randomize entry list
*/
      assert(list != NULL);

      struct sDirEntryList *randlist, *tmp, *dummy1, *dummy2;
      u_int32_t i, j, pos;
      
      randlist=list;
      for (i=0; i < entries; i++) {
            pos=irand(0, entries - 1 - i);
            
            tmp=randlist;
            // after the loop tmp->next is the selected item
            for (j=0; j<pos; j++) {
                  tmp=tmp->next;
            }
            
            // put selected entry to top of list
            dummy1=tmp->next;
            tmp->next=dummy1->next;

            dummy2=randlist->next;
            randlist->next=dummy1;
            dummy1->next=dummy2;
            
            randlist=randlist->next;
      }
}

Generated by  Doxygen 1.6.0   Back to index