void Server::handle_client_mkdir(MDRequestRef& mdr)
{
const MClientRequest::const_ref &req = mdr->client_request;
+ if (req->get_filepath().is_last_dot_or_dotdot()) {
+ respond_to_request(mdr, -EEXIST);
+ return;
+ }
+
set<SimpleLock*> rdlocks, wrlocks, xlocks;
CDentry *dn = rdlock_path_xlock_dentry(mdr, 0, rdlocks, wrlocks, xlocks, false, false, false);
if (!dn) return;
bool rmdir = false;
if (req->get_op() == CEPH_MDS_OP_RMDIR) rmdir = true;
- if (req->get_filepath().depth() == 0) {
+ const filepath& refpath = req->get_filepath();
+ if (refpath.depth() == 0) {
respond_to_request(mdr, -EINVAL);
return;
- }
+ }
+ if (refpath.is_last_dot_or_dotdot()) {
+ respond_to_request(mdr, -ENOTEMPTY);
+ return;
+ }
// traverse to path
vector<CDentry*> trace;
CInode *in;
CF_MDS_MDRContextFactory cf(mdcache, mdr);
- int r = mdcache->path_traverse(mdr, cf, req->get_filepath(), &trace, &in, MDS_TRAVERSE_FORWARD);
+ int r = mdcache->path_traverse(mdr, cf, refpath, &trace, &in, MDS_TRAVERSE_FORWARD);
if (r > 0) return;
if (r < 0) {
if (r == -ESTALE) {
dout(10) << "FAIL on ESTALE but attempting recovery" << dendl;
- mdcache->find_ino_peers(req->get_filepath().get_ino(), new C_MDS_TryFindInode(this, mdr));
+ mdcache->find_ino_peers(refpath.get_ino(), new C_MDS_TryFindInode(this, mdr));
return;
}
respond_to_request(mdr, r);
respond_to_request(mdr, -EINVAL);
return;
}
+ if (srcpath.is_last_dot_or_dotdot() || destpath.is_last_dot_or_dotdot()) {
+ respond_to_request(mdr, -EBUSY);
+ return;
+ }
+
std::string_view destname = destpath.last_dentry();
vector<CDentry*>& srctrace = mdr->dn[1];
ceph_close(cmount, fd);
ceph_shutdown(cmount);
}
+
+TEST(LibCephFS, OperationsOnDotDot) {
+ struct ceph_mount_info *cmount;
+ ASSERT_EQ(ceph_create(&cmount, NULL), 0);
+ ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
+ ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
+ ASSERT_EQ(ceph_mount(cmount, NULL), 0);
+
+ char c_dir[1024], c_dir_dot[1024], c_dir_dotdot[1024];
+ char c_non_existent_dir[1024], c_non_existent_dirs[1024];
+ char c_temp[1024];
+
+ pid_t mypid = getpid();
+ sprintf(c_dir, "/oodd_dir_%d", mypid);
+ sprintf(c_dir_dot, "/%s/.", c_dir);
+ sprintf(c_dir_dotdot, "/%s/..", c_dir);
+ sprintf(c_non_existent_dir, "/%s/../oodd_nonexistent/..", c_dir);
+ sprintf(c_non_existent_dirs,
+ "/%s/../ood_nonexistent1_%d/oodd_nonexistent2_%d", c_dir, mypid, mypid);
+ sprintf(c_temp, "/oodd_temp_%d", mypid);
+
+ ASSERT_EQ(0, ceph_mkdir(cmount, c_dir, 0777));
+ ASSERT_EQ(-EEXIST, ceph_mkdir(cmount, c_dir_dot, 0777));
+ ASSERT_EQ(-EEXIST, ceph_mkdir(cmount, c_dir_dotdot, 0777));
+ ASSERT_EQ(0, ceph_mkdirs(cmount, c_non_existent_dirs, 0777));
+
+ ASSERT_EQ(-ENOTEMPTY, ceph_rmdir(cmount, c_dir_dot));
+ ASSERT_EQ(-ENOTEMPTY, ceph_rmdir(cmount, c_dir_dotdot));
+ // non existent directory should return -ENOENT
+ ASSERT_EQ(-ENOENT, ceph_rmdir(cmount, c_non_existent_dir));
+
+ ASSERT_EQ(-EBUSY, ceph_rename(cmount, c_dir_dot, c_temp));
+ ASSERT_EQ(0, ceph_chdir(cmount, c_dir));
+ ASSERT_EQ(0, ceph_mkdir(cmount, c_temp, 0777));
+ ASSERT_EQ(-EBUSY, ceph_rename(cmount, c_temp, ".."));
+
+ ceph_shutdown(cmount);
+}