2007-07-20 03:15:46 -08:00
|
|
|
/* ncdu - NCurses Disk Usage
|
|
|
|
|
|
2010-02-27 05:20:57 -09:00
|
|
|
Copyright (c) 2007-2010 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-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) { }
|
|
|
|
|
else if(r < 1023e3f) { c = 'k'; r/=1024.0f; }
|
|
|
|
|
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-05-10 01:08:44 -08:00
|
|
|
void freedir_hlnk(compll_t d) {
|
|
|
|
|
compll_t t, par, pt;
|
2010-03-03 04:40:56 -09:00
|
|
|
int i;
|
|
|
|
|
|
2010-05-10 01:08:44 -08:00
|
|
|
if(!(DR(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 */
|
2010-05-10 01:08:44 -08:00
|
|
|
for(i=1,par=DR(d)->parent; i&∥ par=DR(par)->parent) {
|
|
|
|
|
if(DR(d)->hlnk)
|
|
|
|
|
for(t=DR(d)->hlnk; i&&t!=d; t=DR(t)->hlnk)
|
|
|
|
|
for(pt=DR(t)->parent; i&&pt; pt=DR(pt)->parent)
|
2010-03-03 04:40:56 -09:00
|
|
|
if(pt==par)
|
|
|
|
|
i=0;
|
|
|
|
|
if(i) {
|
2010-05-10 01:08:44 -08:00
|
|
|
DW(par)->size -= DR(d)->size;
|
|
|
|
|
DW(par)->asize -= DR(d)->asize;
|
2010-03-03 04:40:56 -09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* remove from hlnk */
|
2010-05-10 01:08:44 -08:00
|
|
|
if(DR(d)->hlnk) {
|
|
|
|
|
for(t=DR(d)->hlnk; DR(t)->hlnk!=d; t=DR(t)->hlnk)
|
2010-03-03 04:40:56 -09:00
|
|
|
;
|
2010-05-10 01:08:44 -08:00
|
|
|
DW(t)->hlnk = DR(d)->hlnk;
|
2010-03-03 04:40:56 -09:00
|
|
|
}
|
2010-02-27 01:29:36 -09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-05-10 01:08:44 -08:00
|
|
|
void freedir_rec(compll_t dr) {
|
|
|
|
|
compll_t tmp, tmp2;
|
2007-07-20 03:15:46 -08:00
|
|
|
tmp2 = dr;
|
2010-05-10 01:08:44 -08:00
|
|
|
while((tmp = tmp2)) {
|
2010-02-27 01:29:36 -09:00
|
|
|
freedir_hlnk(tmp);
|
|
|
|
|
/* remove item */
|
2010-05-10 01:08:44 -08:00
|
|
|
if(DR(tmp)->sub) freedir_rec(DR(tmp)->sub);
|
|
|
|
|
tmp2 = DR(tmp)->next;
|
|
|
|
|
compll_free(tmp);
|
2007-07-20 03:15:46 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-10 01:08:44 -08:00
|
|
|
void freedir(compll_t dr) {
|
|
|
|
|
compll_t tmp;
|
2007-07-20 03:15:46 -08:00
|
|
|
|
2009-04-19 02:47:22 -08:00
|
|
|
/* free dr->sub recursively */
|
2010-05-10 01:08:44 -08:00
|
|
|
if(DR(dr)->sub)
|
|
|
|
|
freedir_rec(DR(dr)->sub);
|
2007-07-20 03:15:46 -08:00
|
|
|
|
2009-04-11 01:37:45 -08:00
|
|
|
/* update references */
|
2010-05-10 01:08:44 -08:00
|
|
|
if(DR(dr)->parent && DR(DR(dr)->parent)->sub == dr)
|
|
|
|
|
DW(DR(dr)->parent)->sub = DR(dr)->next;
|
|
|
|
|
if(DR(dr)->prev)
|
|
|
|
|
DW(DR(dr)->prev)->next = DR(dr)->next;
|
|
|
|
|
if(DR(dr)->next)
|
|
|
|
|
DW(DR(dr)->next)->prev = DR(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 */
|
2010-05-10 01:08:44 -08:00
|
|
|
for(tmp=DR(dr)->parent; tmp; tmp=DR(tmp)->parent) {
|
|
|
|
|
if(!(DR(dr)->flags & FF_HLNKC)) {
|
|
|
|
|
DW(tmp)->size -= DR(dr)->size;
|
|
|
|
|
DW(tmp)->asize -= DR(dr)->asize;
|
2010-03-03 04:40:56 -09:00
|
|
|
}
|
2010-05-10 01:08:44 -08:00
|
|
|
DW(tmp)->items -= DR(dr)->items+1;
|
2010-03-03 04:40:56 -09:00
|
|
|
}
|
|
|
|
|
|
2010-05-10 01:08:44 -08:00
|
|
|
compll_free(dr);
|
2007-07-20 03:15:46 -08:00
|
|
|
}
|
|
|
|
|
|
2009-04-11 01:37:45 -08:00
|
|
|
|
2010-05-10 01:08:44 -08:00
|
|
|
char *getpath(compll_t cur) {
|
|
|
|
|
compll_t d, *list;
|
2009-04-23 11:15:11 -08:00
|
|
|
int c, i;
|
2007-07-26 08:37:33 -08:00
|
|
|
|
2010-05-10 01:08:44 -08:00
|
|
|
if(!DR(cur)->name[0])
|
2009-04-26 03:10:00 -08:00
|
|
|
return "/";
|
|
|
|
|
|
2009-04-23 11:15:11 -08:00
|
|
|
c = i = 1;
|
2010-05-10 01:08:44 -08:00
|
|
|
for(d=cur; d; d=DR(d)->parent) {
|
|
|
|
|
i += strlen(DR(d)->name)+1;
|
2009-04-23 11:15:11 -08:00
|
|
|
c++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(getpathdatl == 0) {
|
|
|
|
|
getpathdatl = i;
|
|
|
|
|
getpathdat = malloc(i);
|
|
|
|
|
} else if(getpathdatl < i) {
|
|
|
|
|
getpathdatl = i;
|
|
|
|
|
getpathdat = realloc(getpathdat, i);
|
|
|
|
|
}
|
2010-05-10 01:08:44 -08:00
|
|
|
list = malloc(c*sizeof(compll_t));
|
2009-04-23 11:15:11 -08:00
|
|
|
|
|
|
|
|
c = 0;
|
2010-05-10 01:08:44 -08:00
|
|
|
for(d=cur; d; d=DR(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--) {
|
2010-05-10 01:08:44 -08:00
|
|
|
if(DR(list[c])->parent)
|
2009-04-23 11:15:11 -08:00
|
|
|
strcat(getpathdat, "/");
|
2010-05-10 01:08:44 -08:00
|
|
|
strcat(getpathdat, DR(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
|
|
|
|