| 16662 | } |
| 16663 | |
| 16664 | int Client::_link(Inode *diri_from, const char* path_from, Inode* diri_to, const char* path_to, const UserPerm& perm, std::string alternate_name) |
| 16665 | { |
| 16666 | ldout(cct, 8) << "_link(" << diri_from->ino << " to " << diri_to->ino << " " << path_to << " " << perm << dendl; |
| 16667 | |
| 16668 | walk_dentry_result wdr_from; |
| 16669 | if (int rc = path_walk(diri_from, filepath(path_from), &wdr_from, perm, {}); rc < 0) { |
| 16670 | return rc; |
| 16671 | } |
| 16672 | |
| 16673 | walk_dentry_result wdr_to; |
| 16674 | if (int rc = path_walk(diri_to, filepath(path_to), &wdr_to, perm, {}); rc == 0) { |
| 16675 | return -EEXIST; |
| 16676 | } else if (rc != -ENOENT) { |
| 16677 | return rc; |
| 16678 | } |
| 16679 | |
| 16680 | if (should_check_perms()) { |
| 16681 | if (S_ISDIR(wdr_from.target->mode)) { |
| 16682 | return -EPERM; |
| 16683 | } |
| 16684 | if (int rc = may_hardlink(wdr_from.target.get(), perm); rc < 0) { |
| 16685 | return rc; |
| 16686 | } |
| 16687 | if (int rc = may_create(wdr_to.diri.get(), perm); rc < 0) { |
| 16688 | return rc; |
| 16689 | } |
| 16690 | } |
| 16691 | |
| 16692 | auto* in = wdr_from.target.get(); |
| 16693 | if (in->snapid != CEPH_NOSNAP || wdr_to.diri->snapid != CEPH_NOSNAP) { |
| 16694 | return -EROFS; |
| 16695 | } |
| 16696 | if (is_quota_files_exceeded(wdr_to.diri.get(), perm)) { |
| 16697 | return -EDQUOT; |
| 16698 | } |
| 16699 | |
| 16700 | in->break_all_delegs(); |
| 16701 | MetaRequest *req = new MetaRequest(CEPH_MDS_OP_LINK); |
| 16702 | |
| 16703 | req->set_filepath(wdr_to.getpath()); |
| 16704 | req->set_alternate_name(alternate_name.empty() ? wdr_to.alternate_name : alternate_name); |
| 16705 | #if defined(__linux__) |
| 16706 | wdr_to.diri->gen_inherited_fscrypt_auth(&req->fscrypt_auth); |
| 16707 | #endif |
| 16708 | req->set_filepath2(wdr_from.getpath()); |
| 16709 | req->set_inode(wdr_to.diri); |
| 16710 | req->inode_drop = CEPH_CAP_FILE_SHARED; |
| 16711 | req->inode_unless = CEPH_CAP_FILE_EXCL; |
| 16712 | req->set_dentry(wdr_to.dn); |
| 16713 | |
| 16714 | int res = make_request(req, perm); |
| 16715 | |
| 16716 | ldout(cct, 10) << "link result is " << res << dendl; |
| 16717 | |
| 16718 | trim_cache(); |
| 16719 | ldout(cct, 8) << "link(" << wdr_from.getpath() << ", " << wdr_to.getpath() << ") = " << res << dendl; |
| 16720 | return res; |
| 16721 | } |
nothing calls this directly
no test coverage detected