2007-07-20 03:15:46 -08:00
|
|
|
/* ncdu - NCurses Disk Usage
|
|
|
|
|
|
2011-10-31 05:46:31 -08:00
|
|
|
Copyright (c) 2007-2011 Yoran Heling
|
2007-07-20 03:15:46 -08:00
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
|
a copy of this software and associated documentation files (the
|
|
|
|
|
"Software"), to deal in the Software without restriction, including
|
|
|
|
|
without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
|
distribute, sublicense, and/or sell copies of the Software, and to
|
|
|
|
|
permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
|
the following conditions:
|
|
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
|
|
|
in all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
|
|
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
|
|
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
|
|
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
|
|
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
2009-04-11 01:37:45 -08:00
|
|
|
#include "util.h"
|
2007-07-20 03:15:46 -08:00
|
|
|
|
2009-04-11 01:37:45 -08:00
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <ncurses.h>
|
|
|
|
|
|
|
|
|
|
int winrows, wincols;
|
|
|
|
|
int subwinr, subwinc;
|
|
|
|
|
|
|
|
|
|
char cropstrdat[4096];
|
2009-08-03 04:26:10 -08:00
|
|
|
char formatsizedat[9]; /* "xxx.xMiB" */
|
2007-08-01 07:01:42 -08:00
|
|
|
char fullsizedat[20]; /* max: 999.999.999.999.999 */
|
2009-04-23 11:15:11 -08:00
|
|
|
char *getpathdat;
|
|
|
|
|
int getpathdatl = 0;
|
2007-07-20 03:15:46 -08:00
|
|
|
|
2009-05-11 09:48:32 -08:00
|
|
|
struct dir **links;
|
|
|
|
|
int linksl = 0, linkst = 0;
|
|
|
|
|
|
2009-04-11 01:37:45 -08:00
|
|
|
|
|
|
|
|
char *cropstr(const char *from, int s) {
|
2007-07-20 03:15:46 -08:00
|
|
|
int i, j, o = strlen(from);
|
|
|
|
|
if(o < s) {
|
2009-04-11 01:37:45 -08:00
|
|
|
strcpy(cropstrdat, from);
|
|
|
|
|
return cropstrdat;
|
2007-07-20 03:15:46 -08:00
|
|
|
}
|
|
|
|
|
j=s/2-3;
|
|
|
|
|
for(i=0; i<j; i++)
|
2009-04-11 01:37:45 -08:00
|
|
|
cropstrdat[i] = from[i];
|
|
|
|
|
cropstrdat[i] = '.';
|
|
|
|
|
cropstrdat[++i] = '.';
|
|
|
|
|
cropstrdat[++i] = '.';
|
2007-07-20 03:15:46 -08:00
|
|
|
j=o-s;
|
|
|
|
|
while(++i<s)
|
2009-04-11 01:37:45 -08:00
|
|
|
cropstrdat[i] = from[j+i];
|
|
|
|
|
cropstrdat[s] = '\0';
|
|
|
|
|
return cropstrdat;
|
2007-07-20 03:15:46 -08:00
|
|
|
}
|
|
|
|
|
|
2009-04-11 01:37:45 -08:00
|
|
|
|
2009-04-18 04:05:45 -08:00
|
|
|
char *formatsize(const off_t from) {
|
2007-07-20 03:15:46 -08:00
|
|
|
float r = from;
|
|
|
|
|
char c = ' ';
|
2009-04-18 04:05:45 -08:00
|
|
|
if(r < 1000.0f) { }
|
2011-09-08 22:57:10 -08:00
|
|
|
else if(r < 1023e3f) { c = 'K'; r/=1024.0f; }
|
2009-04-18 04:05:45 -08:00
|
|
|
else if(r < 1023e6f) { c = 'M'; r/=1048576.0f; }
|
|
|
|
|
else if(r < 1023e9f) { c = 'G'; r/=1073741824.0f; }
|
|
|
|
|
else { c = 'T'; r/=1099511627776.0f; }
|
2009-08-03 04:26:10 -08:00
|
|
|
sprintf(formatsizedat, "%5.1f%c%cB", r, c, c == ' ' ? ' ' : 'i');
|
2009-04-11 01:37:45 -08:00
|
|
|
return formatsizedat;
|
2007-07-20 03:15:46 -08:00
|
|
|
}
|
|
|
|
|
|
2009-04-11 01:37:45 -08:00
|
|
|
|
2007-08-01 07:01:42 -08:00
|
|
|
char *fullsize(const off_t from) {
|
|
|
|
|
char tmp[20];
|
2007-08-16 00:36:58 -08:00
|
|
|
off_t n = from;
|
|
|
|
|
int i, j;
|
|
|
|
|
|
2009-04-11 01:37:45 -08:00
|
|
|
/* the K&R method - more portable than sprintf with %lld */
|
2007-08-16 00:36:58 -08:00
|
|
|
i = 0;
|
|
|
|
|
do {
|
|
|
|
|
tmp[i++] = n % 10 + '0';
|
|
|
|
|
} while((n /= 10) > 0);
|
|
|
|
|
tmp[i] = '\0';
|
|
|
|
|
|
2009-04-11 01:37:45 -08:00
|
|
|
/* reverse and add thousand seperators */
|
2007-08-16 00:36:58 -08:00
|
|
|
j = 0;
|
|
|
|
|
while(i--) {
|
|
|
|
|
fullsizedat[j++] = tmp[i];
|
|
|
|
|
if(i != 0 && i%3 == 0)
|
|
|
|
|
fullsizedat[j++] = '.';
|
2007-08-01 07:01:42 -08:00
|
|
|
}
|
2007-08-16 00:36:58 -08:00
|
|
|
fullsizedat[j] = '\0';
|
|
|
|
|
|
2009-04-11 01:37:45 -08:00
|
|
|
return fullsizedat;
|
2007-08-01 07:01:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-04-11 01:37:45 -08:00
|
|
|
int ncresize(int minrows, int mincols) {
|
2007-07-20 03:15:46 -08:00
|
|
|
int ch;
|
2009-04-11 01:37:45 -08:00
|
|
|
|
2007-07-20 03:15:46 -08:00
|
|
|
getmaxyx(stdscr, winrows, wincols);
|
2009-04-11 01:37:45 -08:00
|
|
|
while((minrows && winrows < minrows) || (mincols && wincols < mincols)) {
|
2007-07-20 03:15:46 -08:00
|
|
|
erase();
|
|
|
|
|
mvaddstr(0, 0, "Warning: terminal too small,");
|
|
|
|
|
mvaddstr(1, 1, "please either resize your terminal,");
|
|
|
|
|
mvaddstr(2, 1, "press i to ignore, or press q to quit.");
|
|
|
|
|
refresh();
|
|
|
|
|
nodelay(stdscr, 0);
|
|
|
|
|
ch = getch();
|
|
|
|
|
getmaxyx(stdscr, winrows, wincols);
|
|
|
|
|
if(ch == 'q') {
|
|
|
|
|
erase();
|
|
|
|
|
refresh();
|
|
|
|
|
endwin();
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
if(ch == 'i')
|
2009-04-11 01:37:45 -08:00
|
|
|
return 1;
|
2007-07-20 03:15:46 -08:00
|
|
|
}
|
2007-07-26 04:56:24 -08:00
|
|
|
erase();
|
2009-04-11 01:37:45 -08:00
|
|
|
return 0;
|
2007-07-20 03:15:46 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2007-08-16 00:36:58 -08:00
|
|
|
void nccreate(int height, int width, char *title) {
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
subwinr = winrows/2-height/2;
|
|
|
|
|
subwinc = wincols/2-width/2;
|
|
|
|
|
|
2009-04-11 01:37:45 -08:00
|
|
|
/* clear window */
|
2007-08-16 00:36:58 -08:00
|
|
|
for(i=0; i<height; i++)
|
|
|
|
|
mvhline(subwinr+i, subwinc, ' ', width);
|
|
|
|
|
|
2009-04-11 01:37:45 -08:00
|
|
|
/* box() only works around curses windows, so create our own */
|
2007-08-16 00:36:58 -08:00
|
|
|
move(subwinr, subwinc);
|
|
|
|
|
addch(ACS_ULCORNER);
|
|
|
|
|
for(i=0; i<width-2; i++)
|
|
|
|
|
addch(ACS_HLINE);
|
|
|
|
|
addch(ACS_URCORNER);
|
|
|
|
|
|
|
|
|
|
move(subwinr+height-1, subwinc);
|
|
|
|
|
addch(ACS_LLCORNER);
|
|
|
|
|
for(i=0; i<width-2; i++)
|
|
|
|
|
addch(ACS_HLINE);
|
|
|
|
|
addch(ACS_LRCORNER);
|
|
|
|
|
|
|
|
|
|
mvvline(subwinr+1, subwinc, ACS_VLINE, height-2);
|
|
|
|
|
mvvline(subwinr+1, subwinc+width-1, ACS_VLINE, height-2);
|
|
|
|
|
|
2009-04-11 01:37:45 -08:00
|
|
|
/* title */
|
2007-08-16 00:36:58 -08:00
|
|
|
attron(A_BOLD);
|
|
|
|
|
mvaddstr(subwinr, subwinc+4, title);
|
|
|
|
|
attroff(A_BOLD);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ncprint(int r, int c, char *fmt, ...) {
|
|
|
|
|
va_list arg;
|
|
|
|
|
va_start(arg, fmt);
|
|
|
|
|
move(subwinr+r, subwinc+c);
|
|
|
|
|
vw_printw(stdscr, fmt, arg);
|
|
|
|
|
va_end(arg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-03-03 04:40:56 -09:00
|
|
|
/* removes item from the hlnk circular linked list and size counts of the parents */
|
2010-02-27 01:29:36 -09:00
|
|
|
void freedir_hlnk(struct dir *d) {
|
2010-03-03 04:40:56 -09:00
|
|
|
struct dir *t, *par, *pt;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if(!(d->flags & FF_HLNKC))
|
2010-02-27 01:29:36 -09:00
|
|
|
return;
|
2010-03-03 04:40:56 -09:00
|
|
|
|
|
|
|
|
/* remove size from parents.
|
|
|
|
|
* This works the same as with adding: only the parents in which THIS is the
|
|
|
|
|
* only occurence of the hard link will be modified, if the same file still
|
|
|
|
|
* exists within the parent it shouldn't get removed from the count.
|
|
|
|
|
* XXX: Same note as for calc.c / calc_hlnk_check():
|
|
|
|
|
* this is probably not the most efficient algorithm */
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* remove from hlnk */
|
|
|
|
|
if(d->hlnk) {
|
|
|
|
|
for(t=d->hlnk; t->hlnk!=d; t=t->hlnk)
|
|
|
|
|
;
|
|
|
|
|
t->hlnk = d->hlnk;
|
|
|
|
|
}
|
2010-02-27 01:29:36 -09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2007-07-20 03:15:46 -08:00
|
|
|
void freedir_rec(struct dir *dr) {
|
|
|
|
|
struct dir *tmp, *tmp2;
|
|
|
|
|
tmp2 = dr;
|
|
|
|
|
while((tmp = tmp2) != NULL) {
|
2010-02-27 01:29:36 -09:00
|
|
|
freedir_hlnk(tmp);
|
|
|
|
|
/* remove item */
|
2007-07-20 03:15:46 -08:00
|
|
|
if(tmp->sub) freedir_rec(tmp->sub);
|
|
|
|
|
tmp2 = tmp->next;
|
|
|
|
|
free(tmp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-11 01:37:45 -08:00
|
|
|
|
2009-04-19 02:47:22 -08:00
|
|
|
void freedir(struct dir *dr) {
|
|
|
|
|
struct dir *tmp;
|
2007-07-20 03:15:46 -08:00
|
|
|
|
2009-04-19 02:47:22 -08:00
|
|
|
/* free dr->sub recursively */
|
|
|
|
|
if(dr->sub)
|
|
|
|
|
freedir_rec(dr->sub);
|
2007-07-20 03:15:46 -08:00
|
|
|
|
2009-04-11 01:37:45 -08:00
|
|
|
/* update references */
|
2010-04-27 07:01:43 -08:00
|
|
|
if(dr->parent && dr->parent->sub == dr)
|
|
|
|
|
dr->parent->sub = dr->next;
|
|
|
|
|
if(dr->prev)
|
|
|
|
|
dr->prev->next = dr->next;
|
|
|
|
|
if(dr->next)
|
|
|
|
|
dr->next->prev = dr->prev;
|
2007-07-20 03:15:46 -08:00
|
|
|
|
2010-02-27 01:29:36 -09:00
|
|
|
freedir_hlnk(dr);
|
2010-03-03 04:40:56 -09:00
|
|
|
|
|
|
|
|
/* update sizes of parent directories if this isn't a hard link.
|
|
|
|
|
* If this is a hard link, freedir_hlnk() would have done so already */
|
|
|
|
|
for(tmp=dr->parent; tmp; tmp=tmp->parent) {
|
|
|
|
|
if(!(dr->flags & FF_HLNKC)) {
|
|
|
|
|
tmp->size -= dr->size;
|
|
|
|
|
tmp->asize -= dr->asize;
|
|
|
|
|
}
|
|
|
|
|
tmp->items -= dr->items+1;
|
|
|
|
|
}
|
|
|
|
|
|
2007-07-20 03:15:46 -08:00
|
|
|
free(dr);
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-11 01:37:45 -08:00
|
|
|
|
2009-04-23 11:15:11 -08:00
|
|
|
char *getpath(struct dir *cur) {
|
|
|
|
|
struct dir *d, **list;
|
|
|
|
|
int c, i;
|
2007-07-26 08:37:33 -08:00
|
|
|
|
2009-04-26 03:10:00 -08:00
|
|
|
if(!cur->name[0])
|
|
|
|
|
return "/";
|
|
|
|
|
|
2009-04-23 11:15:11 -08:00
|
|
|
c = i = 1;
|
|
|
|
|
for(d=cur; d!=NULL; d=d->parent) {
|
|
|
|
|
i += strlen(d->name)+1;
|
|
|
|
|
c++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(getpathdatl == 0) {
|
|
|
|
|
getpathdatl = i;
|
|
|
|
|
getpathdat = malloc(i);
|
|
|
|
|
} else if(getpathdatl < i) {
|
|
|
|
|
getpathdatl = i;
|
|
|
|
|
getpathdat = realloc(getpathdat, i);
|
|
|
|
|
}
|
|
|
|
|
list = malloc(c*sizeof(struct dir *));
|
|
|
|
|
|
|
|
|
|
c = 0;
|
|
|
|
|
for(d=cur; d!=NULL; d=d->parent)
|
2007-07-26 08:37:33 -08:00
|
|
|
list[c++] = d;
|
|
|
|
|
|
2009-04-23 11:15:11 -08:00
|
|
|
getpathdat[0] = '\0';
|
2007-07-26 08:37:33 -08:00
|
|
|
while(c--) {
|
2009-04-23 11:15:11 -08:00
|
|
|
if(list[c]->parent)
|
|
|
|
|
strcat(getpathdat, "/");
|
|
|
|
|
strcat(getpathdat, list[c]->name);
|
2007-07-20 03:15:46 -08:00
|
|
|
}
|
2009-04-23 11:15:11 -08:00
|
|
|
free(list);
|
|
|
|
|
return getpathdat;
|
2007-07-20 03:15:46 -08:00
|
|
|
}
|
2009-04-11 01:37:45 -08:00
|
|
|
|