summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSaagar Jha <saagar@saagarjha.com>2020-05-07 16:09:17 -0700
committerSaagar Jha <saagar@saagarjha.com>2020-05-13 11:29:55 -0700
commitc9ce16a63376389c6fdcdec01512754fd36fe12e (patch)
tree0774a27d46de66d6432069124dfa652c30e2285f
parent684e9e04ad437e26a785e46aca8740e6831343be (diff)
Support excluding firmlinks on macOS
-rw-r--r--configure.ac5
-rw-r--r--src/browser.c1
-rw-r--r--src/dir_export.c4
-rw-r--r--src/dir_import.c2
-rw-r--r--src/dir_scan.c27
-rw-r--r--src/global.h3
-rw-r--r--src/main.c12
7 files changed, 51 insertions, 3 deletions
diff --git a/configure.ac b/configure.ac
index f238137..9cec626 100644
--- a/configure.ac
+++ b/configure.ac
@@ -30,6 +30,11 @@ AC_CHECK_FUNCS(
AC_CHECK_FUNCS(statfs)
+AC_CHECK_HEADERS([sys/attr.h])
+
+AC_CHECK_FUNCS([getattrlist])
+
+AC_CHECK_DECLS([ATTR_CMNEXT_NOFIRMLINKPATH], [], [], [[#include <sys/attr.h>]])
# Look for ncurses library to link to
ncurses=auto
diff --git a/src/browser.c b/src/browser.c
index 3a9971f..4306cbd 100644
--- a/src/browser.c
+++ b/src/browser.c
@@ -119,6 +119,7 @@ static void browse_draw_flag(struct dir *n, int *x) {
n->flags & FF_SERR ? '.' :
n->flags & FF_OTHFS ? '>' :
n->flags & FF_KERNFS ? '^' :
+ n->flags & FF_FRMLNK ? 'F' :
n->flags & FF_HLNKC ? 'H' :
!(n->flags & FF_FILE
|| n->flags & FF_DIR) ? '@' :
diff --git a/src/dir_export.c b/src/dir_export.c
index f602421..dd96721 100644
--- a/src/dir_export.c
+++ b/src/dir_export.c
@@ -116,7 +116,7 @@ static void output_info(struct dir *d, const char *name, struct dir_ext *e) {
if(d->flags & FF_ERR)
fputs(",\"read_error\":true", stream);
/* excluded/error'd files are "unknown" with respect to the "notreg" field. */
- if(!(d->flags & (FF_DIR|FF_FILE|FF_ERR|FF_EXL|FF_OTHFS|FF_KERNFS)))
+ if(!(d->flags & (FF_DIR|FF_FILE|FF_ERR|FF_EXL|FF_OTHFS|FF_KERNFS|FF_FRMLNK)))
fputs(",\"notreg\":true", stream);
if(d->flags & FF_EXL)
fputs(",\"excluded\":\"pattern\"", stream);
@@ -124,6 +124,8 @@ static void output_info(struct dir *d, const char *name, struct dir_ext *e) {
fputs(",\"excluded\":\"othfs\"", stream);
else if(d->flags & FF_KERNFS)
fputs(",\"excluded\":\"kernfs\"", stream);
+ else if(d->flags & FF_FRMLNK)
+ fputs(",\"excluded\":\"frmlnk\"", stream);
fputc('}', stream);
}
diff --git a/src/dir_import.c b/src/dir_import.c
index b3aeb7b..142b5e4 100644
--- a/src/dir_import.c
+++ b/src/dir_import.c
@@ -482,6 +482,8 @@ static int iteminfo(void) {
ctx->buf_dir->flags |= FF_OTHFS;
else if(strcmp(ctx->val, "kernfs") == 0)
ctx->buf_dir->flags |= FF_KERNFS;
+ else if(strcmp(ctx->val, "frmlnk") == 0)
+ ctx->buf_dir->flags |= FF_FRMLNK;
else
ctx->buf_dir->flags |= FF_EXL;
} else if(strcmp(ctx->val, "notreg") == 0) { /* notreg */
diff --git a/src/dir_scan.c b/src/dir_scan.c
index 74c123a..ea3c267 100644
--- a/src/dir_scan.c
+++ b/src/dir_scan.c
@@ -34,6 +34,10 @@
#include <sys/stat.h>
#include <dirent.h>
+#if HAVE_SYS_ATTR_H && HAVE_GETATTRLIST && HAVE_DECL_ATTR_CMNEXT_NOFIRMLINKPATH
+#include <sys/attr.h>
+#endif
+
#if HAVE_LINUX_MAGIC_H && HAVE_SYS_STATFS_H && HAVE_STATFS
#include <sys/statfs.h>
#include <linux/magic.h>
@@ -241,6 +245,25 @@ static int dir_scan_item(const char *name) {
}
#endif
+#if HAVE_SYS_ATTR_H && HAVE_GETATTRLIST && HAVE_DECL_ATTR_CMNEXT_NOFIRMLINKPATH
+ if(!follow_firmlinks) {
+ struct attrlist list = {
+ .bitmapcount = ATTR_BIT_MAP_COUNT,
+ .forkattr = ATTR_CMNEXT_NOFIRMLINKPATH,
+ };
+ struct {
+ uint32_t length;
+ attrreference_t reference;
+ char extra[PATH_MAX];
+ } __attribute__((aligned(4), packed)) attributes;
+ if (getattrlist(name, &list, &attributes, sizeof(attributes), FSOPT_ATTR_CMN_EXTENDED) == -1) {
+ buf_dir->flags |= FF_ERR;
+ dir_setlasterr(dir_curpath);
+ } else if (strcmp(dir_curpath, (char *)&attributes.reference + attributes.reference.attr_dataoffset))
+ buf_dir->flags |= FF_FRMLNK;
+ }
+#endif
+
if(!(buf_dir->flags & (FF_ERR|FF_EXL))) {
if(follow_symlinks && S_ISLNK(st.st_mode) && !stat(name, &stl) && !S_ISDIR(stl.st_mode))
stat_to_dir(&stl);
@@ -248,14 +271,14 @@ static int dir_scan_item(const char *name) {
stat_to_dir(&st);
}
- if(cachedir_tags && (buf_dir->flags & FF_DIR) && !(buf_dir->flags & (FF_ERR|FF_EXL|FF_OTHFS|FF_KERNFS)))
+ if(cachedir_tags && (buf_dir->flags & FF_DIR) && !(buf_dir->flags & (FF_ERR|FF_EXL|FF_OTHFS|FF_KERNFS|FF_FRMLNK)))
if(has_cachedir_tag(name)) {
buf_dir->flags |= FF_EXL;
buf_dir->size = buf_dir->asize = 0;
}
/* Recurse into the dir or output the item */
- if(buf_dir->flags & FF_DIR && !(buf_dir->flags & (FF_ERR|FF_EXL|FF_OTHFS|FF_KERNFS)))
+ if(buf_dir->flags & FF_DIR && !(buf_dir->flags & (FF_ERR|FF_EXL|FF_OTHFS|FF_KERNFS|FF_FRMLNK)))
fail = dir_scan_recurse(name);
else if(buf_dir->flags & FF_DIR) {
if(dir_output.item(buf_dir, name, buf_ext) || dir_output.item(NULL, 0, NULL)) {
diff --git a/src/global.h b/src/global.h
index de7a9c2..afb9c5e 100644
--- a/src/global.h
+++ b/src/global.h
@@ -52,6 +52,7 @@
#define FF_BSEL 0x80 /* selected */
#define FF_EXT 0x100 /* extended struct available */
#define FF_KERNFS 0x200 /* excluded because it was a Linux pseudo filesystem */
+#define FF_FRMLNK 0x400 /* excluded because it was a firmlink */
/* Program states */
#define ST_CALC 0
@@ -106,6 +107,8 @@ extern int confirm_quit;
extern int extended_info;
/* flag whether we want to follow symlinks */
extern int follow_symlinks;
+/* flag whether we want to follow firmlinks */
+extern int follow_firmlinks;
/* handle input from keyboard and update display */
int input_handle(int);
diff --git a/src/main.c b/src/main.c
index cc7d43b..13b6de8 100644
--- a/src/main.c
+++ b/src/main.c
@@ -42,6 +42,7 @@ long update_delay = 100;
int cachedir_tags = 0;
int extended_info = 0;
int follow_symlinks = 0;
+int follow_firmlinks = 0;
int confirm_quit = 0;
static int min_rows = 17, min_cols = 60;
@@ -138,6 +139,7 @@ static void argv_parse(int argc, char **argv) {
{ 'L', 0, "-L,--follow-symlinks" },
{ 'C', 0, "--exclude-caches" },
{ 2, 0, "--exclude-kernfs" },
+ { 3, 0, "--follow-firmlinks" },
{ 's', 0, "--si" },
{ 'Q', 0, "--confirm-quit" },
{ 'c', 1, "--color" },
@@ -170,6 +172,9 @@ static void argv_parse(int argc, char **argv) {
#if HAVE_LINUX_MAGIC_H && HAVE_SYS_STATFS_H && HAVE_STATFS
printf(" --exclude-kernfs Exclude Linux pseudo filesystems (procfs,sysfs,cgroup,...)\n");
#endif
+#if HAVE_SYS_ATTR_H && HAVE_GETATTRLIST && HAVE_DECL_ATTR_CMNEXT_NOFIRMLINKPATH
+ printf(" --follow-firmlinks Follow firmlinks on macOS\n");
+#endif
printf(" --confirm-quit Confirm quitting ncdu\n");
printf(" --color SCHEME Set color scheme (off/dark)\n");
exit(0);
@@ -206,6 +211,13 @@ static void argv_parse(int argc, char **argv) {
fprintf(stderr, "This feature is not supported on your platform\n");
exit(1);
#endif
+ case 3 :
+#if HAVE_SYS_ATTR_H && HAVE_GETATTRLIST && HAVE_DECL_ATTR_CMNEXT_NOFIRMLINKPATH
+ follow_firmlinks = 1; break;
+#else
+ fprintf(stderr, "This feature is not supported on your platform\n");
+ exit(1);
+#endif
case 'c':
if(strcmp(val, "off") == 0) { uic_theme = 0; }
else if(strcmp(val, "dark") == 0) { uic_theme = 1; }