Browse Source

refresh

master
boB Rudis 5 years ago
parent
commit
5d25f7cece
No known key found for this signature in database GPG Key ID: 1D7529BE14E2BBA9
  1. 1
      .Rbuildignore
  2. 8
      DESCRIPTION
  3. 1
      R/df.R
  4. 10
      R/get.R
  5. 2
      R/rm.R
  6. 4
      R/set.R
  7. 16
      R/util.R
  8. 2
      R/xattrs-package.R
  9. 79
      README.Rmd
  10. 77
      README.md
  11. 8
      man/xattrs.Rd
  12. 2
      src/extattr.h
  13. 14
      src/xattrs-main.cpp

1
.Rbuildignore

@ -12,3 +12,4 @@
^README\.Rmd$
^README-.*\.png$
^CONDUCT\.md$
^docs$

8
DESCRIPTION

@ -1,8 +1,8 @@
Package: xattrs
Type: Package
Title: Work With Filesystem Object Extended Attributes
Version: 0.1.0
Date: 2018-05-30
Version: 0.1.1
Date: 2019-08-23
Authors@R: c(
person("Bob", "Rudis", email = "bob@rud.is", role = c("aut", "cre"),
comment = c(ORCID = "0000-0001-5670-2640")),
@ -14,8 +14,8 @@ Description: Filesystem path target extended attributes store extra, customizabl
small bits of info. For example, author name, file character encoding, short
comments, security status, etc. Methods are provided to list, extract and work
with these attributes.
URL: https://github.com/hrbrmstr/xattrs
BugReports: https://github.com/hrbrmstr/xattrs/issues
URL: https://gitlab.com/hrbrmstr/xattrs
BugReports: https://gitlab.com/hrbrmstr/xattrs/issues
Encoding: UTF-8
License: MIT + file LICENSE
Suggests:

1
R/df.R

@ -7,6 +7,7 @@
#' @example inst/examples/ex1.R
get_xattr_df <- function(path, follow_symlinks = TRUE) {
path <- path.expand(path[1])
xattr_list <- rcpp_get_xattr_df(path, follow_symlinks)
class(xattr_list$contents) <- c("AsIs", "list")
xdf <- as.data.frame(xattr_list, stringsAsFactors=FALSE)

10
R/get.R

@ -8,7 +8,7 @@
#' @example inst/examples/ex1.R
get_xattr <- function(path, name, follow_symlinks=TRUE) {
path <- path.expand(path)
path <- path.expand(path[1])
if (!file.exists(path)) stop("File not found.", call.=FALSE)
name <- handle_user_prefix_param(name)
@ -27,10 +27,10 @@ get_xattr <- function(path, name, follow_symlinks=TRUE) {
#' @example inst/examples/ex1.R
get_xattr_raw <- function(path, name, follow_symlinks=TRUE) {
path <- path.expand(path)
path <- path.expand(path[1])
if (!file.exists(path)) stop("File not found.", call.=FALSE)
name <- handle_user_prefix_param(name)
name <- handle_user_prefix_param(name[1])
ret <- rcpp_get_xattr_raw(path, name, follow_symlinks)
@ -46,10 +46,10 @@ get_xattr_raw <- function(path, name, follow_symlinks=TRUE) {
#' @example inst/examples/ex1.R
get_xattr_size <- function(path, name, follow_symlinks=TRUE) {
path <- path.expand(path)
path <- path.expand(path[1])
if (!file.exists(path)) stop("File not found.", call.=FALSE)
name <- handle_user_prefix_param(name)
name <- handle_user_prefix_param(name[1])
ret <- rcpp_get_xattr_size(path, name, follow_symlinks)

2
R/rm.R

@ -8,7 +8,7 @@
#' @example inst/examples/ex1.R
rm_xattr <- function(path, name, follow_symlinks=TRUE) {
path <- path.expand(path)
path <- path.expand(path[1])
if (!file.exists(path)) stop("File not found.", call.=FALSE)
name <- handle_user_prefix_param(name)

4
R/set.R

@ -9,10 +9,10 @@
#' @example inst/examples/ex1.R
set_xattr <- function(path, name, value, follow_symlinks=TRUE) {
path <- path.expand(path)
path <- path.expand(path[1])
if (!file.exists(path)) stop("File not found.", call.=FALSE)
name <- handle_user_prefix_param(name)
name <- handle_user_prefix_param(name[1])
value <- value[1]
if (is.character(value)) value <- charToRaw(value)

16
R/util.R

@ -16,6 +16,8 @@ find_plutil <- function() {
convert_plist <- function(path) {
path <- path[1]
plutil <- find_plutil()
if (plutil == "plistutil") {
@ -43,14 +45,14 @@ convert_plist <- function(path) {
}
# Linux: attributes are prefixed with a namespace, that is,
# an attribute has the form: namespace.attribute
# Linux: attributes are prefixed with a namespace, that is,
# an attribute has the form: namespace.attribute
# Examples: user.mime_type, trusted.md5sum, system.posix_acl_access
# for xattrs, the interest is primarily to access the user
# namespace. When a namespace is missing, "user" is used as namespace.
# https://linux.die.net/man/5/attr
#
# Removing the namespace "user" from attribute names used in
# Removing the namespace "user" from attribute names used in
# parameters or when listing attributes enables to use the same
# R code across platforms
@ -64,10 +66,10 @@ linux_namespaces <- c("user", "security", "system", "trusted")
handle_user_prefix_param <- function(stringvector){
# vectorised function to work on linux where attribute
# name are to be prefixed with "user." for parameters
# name are to be prefixed with "user." for parameters
if(grepl("linux", sessionInfo()$platform)) {
unname(sapply(stringvector, function(x)
unname(sapply(stringvector, function(x)
ifelse(grepl(paste0("^(", paste0(linux_namespaces, collapse = "|"), ")[.]"), x), x, paste0("user.", x))))
} else {
stringvector
@ -83,7 +85,7 @@ handle_user_prefix_return <- function(stringvector){
# vectorised function to work on linux where from
# attribute names the prefix "user." should be removed
if(grepl("linux", sessionInfo()$platform)) {
unname(sapply(stringvector, function(x) ifelse(grepl("^user.", x), sub("^user.(.*)$", "\\1", x))))
} else {

2
R/xattrs-package.R

@ -13,4 +13,4 @@
#' @importFrom sys exec_internal
#' @importFrom Rcpp sourceCpp
#' @example inst/examples/ex1.R
NULL
"_PACKAGE"

79
README.Rmd

@ -1,25 +1,19 @@
---
output: github_document
editor_options:
chunk_output_type: console
output:
rmarkdown::github_document:
df_print: kable
---
<!-- README.md is generated from README.Rmd. Please edit that file -->
```{r, echo = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "##",
fig.path = "README-"
)
```{r pkg-knitr-opts, include=FALSE}
hrbrpkghelpr::global_opts()
```
# xattrs
Work With Filesystem Object Extended Attributes
## Description
```{r badges, results='asis', echo=FALSE, cache=FALSE}
hrbrpkghelpr::stinking_badges()
```
Filesystem path target extended attributes store extra, customizable, small bits of info. For example, author name, file character encoding, short comments, security status, etc. Methods are provided to list, extract and work with these attributes.
```{r description, results='asis', echo=FALSE, cache=FALSE}
hrbrpkghelpr::yank_title_and_description()
```
## NOTE
@ -29,28 +23,19 @@ I don't think this will work on Windows.
The following functions are implemented:
- `get_xattr`: Retrieve the contents of the named xattr
- `get_xattr_df`: Retrieve a data frame of xattr names, sizes and (raw) contents for a target path
- `get_xattr_raw`: Retrieve the (raw) contents of the named xattr
- `get_xattr_size`: Retrieve the size (bytes) of the named xattr
- `has_xattrs`: Test if a target path has xattrs
- `is_bplist`: Tests whether a raw vector is really a binary plist
- `list_xattrs`: List extended attribute names of a target path
- `read_bplist`: Convert binary plist to something usable in R
```{r ingredients, results='asis', echo=FALSE, cache=FALSE}
hrbrpkghelpr::describe_ingredients()
```
## Installation
```{r eval=FALSE}
devtools::install_github("hrbrmstr/xattrs")
```
```{r message=FALSE, warning=FALSE, error=FALSE, include=FALSE}
options(width=120)
```{r install-ex, results='asis', echo=FALSE, cache=FALSE}
hrbrpkghelpr::install_block()
```
## Usage
```{r message=FALSE, warning=FALSE, error=FALSE}
```{r usage, cache=FALSE}
library(xattrs)
library(tidyverse) # for printing
@ -63,7 +48,7 @@ packageVersion("xattrs")
Extended attributes seem to get stripped when R builds pkgs so until I can figure out an easy way not to do that, just find any file on your system that has an `@` next to the permissions string in an `ls -l` directory listing.
```{r eval=FALSE}
```{r 1, eval=FALSE}
sample_file <- "~/Downloads/AdvancedTechniquesWithAWSGlueETLJobs.pdf"
list_xattrs(sample_file)
@ -76,7 +61,7 @@ get_xattr_size(sample_file, "com.apple.metadata:kMDItemWhereFroms")
Extended attributes can be _anything_ so it makes alot of sense to work with the contents as a raw vector:
```{r eval=FALSE}
```{r 2, eval=FALSE}
get_xattr_raw(sample_file, "com.apple.metadata:kMDItemWhereFroms")
## [1] 62 70 6c 69 73 74 30 30 a2 01 02 5f 10 6b 68 74 74 70 73 3a 2f
## [22] 2f 66 69 6c 65 73 2e 73 6c 61 63 6b 2e 63 6f 6d 2f 66 69 6c 65
@ -90,28 +75,28 @@ get_xattr_raw(sample_file, "com.apple.metadata:kMDItemWhereFroms")
There is a "string" version of the function, but it may return "nothing" if there are embedded NULLs or other breaking characters in the contents:
```{r eval=FALSE}
```{r 3, eval=FALSE}
get_xattr(sample_file, "com.apple.metadata:kMDItemWhereFroms")
## [1] "bplist00\xa2\001\002_\020khttps://files.slack.com/files-pri/T3V1ZDQHM-FDJGYKWJ3/download/advancedtechniqueswithawsglueetljobs__1_.pdfP\b\vy"
```
You are really better off doing this if you really want a raw string conversion:
```{r eval=FALSE}
```{r 4, eval=FALSE}
readBin(get_xattr_raw(sample_file, "com.apple.metadata:kMDItemWhereFroms"), "character")
## [1] "bplist00\xa2\001\002_\020khttps://files.slack.com/files-pri/T3V1ZDQHM-FDJGYKWJ3/download/advancedtechniqueswithawsglueetljobs__1_.pdfP\b\vy"
```
More often than not (on macOS) extended attributes are "binary property lists" (or "binary plist" for short). You can test to see if the returned raw vector is likely a binary plist:
```{r eval=FALSE}
```{r 5, eval=FALSE}
is_bplist(get_xattr_raw(sample_file, "com.apple.metadata:kMDItemWhereFroms"))
## [1] TRUE
```
If it is, you can get the data out of it. For now, this makes a system call to `plutil` on macOS and `plistutil` on other systems. You'll be given a hint on how to install `plistutil` if it's not found.
```{r eval=FALSE}
```{r 6, eval=FALSE}
read_bplist(get_xattr_raw(sample_file, "com.apple.metadata:kMDItemWhereFroms"))
## $plist
## $plist$array
@ -130,7 +115,7 @@ read_bplist(get_xattr_raw(sample_file, "com.apple.metadata:kMDItemWhereFroms"))
This is R, so you should really consider doing this instead of any of the above #rectanglesrule:
```{r eval=FALSE}
```{r 7, eval=FALSE}
get_xattr_df(sample_file)
## # A tibble: 2 x 3
## name size contents
@ -141,7 +126,7 @@ get_xattr_df(sample_file)
you can live dangerously even with data frames, tho:
```{r eval=FALSE}
```{r 8, eval=FALSE}
get_xattr_df(sample_file) %>%
mutate(txt = map_chr(contents, readBin, "character")) # potentially "dangerous"
## # A tibble: 2 x 4
@ -155,7 +140,7 @@ get_xattr_df(sample_file) %>%
We can process a whole directory of files to see what extended attributes various path targets have:
```{r eval=FALSE}
```{r 9, eval=FALSE}
fils <- list.files("~/Downloads", full.names = TRUE)
xdf <- map_df(set_names(fils, fils), get_xattr_df, .id="path")
@ -179,7 +164,7 @@ count(xdf, name, sort=TRUE)
And we can work with `com.apple.metadata:kMDItemWhereFroms` binary plist data in bulk:
```{r eval=FALSE}
```{r 10, eval=FALSE}
filter(xdf, name == "com.apple.metadata:kMDItemWhereFroms") %>%
filter(map_lgl(contents, is_bplist)) %>%
mutate(converted = map(contents, read_bplist)) %>%
@ -205,7 +190,7 @@ filter(xdf, name == "com.apple.metadata:kMDItemWhereFroms") %>%
### Full Suite
```{r}
```{r full-suite}
# Create a temp file for the example
tf <- tempfile(fileext = ".csv")
write.csv(mtcars, tf)
@ -245,6 +230,12 @@ get_xattr(tf, "is.rud.setting")
unlink(tf)
```
## xattrs Metrics
```{r cloc, echo=FALSE}
cloc::cloc_pkg_md()
```
## Code of Conduct
Please note that this project is released with a [Contributor Code of Conduct](CONDUCT.md). By participating in this project you agree to abide by its terms.
Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.

77
README.md

@ -1,5 +1,18 @@
<!-- README.md is generated from README.Rmd. Please edit that file -->
[![Project Status: Active – The project has reached a stable, usable
state and is being actively
developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active)
[![Signed
by](https://img.shields.io/badge/Keybase-Verified-brightgreen.svg)](https://keybase.io/hrbrmstr)
![Signed commit
%](https://img.shields.io/badge/Signed_Commits-22.0%25-lightgrey.svg)
[![Linux build
Status](https://travis-ci.org/hrbrmstr/xattrs.svg?branch=master)](https://travis-ci.org/hrbrmstr/xattrs)
[![Coverage
Status](https://codecov.io/gh/hrbrmstr/xattrs/branch/master/graph/badge.svg)](https://codecov.io/gh/hrbrmstr/xattrs)
![Minimal R
Version](https://img.shields.io/badge/R%3E%3D-3.2.0-blue.svg)
![License](https://img.shields.io/badge/License-MIT-blue.svg)
# xattrs
@ -20,22 +33,33 @@ I don’t think this will work on Windows.
The following functions are implemented:
- `get_xattr`: Retrieve the contents of the named xattr
- `get_xattr_df`: Retrieve a data frame of xattr names, sizes and
(raw) contents for a target path
- `get_xattr_raw`: Retrieve the (raw) contents of the named xattr
- `get_xattr_size`: Retrieve the size (bytes) of the named xattr
- `get_xattr_raw`: Get raw contents of an extended attribute
- `get_xattr_size`: Get size of an extended attribute
- `get_xattr`: Get an extended attribute
- `handle_user_prefix_param`: handle\_user\_prefix\_param
- `handle_user_prefix_return`: handle\_user\_prefix\_return
- `has_xattrs`: Test if a target path has xattrs
- `is_bplist`: Tests whether a raw vector is really a binary plist
- `list_xattrs`: List extended attribute names of a target path
- `list_xattrs`: List attributes
- `read_bplist`: Convert binary plist to something usable in R
- `rm_xattr`: Remove an extended attribute
- `set_xattr`: Set or modify an extended attribute
## Installation
``` r
devtools::install_github("hrbrmstr/xattrs")
install.packages("xattrs", repos = "https://cinc.rud.is")
# or
remotes::install_gitlab("hrbrmstr/xattrs")
# or
remotes::install_github("hrbrmstr/xattrs")
```
NOTE: To use the ‘remotes’ install options you will need to have the
[{remotes} package](https://github.com/r-lib/remotes) installed.
## Usage
``` r
@ -44,7 +68,7 @@ library(tidyverse) # for printing
# current verison
packageVersion("xattrs")
## [1] '0.1.0'
## [1] '0.1.1'
```
### Basic Operation
@ -99,8 +123,7 @@ readBin(get_xattr_raw(sample_file, "com.apple.metadata:kMDItemWhereFroms"), "cha
More often than not (on macOS) extended attributes are “binary property
lists” (or “binary plist” for short). You can test to see if the
returned raw vector is likely a binary
plist:
returned raw vector is likely a binary plist:
``` r
is_bplist(get_xattr_raw(sample_file, "com.apple.metadata:kMDItemWhereFroms"))
@ -109,8 +132,7 @@ is_bplist(get_xattr_raw(sample_file, "com.apple.metadata:kMDItemWhereFroms"))
If it is, you can get the data out of it. For now, this makes a system
call to `plutil` on macOS and `plistutil` on other systems. You’ll be
given a hint on how to install `plistutil` if it’s not
found.
given a hint on how to install `plistutil` if it’s not found.
``` r
read_bplist(get_xattr_raw(sample_file, "com.apple.metadata:kMDItemWhereFroms"))
@ -250,15 +272,21 @@ list_xattrs(tf)
# data frame vs individual functions
get_xattr_df(tf)
## # A tibble: 2 x 3
## name size contents
## <chr> <dbl> <list>
## 1 is.rud.setting.a 15 <raw [15]>
## 2 is.rud.setting.b 16 <raw [16]>
```
<div class="kable-table">
| name | size | contents |
| :--------------- | ---: | :-------------------------------------------------------------------------------------------------------- |
| is.rud.setting.a | 15 | as.raw(c(0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65)) |
| is.rud.setting.b | 16 | as.raw(c(0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65)) |
</div>
``` r
# remove attribute
rm_xattr(tf, "is.rud.setting")
## Warning: Error -1 while removing attribute.
get_xattr(tf, "is.rud.setting")
## character(0)
@ -266,8 +294,17 @@ get_xattr(tf, "is.rud.setting")
unlink(tf)
```
## xattrs Metrics
| Lang | \# Files | (%) | LoC | (%) | Blank lines | (%) | \# Lines | (%) |
| :----------- | -------: | ---: | --: | ---: | ----------: | ---: | -------: | ---: |
| C/C++ Header | 1 | 0.06 | 283 | 0.35 | 69 | 0.29 | 90 | 0.22 |
| R | 13 | 0.76 | 240 | 0.30 | 86 | 0.36 | 158 | 0.38 |
| C++ | 2 | 0.12 | 228 | 0.28 | 33 | 0.14 | 26 | 0.06 |
| Rmd | 1 | 0.06 | 49 | 0.06 | 54 | 0.22 | 138 | 0.33 |
## Code of Conduct
Please note that this project is released with a [Contributor Code of
Conduct](CONDUCT.md). By participating in this project you agree to
abide by its terms.
Please note that this project is released with a Contributor Code of
Conduct. By participating in this project you agree to abide by its
terms.

8
man/xattrs.Rd

@ -50,6 +50,14 @@ get_xattr(tf, "is.rud.setting")
unlink(tf)
}
\seealso{
Useful links:
\itemize{
\item \url{https://gitlab.com/hrbrmstr/xattrs}
\item Report bugs at \url{https://gitlab.com/hrbrmstr/xattrs/issues}
}
}
\author{
Bob Rudis (bob@rud.is)
}

2
src/extattr.h

@ -19,7 +19,6 @@
#include <attr/xattr.h>
#endif
#if defined(__FreeBSD__)
#include <sys/extattr.h>
#endif
@ -46,7 +45,6 @@ inline int setxattr(int fd, const std::string &name, const std::string &value, i
}
*/
inline int setxattr(const std::string path, const std::string &name, const std::string &value, int options=0)
{
#if defined(__APPLE__) && defined(__MACH__)

14
src/xattrs-main.cpp

@ -11,7 +11,6 @@
using namespace Rcpp;
//' Test if a target path has xattrs
//'
//' @md
@ -27,14 +26,12 @@ bool has_xattrs(const std::string path, bool follow_symlinks=true) {
return(listxattrsize(full_path, options) > 0);
}
inline RawVector getxattr_raw(const std::string path, const std::string &name, int options=0) {
ssize_t size = getxattrsize(path, name, options);
uint8_t *buf;
if( size <= 0 ) return RawVector::create();
if (size <= 0) return RawVector::create();
buf = new uint8_t[size];
@ -54,7 +51,6 @@ inline RawVector getxattr_raw(const std::string path, const std::string &name, i
}
inline int setxattr_raw(const std::string path, const std::string &name, RawVector value, int options=0) {
#if defined(__APPLE__) && defined(__MACH__)
return setxattr(path.c_str(), name.c_str(), value.begin(), value.size(), 0, options);
@ -74,7 +70,6 @@ int rcpp_set_xattr(std::string path, std::string name, RawVector value, bool fol
return(setxattr_raw(path, name, value, options));
}
// [[Rcpp::export]]
int rcpp_rm_xattr(std::string path, std::string name, bool follow_symlinks=true) {
int options = 0;
@ -91,7 +86,6 @@ int rcpp_rm_xattr(std::string path, std::string name, bool follow_symlinks=true)
}
// [[Rcpp::export]]
CharacterVector rcpp_list_xattrs(const std::string path, bool follow_symlinks=true) {
std::string full_path = std::string(R_ExpandFileName(path.c_str()));
@ -103,7 +97,6 @@ CharacterVector rcpp_list_xattrs(const std::string path, bool follow_symlinks=tr
return(CharacterVector::create());
}
// [[Rcpp::export]]
CharacterVector rcpp_get_xattr(const std::string path, std::string name, bool follow_symlinks=true) {
std::string full_path = std::string(R_ExpandFileName(path.c_str()));
@ -128,7 +121,6 @@ RawVector rcpp_get_xattr_raw(const std::string path, std::string name, bool foll
return(RawVector::create());
}
// [[Rcpp::export]]
ssize_t rcpp_get_xattr_size(const std::string path, std::string name, bool follow_symlinks=true) {
std::string full_path = std::string(R_ExpandFileName(path.c_str()));
@ -153,7 +145,7 @@ List rcpp_get_xattr_df(const std::string path, bool follow_symlinks=true) {
std::vector<ssize_t> sz(xnames.size());
std::vector<RawVector> contents(xnames.size());
for (unsigned int i=0; i<xnames.size(); i++) {
for (R_xlen_t i=0; i<xnames.size(); i++) {
sz[i] = getxattrsize(full_path, xnames[i], options);
contents[i] = RawVector(getxattr_raw(full_path, xnames[i], options));
}
@ -167,5 +159,3 @@ List rcpp_get_xattr_df(const std::string path, bool follow_symlinks=true) {
return(xdf);
}

Loading…
Cancel
Save