diff options
author | Yorhel <git@yorhel.nl> | 2021-05-12 11:28:00 +0200 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2021-05-12 11:28:26 +0200 |
commit | ca51d4ed1a0f61042fc43d2a7ae8732351431654 (patch) | |
tree | d8b7d56696094f4cd3bd55b4701c7a188cabe7b2 | |
parent | 9337cdc99e8c205e6e75de25de29a5be53ea858c (diff) |
JSON Export: only export ino for hlinks and include hlink count
Bumping the minor version of the file format to '2'.
The "ino" field is only interesting for hardlinks, so we can save space
by not exporting it for other entries.
The hlink count will be interesting later on when I implement tracking
of shared data between directories. It's currently ignored on import.
The "nlink" field makes the "hlnkc" field redundant, but let's keep
including that field anyway for backwards compatibility.
-rw-r--r-- | src/dir.h | 2 | ||||
-rw-r--r-- | src/dir_export.c | 18 | ||||
-rw-r--r-- | src/dir_import.c | 15 | ||||
-rw-r--r-- | src/dir_mem.c | 3 | ||||
-rw-r--r-- | src/dir_scan.c | 24 |
5 files changed, 39 insertions, 23 deletions
@@ -69,7 +69,7 @@ struct dir_output { * The function should return non-zero on error, at which point errno is * assumed to be set to something sensible. */ - int (*item)(struct dir *, const char *, struct dir_ext *); + int (*item)(struct dir *, const char *, struct dir_ext *, unsigned int); /* Finalizes the output to go to the next program state or exit ncdu. Called * after item(NULL) has been called for the root item or before any item() diff --git a/src/dir_export.c b/src/dir_export.c index dd96721..83590d4 100644 --- a/src/dir_export.c +++ b/src/dir_export.c @@ -74,7 +74,7 @@ static void output_int(uint64_t n) { } -static void output_info(struct dir *d, const char *name, struct dir_ext *e) { +static void output_info(struct dir *d, const char *name, struct dir_ext *e, unsigned int nlink) { if(!extended_info || !(d->flags & FF_EXT)) e = NULL; @@ -96,8 +96,6 @@ static void output_info(struct dir *d, const char *name, struct dir_ext *e) { fputs(",\"dev\":", stream); output_int(d->dev); } - fputs(",\"ino\":", stream); - output_int(d->ino); if(e) { fputs(",\"uid\":", stream); @@ -111,8 +109,12 @@ static void output_info(struct dir *d, const char *name, struct dir_ext *e) { } /* TODO: Including the actual number of links would be nicer. */ - if(d->flags & FF_HLNKC) - fputs(",\"hlnkc\":true", stream); + if(d->flags & FF_HLNKC) { + fputs(",\"ino\":", stream); + output_int(d->ino); + fputs(",\"hlnkc\":true,\"nlink\":", stream); + output_int(nlink); + } if(d->flags & FF_ERR) fputs(",\"read_error\":true", stream); /* excluded/error'd files are "unknown" with respect to the "notreg" field. */ @@ -136,7 +138,7 @@ static void output_info(struct dir *d, const char *name, struct dir_ext *e) { * item() call do we check for ferror(). This greatly simplifies the code, but * assumes that calls to fwrite()/fput./etc don't do any weird stuff when * called with a stream that's in an error state. */ -static int item(struct dir *item, const char *name, struct dir_ext *ext) { +static int item(struct dir *item, const char *name, struct dir_ext *ext, unsigned int nlink) { if(!item) { nstack_pop(&stack); if(!stack.top) { /* closing of the root item */ @@ -152,7 +154,7 @@ static int item(struct dir *item, const char *name, struct dir_ext *ext) { /* File header. * TODO: Add scan options? */ if(!stack.top) { - fputs("[1,1,{\"progname\":\""PACKAGE"\",\"progver\":\""PACKAGE_VERSION"\",\"timestamp\":", stream); + fputs("[1,2,{\"progname\":\""PACKAGE"\",\"progver\":\""PACKAGE_VERSION"\",\"timestamp\":", stream); output_int((uint64_t)time(NULL)); fputc('}', stream); } @@ -161,7 +163,7 @@ static int item(struct dir *item, const char *name, struct dir_ext *ext) { if(item->flags & FF_DIR) fputc('[', stream); - output_info(item, name, ext); + output_info(item, name, ext, nlink); if(item->flags & FF_DIR) nstack_push(&stack, item->dev); diff --git a/src/dir_import.c b/src/dir_import.c index bde822c..cdb94a0 100644 --- a/src/dir_import.c +++ b/src/dir_import.c @@ -72,6 +72,7 @@ static struct ctx { /* scratch space */ struct dir *buf_dir; struct dir_ext buf_ext[1]; + unsigned int nlink; char buf_name[MAX_VAL]; char val[MAX_VAL]; @@ -421,7 +422,7 @@ static int itemdir(uint64_t dev) { /* Reads a JSON object representing a struct dir/dir_ext item. Writes to - * ctx->buf_dir, ctx->buf_ext and ctx->buf_name. */ + * ctx->buf_dir, ctx->buf_ext, ctx->buf_name and ctx->nlink. */ static int iteminfo(void) { uint64_t iv; @@ -470,6 +471,11 @@ static int iteminfo(void) { ctx->buf_dir->flags |= FF_HLNKC; } else C(rlit("false", 5)); + } else if(strcmp(ctx->val, "nlink") == 0) { /* nlink */ + C(rint64(&iv, UINT32_MAX)); + if(iv > 1) + ctx->buf_dir->flags |= FF_HLNKC; + ctx->nlink = iv; } else if(strcmp(ctx->val, "read_error") == 0) { /* read_error */ if(*ctx->buf == 't') { C(rlit("true", 4)); @@ -526,6 +532,7 @@ static int item(uint64_t dev) { memset(ctx->buf_dir, 0, offsetof(struct dir, name)); memset(ctx->buf_ext, 0, sizeof(struct dir_ext)); + ctx->nlink = 0; *ctx->buf_name = 0; ctx->buf_dir->flags |= isdir ? FF_DIR : FF_FILE; ctx->buf_dir->dev = dev; @@ -539,16 +546,16 @@ static int item(uint64_t dev) { dir_curpath_enter(ctx->buf_name); if(isdir) { - if(dir_output.item(ctx->buf_dir, ctx->buf_name, ctx->buf_ext)) { + if(dir_output.item(ctx->buf_dir, ctx->buf_name, ctx->buf_ext, ctx->nlink)) { dir_seterr("Output error: %s", strerror(errno)); return 1; } C(itemdir(dev)); - if(dir_output.item(NULL, 0, NULL)) { + if(dir_output.item(NULL, 0, NULL, 0)) { dir_seterr("Output error: %s", strerror(errno)); return 1; } - } else if(dir_output.item(ctx->buf_dir, ctx->buf_name, ctx->buf_ext)) { + } else if(dir_output.item(ctx->buf_dir, ctx->buf_name, ctx->buf_ext, ctx->nlink)) { dir_seterr("Output error: %s", strerror(errno)); return 1; } diff --git a/src/dir_mem.c b/src/dir_mem.c index d1dce8d..f513ab7 100644 --- a/src/dir_mem.c +++ b/src/dir_mem.c @@ -109,8 +109,9 @@ static void item_add(struct dir *item) { } -static int item(struct dir *dir, const char *name, struct dir_ext *ext) { +static int item(struct dir *dir, const char *name, struct dir_ext *ext, unsigned int nlink) { struct dir *t, *item; + (void)nlink; /* Go back to parent dir */ if(!dir) { diff --git a/src/dir_scan.c b/src/dir_scan.c index 03a582b..9629f32 100644 --- a/src/dir_scan.c +++ b/src/dir_scan.c @@ -57,6 +57,7 @@ static uint64_t curdev; /* current device we're scanning on */ /* scratch space */ static struct dir *buf_dir; static struct dir_ext buf_ext[1]; +static unsigned int buf_nlink; #if HAVE_LINUX_MAGIC_H && HAVE_SYS_STATFS_H && HAVE_STATFS @@ -120,8 +121,11 @@ static void stat_to_dir(struct stat *fs) { else if(S_ISDIR(fs->st_mode)) buf_dir->flags |= FF_DIR; - if(!S_ISDIR(fs->st_mode) && fs->st_nlink > 1) + if(!S_ISDIR(fs->st_mode) && fs->st_nlink > 1) { buf_dir->flags |= FF_HLNKC; + buf_nlink = fs->st_nlink; + } else + buf_nlink = 0; if(dir_scan_smfs && curdev != buf_dir->dev) buf_dir->flags |= FF_OTHFS; @@ -193,7 +197,7 @@ static int dir_scan_recurse(const char *name) { if(chdir(name)) { dir_setlasterr(dir_curpath); buf_dir->flags |= FF_ERR; - if(dir_output.item(buf_dir, name, buf_ext) || dir_output.item(NULL, 0, NULL)) { + if(dir_output.item(buf_dir, name, buf_ext, buf_nlink) || dir_output.item(NULL, 0, NULL, 0)) { dir_seterr("Output error: %s", strerror(errno)); return 1; } @@ -203,7 +207,7 @@ static int dir_scan_recurse(const char *name) { if((dir = dir_read(&fail)) == NULL) { dir_setlasterr(dir_curpath); buf_dir->flags |= FF_ERR; - if(dir_output.item(buf_dir, name, buf_ext) || dir_output.item(NULL, 0, NULL)) { + if(dir_output.item(buf_dir, name, buf_ext, buf_nlink) || dir_output.item(NULL, 0, NULL, 0)) { dir_seterr("Output error: %s", strerror(errno)); return 1; } @@ -218,12 +222,12 @@ static int dir_scan_recurse(const char *name) { if(fail) buf_dir->flags |= FF_ERR; - if(dir_output.item(buf_dir, name, buf_ext)) { + if(dir_output.item(buf_dir, name, buf_ext, buf_nlink)) { dir_seterr("Output error: %s", strerror(errno)); return 1; } fail = dir_walk(dir); - if(dir_output.item(NULL, 0, NULL)) { + if(dir_output.item(NULL, 0, NULL, 0)) { dir_seterr("Output error: %s", strerror(errno)); return 1; } @@ -308,11 +312,11 @@ static int dir_scan_item(const char *name) { 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)) { + if(dir_output.item(buf_dir, name, buf_ext, 0) || dir_output.item(NULL, 0, NULL, 0)) { dir_seterr("Output error: %s", strerror(errno)); fail = 1; } - } else if(dir_output.item(buf_dir, name, buf_ext)) { + } else if(dir_output.item(buf_dir, name, buf_ext, buf_nlink)) { dir_seterr("Output error: %s", strerror(errno)); fail = 1; } @@ -333,6 +337,7 @@ static int dir_walk(char *dir) { dir_curpath_enter(cur); memset(buf_dir, 0, offsetof(struct dir, name)); memset(buf_ext, 0, sizeof(struct dir_ext)); + buf_nlink = 0; fail = dir_scan_item(cur); dir_curpath_leave(); } @@ -350,6 +355,7 @@ static int process(void) { memset(buf_dir, 0, offsetof(struct dir, name)); memset(buf_ext, 0, sizeof(struct dir_ext)); + buf_nlink = 0; if((path = path_real(dir_curpath)) == NULL) dir_seterr("Error obtaining full path: %s", strerror(errno)); @@ -376,13 +382,13 @@ static int process(void) { buf_dir->flags |= FF_ERR; stat_to_dir(&fs); - if(dir_output.item(buf_dir, dir_curpath, buf_ext)) { + if(dir_output.item(buf_dir, dir_curpath, buf_ext, buf_nlink)) { dir_seterr("Output error: %s", strerror(errno)); fail = 1; } if(!fail) fail = dir_walk(dir); - if(!fail && dir_output.item(NULL, 0, NULL)) { + if(!fail && dir_output.item(NULL, 0, NULL, 0)) { dir_seterr("Output error: %s", strerror(errno)); fail = 1; } |