From: Timo Sirainen Date: Sat, 23 Jul 2016 16:02:29 +0000 (-0400) Subject: lib-fs: Added fs_get_nlinks() X-Git-Tag: 2.3.0.rc1~3276 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a63cd84128875485e40ed804dbf0b0945526989c;p=thirdparty%2Fdovecot%2Fcore.git lib-fs: Added fs_get_nlinks() Although fs_stat() could return this, its caller can't indicate whether it actually wants the link count. Usually fs_stat() is used only to get the file's size. In some backends it's not cheap to get the link count, so adding this function allows the caller to explicitly ask for it. --- diff --git a/src/lib-fs/fs-api-private.h b/src/lib-fs/fs-api-private.h index 28f2c4ad9a..0d71a9a2e5 100644 --- a/src/lib-fs/fs-api-private.h +++ b/src/lib-fs/fs-api-private.h @@ -69,6 +69,7 @@ struct fs_vfuncs { int (*iter_deinit)(struct fs_iter *iter); bool (*switch_ioloop)(struct fs *fs); + int (*get_nlinks)(struct fs_file *file, nlink_t *nlinks_r); }; struct fs { diff --git a/src/lib-fs/fs-api.c b/src/lib-fs/fs-api.c index bac5d16121..e53059348c 100644 --- a/src/lib-fs/fs-api.c +++ b/src/lib-fs/fs-api.c @@ -848,6 +848,33 @@ int fs_stat(struct fs_file *file, struct stat *st_r) return ret; } +int fs_get_nlinks(struct fs_file *file, nlink_t *nlinks_r) +{ + int ret; + + if (file->fs->v.get_nlinks == NULL) { + struct stat st; + + if (fs_stat(file, &st) < 0) + return -1; + *nlinks_r = st.st_nlink; + return 0; + } + + if (!file->read_or_prefetch_counted && + !file->lookup_metadata_counted && !file->stat_counted) { + file->stat_counted = TRUE; + file->fs->stats.stat_count++; + fs_file_timing_start(file, FS_OP_STAT); + } + T_BEGIN { + ret = file->fs->v.get_nlinks(file, nlinks_r); + } T_END; + if (!(ret < 0 && errno == EAGAIN)) + fs_file_timing_end(file, FS_OP_STAT); + return ret; +} + int fs_default_copy(struct fs_file *src, struct fs_file *dest) { /* we're going to be counting this as read+write, so remove the diff --git a/src/lib-fs/fs-api.h b/src/lib-fs/fs-api.h index 1e42504d5c..cf285b1716 100644 --- a/src/lib-fs/fs-api.h +++ b/src/lib-fs/fs-api.h @@ -303,6 +303,10 @@ int fs_delete(struct fs_file *file); /* Returns 0 if ok, -1 if error occurred (e.g. errno=ENOENT). All fs backends may not support all stat fields. */ int fs_stat(struct fs_file *file, struct stat *st_r); +/* Get number of links to the file. This is the same as using fs_stat()'s + st_nlinks field, except not all backends support returning it via fs_stat(). + Returns 0 if ok, -1 if error occurred. */ +int fs_get_nlinks(struct fs_file *file, nlink_t *nlinks_r); /* Copy an object with possibly updated metadata. Destination parent directories are created automatically. Returns 0 if ok, -1 if error occurred. */ diff --git a/src/lib-fs/fs-dict.c b/src/lib-fs/fs-dict.c index 3b0ba32ea5..035005a758 100644 --- a/src/lib-fs/fs-dict.c +++ b/src/lib-fs/fs-dict.c @@ -323,6 +323,7 @@ const struct fs fs_class_dict = { fs_dict_iter_init, fs_dict_iter_next, fs_dict_iter_deinit, + NULL, NULL } }; diff --git a/src/lib-fs/fs-metawrap.c b/src/lib-fs/fs-metawrap.c index 3432df6174..4b6519a2cb 100644 --- a/src/lib-fs/fs-metawrap.c +++ b/src/lib-fs/fs-metawrap.c @@ -496,6 +496,7 @@ const struct fs fs_class_metawrap = { fs_wrapper_iter_init, fs_wrapper_iter_next, fs_wrapper_iter_deinit, - NULL + NULL, + fs_wrapper_get_nlinks, } }; diff --git a/src/lib-fs/fs-posix.c b/src/lib-fs/fs-posix.c index a28ce22d9c..a4baeae36d 100644 --- a/src/lib-fs/fs-posix.c +++ b/src/lib-fs/fs-posix.c @@ -884,6 +884,7 @@ const struct fs fs_class_posix = { fs_posix_iter_init, fs_posix_iter_next, fs_posix_iter_deinit, - NULL + NULL, + NULL, } }; diff --git a/src/lib-fs/fs-randomfail.c b/src/lib-fs/fs-randomfail.c index e133bad3f8..484a12328b 100644 --- a/src/lib-fs/fs-randomfail.c +++ b/src/lib-fs/fs-randomfail.c @@ -446,6 +446,17 @@ static int fs_randomfail_stat(struct fs_file *_file, struct stat *st_r) return fs_file_random_fail_end(file, ret, FS_OP_STAT); } +static int fs_randomfail_get_nlinks(struct fs_file *_file, nlink_t *nlinks_r) +{ + struct randomfail_fs_file *file = (struct randomfail_fs_file *)_file; + int ret; + + if (fs_file_random_fail_begin(file, FS_OP_STAT)) + return -1; + ret = fs_get_nlinks(file->super, nlinks_r); + return fs_file_random_fail_end(file, ret, FS_OP_STAT); +} + static int fs_randomfail_copy(struct fs_file *_src, struct fs_file *_dest) { struct randomfail_fs_file *src = (struct randomfail_fs_file *)_src; @@ -566,6 +577,7 @@ const struct fs fs_class_randomfail = { fs_randomfail_iter_init, fs_randomfail_iter_next, fs_randomfail_iter_deinit, - NULL + NULL, + fs_randomfail_get_nlinks, } }; diff --git a/src/lib-fs/fs-sis-queue.c b/src/lib-fs/fs-sis-queue.c index 588776e45f..1e38d643db 100644 --- a/src/lib-fs/fs-sis-queue.c +++ b/src/lib-fs/fs-sis-queue.c @@ -200,6 +200,7 @@ const struct fs fs_class_sis_queue = { fs_wrapper_iter_init, NULL, NULL, - NULL + NULL, + fs_wrapper_get_nlinks, } }; diff --git a/src/lib-fs/fs-sis.c b/src/lib-fs/fs-sis.c index 143463f065..eb947c101f 100644 --- a/src/lib-fs/fs-sis.c +++ b/src/lib-fs/fs-sis.c @@ -351,6 +351,7 @@ const struct fs fs_class_sis = { fs_wrapper_iter_init, NULL, NULL, - NULL + NULL, + fs_wrapper_get_nlinks, } }; diff --git a/src/lib-fs/fs-test.c b/src/lib-fs/fs-test.c index d35caf5366..cf912b0b9c 100644 --- a/src/lib-fs/fs-test.c +++ b/src/lib-fs/fs-test.c @@ -417,6 +417,7 @@ const struct fs fs_class_test = { fs_test_iter_init, fs_test_iter_next, fs_test_iter_deinit, - NULL + NULL, + NULL, } }; diff --git a/src/lib-fs/fs-wrapper.c b/src/lib-fs/fs-wrapper.c index 8d90561499..524f113131 100644 --- a/src/lib-fs/fs-wrapper.c +++ b/src/lib-fs/fs-wrapper.c @@ -108,6 +108,11 @@ int fs_wrapper_stat(struct fs_file *file, struct stat *st_r) return fs_stat(file->parent, st_r); } +int fs_wrapper_get_nlinks(struct fs_file *file, nlink_t *nlinks_r) +{ + return fs_get_nlinks(file->parent, nlinks_r); +} + int fs_wrapper_copy(struct fs_file *src, struct fs_file *dest) { if (src != NULL) diff --git a/src/lib-fs/fs-wrapper.h b/src/lib-fs/fs-wrapper.h index 992b020070..c6d99da069 100644 --- a/src/lib-fs/fs-wrapper.h +++ b/src/lib-fs/fs-wrapper.h @@ -24,6 +24,7 @@ int fs_wrapper_lock(struct fs_file *file, unsigned int secs, void fs_wrapper_unlock(struct fs_lock *_lock); int fs_wrapper_exists(struct fs_file *file); int fs_wrapper_stat(struct fs_file *file, struct stat *st_r); +int fs_wrapper_get_nlinks(struct fs_file *file, nlink_t *nlinks_r); int fs_wrapper_copy(struct fs_file *src, struct fs_file *dest); int fs_wrapper_rename(struct fs_file *src, struct fs_file *dest); int fs_wrapper_delete(struct fs_file *file); diff --git a/src/plugins/fs-compress/fs-compress.c b/src/plugins/fs-compress/fs-compress.c index e09cb5d504..e1e3ceafa3 100644 --- a/src/plugins/fs-compress/fs-compress.c +++ b/src/plugins/fs-compress/fs-compress.c @@ -254,6 +254,7 @@ const struct fs fs_class_compress = { fs_wrapper_iter_init, fs_wrapper_iter_next, fs_wrapper_iter_deinit, - NULL + NULL, + fs_wrapper_get_nlinks } };