Eryk Sun added the comment:

Richard wrote:
> while a handle is open with share mode X, you can only reopen 
> the file if you also use share mode X

To clarify, the share mode is not a property of a handle. It's a property of a 
File object. A handle is a generic reference to any kind of kernel object, not 
just a File.

The following is a brief discussion about access sharing and the way file 
deletion works in Windows. Both of these tend to frustrate Unix programmers who 
end up supporting Windows. In this discussion, a "File", with an uppercase 'F', 
is the Windows kernel object type that references an open device or file-system 
directory, file, or stream. A "file", with a lowercase 'f', is a data file.

Shared access is implemented for File objects [1] and tracked in a SHARE_ACCESS 
record. When opening a file or directory, its shared access state is updated by 
the kernel function IoCheckShareAccess [2]. Discretionary shared access is 
primarily a concern for file systems, but volume devices and disk devices (e.g. 
\\.\C: and \\.\PhysicalDrive0) also use it. Devices that are flagged for 
mandatory exclusive access [3] (e.g. \\.\COM1) generally ignore the share mode. 
Some non-exclusive devices also ignore the share mode (e.g. \\.NUL and \\.CON). 

If it's not ignored, the share mode affects delete, write, read, and execute 
access. The following File access rights are affected: DELETE, FILE_WRITE_DATA, 
FILE_APPEND_DATA, FILE_READ_DATA, and FILE_EXECUTE. The share mode thus affects 
any combination of generic access -- GENERIC_ALL, GENERIC_WRITE, GENERIC_READ, 
GENERIC_EXECUTE. 

A File object's requested sharing is stored in its SharedDelete, SharedWrite, 
and SharedRead members. The granted access that's relevant to the share mode is 
stored in the DeleteAccess, WriteAccess (write/append), and ReadAccess 
(read/execute) members. Given these values, checking for a sharing violation 
and updating the shared access counts uses the following logic:

    RequireSharedDelete = DeleteAccessCount > 0;
    RequireSharedWrite = WriteAccessCount > 0;
    RequireSharedRead = ReadAccessCount > 0;
    DenyDeleteAccess = SharedDeleteCount < OpenCount;
    DenyWriteAccess = SharedWriteCount < OpenCount;
    DenyReadAccess = SharedReadCount < OpenCount;
    
    if (RequireSharedDelete && !SharedDelete ||
        RequireSharedWrite && !SharedWrite ||
        RequireSharedRead && !SharedRead ||
        DenyDeleteAccess && DeleteAccess ||
        DenyWriteAccess && WriteAccess ||
        DenyReadAccess && ReadAccess)
    {
        return STATUS_SHARING_VIOLATION;
    }

    OpenCount++;
    DeleteAccessCount += DeleteAccess;
    WriteAccessCount += WriteAccess;
    ReadAccessCount += ReadAccess;
    SharedDeleteCount += SharedDelete;
    SharedWriteCount += SharedWrite;
    SharedReadCount += SharedRead;

For example, to be granted delete access, all existing File object references 
must share delete access. However, if a file is opened with delete sharing but 
delete access hasn't been granted, then it can be opened again without delete 
sharing.

The SHARE_ACCESS structure is usually stored in a file (or stream) control 
block (FCB/SCB), which is a structure that coordinates access to a file or 
directory across multiple File objects. The FsContext member of a File object 
points at the FCB. 

A file system stores its private state for a File in a context control block 
(CCB), to which the File's FsContext2 member points. The CCB is where a file 
system tracks, for example, whether the file should be deleted when the object 
is closed. 

Deleting a file sets a delete disposition in the FCB/SCB (or LCB if hard links 
are supported). The file can't be unlinked until all referencing File objects 
have been closed and the underlying FCB/SCB/LCB is closing. Until then a 
'deleted' file is still linked in the parent directory and prevents the 
directory from being deleted.

A deleted but still referenced file is in a semi-zombie state. Windows file 
systems don't allow opening such a file for any access, but it can still be 
accessed via existing objects. If one of these File objects has delete access, 
it can be used to unset the delete disposition (e.g. via 
SetFileInformationByHandle) to make the file accessible again.

[1]: https://msdn.microsoft.com/en-us/library/ff545834
[2]: https://msdn.microsoft.com/en-us/library/ff548341
[3]: https://msdn.microsoft.com/en-us/library/ff563827

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue14243>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to