diff --git a/homework_2/ls/.idea/.gitignore b/homework_2/ls/.idea/.gitignore
new file mode 100644
index 0000000..73f69e0
--- /dev/null
+++ b/homework_2/ls/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/homework_2/ls/.idea/ls.iml b/homework_2/ls/.idea/ls.iml
new file mode 100644
index 0000000..c254557
--- /dev/null
+++ b/homework_2/ls/.idea/ls.iml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/homework_2/ls/.idea/modules.xml b/homework_2/ls/.idea/modules.xml
new file mode 100644
index 0000000..ce4a5a0
--- /dev/null
+++ b/homework_2/ls/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/homework_2/ls/.idea/vcs.xml b/homework_2/ls/.idea/vcs.xml
new file mode 100644
index 0000000..b2bdec2
--- /dev/null
+++ b/homework_2/ls/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/homework_2/ls/Cargo.lock b/homework_2/ls/Cargo.lock
new file mode 100644
index 0000000..4d3603b
--- /dev/null
+++ b/homework_2/ls/Cargo.lock
@@ -0,0 +1,223 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+
+[[package]]
+name = "clap"
+version = "2.33.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
+dependencies = [
+ "ansi_term",
+ "atty",
+ "bitflags",
+ "strsim",
+ "textwrap",
+ "unicode-width",
+ "vec_map",
+]
+
+[[package]]
+name = "heck"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.91"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7"
+
+[[package]]
+name = "ls"
+version = "0.1.0"
+dependencies = [
+ "structopt",
+]
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "strsim"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+
+[[package]]
+name = "structopt"
+version = "0.3.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c"
+dependencies = [
+ "clap",
+ "lazy_static",
+ "structopt-derive",
+]
+
+[[package]]
+name = "structopt-derive"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90"
+dependencies = [
+ "heck",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
+
+[[package]]
+name = "vec_map"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
+
+[[package]]
+name = "version_check"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/homework_2/ls/Cargo.toml b/homework_2/ls/Cargo.toml
new file mode 100644
index 0000000..627a9bb
--- /dev/null
+++ b/homework_2/ls/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "ls"
+version = "0.1.0"
+authors = ["Maksym-Yurii Rudko "]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+structopt = "0.3.21"
diff --git a/homework_2/ls/src/main.rs b/homework_2/ls/src/main.rs
new file mode 100644
index 0000000..20f212a
--- /dev/null
+++ b/homework_2/ls/src/main.rs
@@ -0,0 +1,74 @@
+mod models;
+mod providers;
+
+use std::io;
+use std::path::PathBuf;
+use providers::file_provider;
+use structopt::StructOpt;
+use crate::models::FileModel;
+
+#[derive(StructOpt)]
+struct CliArgs {
+ #[structopt(short, long = "human")]
+ human_readable: bool,
+ #[structopt(name = "Show all", short = "a", long = "all")]
+ show_hidden: bool,
+ #[structopt(parse(from_os_str), default_value = ".")]
+ start_dir: PathBuf,
+}
+
+fn main() -> io::Result<()> {
+ let args: CliArgs = CliArgs::from_args();
+ let start_path = args.start_dir.as_path();
+
+ // If the path provided to us is a directory, read its entries
+ if start_path.is_dir() {
+ match file_provider::get_files_in_directory(start_path) {
+ Ok(mut file_models) => {
+ let start_path = start_path.to_string_lossy();
+
+ sort_file_table(&mut file_models);
+ filter_file_table(&mut file_models, args.show_hidden);
+ print_file_table(start_path.as_ref(), &file_models, args.human_readable);
+ }
+ Err(e) => {
+ eprintln!("Error reading files in directory: {}", e);
+ return Err(e);
+ }
+ }
+ } else {
+ let parsed_file = file_provider::parse_dir_entry(start_path)?;
+ // If the path provided is a single file, just print its data
+ print_file_model(&parsed_file, args.human_readable);
+ }
+
+ Ok(())
+}
+
+fn filter_file_table(file_table: &mut Vec, should_show_hidden: bool) {
+ file_table.retain(|f| !f.is_hidden || should_show_hidden)
+}
+
+fn print_file_table(start_path: &str, file_table: &Vec, human_readable: bool) {
+ println!("List of files in {}", start_path);
+ println!("{:36} {:9}", "Name", "Size");
+
+ for model in file_table {
+ print_file_model(model, human_readable)
+ }
+}
+
+fn print_file_model(model: &FileModel, human_readable: bool) {
+ println!(
+ "{:36} {:9}",
+ format!("{}{}", model.name, if model.is_directory { "/" } else { "" }),
+ if human_readable { model.size.to_human_str() } else { model.size.to_raw_str() }
+ )
+}
+
+fn sort_file_table(file_table: &mut Vec) {
+ file_table.sort_unstable_by(|a, b| a.is_directory
+ .cmp(&b.is_directory)
+ .reverse()
+ .then(a.name.cmp(&b.name)));
+}
diff --git a/homework_2/ls/src/models.rs b/homework_2/ls/src/models.rs
new file mode 100644
index 0000000..dbcc0f8
--- /dev/null
+++ b/homework_2/ls/src/models.rs
@@ -0,0 +1,49 @@
+pub struct FileModel {
+ pub name: String,
+ pub is_hidden: bool,
+ pub is_directory: bool,
+ pub size: FileSize,
+ pub is_ro: bool,
+}
+
+pub struct FileSize {
+ pub size: u64
+}
+
+impl FileSize {
+ pub fn to_raw_str(&self) -> String {
+ format!("{} B", self.size)
+ }
+
+ pub fn to_human_str(&self) -> String {
+ if self.size < 1024 {
+ self.to_raw_str()
+ } else {
+ let mut i: u8 = 0;
+ let mut human_size: f64 = self.size as f64;
+ loop {
+ human_size /= 1024.0;
+ i += 1;
+
+ if human_size < 1024.0 {
+ break;
+ }
+ }
+ format!("{:.2} {}", human_size, FileSize::get_size_label(i))
+ }
+ }
+
+ fn get_size_label(size_order: u8) -> String {
+ String::from(
+ match size_order {
+ 0 => "B",
+ 1 => "KiB",
+ 2 => "MiB",
+ 3 => "GiB",
+ 4 => "TiB",
+ 5 => "EiB",
+ _ => "B"
+ }
+ )
+ }
+}
diff --git a/homework_2/ls/src/providers.rs b/homework_2/ls/src/providers.rs
new file mode 100644
index 0000000..78b43fc
--- /dev/null
+++ b/homework_2/ls/src/providers.rs
@@ -0,0 +1,33 @@
+pub mod file_provider {
+ use std::path::Path;
+ use crate::models::{FileModel, FileSize};
+ use std::{io, fs};
+ use std::io::Error;
+
+ pub fn get_files_in_directory(directory: &Path) -> Result, Error> {
+ let mut file_vector = Vec::new();
+ // Iterate over entries in the directory
+ for entry in fs::read_dir(directory)? {
+ let entry = entry?;
+
+ file_vector.push(parse_dir_entry(&entry.path().as_path())?);
+ }
+ Ok(file_vector)
+ }
+
+ pub fn parse_dir_entry(entry: &Path) -> io::Result {
+ let name = {
+ let os_file_name = entry.file_name()
+ .expect("Could not read file name from a given path");
+ String::from(os_file_name.to_string_lossy())
+ };
+ let metadata = entry.metadata()?;
+
+ let is_hidden = name.starts_with(".");
+ let is_directory = metadata.is_dir();
+ let size: u64 = metadata.len();
+ let is_ro = metadata.permissions().readonly();
+
+ Ok(FileModel { name, is_hidden, is_directory, size: FileSize { size }, is_ro })
+ }
+}
\ No newline at end of file