mirror of
https://code.blicky.net/yorhel/ncdu.git
synced 2026-01-15 18:18:41 -09:00
Split path handling into path.c and replaced rpath() with a better implementation
This is the first step into replacing all code that relies on PATH_MAX, more changes will follow.
This commit is contained in:
parent
1739ee74d6
commit
7698bfd980
4 changed files with 296 additions and 122 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
bin_PROGRAMS = ncdu
|
bin_PROGRAMS = ncdu
|
||||||
|
|
||||||
ncdu_SOURCES = browser.c calc.c delete.c exclude.c help.c main.c util.c
|
ncdu_SOURCES = browser.c calc.c delete.c exclude.c help.c main.c path.c util.c
|
||||||
|
|
||||||
noinst_HEADERS = browser.h calc.h delete.h exclude.h help.h ncdu.h util.h
|
noinst_HEADERS = browser.h calc.h delete.h exclude.h help.h ncdu.h path.h util.h
|
||||||
|
|
|
||||||
124
src/calc.c
124
src/calc.c
|
|
@ -28,6 +28,7 @@
|
||||||
#include "exclude.h"
|
#include "exclude.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "browser.h"
|
#include "browser.h"
|
||||||
|
#include "path.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
@ -45,21 +46,6 @@
|
||||||
# define S_BLKSIZE 512
|
# define S_BLKSIZE 512
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef LINK_MAX
|
|
||||||
# ifdef _POSIX_LINK_MAX
|
|
||||||
# define LINK_MAX _POSIX_LINK_MAX
|
|
||||||
# else
|
|
||||||
# define LINK_MAX 32
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef S_ISLNK
|
|
||||||
# ifndef S_IFLNK
|
|
||||||
# define S_IFLNK 0120000
|
|
||||||
# endif
|
|
||||||
# define S_ISLNK(x) (x & S_IFLNK)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* external vars */
|
/* external vars */
|
||||||
int calc_delay = 100;
|
int calc_delay = 100;
|
||||||
|
|
@ -77,107 +63,6 @@ long lastupdate; /* time of the last screen update */
|
||||||
int anpos; /* position of the animation string */
|
int anpos; /* position of the animation string */
|
||||||
|
|
||||||
|
|
||||||
/* My own implementation of realpath()
|
|
||||||
- assumes that *every* possible path fits in PATH_MAX bytes
|
|
||||||
- does not set errno on error
|
|
||||||
- has not yet been fully tested
|
|
||||||
*/
|
|
||||||
char *rpath(const char *from, char *to) {
|
|
||||||
char tmp[PATH_MAX], cwd[PATH_MAX], cur[PATH_MAX], app[PATH_MAX];
|
|
||||||
int i, j, l, k, last, ll = 0;
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
getcwd(cwd, PATH_MAX);
|
|
||||||
strcpy(cur, from);
|
|
||||||
app[0] = 0;
|
|
||||||
|
|
||||||
loop:
|
|
||||||
/* not an absolute path, add current directory */
|
|
||||||
if(cur[0] != '/') {
|
|
||||||
if(!(cwd[0] == '/' && cwd[1] == 0))
|
|
||||||
strcpy(tmp, cwd);
|
|
||||||
else
|
|
||||||
tmp[0] = 0;
|
|
||||||
if(strlen(cur) + 2 > PATH_MAX - strlen(tmp))
|
|
||||||
return(NULL);
|
|
||||||
strcat(tmp, "/");
|
|
||||||
strcat(tmp, cur);
|
|
||||||
} else
|
|
||||||
strcpy(tmp, cur);
|
|
||||||
|
|
||||||
/* now fix things like '.' and '..' */
|
|
||||||
i = j = last = 0;
|
|
||||||
l = strlen(tmp);
|
|
||||||
while(1) {
|
|
||||||
if(tmp[i] == 0)
|
|
||||||
break;
|
|
||||||
/* . */
|
|
||||||
if(l >= i+2 && tmp[i] == '/' && tmp[i+1] == '.' && (tmp[i+2] == 0 || tmp[i+2] == '/')) {
|
|
||||||
i+= 2;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* .. */
|
|
||||||
if(l >= i+3 && tmp[i] == '/' && tmp[i+1] == '.' && tmp[i+2] == '.' && (tmp[i+3] == 0 || tmp[i+3] == '/')) {
|
|
||||||
for(k=j; --k>0;)
|
|
||||||
if(to[k] == '/' && k != j-1)
|
|
||||||
break;
|
|
||||||
j -= j-k;
|
|
||||||
if(j < 1) j = 1;
|
|
||||||
i += 3;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* remove double slashes */
|
|
||||||
if(tmp[i] == '/' && i>0 && tmp[i-1] == '/') {
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
to[j++] = tmp[i++];
|
|
||||||
}
|
|
||||||
/* remove leading slashes */
|
|
||||||
while(--j > 0) {
|
|
||||||
if(to[j] != '/')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
to[j+1] = 0;
|
|
||||||
/* make sure we do have something left in case our path is / */
|
|
||||||
if(to[0] == 0) {
|
|
||||||
to[0] = '/';
|
|
||||||
to[1] = 0;
|
|
||||||
}
|
|
||||||
/* append 'app' */
|
|
||||||
if(app[0] != 0)
|
|
||||||
strcat(to, app);
|
|
||||||
|
|
||||||
j = strlen(to);
|
|
||||||
/* check for symlinks */
|
|
||||||
for(i=1; i<=j; i++) {
|
|
||||||
if(to[i] == '/' || to[i] == 0) {
|
|
||||||
strncpy(tmp, to, i);
|
|
||||||
tmp[i] = 0;
|
|
||||||
if(lstat(tmp, &st) < 0)
|
|
||||||
return(NULL);
|
|
||||||
if(S_ISLNK(st.st_mode)) {
|
|
||||||
if(++ll > LINK_MAX || (k = readlink(tmp, cur, PATH_MAX)) < 0)
|
|
||||||
return(NULL);
|
|
||||||
cur[k] = 0;
|
|
||||||
if(to[i] != 0)
|
|
||||||
strcpy(app, &to[i]);
|
|
||||||
strcpy(cwd, tmp);
|
|
||||||
for(k=strlen(cwd); --k>0;)
|
|
||||||
if(cwd[k] == '/')
|
|
||||||
break;
|
|
||||||
cwd[k] = 0;
|
|
||||||
goto loop;
|
|
||||||
}
|
|
||||||
if(!S_ISDIR(st.st_mode))
|
|
||||||
return(NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return(to);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int calc_item(struct dir *par, char *path, char *name) {
|
int calc_item(struct dir *par, char *path, char *name) {
|
||||||
char tmp[PATH_MAX];
|
char tmp[PATH_MAX];
|
||||||
struct dir *t, *d;
|
struct dir *t, *d;
|
||||||
|
|
@ -400,12 +285,12 @@ int calc_key(int ch) {
|
||||||
|
|
||||||
|
|
||||||
void calc_process() {
|
void calc_process() {
|
||||||
char tmp[PATH_MAX];
|
char *tmp;
|
||||||
struct stat fs;
|
struct stat fs;
|
||||||
struct dir *t;
|
struct dir *t;
|
||||||
|
|
||||||
/* check root directory */
|
/* check root directory */
|
||||||
if(rpath(curpath, tmp) == NULL || lstat(tmp, &fs) != 0 || !S_ISDIR(fs.st_mode)) {
|
if((tmp = path_real(curpath)) == NULL || lstat(tmp, &fs) != 0 || !S_ISDIR(fs.st_mode)) {
|
||||||
failed = 1;
|
failed = 1;
|
||||||
strcpy(errmsg, "Directory not found");
|
strcpy(errmsg, "Directory not found");
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
@ -416,8 +301,7 @@ void calc_process() {
|
||||||
t->size = fs.st_blocks * S_BLKSIZE;
|
t->size = fs.st_blocks * S_BLKSIZE;
|
||||||
t->asize = fs.st_size;
|
t->asize = fs.st_size;
|
||||||
t->flags |= FF_DIR;
|
t->flags |= FF_DIR;
|
||||||
t->name = (char *) malloc(strlen(tmp)+1);
|
t->name = tmp;
|
||||||
strcpy(t->name, orig ? orig->name : tmp);
|
|
||||||
root = t;
|
root = t;
|
||||||
curdev = fs.st_dev;
|
curdev = fs.st_dev;
|
||||||
|
|
||||||
|
|
|
||||||
243
src/path.c
Normal file
243
src/path.c
Normal file
|
|
@ -0,0 +1,243 @@
|
||||||
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
|
Copyright (c) 2007-2009 Yoran Heling
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "path.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
#ifndef LINK_MAX
|
||||||
|
# ifdef _POSIX_LINK_MAX
|
||||||
|
# define LINK_MAX _POSIX_LINK_MAX
|
||||||
|
# else
|
||||||
|
# define LINK_MAX 32
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define RPATH_CNKSZ 256
|
||||||
|
|
||||||
|
|
||||||
|
/* splits a path into components and does a bit of cannonicalization.
|
||||||
|
a pointer to a reversed array of components is stored in res and the
|
||||||
|
number of components is returned.
|
||||||
|
cur is modified, and res has to be free()d after use */
|
||||||
|
int path_split(char *cur, char ***res) {
|
||||||
|
char **old;
|
||||||
|
int i, j, n;
|
||||||
|
|
||||||
|
cur += strspn(cur, "/");
|
||||||
|
n = strlen(cur);
|
||||||
|
|
||||||
|
/* replace slashes with zeros */
|
||||||
|
for(i=j=0; i<n; i++)
|
||||||
|
if(cur[i] == '/') {
|
||||||
|
cur[i] = 0;
|
||||||
|
if(cur[i-1] != 0)
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create array of the components */
|
||||||
|
old = malloc((j+1)*sizeof(char *));
|
||||||
|
*res = malloc((j+1)*sizeof(char *));
|
||||||
|
for(i=j=0; i<n; i++)
|
||||||
|
if(i == 0 || (cur[i-1] == 0 && cur[i] != 0))
|
||||||
|
old[j++] = cur+i;
|
||||||
|
|
||||||
|
/* re-order and remove parts */
|
||||||
|
for(i=n=0; --j>=0; ) {
|
||||||
|
if(!strcmp(old[j], "..")) {
|
||||||
|
n++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(!strcmp(old[j], "."))
|
||||||
|
continue;
|
||||||
|
if(n) {
|
||||||
|
n--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
(*res)[i++] = old[j];
|
||||||
|
}
|
||||||
|
free(old);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* copies path and prepends cwd if needed, to ensure an absolute path
|
||||||
|
return value has to be free()'d manually */
|
||||||
|
char *path_absolute(const char *path) {
|
||||||
|
int i, n;
|
||||||
|
char *ret;
|
||||||
|
|
||||||
|
/* not an absolute path? prepend cwd */
|
||||||
|
if(path[0] != '/') {
|
||||||
|
n = RPATH_CNKSZ;
|
||||||
|
ret = malloc(n);
|
||||||
|
errno = 0;
|
||||||
|
while(!getcwd(ret, n) && errno == ERANGE) {
|
||||||
|
n += RPATH_CNKSZ;
|
||||||
|
ret = realloc(ret, n);
|
||||||
|
errno = 0;
|
||||||
|
}
|
||||||
|
if(errno) {
|
||||||
|
free(ret);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = strlen(path) + strlen(ret) + 2;
|
||||||
|
if(i > n)
|
||||||
|
ret = realloc(ret, i);
|
||||||
|
strcat(ret, "/");
|
||||||
|
strcat(ret, path);
|
||||||
|
/* otherwise, just make a copy */
|
||||||
|
} else {
|
||||||
|
ret = malloc(strlen(path)+1);
|
||||||
|
strcpy(ret, path);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* NOTE: cwd and the memory cur points to are unreliable after calling this function */
|
||||||
|
char *path_real_rec(char *cur, int *links) {
|
||||||
|
int i, j, n, tmpl, lnkl = 0;
|
||||||
|
char **arr, *tmp, *lnk, *ret = NULL;
|
||||||
|
|
||||||
|
tmpl = strlen(cur);
|
||||||
|
tmp = malloc(tmpl);
|
||||||
|
|
||||||
|
/* split path */
|
||||||
|
i = path_split(cur, &arr);
|
||||||
|
|
||||||
|
/* re-create full path */
|
||||||
|
strcpy(tmp, "/");
|
||||||
|
if(i > 0) {
|
||||||
|
j = 1;
|
||||||
|
lnkl = RPATH_CNKSZ;
|
||||||
|
lnk = malloc(lnkl);
|
||||||
|
if(chdir("/") < 0)
|
||||||
|
goto path_real_done;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(--i>=0) {
|
||||||
|
if(arr[i][0] == 0)
|
||||||
|
continue;
|
||||||
|
/* check for symlink */
|
||||||
|
while((n = readlink(arr[i], lnk, lnkl)) == lnkl || (n < 0 && errno == ERANGE)) {
|
||||||
|
lnkl += RPATH_CNKSZ;
|
||||||
|
lnk = realloc(lnk, lnkl);
|
||||||
|
}
|
||||||
|
if(n < 0 && errno != EINVAL)
|
||||||
|
goto path_real_done;
|
||||||
|
if(n > 0) {
|
||||||
|
if(++*links > LINK_MAX) {
|
||||||
|
errno = ELOOP;
|
||||||
|
goto path_real_done;
|
||||||
|
}
|
||||||
|
lnk[n] = 0;
|
||||||
|
/* create new path and call path_real_rec() again */
|
||||||
|
if(lnk[0] != '/') {
|
||||||
|
n += strlen(tmp) + 1;
|
||||||
|
if(tmpl < n) {
|
||||||
|
tmpl = n;
|
||||||
|
tmp = realloc(tmp, tmpl);
|
||||||
|
}
|
||||||
|
strcat(tmp, lnk);
|
||||||
|
} else
|
||||||
|
strcpy(tmp, lnk);
|
||||||
|
ret = path_real_rec(tmp, links);
|
||||||
|
goto path_real_done;
|
||||||
|
}
|
||||||
|
/* not a symlink, append component and go to the next part */
|
||||||
|
strcat(tmp, arr[i]);
|
||||||
|
if(i) {
|
||||||
|
if(chdir(arr[i]) < 0)
|
||||||
|
goto path_real_done;
|
||||||
|
strcat(tmp, "/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = tmp;
|
||||||
|
|
||||||
|
path_real_done:
|
||||||
|
if(ret != tmp)
|
||||||
|
free(tmp);
|
||||||
|
if(lnkl > 0)
|
||||||
|
free(lnk);
|
||||||
|
free(arr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *path_real(const char *orig) {
|
||||||
|
int links = 0;
|
||||||
|
char *tmp, *ret;
|
||||||
|
DIR *d;
|
||||||
|
|
||||||
|
if(orig == NULL)
|
||||||
|
return NULL;
|
||||||
|
if((d = opendir(".")) == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
tmp = path_absolute(orig);
|
||||||
|
ret = path_real_rec(tmp, &links);
|
||||||
|
free(tmp);
|
||||||
|
fchdir(dirfd(d));
|
||||||
|
closedir(d);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int path_chdir(const char *path) {
|
||||||
|
char **arr, *cur;
|
||||||
|
int i, r = -1;
|
||||||
|
DIR *d;
|
||||||
|
|
||||||
|
if((d = opendir(".")) == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if((cur = path_absolute(path)) == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
i = path_split(cur, &arr);
|
||||||
|
if(chdir("/") < 0)
|
||||||
|
goto path_chdir_done;
|
||||||
|
while(--i >= 0)
|
||||||
|
if(chdir(arr[i]) < 0)
|
||||||
|
goto path_chdir_done;
|
||||||
|
r = 0;
|
||||||
|
|
||||||
|
path_chdir_done:
|
||||||
|
if(r < 0)
|
||||||
|
fchdir(dirfd(d));
|
||||||
|
free(cur);
|
||||||
|
free(arr);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
47
src/path.h
Normal file
47
src/path.h
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
|
Copyright (c) 2007-2009 Yoran Heling
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
path.c reimplements realpath() and chdir(), both functions accept
|
||||||
|
arbitrary long path names not limited by PATH_MAX.
|
||||||
|
|
||||||
|
Caveats/bugs:
|
||||||
|
- path_real uses chdir(), so it's not thread safe
|
||||||
|
- Process requires +x access for all directory components
|
||||||
|
- Potentionally slow
|
||||||
|
- Doesn't check return value of malloc() and realloc()
|
||||||
|
- path_real doesn't check for the existance of the last component
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _path_h
|
||||||
|
#define _path_h
|
||||||
|
|
||||||
|
/* path_real reimplements realpath(). The returned string is allocated
|
||||||
|
by malloc() and should be manually free()d by the programmer. */
|
||||||
|
extern char *path_real(const char *);
|
||||||
|
|
||||||
|
/* works exactly the same as chdir() */
|
||||||
|
extern int path_chdir(const char *);
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Reference in a new issue