Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

unlink() calls fail in BaseFileHelper.php on Windows hosted Nanobox environment #17222

Closed
jamesmacwhite opened this issue Mar 23, 2019 · 9 comments
Labels
status:to be verified Needs to be reproduced and validated. type:bug Bug

Comments

@jamesmacwhite
Copy link

jamesmacwhite commented Mar 23, 2019

What steps will reproduce the problem?

On my Nanobox environment which is running in VirtualBox but ultimately is hosted on a Windows host, unlink() related calls are failing within: https://github.com/yiisoft/yii2/blob/master/framework/helpers/BaseFileHelper.php#L406-L408. This is happening within Craft CMS 3 in several file situations, reported here:

I am using the WINDOWS_FS environment variable because the file share Nanobox points to is a Windows FS and is required otherwise I get various file mutex issues with file locking.

If I remove the unlink() call in 406-408, everything works. If I also change the line to:

return @unlink($path);

This also allows it to work, but it seems it's more of a hack. I don't know if the problem is due to the fact Yii is essentially running within a Unix-like system but the file share Nanobox points to is a Windows filesystem, so it's a bit of a mix match.

What is the expected result?

File delete operation should be successful and removed without any error.

What do you get instead?

PHP exception with unlink(). Text file is busy/permission denied depending on file operation performed.

Additional info

Q A
Yii version 2.0.16
PHP version 7.1
Operating system Windows 10 64-bit
@rob006
Copy link
Contributor

rob006 commented Mar 23, 2019

Looks like the same story as #16603.
Related discussion: #16604 (comment)

Can you give some context what you're doing with this helper?

@jamesmacwhite
Copy link
Author

I'm not directly doing anything with it. It's what Craft CMS is using. Generally the file operations that fail are removing temp files generated from various operations, because they are being tried with unlink() condition highlighted. However for a Windows FS this condition doesn't look like it should be tried in this way, but the fact that the $isWindows test, won't actually be true in my case, because the PHP directory separator will return / (as Nanobox is running in a Linux VM) but the app path is being hosted on a Windows FS mountpoint.

Ultimately, I think it all falls down to how Nanobox is mounting the app path:

nanobox-io/nanobox#462

I cannot get the netfs option to work, so I have to fallback to native. If the mountpoint was netfs, things would probably work a lot better, but as of now I have never got Nanobox to mount properly with it. Despite looking at all available resources and configurations that say this "works".

I guess this is kind of an edge case given the mixture of a Linux VM running on a Windows FS.

@rob006
Copy link
Contributor

rob006 commented Mar 23, 2019

I'm not directly doing anything with it. It's what Craft CMS is using.

Then what Craft is doing with it? Can you share stack trace of this error?

@jamesmacwhite
Copy link
Author

Sure, here's an example exception thrown:

2019-03-13 13:12:00 [-][43903][51b97db60ebb60aebd1239f015978078][error][yii\base\ErrorException:2] yii\base\ErrorException: unlink(/app/storage/runtime/temp/example.jpg): Text file busy in /app/vendor/yiisoft/yii2/helpers/BaseFileHelper.php:407
Stack trace:
#0 /app/vendor/yiisoft/yii2/helpers/BaseFileHelper.php(407): ::unlink()
#1 /app/vendor/craftcms/cms/src/controllers/AssetsController.php(812): yii\helpers\BaseFileHelper::unlink()
#2 /app/vendor/yiisoft/yii2/base/InlineAction.php(57): craft\controllers\AssetsController->actionDownloadAsset()
#3 /app/vendor/yiisoft/yii2/base/InlineAction.php(57): ::call_user_func_array:{/app/vendor/yiisoft/yii2/base/InlineAction.php:57}()
#4 /app/vendor/yiisoft/yii2/base/Controller.php(157): yii\base\InlineAction->runWithParams()
#5 /app/vendor/craftcms/cms/src/web/Controller.php(109): craft\controllers\AssetsController->runAction()
#6 /app/vendor/yiisoft/yii2/base/Module.php(528): craft\controllers\AssetsController->runAction()
#7 /app/vendor/craftcms/cms/src/web/Application.php(297): craft\web\Application->runAction()
#8 /app/vendor/craftcms/cms/src/web/Application.php(561): craft\web\Application->runAction()
#9 /app/vendor/craftcms/cms/src/web/Application.php(281): craft\web\Application->_processActionRequest()
#10 /app/vendor/yiisoft/yii2/base/Application.php(386): craft\web\Application->handleRequest()
#11 /app/web/index.php(21): craft\web\Application->run()
#12 {main}

A file is written to the temp download folder, but unlink fails causing an exception.

@samdark samdark added type:bug Bug status:to be verified Needs to be reproduced and validated. labels Mar 23, 2019
@jamesmacwhite
Copy link
Author

jamesmacwhite commented Mar 24, 2019

Thanks. I understand why the error can be thrown, but I believe the discussion referenced here: #16604 (comment) about the whole $isWindows condition is something this relates to.

Currently in the BaseFileHelper.php, the condition is being done on PHP's directory separator value by the looks of it. Given this is a Unix-like VM ultimately reading/writing to a Windows FS, this condition will never be true, because based on that condition, it isn't Windows, so unlink() is tried.

https://github.com/yiisoft/yii2/blob/master/framework/helpers/BaseFileHelper.php#L404-L408

However, given I am telling the file mutex that this is Windows system with an env var, surely, the same logic should be used across all the areas. @brandonkelly discussed this in is proposal, given $isWindows = DIRECTORY_SEPARATOR === '\\'; is used elsewhere, but in this case this is what's causing the problem. My PHP directory separator won't look like Windows, because it isn't, only the underlying FS which the Nanobox environment points to is, if that makes sense.

I suspect, if I could get the netfs mount type working, most of these issues would not happen but I have yet to find a way to get it work, so I am stuck with the default VirtualBox mounting, which is slower, but at least works, but then introduces filesystem related issues. Can't win!

@jamesmacwhite
Copy link
Author

I have managed to get a project running under the Nanobox netfs mount type which pretty much resolves all the issues highlighted. It is ultimately a underlying FS problem in the way the app directory is mounted and performs various actions, it would seem file locking and other areas are pretty sensitive when using the VirtualBox driver.

However, I would still suggest there is an argument to make the $isWindows condition the same across the various areas and not using the PHP directory separator as the condition. If the isWindows option is being used in the file mutex, shouldn't this be the flag in other places as discussed previously?

@samdark
Copy link
Member

samdark commented Mar 24, 2019

Probably but since that's quite rare use case, I don't think we'll get to implementing it anytime soon.

@jamesmacwhite
Copy link
Author

Fair enough. At least it's documented if someone else comes across this!

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
status:to be verified Needs to be reproduced and validated. type:bug Bug
Projects
None yet
Development

No branches or pull requests

3 participants