1
1

Link hard linked files together with a circular linked list

The directory sizes are now incorrect as hard links will be counted
twice again (as if there wasn't any detection in the first place), but
this will get fixed by adding a shared size field.

This method of keeping track of hard links is a lot faster and allows
adding an interface which lists the found links.
Этот коммит содержится в:
Yorhel 2010-02-27 11:29:36 +01:00
родитель 101731ed13
Коммит 88cd199d94
6 изменённых файлов: 94 добавлений и 105 удалений

Просмотреть файл

@ -176,7 +176,7 @@ void browse_draw_item(struct dir *n, int row, off_t max, int ispar) {
n->flags & FF_ERR ? '!' :
n->flags & FF_SERR ? '.' :
n->flags & FF_OTHFS ? '>' :
n->flags & FF_HLNK ? 'H' :
n->flags & FF_HLNKC ? 'H' :
!(n->flags & FF_FILE
|| n->flags & FF_DIR) ? '@' :
n->flags & FF_DIR

Просмотреть файл

@ -55,6 +55,9 @@ dev_t curdev; /* current device we're calculating on */
int anpos; /* position of the animation string */
int curpathl = 0, lasterrl = 0;
struct dir **links = NULL;
int linksl, linkst;
/* adds name to curpath */
@ -84,6 +87,63 @@ void calc_leavepath() {
}
/* looks in the links list and adds the file when not found */
int calc_hlink_add(struct dir *d) {
int i;
/* check the list */
for(i=0; i<linkst; i++)
if(links[i]->dev == d->dev && links[i]->ino == d->ino)
break;
/* found, do nothing and return the index */
if(i != linkst)
return i;
/* otherwise, add to list and return -1 */
if(++linkst > linksl) {
linksl *= 2;
if(!linksl) {
linksl = 64;
links = malloc(linksl*sizeof(struct dir *));
} else
links = realloc(links, linksl*sizeof(struct dir *));
}
links[linkst-1] = d;
return -1;
}
/* recursively checks a dir structure for hard links and fills the lookup array */
void calc_hlink_init(struct dir *d) {
struct dir *t;
for(t=d->sub; t!=NULL; t=t->next)
calc_hlink_init(t);
if(!(d->flags & FF_HLNKC))
return;
calc_hlink_add(d);
}
/* checks an individual file and updates the flags and cicrular linked list */
void calc_hlink_check(struct dir *d) {
struct dir *t;
int i;
d->flags |= FF_HLNKC;
i = calc_hlink_add(d);
/* found in the list? update hlnk */
if(i >= 0) {
t = d->hlnk = links[i];
if(t->hlnk != NULL)
for(t=t->hlnk; t->hlnk!=d->hlnk; t=t->hlnk)
;
t->hlnk = d;
return;
}
}
int calc_item(struct dir *par, char *name) {
struct dir *t, *d;
struct stat fs;
@ -131,11 +191,11 @@ int calc_item(struct dir *par, char *name) {
for(t=d->parent; t!=NULL; t=t->parent)
t->items++;
/* Provide the necessary information for hard link checking */
/* Hard link checking */
d->ino = fs.st_ino;
d->dev = fs.st_dev;
if(!S_ISDIR(fs.st_mode) && fs.st_nlink > 1)
d->flags |= FF_HLNKC;
calc_hlink_check(d);
/* count the size */
if(!(d->flags & FF_EXL || d->flags & FF_OTHFS)) {
@ -309,6 +369,14 @@ int calc_process() {
struct dir *t;
int n;
/* create initial links array */
linksl = linkst = 0;
if(orig) {
for(t=orig; t->parent!=NULL; t=t->parent)
;
calc_hlink_init(t);
}
/* check root directory */
if((path = path_real(curpath)) == NULL) {
failed = 1;
@ -384,6 +452,9 @@ int calc_process() {
free(name);
free(path);
if(links != NULL)
free(links);
/* success */
if(!n && !failed) {
if(root->sub == NULL) {
@ -414,8 +485,6 @@ int calc_process() {
}
freedir(orig);
}
link_del(root);
browse_init(root->sub);
return 0;
}
@ -436,8 +505,7 @@ calc_fail:
void calc_init(char *dir, struct dir *org) {
failed = anpos = 0;
if((orig = org) != NULL)
link_add(orig);
orig = org;
if(curpathl == 0) {
curpathl = strlen(dir)+1;
curpath = malloc(curpathl);

Просмотреть файл

@ -222,19 +222,13 @@ void delete_process() {
return;
}
/* temporarily re-add hard links, so we won't lose sizes in case we delete
a file of which another file outside this directory was marked as duplicate */
link_add(root);
/* chdir */
if(path_chdir(getpath(root->parent)) < 0) {
state = DS_FAILED;
lasterrno = errno;
while(state == DS_FAILED)
if(input_handle(0)) {
link_del(root);
if(input_handle(0))
return;
}
}
/* delete */
@ -247,8 +241,6 @@ void delete_process() {
nextsel->flags |= FF_BSEL;
browse_init(n);
}
if(n != NULL)
link_del(n);
}

Просмотреть файл

@ -38,9 +38,8 @@
#define FF_OTHFS 0x08 /* excluded because it was an other filesystem */
#define FF_EXL 0x10 /* excluded using exlude patterns */
#define FF_SERR 0x20 /* error in subdirectory */
#define FF_HLNK 0x40 /* hard link (same file already encountered before) */
#define FF_HLNKC 0x80 /* hard link candidate (file with st_nlink > 1) */
#define FF_BSEL 0x100 /* selected */
#define FF_HLNKC 0x40 /* hard link candidate (file with st_nlink > 1) */
#define FF_BSEL 0x80 /* selected */
/* Program states */
#define ST_CALC 0
@ -51,11 +50,11 @@
/* structure representing a file or directory */
struct dir {
struct dir *parent, *next, *sub;
struct dir *parent, *next, *sub, *hlnk;
char *name;
off_t size, asize;
unsigned long items;
unsigned short flags;
unsigned char flags;
dev_t dev;
ino_t ino;
};

Просмотреть файл

@ -169,10 +169,23 @@ void ncprint(int r, int c, char *fmt, ...) {
}
/* removes item from the hlnk circular linked list */
void freedir_hlnk(struct dir *d) {
struct dir *t;
if(!d->hlnk)
return;
for(t=d->hlnk; t->hlnk!=d; t=t->hlnk)
;
t->hlnk = d->hlnk;
}
void freedir_rec(struct dir *dr) {
struct dir *tmp, *tmp2;
tmp2 = dr;
while((tmp = tmp2) != NULL) {
freedir_hlnk(tmp);
/* remove item */
if(tmp->sub) freedir_rec(tmp->sub);
free(tmp->name);
tmp2 = tmp->next;
@ -208,6 +221,7 @@ void freedir(struct dir *dr) {
tmp->next = dr->next;
}
freedir_hlnk(dr);
free(dr->name);
free(dr);
}
@ -249,81 +263,3 @@ char *getpath(struct dir *cur) {
return getpathdat;
}
/* act = 0 -> just fill the links array
act = 1 -> fill array and remove duplicates
act = -1 -> use array to re-add duplicates */
void link_list_rec(struct dir *d, int act) {
struct dir *t;
int i;
/* recursion, check sub directories */
for(t=d->sub; t!=NULL; t=t->next)
link_list_rec(t, act);
/* not a link candidate? ignore */
if(!(d->flags & FF_HLNKC))
return;
/* check against what we've found so far */
for(i=0; i<linkst; i++)
if(links[i]->dev == d->dev && links[i]->ino == d->ino)
break;
/* found in the list, set link flag and set size to zero */
if(act == 1 && i != linkst) {
d->flags |= FF_HLNK;
for(t=d->parent; t!=NULL; t=t->parent) {
t->size -= d->size;
t->asize -= d->asize;
}
d->size = d->asize = 0;
return;
}
/* found in the list, reset flag and re-add size */
if(act == -1 && i != linkst && d->flags & FF_HLNK) {
d->flags -= FF_HLNK;
d->size = links[i]->size;
d->asize = links[i]->asize;
for(t=d->parent; t!=NULL; t=t->parent) {
t->size += d->size;
t->asize += d->asize;
}
}
/* not found, add to the list */
if(act == 1 || (act == 0 && !(d->flags & FF_HLNK))) {
if(++linkst > linksl) {
linksl *= 2;
if(!linksl) {
linksl = 64;
links = malloc(linksl*sizeof(struct dir *));
} else
links = realloc(links, linksl*sizeof(struct dir *));
}
links[i] = d;
}
}
void link_del(struct dir *par) {
while(par->parent != NULL)
par = par->parent;
link_list_rec(par, 1);
linkst = 0;
}
void link_add(struct dir *par) {
while(par->parent != NULL)
par = par->parent;
/* In order to correctly re-add the duplicates, we'll have to pass the entire
tree twice, one time to get a list of all links, second time to re-add them */
link_list_rec(par, 0);
link_list_rec(par, -1);
linkst = 0;
}

Просмотреть файл

@ -78,11 +78,5 @@ void freedir(struct dir *);
returned pointer will be overwritten with a subsequent call */
char *getpath(struct dir *);
/* removes all hard links from a tree */
void link_del(struct dir *);
/* re-adds all hard links in a tree */
void link_add(struct dir *);
#endif