diff --git a/src/feature/xattr.rs b/src/feature/xattr.rs index 5a4d972..392b5fc 100644 --- a/src/feature/xattr.rs +++ b/src/feature/xattr.rs @@ -39,23 +39,29 @@ pub struct Attribute { pub fn list_attrs(lister: lister::Lister, path: &Path) -> io::Result<Vec<Attribute>> { let c_path = match path.as_os_str().to_cstring() { Some(cstring) => cstring, - None => return Err(io::Error::new(io::ErrorKind::Other, "could not read extended attributes")), + None => return Err(io::Error::new(io::ErrorKind::Other, "Error: path somehow contained a NUL?")), }; + let mut names = Vec::new(); let bufsize = lister.listxattr_first(&c_path); - if bufsize > 0 { + if bufsize < 0 { + return Err(io::Error::last_os_error()); + } + else if bufsize > 0 { let mut buf = vec![0u8; bufsize as usize]; let err = lister.listxattr_second(&c_path, &mut buf, bufsize); + if err < 0 { + return Err(io::Error::last_os_error()); + } + if err > 0 { // End indicies of the attribute names // the buffer contains 0-terminates c-strings let idx = buf.iter().enumerate().filter_map(|(i, v)| if *v == 0 { Some(i) } else { None } ); - - let mut names = Vec::new(); let mut start = 0; for end in idx { @@ -72,15 +78,10 @@ pub fn list_attrs(lister: lister::Lister, path: &Path) -> io::Result<Vec<Attribu start = c_end; } - Ok(names) - } - else { - Err(io::Error::new(io::ErrorKind::Other, "could not read extended attributes")) } + } - else { - Err(io::Error::new(io::ErrorKind::Other, "could not read extended attributes")) - } + Ok(names) } #[cfg(target_os = "macos")] diff --git a/src/file.rs b/src/file.rs index b4d104b..0b65bb5 100644 --- a/src/file.rs +++ b/src/file.rs @@ -12,7 +12,6 @@ use unicode_width::UnicodeWidthStr; use dir::Dir; use options::TimeType; -use feature::xattr::{Attribute, FileAttributes}; use self::fields as f; @@ -45,10 +44,6 @@ pub struct File<'dir> { /// cache it. pub metadata: fs::Metadata, - /// List of this file's extended attributes. These are only loaded if the - /// `xattr` feature is in use. - pub xattrs: Vec<Attribute>, - /// A reference to the directory that contains this file, if present. /// /// Filenames that get passed in on the command-line directly will have no @@ -93,7 +88,6 @@ impl<'dir> File<'dir> { dir: parent, metadata: metadata, ext: ext(&filename), - xattrs: path.symlink_attributes().unwrap_or(Vec::new()), name: filename.to_string(), this: this, } @@ -199,7 +193,6 @@ impl<'dir> File<'dir> { dir: self.dir, metadata: metadata, ext: ext(&filename), - xattrs: target_path.attributes().unwrap_or(Vec::new()), name: filename.to_string(), this: None, }) @@ -316,7 +309,7 @@ impl<'dir> File<'dir> { other_read: has_bit(unix::fs::OTHER_READ), other_write: has_bit(unix::fs::OTHER_WRITE), other_execute: has_bit(unix::fs::OTHER_EXECUTE), - attribute: !self.xattrs.is_empty() + attribute: false, // !self.xattrs.is_empty() } } diff --git a/src/output/details.rs b/src/output/details.rs index acc3f7d..72dc1ba 100644 --- a/src/output/details.rs +++ b/src/output/details.rs @@ -1,13 +1,12 @@ use std::error::Error; use std::io; -use std::iter::repeat; use std::path::Path; use std::string::ToString; use colours::Colours; use column::{Alignment, Column, Cell}; use dir::Dir; -use feature::xattr::Attribute; +use feature::xattr::{Attribute, FileAttributes}; use file::fields as f; use file::File; use options::{Columns, FileFilter, RecurseOptions, SizeFormat}; @@ -78,7 +77,7 @@ impl Details { // Then add files to the table and print it out. self.add_files_to_table(&mut table, files, 0); - for cell in table.print_table(self.xattr, self.recurse.is_some()) { + for cell in table.print_table() { println!("{}", cell.text); } } @@ -89,6 +88,17 @@ impl Details { for (index, file) in src.iter().enumerate() { table.add_file(file, depth, index == src.len() - 1, true); + if self.xattr { + match file.path.attributes() { + Ok(xattrs) => { + for xattr in xattrs { + table.add_xattr(xattr, depth + 1, false); + } + }, + Err(e) => table.add_error(&e, depth + 1, true, None), + } + } + // There are two types of recursion that exa supports: a tree // view, which is dealt with here, and multiple listings, which is // dealt with in the main module. So only actually recurse if we @@ -149,16 +159,9 @@ struct Row { /// on top have depth 0. depth: usize, - /// Vector of this file's extended attributes, if that feature is active. - attrs: Vec<Attribute>, - /// Whether this is the last entry in the directory. This flag is used /// when calculating the tree view. last: bool, - - /// Whether this file is a directory and has any children. Also used when - /// calculating the tree view. - children: bool, } impl Row { @@ -232,8 +235,6 @@ impl<U> Table<U> where U: Users { cells: Some(self.columns.iter().map(|c| Cell::paint(self.colours.header, c.header())).collect()), name: Cell::paint(self.colours.header, "Name"), last: false, - attrs: Vec::new(), - children: false, }; self.rows.push(row); @@ -250,8 +251,17 @@ impl<U> Table<U> where U: Users { cells: None, name: Cell::paint(self.colours.broken_arrow, &error_message), last: last, - attrs: Vec::new(), - children: false, + }; + + self.rows.push(row); + } + + pub fn add_xattr(&mut self, xattr: Attribute, depth: usize, last: bool) { + let row = Row { + depth: depth, + cells: None, + name: Cell::paint(self.colours.perms.attribute, &format!("{}\t{}", xattr.name, xattr.size)), + last: last, }; self.rows.push(row); @@ -269,8 +279,6 @@ impl<U> Table<U> where U: Users { cells: Some(cells), name: Cell { text: filename(file, &self.colours, links), length: file.file_name_width() }, last: last, - attrs: file.xattrs.clone(), - children: file.this.is_some(), }; self.rows.push(row); @@ -445,7 +453,7 @@ impl<U> Table<U> where U: Users { } /// Render the table as a vector of Cells, to be displayed on standard output. - pub fn print_table(&self, xattr: bool, show_children: bool) -> Vec<Cell> { + pub fn print_table(&self) -> Vec<Cell> { let mut stack = Vec::new(); let mut cells = Vec::new(); @@ -482,40 +490,27 @@ impl<U> Table<U> where U: Users { // necessary to maintain information about the previously-printed // lines, as the output will change based on whether the // *previous* entry was the last in its directory. - if show_children { - stack.resize(row.depth + 1, TreePart::Edge); - stack[row.depth] = if row.last { TreePart::Corner } else { TreePart::Edge }; + stack.resize(row.depth + 1, TreePart::Edge); + stack[row.depth] = if row.last { TreePart::Corner } else { TreePart::Edge }; - for i in 1 .. row.depth + 1 { - filename.push_str(&*self.colours.punctuation.paint(stack[i].ascii_art()).to_string()); - filename_length += 4; - } + for i in 1 .. row.depth + 1 { + filename.push_str(&*self.colours.punctuation.paint(stack[i].ascii_art()).to_string()); + filename_length += 4; + } - if row.children { - stack[row.depth] = if row.last { TreePart::Blank } else { TreePart::Line }; - } + stack[row.depth] = if row.last { TreePart::Blank } else { TreePart::Line }; - // If any tree characters have been printed, then add an extra - // space, which makes the output look much better. - if row.depth != 0 { - filename.push(' '); - filename_length += 1; - } + // If any tree characters have been printed, then add an extra + // space, which makes the output look much better. + if row.depth != 0 { + filename.push(' '); + filename_length += 1; } // Print the name without worrying about padding. filename.push_str(&*row.name.text); filename_length += row.name.length; - if xattr { - let width = row.attrs.iter().map(|a| a.name.len()).max().unwrap_or(0); - for attr in row.attrs.iter() { - let name = &*attr.name; - let spaces: String = repeat(" ").take(width - name.len()).collect(); - filename.push_str(&*format!("\n{}{} {}", name, spaces, attr.size)) - } - } - cell.append(&Cell { text: filename, length: filename_length }); cells.push(cell); } diff --git a/src/output/grid_details.rs b/src/output/grid_details.rs index 4daf85a..5a5804d 100644 --- a/src/output/grid_details.rs +++ b/src/output/grid_details.rs @@ -73,7 +73,7 @@ impl GridDetails { tables[index].add_file_with_cells(row, file, 0, false, false); } - let columns: Vec<_> = tables.iter().map(|t| t.print_table(false, false)).collect(); + let columns: Vec<_> = tables.iter().map(|t| t.print_table()).collect(); let direction = if self.grid.across { grid::Direction::LeftToRight } else { grid::Direction::TopToBottom };