Re: Pinned files at Windows

From: Konstantin Knizhnik <k(dot)knizhnik(at)postgrespro(dot)ru>
To: Michael Paquier <michael(at)paquier(dot)xyz>
Cc: pgsql-hackers(at)lists(dot)postgresql(dot)org
Subject: Re: Pinned files at Windows
Date: 2019-05-30 07:25:17
Message-ID: a24a0303-4883-327d-322e-b7e267a094c6@postgrespro.ru
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On 29.05.2019 22:20, Michael Paquier wrote:
> On Mon, May 27, 2019 at 05:52:13PM +0300, Konstantin Knizhnik wrote:
>> Postgres is opening file with FILE_SHARE_DELETE  flag which makes it
>> possible to unlink opened file.
>> But unlike Unixes, the file is not actually deleted. You can see it using
>> "dir" command.
>> And stat() function also doesn't return error in this case:
>>
>> https://stackoverflow.com/questions/27270374/deletefile-or-unlink-calls-succeed-but-doesnt-remove-file
>>
>> So first check in  pgwin32_safestat (r < 0) is not working at all: stat()
>> returns 0, but subsequent call of GetFileAttributesEx
>> returns 5 (ERROR_ACCESS_DENIED).
> So you would basically hijack the result of GetFileAttributesEx() so
> as any errors returned by this function complain with ENOENT for
> everything seen. Why would that be a sane idea? What if say a
> permission or another error is legit, but instead ENOENT is returned
> as you propose, then the caller would be confused by an incorrect
> status.

If access to the file is prohibited by lack of permissions, then stat()
should fail with error
and this error is returned by  pgwin32_safestat function.

If call of stat() is succeed, then my assumption is that the only reason
of GetFileAttributesEx
failure is that file is deleted and returning ENOENT error code in this
case is correct behavior.

>
> As you mention, what we did as of 9951741 may not be completely right,
> and the reason why it was done this way comes from here:
> https://www.postgresql.org/message-id/20160712083220.1426.58667@wrigleys.postgresql.org

Yes, this is the same reason, but handling STATUS_DELETE_PENDING is not
correct.
>
> Could we instead come up with a reliable way to detect if a file is in
> a deletion pending state? Mapping blindly EACCES to ENOENT is not a
> solution I think we can rely on (perhaps we could check only after
> ERROR_ACCESS_DENIED using GetLastError() and map back to ENOENT in
> this case still this can be triggered if a virus scanner holds the
> file for read, no?). stat() returning 0 for a file pending for
> deletion which will go away physically once the handles still keeping
> the file around are closed is not something I would have imagined is
> sane, but that's what we need to deal with... Windows has a long
> history of keeping things compatible, sometimes in their own weird
> way, and it seems that we have one here so I cannot imagine that this
> behavior is going to change.
>
> Looking around, I have found out about NtCreateFile() which could be
> able to report a proper pending deletion status, still that's only
> available in kernel mode. Perhaps others have ideas?

Sorry, I do not know better solution.
I have written small test reproducing the problem which proves that
if file is opened with FILE_SHARE_DELETE flag, then
it is possible to delete it using unlink() - no error is returned and
call stat() for it - also succeed.
By any attempt to open this file for reading/writing or performing
GetFileAttributesEx
are failed with  ERROR_ACCESS_DENIED (not with ERROR_DELETE_PENDING
which is hidden by Win32 API).

--
Konstantin Knizhnik
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Amit Langote 2019-05-30 07:33:17 Re: How to know referenced sub-fields of a composite type?
Previous Message Donald Dong 2019-05-30 04:26:27 Re: undefined symbol: PQgssEncInUse