為什麼 SFTP 客戶端不能在其 NFS 掛載的主目錄中重命名文件?
我有一個執行 SSH 的 Amazon Linux 實例作為 SFTP 伺服器。客戶端登錄,並被 chroot 到 NFS 掛載的目錄中。使用者可以讀取、寫入和刪除文件,但重命名文件失敗並出現非特定的“協議錯誤”。
這是我的
sshd_config
文件的副本:Port 22 Protocol 2 HostKey /etc/ssh/ssh_host_rsa_key UsePrivilegeSeparation yes KeyRegenerationInterval 3600 ServerKeyBits 1024 SyslogFacility AUTH LogLevel INFO LoginGraceTime 120 PermitRootLogin prohibit-password StrictModes yes RSAAuthentication yes PubkeyAuthentication yes IgnoreRhosts yes RhostsRSAAuthentication no HostbasedAuthentication no PermitEmptyPasswords no ChallengeResponseAuthentication no PasswordAuthentication yes X11Forwarding yes X11DisplayOffset 10 PrintMotd no PrintLastLog yes TCPKeepAlive yes #UseLogin no AcceptEnv LANG LC_* # Subsystem sftp /usr/lib/openssh/sftp-server -u 0002 Subsystem sftp internal-sftp -l DEBUG -u 002 -d %u UsePAM yes Match Group sftpusers ChrootDirectory /autohome AllowTCPForwarding no X11Forwarding no ForceCommand internal-sftp -l DEBUG -u 002 -d %u
當源和目標位於不同的文件系統上時,我已經看到對 sftp rename 的引用不起作用,但這裡不是這種情況。我還看到對 sftp rename 的引用在不支持硬連結的文件系統上不起作用,但我認為我們的 NFS 伺服器(AWS 文件儲存網關)應該沒問題。我很茫然,任何幫助表示讚賞。
感謝@Kenster 的提示,我發現了這個問題。我錯誤地假設 AWS 文件儲存網關 NFS 掛載支持硬連結,因為文件明確指出它不支持。
我非常確定我最終使用 strace 跟踪系統呼叫就是這種情況。如果在 ssh 連接到伺服器時將 sftp 客戶端附加到伺服器,則使用 .d 獲取目前 sftp 程序的 pid
ps -eaf | grep sftp
。然後,您可以使用 strace 跟踪系統呼叫並使用以下命令將輸出保存到文件中:strace -ff -p 2116 -o sftp_rename.log
其中 -ff 跟踪子程序,-p 是 pid,-o 是輸出文件。這會給你一些看起來很糟糕的輸出,但我發現有趣的是這一點:
write(7, "\0\0\0L\0\0\0\3\0\0\0Drename old \"/testuse"..., 80) = 80 lstat("/testuser/test/asdfasdf.txt", {st_mode=S_IFREG|0664, st_size=159, ...}) = 0 link("/testuser/test/asdfasdf.txt", "/testuser/test/as.txt") = -1 ENOTSUPP (Unknown error 524)
然後我用一個簡單的連結命令對其進行了測試,以創建一個硬連結,但失敗了。
# ln asdfasdf.txt link.txt ln: failed to create hard link ‘link.txt’ => ‘asdfasdf.txt’: Unknown error 524 #
這讓我回到了 AWS 的文件。但這還不是全部,顯然 SFTP 重命名將與實現供應商特定
CMD_EXTENDED
協議的某些客戶端(如 Paramiko)一起使用,正如Paramiko 所做的那樣:oldpath = self._adjust_cwd(oldpath) newpath = self._adjust_cwd(newpath) self._log(DEBUG, 'posix_rename({!r}, {!r})'.format(oldpath, newpath)) self._request( CMD_EXTENDED, "posix-rename@openssh.com", oldpath, newpath )
似乎沒有任何方法可以強制
posix-rename
所有客戶端使用該選項,但至少我們知道發生了什麼以及為什麼。