// Set this if you don't want MIME types //#define NO_MIME #include #include #include #include #include #include #ifndef NO_MIME #include #endif #include #include #include #include enum FileType { Unknown, File, Folder, #ifndef NO_MIME Archive, Audio, Application, Video, Binary, Text #endif }; std::vector 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 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) { #ifndef NO_MIME case FileType::Application: return "Application"; case FileType::Archive: return "Archive"; case FileType::Audio: return "Audio"; case FileType::Binary: return "Binary"; #endif case FileType::File: return "File"; case FileType::Folder: return "Folder"; #ifndef NO_MIME case FileType::Text: return "Text"; case FileType::Video: return "Video"; #endif default: return "Unknown"; } } std::string get_emoji_from_filetype(const enum FileType fs) { switch (fs) { #ifndef NO_MIME case FileType::Application: return "⚙️"; case FileType::Archive: return "🗜️"; case FileType::Audio: return "🎵"; case FileType::Binary: return "⚙️"; #endif case FileType::File: return "📄"; case FileType::Folder: return "📁"; #ifndef NO_MIME case FileType::Text: return "📝"; case FileType::Video: return "🎥"; #endif 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(size)); std::string result(buffer); return buffer; } auto result = static_cast(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; } #ifndef NO_MIME std::string get_mime(const std::string& filename) { const char* file_path = filename.c_str(); const auto magic_cookie = static_cast(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; } #endif 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 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(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 += "/"; #ifndef NO_MIME std::string mime_type = get_mime(full_name); #endif FileType file; #ifdef NO_MIME file = (is_file) ? FileType::File : FileType::Folder; #else 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; } #endif 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()); #ifndef NO_MIME printf("\tMIME: %s\n", mime_type.c_str()); #endif 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; }