mirror of
https://github.com/facebook/sapling.git
synced 2024-10-05 14:28:17 +03:00
b12c397618
Summary: GCC provides some useful warnings and errors when compiling EdenFS, and I noticed our open source build was failing. Fix some of the issues. Reviewed By: xavierd Differential Revision: D37157074 fbshipit-source-id: de5705ec2eac18cd269143739289031ca5d478fc
196 lines
5.7 KiB
C++
196 lines
5.7 KiB
C++
/*
|
|
* Copyright (c) Meta Platforms, Inc. and 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 <folly/Try.h>
|
|
#include <sys/stat.h>
|
|
#include "eden/fs/nfs/NfsdRpc.h"
|
|
#include "eden/fs/utils/Throw.h"
|
|
|
|
namespace facebook::eden {
|
|
|
|
/**
|
|
* Convert the POSIX mode to NFS file type.
|
|
*/
|
|
inline ftype3 modeToFtype3(mode_t mode) {
|
|
if (S_ISREG(mode)) {
|
|
return ftype3::NF3REG;
|
|
} else if (S_ISDIR(mode)) {
|
|
return ftype3::NF3DIR;
|
|
} else if (S_ISBLK(mode)) {
|
|
return ftype3::NF3BLK;
|
|
} else if (S_ISCHR(mode)) {
|
|
return ftype3::NF3CHR;
|
|
} else if (S_ISLNK(mode)) {
|
|
return ftype3::NF3LNK;
|
|
} else if (S_ISSOCK(mode)) {
|
|
return ftype3::NF3SOCK;
|
|
} else {
|
|
XDCHECK(S_ISFIFO(mode));
|
|
return ftype3::NF3FIFO;
|
|
}
|
|
}
|
|
|
|
inline mode_t ftype3ToMode(ftype3 type) {
|
|
switch (type) {
|
|
case ftype3::NF3REG:
|
|
return S_IFREG;
|
|
case ftype3::NF3DIR:
|
|
return S_IFDIR;
|
|
case ftype3::NF3BLK:
|
|
return S_IFBLK;
|
|
case ftype3::NF3CHR:
|
|
return S_IFCHR;
|
|
case ftype3::NF3LNK:
|
|
return S_IFLNK;
|
|
case ftype3::NF3SOCK:
|
|
return S_IFSOCK;
|
|
case ftype3::NF3FIFO:
|
|
return S_IFIFO;
|
|
}
|
|
throw_<std::domain_error>("unexpected ftype3 ", type);
|
|
}
|
|
|
|
/**
|
|
* Convert the POSIX mode to NFS mode.
|
|
*/
|
|
inline uint32_t modeToNfsMode(mode_t mode) {
|
|
uint32_t nfsMode = 0;
|
|
|
|
// Owner bits:
|
|
nfsMode |= mode & S_IRUSR ? kReadOwnerBit : 0;
|
|
nfsMode |= mode & S_IWUSR ? kWriteOwnerBit : 0;
|
|
nfsMode |= mode & S_IXUSR ? kExecOwnerBit : 0;
|
|
|
|
// Group bits:
|
|
nfsMode |= mode & S_IRGRP ? kReadGroupBit : 0;
|
|
nfsMode |= mode & S_IWGRP ? kWriteGroupBit : 0;
|
|
nfsMode |= mode & S_IXGRP ? kExecGroupBit : 0;
|
|
|
|
// Other bits:
|
|
nfsMode |= mode & S_IROTH ? kReadOtherBit : 0;
|
|
nfsMode |= mode & S_IWOTH ? kWriteOtherBit : 0;
|
|
nfsMode |= mode & S_IXOTH ? kExecOtherBit : 0;
|
|
|
|
nfsMode |= mode & S_ISUID ? kSUIDBit : 0;
|
|
nfsMode |= mode & S_ISGID ? kGIDBit : 0;
|
|
|
|
return nfsMode;
|
|
}
|
|
|
|
/**
|
|
* Convert a POSIX timespec to an NFS time.
|
|
*/
|
|
inline nfstime3 timespecToNfsTime(const struct timespec& time) {
|
|
return nfstime3{
|
|
folly::to_narrow(folly::to_unsigned(time.tv_sec)),
|
|
folly::to_narrow(folly::to_unsigned(time.tv_nsec))};
|
|
}
|
|
|
|
/**
|
|
* Convert a NFS time to a POSIX timespec.
|
|
*/
|
|
inline struct timespec nfsTimeToTimespec(const nfstime3& time) {
|
|
timespec spec;
|
|
spec.tv_sec = time.seconds;
|
|
spec.tv_nsec = time.nseconds;
|
|
return spec;
|
|
}
|
|
|
|
inline fattr3 statToFattr3(const struct stat& stat) {
|
|
return fattr3{
|
|
/*type*/ modeToFtype3(stat.st_mode),
|
|
/*mode*/ modeToNfsMode(stat.st_mode),
|
|
/*nlink*/ folly::to_narrow(stat.st_nlink),
|
|
/*uid*/ stat.st_uid,
|
|
/*gid*/ stat.st_gid,
|
|
/*size*/ folly::to_unsigned(stat.st_size),
|
|
/*used*/ folly::to_unsigned(stat.st_blocks) * 512u,
|
|
/*rdev*/ specdata3{0, 0}, // TODO(xavierd)
|
|
/*fsid*/ folly::to_unsigned(stat.st_dev),
|
|
/*fileid*/ stat.st_ino,
|
|
#ifdef __linux__
|
|
/*atime*/ timespecToNfsTime(stat.st_atim),
|
|
/*mtime*/ timespecToNfsTime(stat.st_mtim),
|
|
/*ctime*/ timespecToNfsTime(stat.st_ctim),
|
|
#else
|
|
/*atime*/ timespecToNfsTime(stat.st_atimespec),
|
|
/*mtime*/ timespecToNfsTime(stat.st_mtimespec),
|
|
/*ctime*/ timespecToNfsTime(stat.st_ctimespec),
|
|
#endif
|
|
};
|
|
}
|
|
|
|
inline pre_op_attr statToPreOpAttr(const struct stat& stat) {
|
|
return pre_op_attr{wcc_attr{
|
|
/*size*/ folly::to_unsigned(stat.st_size),
|
|
#ifdef __linux__
|
|
/*mtime*/ timespecToNfsTime(stat.st_mtim),
|
|
/*ctime*/ timespecToNfsTime(stat.st_ctim),
|
|
#else
|
|
/*mtime*/ timespecToNfsTime(stat.st_mtimespec),
|
|
/*ctime*/ timespecToNfsTime(stat.st_ctimespec),
|
|
#endif
|
|
}};
|
|
}
|
|
|
|
/**
|
|
* Convert the struct stat returned from the NfsDispatcher into a wcc_data
|
|
* useable by NFS.
|
|
*/
|
|
inline wcc_data statToWccData(
|
|
const std::optional<struct stat>& preStat,
|
|
const std::optional<struct stat>& postStat) {
|
|
return wcc_data{
|
|
/*before*/ preStat.has_value() ? statToPreOpAttr(preStat.value())
|
|
: pre_op_attr{},
|
|
/*after*/ postStat.has_value()
|
|
? post_op_attr{statToFattr3(postStat.value())}
|
|
: post_op_attr{},
|
|
};
|
|
}
|
|
|
|
inline post_op_attr statToPostOpAttr(const folly::Try<struct stat>& stat) {
|
|
if (stat.hasException()) {
|
|
return post_op_attr{};
|
|
} else {
|
|
return post_op_attr{statToFattr3(stat.value())};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determine which of the `desiredAccess`'s a client should be granted for a
|
|
* certain file or directory based on the the `stat` of that file or directory.
|
|
* This result is an advisory result for the access call. Clients use this call
|
|
* to block IO that user's do not have access for, but procedures are still
|
|
* welcome to refuse to perform an action due to access restrictions. Thus
|
|
* this result should err on the side of being more permissive than restrictive.
|
|
*
|
|
* Really this should look at the uid & gid of the client issuing the request.
|
|
* These credentials are sent as part of the RPC credentials. This gets
|
|
* complicated because many of the authentication protocols in NFS v3 allow
|
|
* clients to spoof their uid/gid very easily. We would need to use a
|
|
* complicated authentication protocol like RPCSEC_GSS to be able to perform
|
|
* proper access checks
|
|
*
|
|
* To simplify for now, we give user's the most permissive access they could
|
|
* have as any user except root (we highly discourage acting as root inside an
|
|
* EdenFS repo). This provides a little bit of access restriction, so that
|
|
* access calls behave some what normally. However, long term we likely need to
|
|
* implement full authentication and respond properly here. We also should
|
|
* enforce permissions on each procedure call.
|
|
*/
|
|
uint32_t getEffectiveAccessRights(
|
|
const struct stat& stat,
|
|
uint32_t desiredAccess);
|
|
|
|
} // namespace facebook::eden
|
|
#endif
|