|
|
|
@ -18,13 +18,20 @@ usage(std::ostream& os, const char* name, int code){
|
|
|
|
|
exit(code);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// context as configured on the command line
|
|
|
|
|
struct lsContext {
|
|
|
|
|
bool longlisting;
|
|
|
|
|
bool recursedirs;
|
|
|
|
|
bool directories;
|
|
|
|
|
bool dereflinks;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
handle_path(const char* p, bool longlisting, bool recursedirs,
|
|
|
|
|
bool directories, bool dereflinks, bool toplevel);
|
|
|
|
|
handle_path(const char* p, const lsContext& ctx, bool toplevel);
|
|
|
|
|
|
|
|
|
|
// handle a single inode of arbitrary type
|
|
|
|
|
static int
|
|
|
|
|
handle_inode(const char* p, const struct stat* st, bool longlisting){
|
|
|
|
|
handle_inode(const char* p, const struct stat* st, const lsContext& ctx){
|
|
|
|
|
std::cout << p << std::endl; // FIXME handle symlink (dereflinks)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -33,12 +40,11 @@ handle_inode(const char* p, const struct stat* st, bool longlisting){
|
|
|
|
|
// if |recursedirs| or |toplevel| is set, we will recurse, passing false as
|
|
|
|
|
// toplevel (but preserving |recursedirs|).
|
|
|
|
|
static int
|
|
|
|
|
handle_dir(const char* p, const struct stat* st, bool longlisting,
|
|
|
|
|
bool recursedirs, bool directories, bool toplevel){
|
|
|
|
|
if(directories){
|
|
|
|
|
return handle_inode(p, st, longlisting);
|
|
|
|
|
handle_dir(const char* p, const struct stat* st, const lsContext& ctx, bool toplevel){
|
|
|
|
|
if(ctx.directories){
|
|
|
|
|
return handle_inode(p, st, ctx);
|
|
|
|
|
}
|
|
|
|
|
if(!recursedirs && !toplevel){
|
|
|
|
|
if(!ctx.recursedirs && !toplevel){
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
DIR* dir = opendir(p);
|
|
|
|
@ -49,7 +55,7 @@ handle_dir(const char* p, const struct stat* st, bool longlisting,
|
|
|
|
|
struct dirent* dent;
|
|
|
|
|
int r = 0;
|
|
|
|
|
while(errno = 0, (dent = readdir(dir))){
|
|
|
|
|
r |= handle_path(dent->d_name, longlisting, recursedirs, directories, false, false);
|
|
|
|
|
r |= handle_path(dent->d_name, ctx, false);
|
|
|
|
|
}
|
|
|
|
|
if(errno){
|
|
|
|
|
std::cerr << "Error reading from " << p << ": " << strerror(errno) << std::endl;
|
|
|
|
@ -61,60 +67,65 @@ handle_dir(const char* p, const struct stat* st, bool longlisting,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
handle_deref(const char* p, const struct stat* st, bool longlisting,
|
|
|
|
|
bool recursedirs, bool directories){
|
|
|
|
|
handle_deref(const char* p, const struct stat* st, const lsContext& ctx){
|
|
|
|
|
// FIXME dereference and rerun on target
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// handle some path, either absolute or relative to the current directory.
|
|
|
|
|
// toplevel is true iff the path was directly listed on the command line.
|
|
|
|
|
// recursedirs, directories, longlisting, and dereflinks are all based off
|
|
|
|
|
// command-line parameters.
|
|
|
|
|
static int
|
|
|
|
|
handle_path(const char* p, bool longlisting, bool recursedirs,
|
|
|
|
|
bool directories, bool dereflinks, bool toplevel){
|
|
|
|
|
handle_path(const char* p, const lsContext& ctx, bool toplevel){
|
|
|
|
|
struct stat st;
|
|
|
|
|
if(stat(p, &st)){
|
|
|
|
|
std::cerr << "Error running stat(" << p << "): " << strerror(errno) << std::endl;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if((st.st_mode & S_IFMT) == S_IFDIR){
|
|
|
|
|
return handle_dir(p, &st, longlisting, recursedirs, directories, toplevel);
|
|
|
|
|
return handle_dir(p, &st, ctx, toplevel);
|
|
|
|
|
}else if((st.st_mode & S_IFMT) == S_IFLNK){
|
|
|
|
|
if(toplevel && dereflinks){
|
|
|
|
|
return handle_deref(p, &st, longlisting, recursedirs, directories);
|
|
|
|
|
if(toplevel && ctx.dereflinks){
|
|
|
|
|
return handle_deref(p, &st, ctx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return handle_inode(p, &st, longlisting);
|
|
|
|
|
return handle_inode(p, &st, ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// these are our command line arguments. they're the only paths for which
|
|
|
|
|
// handle_path() gets toplevel == true.
|
|
|
|
|
static int
|
|
|
|
|
list_paths(const char* const * argv, bool longlisting, bool recursedirs,
|
|
|
|
|
bool directories, bool dereflinks){
|
|
|
|
|
list_paths(const char* const * argv, const lsContext& ctx){
|
|
|
|
|
int ret = 0;
|
|
|
|
|
while(*argv){
|
|
|
|
|
ret |= handle_path(*argv, longlisting, recursedirs, directories, dereflinks, true);
|
|
|
|
|
ret |= handle_path(*argv, ctx, true);
|
|
|
|
|
++argv;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char* const * argv){
|
|
|
|
|
bool longlisting = false;
|
|
|
|
|
bool recursedirs = false;
|
|
|
|
|
bool directories = false;
|
|
|
|
|
bool dereflinks = false;
|
|
|
|
|
lsContext ctx = {
|
|
|
|
|
.longlisting = false,
|
|
|
|
|
.recursedirs = false,
|
|
|
|
|
.directories = false,
|
|
|
|
|
.dereflinks = false,
|
|
|
|
|
};
|
|
|
|
|
int c;
|
|
|
|
|
while((c = getopt(argc, argv, "dhlLR")) != -1){
|
|
|
|
|
switch(c){
|
|
|
|
|
case 'd':
|
|
|
|
|
directories = true;
|
|
|
|
|
ctx.directories = true;
|
|
|
|
|
break;
|
|
|
|
|
case 'l':
|
|
|
|
|
longlisting = true;
|
|
|
|
|
ctx.longlisting = true;
|
|
|
|
|
break;
|
|
|
|
|
case 'L':
|
|
|
|
|
dereflinks = true;
|
|
|
|
|
ctx.dereflinks = true;
|
|
|
|
|
break;
|
|
|
|
|
case 'R':
|
|
|
|
|
recursedirs = true;
|
|
|
|
|
ctx.recursedirs = true;
|
|
|
|
|
break;
|
|
|
|
|
case 'h':
|
|
|
|
|
usage(std::cout, argv[0], EXIT_SUCCESS);
|
|
|
|
@ -125,7 +136,6 @@ int main(int argc, char* const * argv){
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
static const char* const default_args[] = { ".", nullptr };
|
|
|
|
|
list_paths(argv[optind] ? argv + optind : default_args, longlisting,
|
|
|
|
|
recursedirs, directories, dereflinks);
|
|
|
|
|
list_paths(argv[optind] ? argv + optind : default_args, ctx);
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|