mirror of https://github.com/t1meshift/os_labs.git
Add 5th lab
parent
fca8d3a057
commit
ea3de372a4
|
@ -16,4 +16,5 @@ endfunction()
|
||||||
define_lab(lab2)
|
define_lab(lab2)
|
||||||
define_lab(lab3)
|
define_lab(lab3)
|
||||||
define_lab(lab4)
|
define_lab(lab4)
|
||||||
|
define_lab(lab5)
|
||||||
define_lab(lab7)
|
define_lab(lab7)
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
|
||||||
|
echo "TODO!"
|
||||||
|
exit 1
|
|
@ -0,0 +1,39 @@
|
||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
|
||||||
|
# Lab name
|
||||||
|
set(LAB_NAME "lab5")
|
||||||
|
|
||||||
|
# Lab tasks
|
||||||
|
list(APPEND SOURCE_FILES
|
||||||
|
task1.c
|
||||||
|
task2.c
|
||||||
|
mytail.c
|
||||||
|
mystat.c
|
||||||
|
myls.c
|
||||||
|
task6.c
|
||||||
|
)
|
||||||
|
list(APPEND NON_COMPILABLE_SRC
|
||||||
|
.execme
|
||||||
|
)
|
||||||
|
|
||||||
|
### Here goes the template
|
||||||
|
|
||||||
|
project("${LAB_NAME}" C)
|
||||||
|
|
||||||
|
add_custom_target("${LAB_NAME}")
|
||||||
|
|
||||||
|
foreach (file IN LISTS SOURCE_FILES)
|
||||||
|
add_executable("${LAB_NAME}_${file}_run" "${file}")
|
||||||
|
add_dependencies("${LAB_NAME}" "${LAB_NAME}_${file}_run")
|
||||||
|
endforeach ()
|
||||||
|
|
||||||
|
foreach (file IN LISTS NON_COMPILABLE_SRC)
|
||||||
|
add_custom_command(
|
||||||
|
TARGET "${LAB_NAME}" POST_BUILD
|
||||||
|
DEPENDS "${file}"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/${file}"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/${file}"
|
||||||
|
)
|
||||||
|
endforeach ()
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Лабораторная работа №5
|
||||||
|
|
||||||
|
## Задание 1
|
|
@ -0,0 +1,190 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.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 <pwd.h>
|
||||||
|
#include <grp.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
5. Разработать собственную версию (myls) команды ls, которая выводит список файлов в заданной директории.
|
||||||
|
С ключом -l она выводит информацию о каждом файле, включая собственника, группу, разрешения и т.д., получаемые из системного
|
||||||
|
вызова stat().
|
||||||
|
Формат: myls -l directory (или текущую директорию, если параметр не задан)
|
||||||
|
Использовать: stat(), opendir(), readdir(), getcwd(), ...
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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)
|
||||||
|
|
||||||
|
char *path = NULL;
|
||||||
|
bool long_listing = false;
|
||||||
|
bool flag_end = false;
|
||||||
|
|
||||||
|
void cleanup_on_exit() {
|
||||||
|
free(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_entry(char *entry) {
|
||||||
|
if (long_listing) {
|
||||||
|
struct stat fstat;
|
||||||
|
if (lstat(entry, &fstat) == -1) {
|
||||||
|
perror("stat()");
|
||||||
|
FATAL("Couldn't stat %s\n", entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print permissions
|
||||||
|
char entry_type;
|
||||||
|
// setuid, setgid, sticky are not in count
|
||||||
|
const char* perm_sym[] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"};
|
||||||
|
int perm = fstat.st_mode & 0777;
|
||||||
|
struct passwd *pw_data;
|
||||||
|
struct group *gp_data;
|
||||||
|
|
||||||
|
char user_name[33] = "";
|
||||||
|
char group_name[33] = "";
|
||||||
|
char last_mtime[256] = "";
|
||||||
|
|
||||||
|
switch (fstat.st_mode & S_IFMT) {
|
||||||
|
case S_IFREG:
|
||||||
|
entry_type = '-';
|
||||||
|
break;
|
||||||
|
case S_IFDIR:
|
||||||
|
entry_type = 'd';
|
||||||
|
break;
|
||||||
|
case S_IFLNK:
|
||||||
|
entry_type = 'l';
|
||||||
|
break;
|
||||||
|
case S_IFBLK:
|
||||||
|
entry_type = 'b';
|
||||||
|
break;
|
||||||
|
case S_IFSOCK:
|
||||||
|
entry_type = 's';
|
||||||
|
break;
|
||||||
|
case S_IFCHR:
|
||||||
|
entry_type = 'c';
|
||||||
|
break;
|
||||||
|
#ifdef S_IFIFO
|
||||||
|
case S_IFIFO:
|
||||||
|
entry_type = 'p';
|
||||||
|
break;
|
||||||
|
#endif /* S_IFIFO */
|
||||||
|
default:
|
||||||
|
entry_type = '?';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pw_data = getpwuid(fstat.st_uid)) == NULL) {
|
||||||
|
perror("Could not get owner username");
|
||||||
|
errno = 0;
|
||||||
|
snprintf(user_name, 33, "%d", fstat.st_uid);
|
||||||
|
} else {
|
||||||
|
snprintf(user_name, 33, "%s", pw_data->pw_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((gp_data = getgrgid(fstat.st_gid)) == NULL) {
|
||||||
|
perror("Could not get owner group name");
|
||||||
|
errno = 0;
|
||||||
|
snprintf(group_name, 33, "%d", fstat.st_gid);
|
||||||
|
} else {
|
||||||
|
snprintf(group_name, 33, "%s", gp_data->gr_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t mtime = fstat.st_mtime;
|
||||||
|
struct tm* tm_info = localtime(&mtime);
|
||||||
|
strftime(last_mtime, 256, "%Y-%b-%d %T %Z", tm_info);
|
||||||
|
|
||||||
|
printf("%c%s%s%s\t%4lu\t%s %s\t%6ld\t%s\t",
|
||||||
|
entry_type,
|
||||||
|
perm_sym[(perm & S_IRWXU) >> 6],
|
||||||
|
perm_sym[(perm & S_IRWXG) >> 3],
|
||||||
|
perm_sym[perm & S_IRWXO],
|
||||||
|
fstat.st_nlink,
|
||||||
|
user_name,
|
||||||
|
group_name,
|
||||||
|
fstat.st_size,
|
||||||
|
last_mtime);
|
||||||
|
|
||||||
|
}
|
||||||
|
printf("%s\n", entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
atexit(cleanup_on_exit);
|
||||||
|
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
if (argv[i][0] == '-' && !flag_end) {
|
||||||
|
char *flag = argv[i] + 1;
|
||||||
|
if (STR_EQ(flag, "l")) {
|
||||||
|
long_listing = true;
|
||||||
|
}
|
||||||
|
else if (STR_EQ(flag, "-")) {
|
||||||
|
flag_end = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
FATAL("Usage: %s [-l] [--] [path]\n", argv[0]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
path = strdup(argv[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!path) {
|
||||||
|
/*
|
||||||
|
* As an extension to the POSIX.1-2001 standard, glibc's getcwd()
|
||||||
|
* allocates the buffer dynamically using malloc(3) if buf is NULL. In
|
||||||
|
* this case, the allocated buffer has the length size unless size is
|
||||||
|
* zero, when buf is allocated as big as necessary. The caller should
|
||||||
|
* free(3) the returned buffer.
|
||||||
|
*/
|
||||||
|
if ((path = getcwd(NULL, 0)) == NULL) {
|
||||||
|
perror("getcwd()");
|
||||||
|
FATAL("Couldn't get current working directory\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct stat path_stat;
|
||||||
|
DIR *dir = NULL;
|
||||||
|
if (stat(path, &path_stat) == -1) {
|
||||||
|
perror("stat()");
|
||||||
|
FATAL("Couldn't stat %s\n", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_dir = S_ISDIR(path_stat.st_mode);
|
||||||
|
|
||||||
|
if (is_dir) {
|
||||||
|
if ((dir = opendir(path)) == NULL) {
|
||||||
|
perror("opendir()");
|
||||||
|
FATAL("Couldn't open directory %s\n", path);
|
||||||
|
}
|
||||||
|
if (chdir(path) == -1) {
|
||||||
|
perror("chdir()");
|
||||||
|
FATAL("Could not chdir to directory %s\n", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dirent *ent;
|
||||||
|
while ((ent = readdir(dir)) != NULL) {
|
||||||
|
print_entry(ent->d_name);
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
} else {
|
||||||
|
print_entry(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.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>
|
||||||
|
|
||||||
|
/*
|
||||||
|
4. Разработать собственную версию (mystat) команды stat, которая просто осуществляет системный вызов stat(), выводит
|
||||||
|
размер, число задействованных блоков, число ссылок и т.д. Отследить, как меняется число ссылок, когда изменяется
|
||||||
|
содержимое директории.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||||
|
#define FATAL(fmt, ...) do {\
|
||||||
|
fprintf(stderr,fmt,##__VA_ARGS__);\
|
||||||
|
exit(1);\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
if (argc != 2) {
|
||||||
|
FATAL("Usage: %s <path>\n", argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *path = argv[1];
|
||||||
|
struct stat sb;
|
||||||
|
|
||||||
|
if (lstat(path, &sb) == -1) {
|
||||||
|
perror("lstat()");
|
||||||
|
FATAL("Couldn't stat %s\n", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("File: %s\n", path);
|
||||||
|
printf("Size: %ld\tBlocks: %ld\tIO Block: %ld\t", sb.st_size, sb.st_blocks, sb.st_blksize);
|
||||||
|
switch(sb.st_mode & S_IFMT) {
|
||||||
|
case S_IFBLK:
|
||||||
|
puts("block device");
|
||||||
|
break;
|
||||||
|
case S_IFCHR:
|
||||||
|
puts("character device");
|
||||||
|
break;
|
||||||
|
case S_IFDIR:
|
||||||
|
puts("directory");
|
||||||
|
break;
|
||||||
|
case S_IFIFO:
|
||||||
|
puts("FIFO/pipe");
|
||||||
|
break;
|
||||||
|
case S_IFLNK:
|
||||||
|
puts("symlink");
|
||||||
|
break;
|
||||||
|
case S_IFREG:
|
||||||
|
puts("regular file");
|
||||||
|
break;
|
||||||
|
case S_IFSOCK:
|
||||||
|
puts("socket");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
puts("unknown?");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Device: [%04x:%04x]\t", major(sb.st_dev), minor(sb.st_dev));
|
||||||
|
printf("Inode: %lu\t", sb.st_ino);
|
||||||
|
printf("Links: %lu\n", sb.st_nlink);
|
||||||
|
|
||||||
|
printf("Mode: 0%o\tUid: %d\tGid: %d\n", sb.st_mode, sb.st_uid, sb.st_gid);
|
||||||
|
printf("Access (atime): %s", ctime(&sb.st_atime));
|
||||||
|
printf("Modify (mtime): %s", ctime(&sb.st_mtime));
|
||||||
|
printf("Change (ctime): %s", ctime(&sb.st_ctime));
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
3. Разработать собственную версию (mytail) команды tail.
|
||||||
|
Формат: mytail -n file
|
||||||
|
Она читает блок из конца файла, просматривает его с конца до заданного количества строк n и печатает эти строки
|
||||||
|
в соответствующем порядке.
|
||||||
|
Использовать: stat(), lseek(), open(), read(), close(), ...
|
||||||
|
*/
|
||||||
|
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||||
|
#define FATAL(fmt, ...) do {\
|
||||||
|
fprintf(stderr,fmt,##__VA_ARGS__);\
|
||||||
|
exit(1);\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
const int BUFF_SIZE = 4096;
|
||||||
|
long n = 10;
|
||||||
|
char *filename = NULL;
|
||||||
|
|
||||||
|
// Parse arguments (skip 0th arg)
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
if ((argv[i][0] == '-') && (i < argc - 1)) {
|
||||||
|
// -n flag (e.g. -20)
|
||||||
|
n = strtol(argv[i], NULL, 10) * -1;
|
||||||
|
if (n < 1 || errno == ERANGE) {
|
||||||
|
FATAL("Usage: %s [-<number_of_lines>] <file>\n", argv[0]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
filename = argv[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (filename == NULL) FATAL("No file name specified.\n");
|
||||||
|
|
||||||
|
struct stat sb;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (stat(filename, &sb) == -1) {
|
||||||
|
perror("stat()");
|
||||||
|
FATAL("Couldn't stat %s\n", filename);
|
||||||
|
}
|
||||||
|
if ((fd = open(filename, O_RDONLY)) == -1) {
|
||||||
|
perror("open()");
|
||||||
|
FATAL("Couldn't open %s\n", filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *buf = calloc(BUFF_SIZE, 1);
|
||||||
|
int lf_cnt = 0;
|
||||||
|
size_t read_sz = 0;
|
||||||
|
off_t file_offset = MAX(sb.st_size - BUFF_SIZE, 0);
|
||||||
|
bool seek_stop = false;
|
||||||
|
|
||||||
|
lseek(fd, -BUFF_SIZE, SEEK_END);
|
||||||
|
|
||||||
|
do {
|
||||||
|
int data_sz = read(fd, buf, BUFF_SIZE);
|
||||||
|
for (int i = data_sz - 1; i >= 0; --i) {
|
||||||
|
if (buf[i] == '\n') {
|
||||||
|
if (++lf_cnt >= n) {
|
||||||
|
file_offset += i + 1;
|
||||||
|
goto print_lines;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_offset -= BUFF_SIZE;
|
||||||
|
lseek(fd, -BUFF_SIZE, SEEK_CUR);
|
||||||
|
} while ((lf_cnt <= n) && (file_offset > 0));
|
||||||
|
|
||||||
|
print_lines:
|
||||||
|
lseek(fd, file_offset, SEEK_SET);
|
||||||
|
do {
|
||||||
|
read_sz = read(fd, buf, BUFF_SIZE);
|
||||||
|
write(STDOUT_FILENO, buf, read_sz);
|
||||||
|
} while (read_sz == BUFF_SIZE);
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define BENCHMARK(name, payload) \
|
||||||
|
do {\
|
||||||
|
struct timeval t0, t1;\
|
||||||
|
gettimeofday(&t0, NULL);\
|
||||||
|
payload \
|
||||||
|
gettimeofday(&t1, NULL);\
|
||||||
|
struct timeval result;\
|
||||||
|
timersub(&t1, &t0, &result);\
|
||||||
|
printf(name ": %ld.%06lds\n", result.tv_sec, result.tv_usec);\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
1. Используя creat(), write(), fflush(), close(), gettimeofday(), разработать программу, которая
|
||||||
|
открывает файл,
|
||||||
|
записывает туда 300 KB,
|
||||||
|
очищает все записи,
|
||||||
|
закрывает и
|
||||||
|
удаляет файл,
|
||||||
|
а также измеряет и выводит время, затраченное на каждое действие.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int f = -1;
|
||||||
|
|
||||||
|
BENCHMARK("creat() call",{
|
||||||
|
f = creat("task1.txt", S_IWUSR);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (f == -1) {
|
||||||
|
perror("creat()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bytes_written = -1;
|
||||||
|
const size_t data_size = 307200; // bytes, 300KiB
|
||||||
|
char *random_data = malloc(data_size);
|
||||||
|
|
||||||
|
BENCHMARK("write 300KiB", {
|
||||||
|
bytes_written = write(f, random_data, data_size);
|
||||||
|
});
|
||||||
|
free(random_data);
|
||||||
|
|
||||||
|
if (bytes_written == -1) {
|
||||||
|
perror("write()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK("fsync() call", {
|
||||||
|
fsync(f);
|
||||||
|
});
|
||||||
|
|
||||||
|
BENCHMARK("close() call", {
|
||||||
|
close(f);
|
||||||
|
});
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define BENCHMARK(name, payload) \
|
||||||
|
do {\
|
||||||
|
struct timeval __t0, __t1;\
|
||||||
|
gettimeofday(&__t0, NULL);\
|
||||||
|
payload \
|
||||||
|
gettimeofday(&__t1, NULL);\
|
||||||
|
struct timeval __result;\
|
||||||
|
timersub(&__t1, &__t0, &__result);\
|
||||||
|
printf(name ": %ld.%06lds\n", __result.tv_sec, __result.tv_usec);\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
2. Разработать программу, которая замеряет время для 300,000 однобайтовых записей с использованием
|
||||||
|
a) напрямую POSIX: creat(), write(), close().
|
||||||
|
b) с использованием библиотеки stdio (напр., fopen(), fwrite(), and fclose()).
|
||||||
|
Сравнить и объяснить результаты.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
BENCHMARK("POSIX API", {
|
||||||
|
int f = -1;
|
||||||
|
BENCHMARK("creat() call",{
|
||||||
|
f = creat("task2_posix.txt", 0644);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (f == -1) {
|
||||||
|
perror("creat()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bytes_written = -1;
|
||||||
|
const size_t data_size = 300000;
|
||||||
|
char *random_data = malloc(data_size);
|
||||||
|
|
||||||
|
BENCHMARK("write() call", {
|
||||||
|
bytes_written = write(f, random_data, data_size);
|
||||||
|
});
|
||||||
|
free(random_data);
|
||||||
|
|
||||||
|
if (bytes_written == -1) {
|
||||||
|
perror("write()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK("close() call", {
|
||||||
|
close(f);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
BENCHMARK("stdio.h API",{
|
||||||
|
FILE *f = NULL;
|
||||||
|
BENCHMARK("fopen() call", {
|
||||||
|
f = fopen("task2_stdio.txt", "w");
|
||||||
|
});
|
||||||
|
if (f == NULL) {
|
||||||
|
perror("fopen()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bytes_written = -1;
|
||||||
|
const size_t data_size = 300000;
|
||||||
|
char *random_data = malloc(data_size);
|
||||||
|
BENCHMARK("fwrite() call", {
|
||||||
|
bytes_written = fwrite(random_data, 1, 300000, f);
|
||||||
|
});
|
||||||
|
free(random_data);
|
||||||
|
if (bytes_written != data_size) {
|
||||||
|
perror("fwrite()");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK("fclose() call",{
|
||||||
|
fclose(f);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,128 @@
|
||||||
|
#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);
|
||||||
|
}
|
Loading…
Reference in New Issue