mirror of https://github.com/t1meshift/os_labs.git
128 lines
3.3 KiB
C
128 lines
3.3 KiB
C
#include <assert.h>
|
||
#include <ctype.h>
|
||
#include <dirent.h>
|
||
#include <errno.h>
|
||
#include <fcntl.h>
|
||
#include <grp.h>
|
||
#include <pwd.h>
|
||
#include <stdbool.h>
|
||
#include <stdint.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <sys/stat.h>
|
||
#include <sys/sysmacros.h>
|
||
#include <sys/time.h>
|
||
#include <sys/wait.h>
|
||
#include <time.h>
|
||
#include <unistd.h>
|
||
#include <limits.h>
|
||
|
||
/*
|
||
6. Разработать программу, которая выводит имена каждого файла и директории, начиная с заданной точки в дереве каталогов.
|
||
a) Без аргументов: сначала текущая директория и ее содержимое, затем поддиректории и т.д. (пока не закончится дерево,
|
||
root в качестве CWD).
|
||
b) С одним аргументом (который есть имя директории): все поддерево, начиная с заданной директории.
|
||
c) А также еще один какой-либо интересный вариант (см. опции для find).
|
||
*/
|
||
|
||
#define USAGE_STRING "Usage: %s [-d <max_depth>] [-L] [--] [path]\n"
|
||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||
#define STR_EQ(a, b) (!strcmp((a),(b)))
|
||
#define FATAL(fmt, ...) do {\
|
||
fprintf(stderr,fmt,##__VA_ARGS__);\
|
||
exit(1);\
|
||
} while (0)
|
||
#define WARNING(fmt, ...) fprintf(stderr,fmt,##__VA_ARGS__)
|
||
|
||
bool flag_end = false;
|
||
bool follow_symlinks = false;
|
||
long max_depth = LONG_MAX;
|
||
|
||
void traverse_path(char *path, long depth) {
|
||
struct stat pstat;
|
||
DIR *dir = NULL;
|
||
struct dirent *ent;
|
||
int stat_status;
|
||
|
||
printf("%s\n", path);
|
||
|
||
if (depth > max_depth)
|
||
return;
|
||
|
||
if (follow_symlinks) {
|
||
stat_status = stat(path, &pstat);
|
||
} else {
|
||
stat_status = lstat(path, &pstat);
|
||
}
|
||
|
||
if (stat_status == -1) {
|
||
perror("stat()");
|
||
FATAL("Couldn't stat %s\n", path);
|
||
}
|
||
|
||
if (!S_ISDIR(pstat.st_mode))
|
||
return;
|
||
|
||
if ((dir = opendir(path)) == NULL) {
|
||
perror("opendir()");
|
||
FATAL("Couldn't open directory %s\n", path);
|
||
}
|
||
|
||
while ((ent = readdir(dir)) != NULL) {
|
||
if (STR_EQ(ent->d_name, ".") || STR_EQ(ent->d_name, "..")) {
|
||
continue;
|
||
}
|
||
|
||
char path_next[PATH_MAX];
|
||
strcpy(path_next, path);
|
||
|
||
if (path_next[strlen(path_next) - 1] != '/') {
|
||
strcat(path_next, "/");
|
||
}
|
||
|
||
strcat(path_next, ent->d_name);
|
||
|
||
traverse_path(path_next, depth + 1);
|
||
}
|
||
|
||
closedir(dir);
|
||
}
|
||
|
||
int main(int argc, char *argv[]) {
|
||
char *path = ".";
|
||
|
||
for (int i = 1; i < argc; ++i) {
|
||
if (argv[i][0] == '-' && !flag_end) {
|
||
char *flag = argv[i] + 1;
|
||
if (STR_EQ(flag, "d")) {
|
||
if (i + 1 < argc) {
|
||
max_depth = strtol(argv[++i], NULL, 10);
|
||
if (errno == ERANGE) {
|
||
WARNING("Max depth level is out of range, %ld is set\n", max_depth);
|
||
errno = 0;
|
||
}
|
||
if (max_depth < 0) {
|
||
FATAL("Max depth must be non-negative\n");
|
||
}
|
||
} else {
|
||
FATAL(USAGE_STRING, argv[0]);
|
||
}
|
||
}
|
||
else if (STR_EQ(flag, "L")) {
|
||
follow_symlinks = true;
|
||
}
|
||
else if (STR_EQ(flag, "-")) {
|
||
flag_end = true;
|
||
}
|
||
else {
|
||
FATAL(USAGE_STRING, argv[0]);
|
||
}
|
||
} else {
|
||
path = argv[i];
|
||
break;
|
||
}
|
||
}
|
||
|
||
traverse_path(path, 1);
|
||
} |