Загрузка данных
// myls.c — упрощенный аналог ls -l
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h> // Для getpwuid()
#include <grp.h> // Для getgrgid()
#include <time.h> // Для strftime()
#include <errno.h>
#include <dirent.h> // Для opendir(), readdir()
#define MAX_PATH 4096
// Макрос для обработки ошибок
#define err_sys(msg) do { \
fprintf(stderr, "%s: %s\n", msg, strerror(errno)); \
exit(1); \
} while(0)
// Функция для преобразования режима файла в строку прав (например, -rw-r--r--)
void mode_to_string(mode_t mode, char *str) {
// Тип файла
switch (mode & S_IFMT) {
case S_IFDIR: str[0] = 'd'; break; // Директория
case S_IFCHR: str[0] = 'c'; break; // Символьное устройство
case S_IFBLK: str[0] = 'b'; break; // Блочное устройство
case S_IFREG: str[0] = '-'; break; // Обычный файл
case S_IFIFO: str[0] = 'p'; break; // FIFO (именованный канал)
case S_IFLNK: str[0] = 'l'; break; // Символическая ссылка
case S_IFSOCK: str[0] = 's'; break; // Сокет
default: str[0] = '?'; break;
}
// Права владельца (user)
str[1] = (mode & S_IRUSR) ? 'r' : '-';
str[2] = (mode & S_IWUSR) ? 'w' : '-';
str[3] = (mode & S_IXUSR) ? 'x' : '-';
// Права группы (group)
str[4] = (mode & S_IRGRP) ? 'r' : '-';
str[5] = (mode & S_IWGRP) ? 'w' : '-';
str[6] = (mode & S_IXGRP) ? 'x' : '-';
// Права остальных (others)
str[7] = (mode & S_IROTH) ? 'r' : '-';
str[8] = (mode & S_IWOTH) ? 'w' : '-';
str[9] = (mode & S_IXOTH) ? 'x' : '-';
str[10] = '\0';
}
// Функция для форматирования времени
void format_time(time_t t, char *buf, size_t size) {
struct tm *tm_info = localtime(&t);
strftime(buf, size, "%b %d %H:%M", tm_info);
}
// Функция для отображения информации об одном файле
void print_file_info(const char *pathname) {
struct stat statbuf;
char mode_str[11];
char time_str[64];
struct passwd *pwd;
struct group *grp;
// Используем lstat для корректной работы с символическими ссылками
if (lstat(pathname, &statbuf) == -1) {
fprintf(stderr, "Не удалось получить информацию о %s: %s\n",
pathname, strerror(errno));
return;
}
// Преобразуем режим в строку прав
mode_to_string(statbuf.st_mode, mode_str);
// Форматируем время последней модификации
format_time(statbuf.st_mtime, time_str, sizeof(time_str));
// Получаем имя владельца по UID
pwd = getpwuid(statbuf.st_uid);
const char *username = pwd ? pwd->pw_name : "?";
// Получаем имя группы по GID
grp = getgrgid(statbuf.st_gid);
const char *groupname = grp ? grp->gr_name : "?";
// Вывод в формате ls -l
printf("%s %3ld %s %s %8ld %s %s\n",
mode_str, // Права доступа
(long)statbuf.st_nlink, // Количество ссылок
username, // Владелец
groupname, // Группа
(long)statbuf.st_size, // Размер в байтах
time_str, // Время модификации
pathname); // Имя файла
}
// Функция для обработки директории
void list_directory(const char *dirname) {
DIR *dir;
struct dirent *entry;
char fullpath[MAX_PATH];
dir = opendir(dirname);
if (dir == NULL) {
fprintf(stderr, "Не удалось открыть директорию %s: %s\n",
dirname, strerror(errno));
return;
}
// Читаем все записи в директории
while ((entry = readdir(dir)) != NULL) {
// Пропускаем . и ..
if (strcmp(entry->d_name, ".") == 0 ||
strcmp(entry->d_name, "..") == 0) {
continue;
}
// Формируем полный путь
snprintf(fullpath, sizeof(fullpath), "%s/%s", dirname, entry->d_name);
print_file_info(fullpath);
}
closedir(dir);
}
int main(int argc, char *argv[]) {
// Если аргументов нет — используем текущую директорию
if (argc == 1) {
list_directory(".");
} else {
// Обрабатываем каждый аргумент
for (int i = 1; i < argc; i++) {
struct stat statbuf;
// Проверяем, является ли путь директорией
if (lstat(argv[i], &statbuf) == -1) {
fprintf(stderr, "Не удалось получить информацию о %s: %s\n",
argv[i], strerror(errno));
continue;
}
if (S_ISDIR(statbuf.st_mode)) {
// Это директория — перечисляем её содержимое
printf("%s:\n", argv[i]);
list_directory(argv[i]);
printf("\n");
} else {
// Это файл — выводим информацию о нём
print_file_info(argv[i]);
}
}
}
return 0;
}