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