Reimplement fsfs private operations required by `svnfsfs` (stats, dump index, load index) as "ioctls".
Technically we achieve this by introducing the new svn_fs_ioctl() API that adds a generic way of performing backend-specific I/O operations.
This change serves two purposes:
- It allows us to properly expose FS-specific details and invoke FS-specific operations everywhere without necessarily promoting them into a proper public API (the ioctl code itself may be made either public or private, depending on the requirements).
- It solves a potential dependency/linking problem where tools like `svnfsfs` work through the libsvn_fs's loader, but also have to load and call private APIs from libsvn_fs_fs thus ignoring the loader. The latter part may potentially cause issues with the global shared state, etc. With the patch, all such operations always go through the FS loader.
* subversion/include/svn_error_codes.h (SVN_ERR_FS_UNRECOGNIZED_IOCTL_CODE): New error code.
* subversion/include/private/svn_fs_fs_private.h (svn_fs_fs__get_stats, svn_fs_fs__dump_index, svn_fs_fs__load_index): These functions are now implemented as... (SVN_FS_FS__IOCTL_GET_STATS, SVN_FS_FS__IOCTL_DUMP_INDEX, SVN_FS_FS__IOCTL_LOAD_INDEX): ...these new ioctls, which ... (svn_fs_fs__ioctl_get_stats_input_t, svn_fs_fs__ioctl_get_stats_output_t, svn_fs_fs__ioctl_dump_index_input_t, svn_fs_fs__ioctl_load_index_input_t): ...use these new structures.
* subversion/libsvn_fs/fs-loader.h (fs_library_vtable_t.ioctl, fs_vtable_t.ioctl): New vtable members.
* subversion/libsvn_fs/fs-loader.c (svn_fs_ioctl): Implement the new API by forwarding it to an appropriate vtable member.
* subversion/libsvn_fs_fs/fs_fs.h (svn_fs_fs__get_stats, svn_fs_fs__dump_index, svn_fs_fs__load_index): These functions are now declared here.
* subversion/libsvn_fs_fs/fs.c (): Include `svn_fs_fs_private.h`. (fs_ioctl): Implement the ioctl dispatcher for three current fsfs-specific operations. (fs_vtable): Initialize the `ioctl` field. (library_vtable): Initialize the `ioctl` field to NULL.
fsfs: Fix SVN-4791, an issue with the DAG open_path() that was causing unexpected SVN_ERR_FS_NOT_DIRECTORY errors when attempting to open a path with `open_path_node_only | open_path_allow_null` flags.
The implication of this is that certain svn_fs_closest_copy() calls could be returing unexpected errors as well. For the end user, this means that such errors were possible, for example, during certain `svn update`s.
The root cause of this behavior is the implementation of the optimization within the open_path() routine. The optimization attempts to do a cache lookup of the prospective parent directory of the path to be opened. If the cache lookup is successful, the parent node is assumed — but not checked — to be a directory. The absense of the check was causing unexpected errors instead of returning `NULL` in a case where:
- open_path() is called with `open_path_node_only | open_path_allow_null` - the path to be opened points to a non-existing path, but its parent path is a file - the DAG node of the "parent" file is cached
* subversion/libsvn_fs_fs/tree.c (err_not_directory): New helper function factored out from... (open_path): ...here. Check the kind of the DAG node for the prospective parent returned from cache in the `open_path_node_only` optimization. Handle the case where it is not a directory; utilize the new helper to construct the appropriate error.
* subversion/tests/libsvn_fs/fs-test.c (test_closest_copy_file_replaced_with_dir): New regression test. (test_funcs): Run new test.