@@ -2457,121 +2457,6 @@ def GetBinaryFileType(infile, filestart=0, closefp=True):
24572457 # -------------- FALLBACK --------------
24582458 return False
24592459
2460- def _get_seek_consts ():
2461- """Return (SEEK_DATA, SEEK_HOLE) if supported, else (None, None)."""
2462- seek_data = getattr (os , "SEEK_DATA" , None )
2463- seek_hole = getattr (os , "SEEK_HOLE" , None )
2464- if seek_data is None or seek_hole is None :
2465- return None , None
2466- return seek_data , seek_hole
2467-
2468- def pack_sparse_to_stream (path , out_fp , bufsize = 1024 * 1024 ):
2469- """
2470- Write ONLY data extents from sparse file `path` into `out_fp`.
2471- Returns: (logical_size, extents, stored_bytes)
2472- extents: list of (offset, length) in logical file
2473- stored_bytes: total bytes written to out_fp
2474- """
2475- st = os .stat (path , follow_symlinks = False )
2476- logical_size = int (st .st_size )
2477- extents = []
2478- stored = 0
2479-
2480- SEEK_DATA , SEEK_HOLE = _get_seek_consts ()
2481-
2482- with open (path , "rb" , buffering = 0 ) as f :
2483- if SEEK_DATA is not None and SEEK_HOLE is not None :
2484- # Kernel knows where holes are (best, fastest, exact).
2485- pos = 0
2486- while pos < logical_size :
2487- try :
2488- data_off = os .lseek (f .fileno (), pos , SEEK_DATA )
2489- except OSError :
2490- break # no more data
2491- try :
2492- hole_off = os .lseek (f .fileno (), data_off , SEEK_HOLE )
2493- except OSError :
2494- hole_off = logical_size
2495- if hole_off > logical_size :
2496- hole_off = logical_size
2497-
2498- length = hole_off - data_off
2499- if length <= 0 :
2500- pos = max (pos + 1 , hole_off )
2501- continue
2502-
2503- extents .append ((data_off , length ))
2504- # copy that extent’s bytes into out_fp
2505- os .lseek (f .fileno (), data_off , os .SEEK_SET )
2506- remaining = length
2507- while remaining :
2508- chunk = f .read (min (bufsize , remaining ))
2509- if not chunk :
2510- break
2511- out_fp .write (chunk )
2512- stored += len (chunk )
2513- remaining -= len (chunk )
2514-
2515- pos = hole_off
2516- else :
2517- # Portable fallback (no SEEK_HOLE/DATA): scan for non-zero blocks.
2518- # Not perfect (won't detect "real zeros" vs "holes"), but works as a fallback.
2519- block = 4096
2520- pos = 0
2521- while pos < logical_size :
2522- chunk = f .read (block )
2523- if not chunk :
2524- break
2525- if any (b != 0 for b in chunk ):
2526- off = pos
2527- # extend this run while blocks have any non-zero
2528- run = bytearray (chunk )
2529- while True :
2530- nxt = f .read (block )
2531- if not nxt or not any (b != 0 for b in nxt ):
2532- if nxt :
2533- # rewind one block if it was all-zero (we read too far)
2534- f .seek (- len (nxt ), os .SEEK_CUR )
2535- break
2536- run .extend (nxt )
2537- extents .append ((off , len (run )))
2538- out_fp .write (run )
2539- stored += len (run )
2540- pos = off + len (run )
2541- else :
2542- pos += len (chunk )
2543-
2544- out_fp .seek (0 , os .SEEK_SET )
2545- return logical_size , extents , stored
2546-
2547- def write_sparse_to_fileobj (out_fp , logical_size , extents , in_fp , bufsize = 1024 * 1024 ):
2548- """
2549- Recreate sparse file layout into an already-open writable file-like object.
2550- """
2551- out_fp .seek (0 )
2552- out_fp .truncate (int (logical_size ))
2553-
2554- for off , length in extents :
2555- out_fp .seek (int (off ), os .SEEK_SET )
2556- remaining = int (length )
2557- while remaining :
2558- chunk = in_fp .read (min (bufsize , remaining ))
2559- if not chunk :
2560- raise EOFError ("Archive ended while reading sparse extent data" )
2561- out_fp .write (chunk )
2562- remaining -= len (chunk )
2563-
2564- def unpack_sparse_to_path (in_fp , out_path , logical_size , extents , bufsize = 1024 * 1024 ):
2565- os .makedirs (os .path .dirname (out_path ) or "." , exist_ok = True )
2566-
2567- with open (out_path , "wb" ) as f :
2568- write_sparse_to_fileobj (f , logical_size , extents , in_fp , bufsize )
2569-
2570- try :
2571- f .flush ()
2572- os .fsync (f .fileno ())
2573- except Exception :
2574- pass
25752460
25762461def _is_valid_zlib_header (cmf , flg ):
25772462 """
0 commit comments