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 {
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
/* 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. */
fs_dict_iter_init,
fs_dict_iter_next,
fs_dict_iter_deinit,
+ NULL,
NULL
}
};
fs_wrapper_iter_init,
fs_wrapper_iter_next,
fs_wrapper_iter_deinit,
- NULL
+ NULL,
+ fs_wrapper_get_nlinks,
}
};
fs_posix_iter_init,
fs_posix_iter_next,
fs_posix_iter_deinit,
- NULL
+ NULL,
+ NULL,
}
};
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;
fs_randomfail_iter_init,
fs_randomfail_iter_next,
fs_randomfail_iter_deinit,
- NULL
+ NULL,
+ fs_randomfail_get_nlinks,
}
};
fs_wrapper_iter_init,
NULL,
NULL,
- NULL
+ NULL,
+ fs_wrapper_get_nlinks,
}
};
fs_wrapper_iter_init,
NULL,
NULL,
- NULL
+ NULL,
+ fs_wrapper_get_nlinks,
}
};
fs_test_iter_init,
fs_test_iter_next,
fs_test_iter_deinit,
- NULL
+ NULL,
+ NULL,
}
};
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)
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);
fs_wrapper_iter_init,
fs_wrapper_iter_next,
fs_wrapper_iter_deinit,
- NULL
+ NULL,
+ fs_wrapper_get_nlinks
}
};