1
1

Only count the size of each hard link once for each directory

The displayed directory sizes are now fully correct, although in its
current state it's not all that intuitive because:

  directory size != sum(size of all files and subdirectories)

This should probably be fixed later on by splitting the sizes into a
shared and non-shared part.

Also, the sizes displayed after a recalculation or deletion are
incorrect, I'll fix this later on.
Этот коммит содержится в:
Yorhel 2010-02-28 16:50:43 +01:00
родитель 82ec5b9fa8
Коммит 1cc0e5a50f
3 изменённых файлов: 46 добавлений и 23 удалений

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

@ -124,9 +124,10 @@ void calc_hlink_init(struct dir *d) {
} }
/* checks an individual file and updates the flags and cicrular linked list */ /* checks an individual file and updates the flags and cicrular linked list,
* also updates the sizes of the parent dirs */
void calc_hlink_check(struct dir *d) { void calc_hlink_check(struct dir *d) {
struct dir *t; struct dir *t, *pt, *par;
int i; int i;
d->flags |= FF_HLNKC; d->flags |= FF_HLNKC;
@ -139,7 +140,22 @@ void calc_hlink_check(struct dir *d) {
for(t=t->hlnk; t->hlnk!=d->hlnk; t=t->hlnk) for(t=t->hlnk; t->hlnk!=d->hlnk; t=t->hlnk)
; ;
t->hlnk = d; t->hlnk = d;
return; }
/* now update the sizes of the parent directories,
* This works by only counting this file in the parent directories where this
* file hasn't been counted yet, which can be determined from the hlnk list.
* XXX: This may not be the most efficient algorithm to do this */
for(i=1,par=d->parent; i&∥ par=par->parent) {
if(d->hlnk)
for(t=d->hlnk; i&&t!=d; t=t->hlnk)
for(pt=t->parent; i&&pt; pt=pt->parent)
if(pt==par)
i=0;
if(i) {
par->size += d->size;
par->asize += d->asize;
}
} }
} }
@ -186,27 +202,29 @@ int calc_item(struct dir *par, char *name) {
else if(S_ISDIR(fs.st_mode)) else if(S_ISDIR(fs.st_mode))
d->flags |= FF_DIR; d->flags |= FF_DIR;
/* update parent dirs */ /* update the items count of the parent dirs */
if(!(d->flags & FF_EXL)) if(!(d->flags & FF_EXL))
for(t=d->parent; t!=NULL; t=t->parent) for(t=d->parent; t!=NULL; t=t->parent)
t->items++; t->items++;
/* Hard link checking */
d->ino = fs.st_ino;
d->dev = fs.st_dev;
if(!S_ISDIR(fs.st_mode) && fs.st_nlink > 1)
calc_hlink_check(d);
/* count the size */ /* count the size */
if(!(d->flags & FF_EXL || d->flags & FF_OTHFS)) { if(!(d->flags & FF_EXL || d->flags & FF_OTHFS)) {
d->size = fs.st_blocks * S_BLKSIZE; d->size = fs.st_blocks * S_BLKSIZE;
d->asize = fs.st_size; d->asize = fs.st_size;
for(t=d->parent; t!=NULL; t=t->parent) { /* only update the sizes of the parents if it's not a hard link */
t->size += d->size; if(S_ISDIR(fs.st_mode) || fs.st_nlink <= 1)
t->asize += d->asize; for(t=d->parent; t!=NULL; t=t->parent) {
} t->size += d->size;
t->asize += d->asize;
}
} }
/* Hard link checking (also takes care of updating the sizes of the parents) */
d->ino = fs.st_ino;
d->dev = fs.st_dev;
if(!S_ISDIR(fs.st_mode) && fs.st_nlink > 1)
calc_hlink_check(d);
return 0; return 0;
} }
@ -421,6 +439,7 @@ int calc_process() {
if(orig) { if(orig) {
t->name = malloc(strlen(orig->name)+1); t->name = malloc(strlen(orig->name)+1);
strcpy(t->name, orig->name); strcpy(t->name, orig->name);
t->parent = orig->parent;
} else { } else {
t->name = malloc(strlen(path)+strlen(name)+2); t->name = malloc(strlen(path)+strlen(name)+2);
t->name[0] = 0; t->name[0] = 0;
@ -434,6 +453,14 @@ int calc_process() {
root = t; root = t;
curdev = fs.st_dev; curdev = fs.st_dev;
/* make sure to count this directory entry in its parents at this point */
if(orig)
for(t=root->parent; t!=NULL; t=t->parent) {
t->size += root->size;
t->asize += root->asize;
t->items += 1;
}
/* update curpath */ /* update curpath */
if(strcmp(name, ".")) { if(strcmp(name, ".")) {
if((int)strlen(path)+1 > curpathl) { if((int)strlen(path)+1 > curpathl) {
@ -468,14 +495,7 @@ int calc_process() {
/* update references and free original item */ /* update references and free original item */
if(orig) { if(orig) {
root->parent = orig->parent;
root->next = orig->next; root->next = orig->next;
for(t=root->parent; t!=NULL; t=t->parent) {
t->size += root->size;
t->asize += root->asize;
t->items += root->items+1;
}
if(orig->parent) { if(orig->parent) {
t = orig->parent->sub; t = orig->parent->sub;
if(t == orig) if(t == orig)

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

@ -48,7 +48,9 @@
#define ST_HELP 3 #define ST_HELP 3
/* structure representing a file or directory */ /* structure representing a file or directory
* XXX: probably a good idea to get rid of the custom _t types and use
* fixed-size integers instead, which are much more predictable */
struct dir { struct dir {
struct dir *parent, *next, *sub, *hlnk; struct dir *parent, *next, *sub, *hlnk;
char *name; char *name;

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

@ -197,7 +197,8 @@ void freedir_rec(struct dir *dr) {
void freedir(struct dir *dr) { void freedir(struct dir *dr) {
struct dir *tmp; struct dir *tmp;
/* update sizes of parent directories */ /* update sizes of parent directories
* XXX: This breaks when the dir contains hard linked files */
tmp = dr; tmp = dr;
while((tmp = tmp->parent) != NULL) { while((tmp = tmp->parent) != NULL) {
tmp->size -= dr->size; tmp->size -= dr->size;