From 82cd3de3f4acb0e7a19ebec91baa0eba0d23bd9b Mon Sep 17 00:00:00 2001 From: Benjamin Barenblat Date: Mon, 16 Sep 2019 11:04:19 -0400 Subject: walk and sor, a combined replacement for find --- walk.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 walk.c (limited to 'walk.c') diff --git a/walk.c b/walk.c new file mode 100644 index 0000000..6cce89a --- /dev/null +++ b/walk.c @@ -0,0 +1,99 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include + +static const char *const JUST_CURRENT_DIRECTORY[] = {".", NULL}; + +// Like readdir(3), but resets errno(3) before the call to make it easy to +// check. +static struct dirent *readdir2(DIR *const dirp) +{ + errno = 0; + return readdir(dirp); +} + +// Like realloc(3), but exits the binary in an out-of-memory situation. +static void *realloc2(void *ptr, const size_t size) +{ + if (!(ptr = realloc(ptr, size))) { + perror("realloc"); + exit(EXIT_FAILURE); + } + return ptr; +} + +static void strcpy3(char *dest, const char *s1, const char *s2, const char *s3) +{ + stpcpy(stpcpy(stpcpy(dest, s1), s2), s3); +} + +// Walks the directory named dirname, printing the names of all files it +// contains (but not the name of the directory itself). Returns 2 if dirname is +// not a directory and 1 if another error occurs. +static int walk(const char dirname[]) +{ + DIR *const dir = opendir(dirname); + if (!dir) { + if (errno != ENOTDIR) { + perror(dirname); + return 1; + } + return 2; + } + int r = 0; + char *filename = NULL; + for (const struct dirent *f = readdir2(dir); f; f = readdir2(dir)) { + if (strcmp(f->d_name, ".") == 0 + || strcmp(f->d_name, "..") == 0) + continue; + filename = realloc2(filename, + strlen(dirname) + 1 + strlen(f->d_name) + 1); + strcpy3(filename, dirname, "/", f->d_name); + // TODO(bbaren): Emulate Plan 9's cleanname(3). + puts(filename); + // Walk the file if we can successfully open it as a directory. + // Don't worry about it if it's not one (walk(filename) == 2). + if ((f->d_type == DT_DIR || f->d_type == DT_UNKNOWN) + && walk(filename) == 1) + r = 1; + } + if (errno) { // from readdir + perror(dirname); + r = 1; + } + free(filename); + if (closedir(dir)) { + perror(dirname); + r = 1; + } + return r; +} + +int main(const int argc, const char *const argv[]) +{ + int r = 0; + const char *const *const dirs = + argc == 1 ? JUST_CURRENT_DIRECTORY : argv + 1; + for (int i = 0; dirs[i]; ++i) { + puts(dirs[i]); + r |= walk(dirs[i]); + } + return r; +} -- cgit v1.2.3