Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/hrbrmstr/xattrs

πŸ—ƒ Work With Filesystem Object Extended Attributes β€” https://hrbrmstr.github.io/xattrs/index.html
https://github.com/hrbrmstr/xattrs

r r-cyber rstats xattr xattr-support

Last synced: 23 days ago
JSON representation

πŸ—ƒ Work With Filesystem Object Extended Attributes β€” https://hrbrmstr.github.io/xattrs/index.html

Awesome Lists containing this project

README

        

---
output:
rmarkdown::github_document:
df_print: kable
---
```{r pkg-knitr-opts, include=FALSE}
hrbrpkghelpr::global_opts()
```

```{r badges, results='asis', echo=FALSE, cache=FALSE}
hrbrpkghelpr::stinking_badges()
```

```{r description, results='asis', echo=FALSE, cache=FALSE}
hrbrpkghelpr::yank_title_and_description()
```

## NOTE

I don't think this will work on Windows.

## What's Inside The Tin

The following functions are implemented:

```{r ingredients, results='asis', echo=FALSE, cache=FALSE}
hrbrpkghelpr::describe_ingredients()
```

## Installation

```{r install-ex, results='asis', echo=FALSE, cache=FALSE}
hrbrpkghelpr::install_block()
```

## Usage

```{r usage, cache=FALSE}
library(xattrs)
library(tidyverse) # for printing

# current verison
packageVersion("xattrs")

```

### Basic Operation

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 1, eval=FALSE}
sample_file <- "~/Downloads/AdvancedTechniquesWithAWSGlueETLJobs.pdf"

list_xattrs(sample_file)
## [1] "com.apple.metadata:kMDItemWhereFroms"
## [2] "com.apple.quarantine"

get_xattr_size(sample_file, "com.apple.metadata:kMDItemWhereFroms")
## 157
```

Extended attributes can be _anything_ so it makes alot of sense to work with the contents as a raw vector:

```{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
## [43] 73 2d 70 72 69 2f 54 33 56 31 5a 44 51 48 4d 2d 46 44 4a 47 59
## [64] 4b 57 4a 33 2f 64 6f 77 6e 6c 6f 61 64 2f 61 64 76 61 6e 63 65
## [85] 64 74 65 63 68 6e 69 71 75 65 73 77 69 74 68 61 77 73 67 6c 75
## [106] 65 65 74 6c 6a 6f 62 73 5f 5f 31 5f 2e 70 64 66 50 08 0b 79 00
## [127] 00 00 00 00 00 01 01 00 00 00 00 00 00 00 03 00 00 00 00 00 00
## [148] 00 00 00 00 00 00 00 00 00 7a
```

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 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 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 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 6, eval=FALSE}
read_bplist(get_xattr_raw(sample_file, "com.apple.metadata:kMDItemWhereFroms"))
## $plist
## $plist$array
## $plist$array$string
## $plist$array$string[[1]]
## [1] "https://files.slack.com/files-pri/T3V1ZDQHM-FDJGYKWJ3/download/advancedtechniqueswithawsglueetljobs__1_.pdf"
##
##
## $plist$array$string
## list()
##
##
## attr(,"version")
## [1] "1.0"
```

This is R, so you should really consider doing this instead of any of the above #rectanglesrule:

```{r 7, eval=FALSE}
get_xattr_df(sample_file)
## # A tibble: 2 x 3
## name size contents
##
## 1 com.apple.metadata:kMDItemWhereFroms 157
## 2 com.apple.quarantine 56
```

you can live dangerously even with data frames, tho:

```{r 8, eval=FALSE}
get_xattr_df(sample_file) %>%
mutate(txt = map_chr(contents, readBin, "character")) # potentially "dangerous"
## # A tibble: 2 x 4
## name size contents txt
##
## 1 com.apple.metadata… 157
## 1 com.apple.quarantine 55
## 2 com.apple.metadata:kMDItemWhereFroms 46
## 3 com.apple.lastuseddate#PS 13
## 4 com.apple.metadata:_kMDItemUserTags 3
## 5 com.apple.metadata:kMDItemDownloadedDate 2
## 6 com.apple.diskimages.fsck 1
## 7 com.apple.diskimages.recentcksum 1
## 8 com.apple.FinderInfo 1
## 9 com.apple.metadata:com_apple_mail_dateReceived 1
## 10 com.apple.metadata:com_apple_mail_dateSent 1
## 11 com.apple.metadata:com_apple_mail_isRemoteAttachment 1
```

And we can work with `com.apple.metadata:kMDItemWhereFroms` binary plist data in bulk:

```{r 10, eval=FALSE}
filter(xdf, name == "com.apple.metadata:kMDItemWhereFroms") %>%
filter(map_lgl(contents, is_bplist)) %>%
mutate(converted = map(contents, read_bplist)) %>%
select(size, converted) %>%
mutate(converted = map(converted, ~flatten_chr(.x$plist$array$string))) %>%
unnest() %>%
mutate(converted = urltools::domain(converted)) # you don't rly need to see the full URLs for this example
## # A tibble: 44 x 2
## size converted
##
## 1 189 dl.packetstormsecurity.net
## 2 129 files.slack.com
## 3 120 files.slack.com
## 4 117 files.slack.com
## 5 592 irma.nps.gov
## 6 157 files.slack.com
## 7 624 github-production-release-asset-2e65be.s3.amazonaws.com
## 8 197 images.unsplash.com
## 9 197 images.unsplash.com
## 10 185 files.slack.com
## # … with 34 more rows
```

### Full Suite

```{r full-suite}
# Create a temp file for the example
tf <- tempfile(fileext = ".csv")
write.csv(mtcars, tf)

# has attributes? (shld be FALSE)
has_xattrs(tf)
get_xattr(tf, "is.rud.setting")

# set an attribute
set_xattr(tf, "is.rud.setting.a", "first attribut")
get_xattr(tf, "is.rud.setting.a")
get_xattr_size(tf, "is.rud.setting.a")

# shld be TRUE
has_xattrs(tf)

set_xattr(tf, "is.rud.setting.b", "second attribute")
get_xattr(tf, "is.rud.setting.b")
get_xattr_size(tf, "is.rud.setting.b")

# overwrite an attribute
set_xattr(tf, "is.rud.setting.a", "first attribute")
get_xattr(tf, "is.rud.setting.a")
get_xattr_size(tf, "is.rud.setting.a")

# see all the attributes
list_xattrs(tf)

# data frame vs individual functions
get_xattr_df(tf)

# remove attribute
rm_xattr(tf, "is.rud.setting")
get_xattr(tf, "is.rud.setting")

# cleanup
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. By participating in this project you agree to abide by its terms.