fileinfo/main.cpp
2024-08-20 19:51:21 +02:00

356 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
The original of this program belongs to pavlik_tt!
Please, if you are going to modify this code in any way, do one of these things:
* Create a fork on GitHub where you post the source code of this program.
* Leave this comment, but under the line #2 leave your name as the author of the fork.
If you take large blocks of code from here, please provide attribution in a comment above it.
I dont force you to do these things, but it will be more pleasant for me.
*/
/*
Some notes:
1.
*/
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <sys/stat.h>
#include <cstring>
#include <unistd.h>
#include <magic.h>
#include <string>
#include <vector>
#include <sys/types.h>
#include <dirent.h>
#define BUFSIZE 1024
enum FileType {
Unknown,
File, Folder,
Archive, Audio,
Application,
Video, Binary,
Text
};
std::vector<int> get_files_in_directory(const std::string& path)
{
DIR* dp = opendir(path.c_str());
// int normal, hidden;
int normal[2] = {0,0};
int hidden[2] = {0,0};
if (dp != nullptr) {
struct dirent* ep;
while((ep = readdir(dp))) {
// if (ep->d_name[0] != '.') i++;
if (strcmp(ep->d_name, ".") != 0 && strcmp(ep->d_name, "..") != 0) {
if (ep->d_name[0] == '.') {
hidden[(ep->d_type == DT_DIR) ? 1 : 0]++;
}else {
normal[(ep->d_type == DT_DIR) ? 1 : 0]++;
}
}
}
(void)closedir(dp);
}
else
perror("Couldn't open the directory");
std::vector<int> result;
result.insert(result.end(), normal[0]);
result.insert(result.end(), normal[1]);
result.insert(result.end(), hidden[0]);
result.insert(result.end(), hidden[1]);
return result;
}
bool starts_with(const std::string& prefix, const std::string& string) {
return string.rfind(prefix, 0) == 0;
}
bool is_archive(const std::string& mime_type)
{
const std::string archives[] = {
"application/x-archive",
"application/x-cpio",
"application/x-shar",
"application/x-iso9660-image",
"application/x-sbx",
"application/x-tar",
"application/x-brotli",
"application/x-bzip2",
"application/vnd.genozip",
"application/gzip",
"application/x-lzip",
"application/x-lzma",
"application/x-lzop",
"application/x-snappy-framed",
"application/x-xz",
"application/x-compress",
"application/x-compress",
"application/zstd",
"application/x-7z-compressed",
"application/x-ace-compressed",
"application/x-astrotite-afa",
"application/x-alz-compressed",
"application/vnd.android.package-archive",
"application/x-freearc",
"application/x-arj",
"application/x-b1",
"application/vnd.ms-cab-compressed",
"application/x-cfs-compressed",
"application/x-dar",
"application/x-dgc-compressed",
"application/x-apple-diskimage",
"application/x-gca-compressed",
"application/java-archive",
"application/x-lzh",
"application/x-lzx",
"application/x-rar-compressed",
"application/x-stuffit",
"application/x-stuffitx",
"application/x-gtar",
"application/x-ms-wim",
"application/x-xar",
"application/zip",
"application/x-zoo"
};
int len = sizeof(archives)/sizeof(archives[0]);
for(int i = 0; i < len; ++i)
{
if(starts_with(archives[i], mime_type))
{
return true;
}
}
return false;
}
std::string get_name_from_filetype(const enum FileType fs)
{
switch (fs) {
case FileType::Application:
return "Application";
case FileType::Archive:
return "Archive";
case FileType::Audio:
return "Audio";
case FileType::Binary:
return "Binary";
case FileType::File:
return "File";
case FileType::Folder:
return "Folder";
case FileType::Text:
return "Text";
case FileType::Video:
return "Video";
default:
return "Unknown";
}
}
std::string get_emoji_from_filetype(const enum FileType fs)
{
switch (fs) {
case FileType::Application:
return "⚙️";
case FileType::Archive:
return "🗜️";
case FileType::Audio:
return "🎵";
case FileType::Binary:
return "⚙️";
case FileType::File:
return "📄";
case FileType::Folder:
return "📁";
case FileType::Text:
return "📝";
case FileType::Video:
return "🎥";
default:
return "?";
}
}
std::string readable_fs(const long int size /*in bytes*/, const double divide_by = 1024, const std::string& suffix = "B")
{
if(size < 1024) {
char buffer[128];
sprintf(buffer, "%i B", static_cast<int>(size));
std::string result(buffer);
return buffer;
}
auto result = static_cast<double>(size);
int i = 0;
const std::string units[] = {"", "K", "M", "G", "T", "P", "E", "Z", "Y"};
while (result > divide_by) {
result /= divide_by;
i++;
}
char buffer[128];
sprintf(buffer, "%.*f %s%s", i, result, units[i].c_str(), suffix.c_str());
std::string str_result(buffer);
return str_result;
}
std::string get_mime(const std::string& filename)
{
const char* file_path = filename.c_str();
const auto magic_cookie = static_cast<const magic_t>(magic_open(MAGIC_MIME_TYPE));
if (magic_cookie == nullptr) {
std::cerr << "Unable to initialize libmagic\n";
return "";
}
// Load definitions from the mime types database
if (magic_load(magic_cookie, nullptr) != 0) {
std::cerr << "Unable to load database definitions\n";
magic_close(magic_cookie);
return "";
}
// Determines the MIME type of the file
const char *mime_type = magic_file(magic_cookie, file_path);
if (mime_type == nullptr) {
std::cerr << "Unable to determine the MIME type of the file\n";
magic_close(magic_cookie);
return "";
}
std::string result(mime_type);
// Close libmagic
magic_close(magic_cookie);
return result;
}
std::string print_permissions(mode_t mode, bool is_dir) {
std::string user;
user += (mode & S_IRUSR) ? "r" : "-";
user += (mode & S_IWUSR) ? "w" : "-",
user += (mode & S_IXUSR) ? "x" : "-";
std::string group;
group += (mode & S_IRGRP) ? "r" : "-";
group += (mode & S_IWGRP) ? "w" : "-";
group += (mode & S_IXGRP) ? "x" : "-";
std::string other;
other += (mode & S_IROTH) ? "r" : "-";
other += (mode & S_IWOTH) ? "w" : "-";
other += (mode & S_IXOTH) ? "x" : "-";
return (is_dir ? "d" : "-") + user + group + other;
}
std::string basename(const std::string& filepath) {
return filepath.substr(filepath.find_last_of("/\\") + 1);
}
int main(int argc, char *argv[])
{
bool absolute = false;
bool emojis = true;
// char* filename = "/home/pavlik/Desktop/twrp-3.7.0_9-0-starlte.img";
if (argc < 2) {
std::cerr << "Usage:\n\t" << argv[0] << " [args] filename ...\n";
std::cerr << "Args:" << std::endl;
std::cerr << "\t-A Output absolute path" << std::endl;
std::cerr << "\t-E Do not show emojis" << std::endl;
return 255;
}
std::vector<std::string> files;
for (int i = 1; i < argc; ++i) {
if (argv[i][0] != '-') {
std::string temp(argv[i]);
files.insert(files.end(), temp);
} else {
std::string arg(argv[i]);
if(arg == "-A") {
absolute = true;
}
if (arg == "-E") {
emojis = false;
}
}
}
size_t last = files.size();
for (size_t i = 0; i < last; ++i) {
const std::string& filename = files[i];
char* c_filename = const_cast<char*>(filename.c_str());
struct stat file_stat = {};
if (stat(filename.c_str(), &file_stat) != 0) {
perror("stat");
return 1;
}
// start
int is_file = S_ISREG(file_stat.st_mode);
char temp[4097] = {'\0'};
if (realpath(c_filename, temp) == nullptr) {
perror("realpath");
return 1;
}
std::string full_name(temp); // = malloc(4097);
// delete[] temp;
std::string name = basename(full_name);
if(!is_file) name += "/";
std::string mime_type = get_mime(full_name);
FileType file;
if (starts_with("inode/directory", mime_type) || !is_file) {
file = FileType::Folder;
} else if (is_archive(mime_type)) {
file = FileType::Archive;
} else if (starts_with("application/octet-stream", mime_type)) {
file = FileType::Binary;
} else if (starts_with("application", mime_type)) {
file = FileType::Application;
} else if (starts_with("audio", mime_type)) {
file = FileType::Audio;
} else if (starts_with("video", mime_type)) {
file = FileType::Video;
} else if (starts_with("text", mime_type)) {
file = FileType::Text;
} else {
file = FileType::Unknown;
}
std::string type = get_name_from_filetype(file);
std::string emoji = get_emoji_from_filetype(file);
if (emojis) printf("%s ", emoji.c_str());
printf("\033[1m%s\033[0m:\n", name.c_str());
printf("\tName: %s\n", name.c_str());
printf("\tType: %s\n", type.c_str());
if (absolute) printf("\tAbsolute path: %s\n", full_name.c_str());
printf("\tMIME: %s\n", mime_type.c_str()); // Default MIME type, adjust as needed
if (is_file) {
std::string _1024 = readable_fs(file_stat.st_size, 1000, "B");
std::string _1000 = readable_fs(file_stat.st_size, 1024, "iB");
if (file_stat.st_size >= 1000) printf("\tFile size: %s or %s (%li bytes)\n", _1024.c_str(), _1000.c_str(), file_stat.st_size);
else printf("\tFile size: %li bytes\n", file_stat.st_size);
} else {
auto insides = get_files_in_directory(full_name);
printf("\tContents:\n");
printf("\t\tNormal: %i files and %i folders.\n", insides[0], insides[1]);
printf("\t\tHidden: %i files and %i folders.\n", insides[2], insides[3]);
}
printf("\tPermissions: %s\n", print_permissions(file_stat.st_mode, !is_file).c_str());
if (i != last-1) {
printf("\n");
}
}
return 0;
}