マウントしているNASのファイルがfs.rename出来なくなる問題
久しぶりにハマったので同じようにハマってる人の参考になればと思い記録も兼ねて書いていこうと思います。
こういう記事書くのは慣れていないので見にくいと思いますがお許しください。
環境
サーバーOS: CentOS Linux release 7.9.2009 (Core)
サーバープログラム: node.js v16.18.0
fsモジュール:0.0.2
発生状況
自社用の業務管理のスマホアプリを開発していて、案件毎にスマホで写真を保存したり削除したり出来るようにしていたのですが、他のデスクトップアプリやWindowsのエクスプローラーからも写真を追加したり消したりする為に写真の保存先をNASにすることにしました。
社内LINUXサーバーでNASを利用するために/etc/fstabに
\\192.168.0.50\pictures /mnt/nasPictures cifs cifsacl,_netdev,noperm,vers=1.0,user=@@@@,pass=@@@@@ 0 0
てな感じでマウントしてました。
実際にスマホで撮影した写真は問題なくNASに保存されて削除も問題なくできていました。ここで言う削除は実際には.deleteフォルダにファイルを移動させる処理としていて、サーバー側で下記のようなコードで実装していました。
socket.on("deletePictures", (request, callback) => {
const picFolder = `${pictureFolder}/${request.customerJob}`;
const deletedFolder = `${picFolder}/${deletedFolderName}`
try {
if (!fs.existsSync(deletedFolder)) {
fs.mkdirSync(deletedFolder, { recursive: true });
}
for( filename of request.filenames ) {
const filePath = `${picFolder}/${filename}`;
fs.renameSync(filePath, `${deletedFolder}/${filename}`);
}
callback({ status: 'success' });
} catch (e) {
console.log(e);
callback({ status: 'error', detail: e });
}
});
最初に確認した現象は、スマホから撮影した写真がNASに正常に保存されたあと、その写真を上述のコードで削除処理(実際にはファイル移動)をした後に、Windowsのエクスプローラーから削除済みのフォルダから元の場所にファイルを戻したあと、スマホから再度削除処理(実際にはファイル移動)をするとファイルが削除(移動)されないという現象でした。
その状態でもスマホから新たに保存した写真の削除処理(実際にはファイル移動)は問題なく出来るにも関わらず、Windowsのエクスプローラーで移動したファイルだけは移動されないという現象が発生していました。
最初はWindowsでファイルを弄った時にファイルの権限などが書き換えられるからなのかと思ったりして調べてみましたが特にそんなこともなく途方にくれて数日ググりまくっていたわけですが、似たような現象についての書き込みはあるのですが、これといった解決策にはたどり着けずにいました。
原因調査
そこでLinuxのシェルコマンドでも移動が出来ないのかどうかを確認したところ
$ mv IMG_0285.JPG .deleted
mv: `IMG_0285.JPG' と `.deleted/IMG_0285.JPG' は同じファイルです
この時.deletedフォルダには一切ファイルは存在していない状態なのですが、こんな警告が出ていることを確認できました。
ということはWindowsで.deletedフォルダから元のフォルダにファイルを移動した情報がLinux側には知らされていない為にファイルがまだ存在してると勘違いしている為にこんな状態になるんだと納得しました。
解決策
それではということで先程のソースに少し手を加えて確認してみました。
socket.on("deletePictures", (request, callback) => {
const picFolder = `${pictureFolder}/${request.customerJob}`;
const deletedFolder = `${picFolder}/${deletedFolderName}`
try {
if (!fs.existsSync(deletedFolder)) {
fs.mkdirSync(deletedFolder, { recursive: true });
}
for( filename of request.filenames ) {
const filePath = `${picFolder}/${filename}`;
// ここ追加
if( fs.existsSync(`${deletedFolder}/${filename}`))
console.log( "ある" );
elese
console.log( "ない" );
//ここまで
fs.renameSync(filePath, `${deletedFolder}/${filename}`);
}
callback({ status: 'success' });
} catch (e) {
console.log(e);
callback({ status: 'error', detail: e });
}
});
するとWindowsでファイルを移動した後にスマホでファイルの削除処理(実際には移動)をしてもコンソールには「ない」としか表示されず、なんとファイルの移動も常時成功するようになりました。
ファイルの移動処理の直前にファイルの存在確認をしてあげることで最新の状態を認識できるようになるようでした。
最終的にコンソールログ出力を排除して
socket.on("deletePictures", (request, callback) => {
const picFolder = `${pictureFolder}/${request.customerJob}`;
const deletedFolder = `${picFolder}/${deletedFolderName}`
try {
if (!fs.existsSync(deletedFolder)) {
fs.mkdirSync(deletedFolder, { recursive: true });
}
for( filename of request.filenames ) {
const filePath = `${picFolder}/${filename}`;
fs.existsSync(`${deletedFolder}/${filename}`);
fs.renameSync(filePath, `${deletedFolder}/${filename}`);
}
callback({ status: 'success' });
} catch (e) {
console.log(e);
callback({ status: 'error', detail: e });
}
});
これで解決しました。
途中、/etc/fstabでマウントする際のオプションに cache=none をつけるという情報も見つけて試してみたんですが駄目でした。