mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 16:57:49 +03:00
ec5a6ef1f0
Summary: The NFS readdir turns out to be pretty similar to the FUSE one, with a couple of differences. For one, it only populates the directory entry name, it also puts a limit on the total size of the serialized result, including all the NFS/XDR overhead. It is not specified if the . and .. entries need to be returned, but since the NFS spec is usually pretty explicit about these and makes it clear that this is for the most part a client burden, I didn't add these. I may have to revisit this later when I get to manually browse a repository. Since the READDIR RPC doesn't populate any filehandle, the client will have to issue a LOOKUP RPC for each entries, potentially leading to some inefficiencies. A future diff will implement the READDIRPLUS to fix these. Reviewed By: chadaustin Differential Revision: D26802310 fbshipit-source-id: b821b57021d0c2dca33427975b1acd665173bc5c
316 lines
8.8 KiB
C++
316 lines
8.8 KiB
C++
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This software may be used and distributed according to the terms of the
|
|
* GNU General Public License version 2.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#ifndef _WIN32
|
|
|
|
#include <sys/stat.h>
|
|
#ifdef __APPLE__
|
|
#include <sys/mount.h>
|
|
#include <sys/param.h>
|
|
#else
|
|
#include <sys/vfs.h>
|
|
#endif
|
|
|
|
#include "eden/fs/inodes/InodeMetadata.h"
|
|
#include "eden/fs/inodes/InodeNumber.h"
|
|
#include "eden/fs/nfs/DirList.h"
|
|
#include "eden/fs/store/ObjectFetchContext.h"
|
|
#include "eden/fs/utils/PathFuncs.h"
|
|
|
|
namespace folly {
|
|
template <class T>
|
|
class Future;
|
|
}
|
|
|
|
namespace facebook::eden {
|
|
|
|
class EdenStats;
|
|
class Clock;
|
|
|
|
class NfsDispatcher {
|
|
public:
|
|
explicit NfsDispatcher(EdenStats* stats, const Clock& clock)
|
|
: stats_(stats), clock_(clock) {}
|
|
|
|
virtual ~NfsDispatcher() {}
|
|
|
|
EdenStats* getStats() const {
|
|
return stats_;
|
|
}
|
|
|
|
const Clock& getClock() const {
|
|
return clock_;
|
|
}
|
|
|
|
/**
|
|
* Get file attribute for the passed in InodeNumber.
|
|
*/
|
|
virtual folly::Future<struct stat> getattr(
|
|
InodeNumber ino,
|
|
ObjectFetchContext& context) = 0;
|
|
|
|
/**
|
|
* Return value of the setattr method.
|
|
*/
|
|
struct SetattrRes {
|
|
/** Attributes of the file prior to changing its attributes */
|
|
std::optional<struct stat> preStat;
|
|
/** Attributes of the file after changing its attributes */
|
|
std::optional<struct stat> postStat;
|
|
};
|
|
|
|
/**
|
|
* Change the attributes of the file referenced by the InodeNumber ino.
|
|
*
|
|
* See comment on the create method for the meaning of the returned pre and
|
|
* post stat.
|
|
*/
|
|
virtual folly::Future<SetattrRes> setattr(
|
|
InodeNumber ino,
|
|
DesiredMetadata desired,
|
|
ObjectFetchContext& context) = 0;
|
|
|
|
/**
|
|
* Racily obtain the parent directory of the passed in directory.
|
|
*
|
|
* Can be used to handle a ".." filename.
|
|
*/
|
|
virtual folly::Future<InodeNumber> getParent(
|
|
InodeNumber ino,
|
|
ObjectFetchContext& context) = 0;
|
|
|
|
/**
|
|
* Find the given file in the passed in directory. It's InodeNumber and
|
|
* attributes are returned.
|
|
*/
|
|
virtual folly::Future<std::tuple<InodeNumber, struct stat>>
|
|
lookup(InodeNumber dir, PathComponent name, ObjectFetchContext& context) = 0;
|
|
|
|
/**
|
|
* For a symlink, return its destination, fail otherwise.
|
|
*/
|
|
virtual folly::Future<std::string> readlink(
|
|
InodeNumber ino,
|
|
ObjectFetchContext& context) = 0;
|
|
|
|
/**
|
|
* Return value of the read method.
|
|
*/
|
|
struct ReadRes {
|
|
/** Data successfully read */
|
|
std::unique_ptr<folly::IOBuf> data;
|
|
/** Has the read reached the end of file */
|
|
bool isEof;
|
|
};
|
|
|
|
/**
|
|
* Read data from the file referenced by the InodeNumber ino.
|
|
*/
|
|
virtual folly::Future<ReadRes> read(
|
|
InodeNumber ino,
|
|
size_t size,
|
|
off_t offset,
|
|
ObjectFetchContext& context) = 0;
|
|
|
|
/**
|
|
* Return value of the write method.
|
|
*/
|
|
struct WriteRes {
|
|
/** Number of bytes written */
|
|
size_t written;
|
|
|
|
/** Attributes of the directory prior to creating the file */
|
|
std::optional<struct stat> preStat;
|
|
/** Attributes of the directory after creating the file */
|
|
std::optional<struct stat> postStat;
|
|
};
|
|
|
|
/**
|
|
* Write data at offset to the file referenced by the InodeNumber ino.
|
|
*
|
|
* See the comment on the create method below for the meaning of the returned
|
|
* pre and post stat.
|
|
*/
|
|
virtual folly::Future<WriteRes> write(
|
|
InodeNumber ino,
|
|
std::unique_ptr<folly::IOBuf> data,
|
|
off_t offset,
|
|
ObjectFetchContext& context) = 0;
|
|
|
|
/**
|
|
* Return value of the create method.
|
|
*/
|
|
struct CreateRes {
|
|
/** InodeNumber of the created file */
|
|
InodeNumber ino;
|
|
/** Attributes of the created file */
|
|
struct stat stat;
|
|
|
|
/** Attributes of the directory prior to creating the file */
|
|
std::optional<struct stat> preDirStat;
|
|
/** Attributes of the directory after creating the file */
|
|
std::optional<struct stat> postDirStat;
|
|
};
|
|
|
|
/**
|
|
* Create a regular file in the directory referenced by the InodeNumber dir.
|
|
*
|
|
* Both the pre and post stat for that directory needs to be collected in an
|
|
* atomic manner: no other operation on the directory needs to be allowed in
|
|
* between them. This is to ensure that the NFS client can properly detect if
|
|
* its cache needs to be invalidated. Setting them both to std::nullopt is an
|
|
* acceptable approach if the stat cannot be collected atomically.
|
|
*/
|
|
virtual folly::Future<CreateRes> create(
|
|
InodeNumber dir,
|
|
PathComponent name,
|
|
mode_t mode,
|
|
ObjectFetchContext& context) = 0;
|
|
|
|
/**
|
|
* Return value of the mkdir method.
|
|
*/
|
|
struct MkdirRes {
|
|
/** InodeNumber of the created directory */
|
|
InodeNumber ino;
|
|
/** Attributes of the created directory */
|
|
struct stat stat;
|
|
|
|
/** Attributes of the directory prior to creating the subdirectory */
|
|
std::optional<struct stat> preDirStat;
|
|
/** Attributes of the directory after creating the subdirectory */
|
|
std::optional<struct stat> postDirStat;
|
|
};
|
|
|
|
/**
|
|
* Create a subdirectory in the directory referenced by the InodeNumber dir.
|
|
*
|
|
* For the pre and post dir stat, refer to the documentation of the create
|
|
* method above.
|
|
*/
|
|
virtual folly::Future<MkdirRes> mkdir(
|
|
InodeNumber dir,
|
|
PathComponent name,
|
|
mode_t mode,
|
|
ObjectFetchContext& context) = 0;
|
|
|
|
/**
|
|
* Return value of the symlink method.
|
|
*/
|
|
struct SymlinkRes {
|
|
/** InodeNumber of the created symlink */
|
|
InodeNumber ino;
|
|
/** Attributes of the created symlink */
|
|
struct stat stat;
|
|
|
|
/** Attributes of the directory prior to creating the symlink */
|
|
std::optional<struct stat> preDirStat;
|
|
/** Attributes of the directory after creating the symlink */
|
|
std::optional<struct stat> postDirStat;
|
|
};
|
|
|
|
/**
|
|
* Add a symlink in the directory referenced by the InodeNumber dir. The
|
|
* symlink will have the name passed in, and will store data. From EdenFS
|
|
* perspective the data is an opaque value that will be interpreted by the
|
|
* client.
|
|
*
|
|
* For the pre and post dir stat, refer to the documentation of the create
|
|
* method above.
|
|
*/
|
|
virtual folly::Future<SymlinkRes> symlink(
|
|
InodeNumber dir,
|
|
PathComponent name,
|
|
std::string data,
|
|
ObjectFetchContext& context) = 0;
|
|
|
|
/**
|
|
* Return value of the unlink method.
|
|
*/
|
|
struct UnlinkRes {
|
|
/** Attributes of the directory prior to removing the file */
|
|
std::optional<struct stat> preDirStat;
|
|
/** Attributes of the directory after removing the file */
|
|
std::optional<struct stat> postDirStat;
|
|
};
|
|
|
|
/**
|
|
* Remove the file/directory name from the directory referenced by the
|
|
* InodeNumber dir.
|
|
*
|
|
* For the pre and post dir stat, refer to the documentation of the create
|
|
* method above.
|
|
*/
|
|
virtual folly::Future<UnlinkRes>
|
|
unlink(InodeNumber dir, PathComponent name, ObjectFetchContext& context) = 0;
|
|
|
|
struct RenameRes {
|
|
/** Attributes of the from directory prior to renaming the file. */
|
|
std::optional<struct stat> fromPreDirStat;
|
|
/** Attributes of the from directory after renaming the file. */
|
|
std::optional<struct stat> fromPostDirStat;
|
|
/** Attributes of the to directory prior to renaming the file. */
|
|
std::optional<struct stat> toPreDirStat;
|
|
/** Attributes of the to directory after renaming the file. */
|
|
std::optional<struct stat> toPostDirStat;
|
|
};
|
|
|
|
/**
|
|
* Rename a file/directory from the directory referenced by fromIno to the
|
|
* directory referenced by toIno. The file/directory fromName will be renamed
|
|
* onto toName.
|
|
*
|
|
* Fro the pre and post dir stat, refer to the documentation of the create
|
|
* method above.
|
|
*/
|
|
virtual folly::Future<RenameRes> rename(
|
|
InodeNumber fromIno,
|
|
PathComponent fromName,
|
|
InodeNumber toIno,
|
|
PathComponent toName,
|
|
ObjectFetchContext& context) = 0;
|
|
|
|
/**
|
|
* Return value of the readdir method.
|
|
*/
|
|
struct ReaddirRes {
|
|
/** List of directory entries */
|
|
NfsDirList entries;
|
|
/** Has the readdir reached the end of the directory */
|
|
bool isEof;
|
|
};
|
|
|
|
/**
|
|
* Read the content of the directory referenced by the InodeNumber dir. A
|
|
* maximum of count bytes will be added to the returned NfsDirList.
|
|
*
|
|
* For very large directories, it is possible that more than count bytes are
|
|
* necessary to return all the directory entries. In this case, a subsequent
|
|
* readdir call will be made by the NFS client to restart the enumeration at
|
|
* offset. The first readdir will have an offset of 0.
|
|
*/
|
|
virtual folly::Future<ReaddirRes> readdir(
|
|
InodeNumber dir,
|
|
off_t offset,
|
|
uint32_t count,
|
|
ObjectFetchContext& context) = 0;
|
|
|
|
virtual folly::Future<struct statfs> statfs(
|
|
InodeNumber dir,
|
|
ObjectFetchContext& context) = 0;
|
|
|
|
private:
|
|
EdenStats* stats_{nullptr};
|
|
const Clock& clock_;
|
|
};
|
|
|
|
} // namespace facebook::eden
|
|
|
|
#endif
|