

古いPHPスクリプトの保守をしており、以下のようにファイルをtruncateしてから上書きするスクリプトですが、以前は正常に動作していたものがvagrant-
vbguestをインストールして再起動してからftruncateが失敗するようになりました。

[code]

    $file = "./test.txt";
    $str = "書き込み内容";
    $fp = fopen($file, 'a');
    flock($fp, LOCK_EX);
    ftruncate($fp, 0); //ftruncateの戻り値を調べるとfalseとなる
    rewind($fp);
    fputs($fp, $str);
    flock($fp, LOCK_UN);
    fclose($fp);
    
[/code]

ftruncateが失敗するため上書きされず、既存の内容に追記されてしまいます。

【環境】  
Vagrant 2.2.5  
GuestOS Centos6.9  
HostOS Windows10  
PHPバージョン 5.3.3

GuestOSのシャットダウンに失敗したことがあり、その後`vagrant up`すると

[code]

    Vagrant was unable to mount VirtualBox shared folders.
    
[/code]

のようなエラーが表示されたため、

[code]

    vagrant plugin install vagrant-vbguest
    
[/code]

を実行してプラグインをインストール後、仮想マシンを立ち上げ直してから動作内容が変わったように思われます。

ftruncate以外の動作は今のところ問題ないようですが、なぜftruncateが失敗するのかがわからず悩んでいる次第です。

fopenのモードをcやw、rにするとftruncateは正常動作(trueを返す)します。

fopenのモードがaの場合にftruncateが失敗する理由および仮想マシンの修復について、ご存知であれば助言いただけますでしょうか。


CC BY-SA 4.0
2019-09-05T03:36:29.977
57860
2019-09-05T17:09:41.970
2019-09-05T17:09:41.970
3060
25729
question
php vagrant
vagrant-vbguest インストール後、aモードでfopenするとftruncateが失敗する


ひとまずPHPの話題に絞って回答します。

* * *

`ftruncate`で失敗する場合があるのは、ファイルオープン時の **モードによってファイルポインターの位置が違う** ことを意識する必要があります。

[fopen()](https://www.php.net/manual/ja/function.fopen.php)
のモードで`r`,`w`,`c`を使用した場合にはポインター位置が **ファイルの先頭**
に移動するので、そのまま`ftruncate`を実行すれば意図した動作になっていますが、`a`の場合はポインター位置が **ファイルの終端** にあります。

質問のコードでは`rewind`も記述されていますが、これを使用するなら以下の順番で実行する必要があるでしょう。

[code]

    rewind($fp);
    ftruncate($fp, 0);
    
[/code]

ただし [rewind()](https://www.php.net/manual/ja/function.rewind.php)
の説明には以下のような注意書きがあります。

> 注意:  
>  追記モード ("a" もしくは "a+") でファイルをオープンした場合、ファイルのポインターの位置とは  
>  無関係に、 ファイルに書き込まれるデータは常に追加されます。

プログラムの動作として「追記ではなく上書き」を意図しているのであれば、追記モード(`a`)でのオープンがそもそも間違いな気がします。より適切な`w`や`c`を使用しましょう。


CC BY-SA 4.0
2019-09-05T04:41:22.207
57862
2019-09-05T04:41:22.207
3060
57860
answer