
    Loj                    D   % S SK Jr  S SKrS SKrS SKrS SKrS SKJrJrJ	r	  S SK
Jr  S SKJr  SS jrSS jrSS jrSS	 jrSS
.SS jjr\R&                  S:g  =(       a    \R(                  \R*                  ;   rS\S'   \R(                  \R0                  ;   rS\S'   / SQrg)    )annotationsN)EACCESEIOEISDIR)Path)Finalc                    [        U5      nU(       a:  [        R                  " X5      =nS:X  a  [        [        S5      eX#S nU(       a  M9  gg)aC  
Write the whole buffer to *fd*, looping over the short writes ``os.write`` is allowed to make.

A marker written with a bare ``os.write`` can land partially: a peer reading it mid-write parses a truncated record
as malformed or as a foreign holder. Looping until the buffer drains keeps the record atomic in the process and
kernel view. No ``fsync``: filelock needs a complete record, not crash-durable storage.

:param fd: file descriptor open for writing.
:param data: bytes to write in full.

:raises OSError: if a write reports zero progress before the record is complete.

r   z5os.write wrote 0 bytes before the record was completeN)
memoryviewoswriteOSErrorr   )fddata	remainingwrittens       H/mnt/workspace/venv-train/lib/python3.13/site-packages/filelock/_util.py	write_allr      sF     4 I
xx..G14#VWWh'	 )    c                n    [         R                  " U 5      nUR                  [        R
                  -  (       d  [        [        SU 5      e[        R                  " UR                  5      (       a6  [        R                  S:X  a  [        [        SU 5      e[        [        SU 5      eg! [         a     gf = f)a  
Raise an exception if attempting to open the file for writing would fail.

Separates files that can never be written from files that are writable but currently locked.

:param filename: file to check

:raises OSError: as if the file was opened for writing.

NzPermission deniedwin32zIs a directory)r   lstatr   st_modestatS_IWUSRPermissionErrorr   S_ISDIRsysplatformIsADirectoryErrorr   )filename	file_stats     r   raise_on_not_writable_filer"   !   s    
 HHX&	 ,f&98DD||I%%&&<<7"!&*=xHH(8(CC '  s   B' '
B43B4c                J    [        U 5      R                  R                  SSS9  g)zd
Ensure the directory containing the file exists (create it if necessary).

:param filename: file.

T)parentsexist_okN)r   parentmkdir)r    s    r   ensure_directory_existsr(   A   s!     	Nt<r   c                \   U  S[         R                  " 5        S[        R                  " S5       3n[	        U 5      R                  U5         [         R                  " U5      nUR                  U:  d  UR                  U:w  a  g[	        U5      R                  5         g! [         a     gf = f)a  
Atomically break a stale lock file judged stale at modification time *mtime_before*.

Rename the file to a process-private name before unlinking it, so two processes breaking the same lock cannot
delete each other's work: only one rename of a given inode wins, the loser gets ``OSError``. After the rename,
re-check the file. A newer modification time, or a different inode than *ino_before*, means a peer recreated the
lock between the stale decision and the rename, so we grabbed a live file and abort, leaving the renamed file in
place. A rollback rename is itself racy, the same trade-off as the soft read/write marker break. The inode check
matters because filesystems with coarse modification-time granularity (NFS, FAT) can give a same-second recreation
the old mtime, so mtime alone would miss it and unlink a live lock; the inode is the reliable identity, mirroring
the token re-check in the soft read/write marker break. ``lstat`` avoids following a hostile symlink swapped in
after the decision.

The break name carries a random token so it is unguessable and unique per attempt. Without it two breakers in the
same process share ``<lock>.break.<pid>``, and a second break can rename a recreated live lock onto that path in
the window between the re-verify ``lstat`` above and the ``unlink`` below, deleting a live lock the inode check
just approved. A private name keeps anyone else from targeting our break path, matching the soft read/write marker
break.

:param lock_file: path to the lock file to break.
:param mtime_before: modification time observed when the lock was judged stale.
:param ino_before: inode number observed when the lock was judged stale.

:raises OSError: if the rename fails (e.g. the file vanished or is not owned in a sticky directory).

z.break..   N)r   getpidsecrets	token_hexr   renamer   r   st_mtimest_inounlink)	lock_filemtime_before
ino_before
break_pathst_afters        r   break_lock_filer8   K   s    6 ;gbiik]!G4E4Eb4I3JKJO:&88J' <'8??j+H	  s   B 
B+*B+)r   c                   Ub#  [         (       a  [        R                  " US 5        g [        R                  " U S [        (       + S9  g )N)follow_symlinks)_SUPPORTS_UTIME_FDr   utime_SUPPORTS_UTIME_NOFOLLOW)namer   s     r   touchr?   q   s4    
 
~,,
THHT4-E)EFr   r   zFinal[bool]r;   r=   )r8   r(   r"   r?   r   )r   intr   bytesreturnNone)r    strrB   rC   )r    z
Path | strrB   rC   )r3   rD   r4   floatr5   r@   rB   rC   )r>   rD   r   z
int | NonerB   rC   )
__future__r   r   r-   r   r   errnor   r   r   pathlibr   typingr   r   r"   r(   r8   r?   r   r<   supports_fdr;   __annotations__supports_follow_symlinksr=   __all__ r   r   <module>rO      s    " 	   
 % %  (*D@=#L *. G #&,,'"9"Xbhh"..>X K X(*B4O4O(O + Or   