compactrs 2025.12.24

High-performance native Windows file compressor using WOF (Windows Overlay Filter)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
#![allow(non_snake_case, non_camel_case_types)]
use std::ffi::c_void;
use std::fs::File;
use std::mem::size_of;
use std::os::windows::io::AsRawHandle;
use std::os::windows::io::FromRawHandle;
use std::os::windows::fs::OpenOptionsExt; 
use crate::types::*;

// --- Manual Bindings & Constants ---

// IOCTL Codes
const FSCTL_SET_COMPRESSION: u32 = 0x9C040;
const FSCTL_SET_EXTERNAL_BACKING: u32 = 0x9030C;
const FSCTL_GET_EXTERNAL_BACKING: u32 = 0x90310;
const FSCTL_DELETE_EXTERNAL_BACKING: u32 = 0x90314;

// Security Constants
const SE_PRIVILEGE_ENABLED: u32 = 0x00000002;
const TOKEN_ADJUST_PRIVILEGES: u32 = 0x0020;
const TOKEN_QUERY: u32 = 0x0008;

#[repr(C)]
struct LUID_AND_ATTRIBUTES {
    Luid: LUID,
    Attributes: u32,
}

#[repr(C)]
struct TOKEN_PRIVILEGES {
    PrivilegeCount: u32,
    Privileges: [LUID_AND_ATTRIBUTES; 1],
}



use crate::utils::{to_wstring, PathBuffer};

pub fn get_real_file_size(path: &str) -> u64 {
    unsafe {
        let wide = PathBuffer::from(path);
        let mut high: u32 = 0;
        let win_api = crate::engine::dynamic_import::WinApi::get();
        let low = (win_api.GetCompressedFileSizeW.unwrap())(wide.as_ptr(), &mut high);
        
        if low == u32::MAX && GetLastError() != 0 {
            // If error, fall back to logical size or 0
            std::fs::metadata(path).map(|m| m.len()).unwrap_or(0)
        } else {
            ((high as u64) << 32) | (low as u64)
        }
    }
}

/// Get the WOF compression algorithm used for a file
/// Returns None if file is not WOF-compressed, Some(algorithm) if it is
pub fn get_wof_algorithm(path: &str) -> Option<WofAlgorithm> {
    unsafe {
        let wide = PathBuffer::from(path);
        let win_api = crate::engine::dynamic_import::WinApi::get();
        let handle = (win_api.CreateFileW.unwrap())(
            wide.as_ptr(),
            0x80000000, // GENERIC_READ
            FILE_SHARE_READ,
            std::ptr::null(),
            OPEN_EXISTING,
            FILE_FLAG_BACKUP_SEMANTICS,
            std::ptr::null_mut(),
        );

        if handle == INVALID_HANDLE_VALUE {
            return None;
        }

        let result = get_wof_algorithm_from_handle(handle);
        (win_api.CloseHandle.unwrap())(handle);
        result
    }
}

/// Get the WOF compression algorithm from an already-opened file handle.
/// Returns None if file is not WOF-compressed.
/// 
/// # Safety
/// The handle must be a valid, open file handle with at least read access.
pub fn get_wof_algorithm_from_handle(handle: HANDLE) -> Option<WofAlgorithm> {
    unsafe {
        // Buffer for WOF_EXTERNAL_INFO + FILE_PROVIDER_EXTERNAL_INFO_V1
        let mut out_buffer = [0u8; 1024];
        let mut bytes_returned = 0u32;
        
        let win_api = crate::engine::dynamic_import::WinApi::get();
        let result = (win_api.DeviceIoControl.unwrap())(
            handle,
            FSCTL_GET_EXTERNAL_BACKING,
            std::ptr::null(),
            0,
            out_buffer.as_mut_ptr() as *mut _,
            out_buffer.len() as u32,
            &mut bytes_returned,
            std::ptr::null_mut(),
        );
        
        if result == 0 {
            return None;
        }
        
        // Parse the output buffer
        // First comes WOF_EXTERNAL_INFO (8 bytes), then FILE_PROVIDER_EXTERNAL_INFO_V1 (12 bytes)
        if bytes_returned < 20 {
            return None;
        }
        
        let wof_info = &out_buffer[0..8];
        // provider is at offset 4 (u32)
        let provider = u32::from_le_bytes([wof_info[4], wof_info[5], wof_info[6], wof_info[7]]);
        
        // Check if it's WOF_PROVIDER_FILE (2)
        if provider != 2 {
            return None;
        }
        
        let file_info = &out_buffer[8..20];
        // algorithm is at offset 4 (u32)
        let algorithm = u32::from_le_bytes([file_info[4], file_info[5], file_info[6], file_info[7]]);
        
        match algorithm {
            0 => Some(WofAlgorithm::Xpress4K),
            1 => Some(WofAlgorithm::Lzx),
            2 => Some(WofAlgorithm::Xpress8K),
            3 => Some(WofAlgorithm::Xpress16K),
            _ => None,
        }
    }
}

// WOF Definitions

#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct WOF_EXTERNAL_INFO {
    pub version: u32,
    pub provider: u32,
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct FILE_PROVIDER_EXTERNAL_INFO_V1 {
    pub version: u32,
    pub algorithm: u32,
    pub flags: u32,
}

pub const WOF_CURRENT_VERSION: u32 = 1;
pub const WOF_PROVIDER_FILE: u32 = 2;

pub const FILE_PROVIDER_CURRENT_VERSION: u32 = 1;

// Compression Algorithms
pub const FILE_PROVIDER_COMPRESSION_XPRESS4K: u32 = 0;
pub const FILE_PROVIDER_COMPRESSION_LZX: u32 = 1;
pub const FILE_PROVIDER_COMPRESSION_XPRESS8K: u32 = 2;
pub const FILE_PROVIDER_COMPRESSION_XPRESS16K: u32 = 3;

// NTFS Compression Formats
pub const COMPRESSION_FORMAT_NONE: u16 = 0;
pub const COMPRESSION_FORMAT_DEFAULT: u16 = 1;
pub const COMPRESSION_FORMAT_LZNT1: u16 = 2;

#[repr(u32)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum WofAlgorithm {
    Xpress4K = 0,
    Lzx = 1,
    Xpress8K = 2,
    Xpress16K = 3,
}

impl WofAlgorithm {
    fn to_u32(self) -> u32 {
        self as u32
    }
}

/// Represents the compression state of a file or folder
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CompressionState {
    /// Not compressed (or not WOF compressed)
    None,
    /// Compressed with a specific algorithm (all files if folder)
    Specific(WofAlgorithm),
    /// Contains files with different compression algorithms (folder only)
    Mixed,
}

pub fn compress_file(path: &str, algo: WofAlgorithm, force: bool) -> Result<bool, u32> {
    // First attempt: Normal open with permissive sharing
    let file_result = std::fs::OpenOptions::new()
        .read(true)
        .write(true)
        .share_mode(7)
        .open(path);
    
    match file_result {
        Ok(file) => compress_file_handle(&file, algo, force),
        Err(e) => {
            // Check if Access Denied and force is enabled
            if force && e.raw_os_error() == Some(ERROR_ACCESS_DENIED as i32) {
                // Enable backup privileges first
                enable_backup_privileges();
                
                // Remove read-only attribute if set
                force_remove_readonly(path);
                
                // Retry normal open after removing readonly
                if let Ok(file) = std::fs::OpenOptions::new()
                    .read(true)
                    .write(true)
                    .share_mode(7)
                    .open(path)
                {
                    return compress_file_handle(&file, algo, force);
                }
                
                // Try direct Win32 API with backup semantics
                if let Some(result) = compress_file_with_backup_semantics(path, algo, force) {
                    return result;
                }
            }
            // Return raw OS error as u32
            // Use explicit closure type for correct inference if needed, though this simple map usually works
            Err(e.raw_os_error().unwrap_or(0) as u32)
        }
    }
}

/// Smart compression that opens the file once and reuses the handle.
/// 
/// This eliminates redundant syscalls by:
/// 1. Opening the file once with permissive sharing (Read|Write|Delete = 7)
/// 2. Checking current compression state using the same handle
/// 3. Compressing using the same handle if needed
/// 
/// # Returns
/// - `Ok(true)` if compression succeeded or file was already optimally compressed
/// - `Ok(false)` if compression was not beneficial (OS driver decision)
/// - `Err(error_code)` on failure
pub fn smart_compress(path: &str, target_algo: WofAlgorithm, force: bool) -> Result<bool, u32> {
    // First attempt: Normal open with permissive sharing
    let file_result = std::fs::OpenOptions::new()
        .read(true)
        .write(true)
        .share_mode(7) // FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE
        .open(path);
    
    match file_result {
        Ok(file) => {
            let handle = file.as_raw_handle() as HANDLE;
            
            // Check current compression state using the SAME handle
            if !force {
                if let Some(current_algo) = get_wof_algorithm_from_handle(handle) {
                    if current_algo == target_algo {
                        // Already compressed with target algorithm, skip
                        return Ok(true);
                    }
                }
            }
            
            // Proceed with compression using the same file handle
            compress_file_handle(&file, target_algo, force)
        }
        Err(e) => {
            // Check if Access Denied and force is enabled
            if force && e.raw_os_error() == Some(ERROR_ACCESS_DENIED as i32) {
                // Try backup semantics path
                smart_compress_with_backup_semantics(path, target_algo, force)
            } else {
                Err(e.raw_os_error().unwrap_or(0) as u32)
            }
        }
    }
}

/// Internal helper for smart_compress with backup semantics
fn smart_compress_with_backup_semantics(path: &str, algo: WofAlgorithm, force: bool) -> Result<bool, u32> {
    // Remove read-only attribute if set
    force_remove_readonly(path);
    
    // Retry normal open after removing readonly
    if let Ok(file) = std::fs::OpenOptions::new()
        .read(true)
        .write(true)
        .share_mode(7)
        .open(path)
    {
        let handle = file.as_raw_handle() as HANDLE;
        
        // Check current compression state
        if !force {
            if let Some(current_algo) = get_wof_algorithm_from_handle(handle) {
                if current_algo == algo {
                    return Ok(true);
                }
            }
        }
        
        return compress_file_handle(&file, algo, force);
    }
    
    // Try direct Win32 API with backup semantics
    unsafe {
        let wide = PathBuffer::from(path);
        let access = 0x80000000 | 0x40000000; // GENERIC_READ | GENERIC_WRITE
        let win_api = crate::engine::dynamic_import::WinApi::get();
        
        let handle = (win_api.CreateFileW.unwrap())(
            wide.as_ptr(),
            access,
            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
            std::ptr::null(),
            OPEN_EXISTING,
            FILE_FLAG_BACKUP_SEMANTICS,
            std::ptr::null_mut(),
        );
        
        if handle == INVALID_HANDLE_VALUE {
            return Err(GetLastError());
        }
        
        // Check current compression state
        if !force {
            if let Some(current_algo) = get_wof_algorithm_from_handle(handle) {
                if current_algo == algo {
                    (win_api.CloseHandle.unwrap())(handle);
                    return Ok(true);
                }
            }
        }
        
        // Convert to File for compress_file_handle
        let file = File::from_raw_handle(handle as *mut _);
        compress_file_handle(&file, algo, force)
        // File is dropped here, closing the handle
    }
}


/// Force remove read-only attribute from a file
fn force_remove_readonly(path: &str) {
    unsafe {
        let wide = PathBuffer::from(path);
        let win_api = crate::engine::dynamic_import::WinApi::get();
        
        let attrs = (win_api.GetFileAttributesW.unwrap())(wide.as_ptr());
        if attrs != u32::MAX { // INVALID_FILE_ATTRIBUTES
            // Remove read-only flag
            let new_attrs = attrs & !FILE_ATTRIBUTE_READONLY;
            let new_attrs = if new_attrs == 0 { FILE_ATTRIBUTE_NORMAL } else { new_attrs };
            (win_api.SetFileAttributesW.unwrap())(wide.as_ptr(), new_attrs);
        }
    }
}

/// Enable backup and restore privileges for the current process.
/// Call this once per thread for optimal performance (reduces syscalls).
pub fn enable_backup_privileges() {
    unsafe {
        let mut token_handle: HANDLE = std::ptr::null_mut(); // Initialize with null_mut
        let win_api = crate::engine::dynamic_import::WinApi::get();
        
        // Using -1 as pseudo handle for current process
        let current_process = -1isize as HANDLE;
        
        if (win_api.OpenProcessToken.unwrap())(
            current_process,
            TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
            &mut token_handle
        ) == 0 {
            return;
        }
        
        let privileges = [
            to_wstring("SeBackupPrivilege"),
            to_wstring("SeRestorePrivilege"),
            to_wstring("SeTakeOwnershipPrivilege"),
            to_wstring("SeSecurityPrivilege"),
        ];
        
        for priv_name in privileges {
            let mut luid = LUID { LowPart: 0, HighPart: 0 };
            if (win_api.LookupPrivilegeValueW.unwrap())(std::ptr::null(), priv_name.as_ptr(), &mut luid as *mut _ as *mut _) != 0 {
                let tp = TOKEN_PRIVILEGES {
                    PrivilegeCount: 1,
                    Privileges: [LUID_AND_ATTRIBUTES {
                        Luid: luid,
                        Attributes: SE_PRIVILEGE_ENABLED,
                    }],
                };
                (win_api.AdjustTokenPrivileges.unwrap())(
                    token_handle,
                    0, // FALSE
                    &tp as *const _ as *const _,
                    0,
                    std::ptr::null_mut(),
                    std::ptr::null_mut(),
                );
            }
        }
        
        (win_api.CloseHandle.unwrap())(token_handle);
    }
}

/// Compress file using CreateFileW with FILE_FLAG_BACKUP_SEMANTICS
fn compress_file_with_backup_semantics(path: &str, algo: WofAlgorithm, force: bool) -> Option<Result<bool, u32>> {
    unsafe {
        let wide = PathBuffer::from(path);
        
        // GENERIC_READ (0x80000000) | GENERIC_WRITE (0x40000000)
        let access = 0x80000000 | 0x40000000;
        
        let handle = (crate::engine::dynamic_import::WinApi::get().CreateFileW.unwrap())(
            wide.as_ptr(),
            access,
            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
            std::ptr::null(),
            OPEN_EXISTING,
            FILE_FLAG_BACKUP_SEMANTICS, // Key: bypass security with backup semantics
            std::ptr::null_mut(),
        );
        
        if handle != INVALID_HANDLE_VALUE {
            // Convert HANDLE to File for compress_file_handle
            let file = File::from_raw_handle(handle as *mut _);
            let result = compress_file_handle(&file, algo, force);
            // File will be dropped here, closing the handle
            Some(result)
        } else {
            None
        }
    }
}

pub fn compress_file_handle(file: &File, algo: WofAlgorithm, force: bool) -> Result<bool, u32> {
    let handle = file.as_raw_handle() as HANDLE;

    // 1. Prepare WOF_EXTERNAL_INFO
    let wof_info = WOF_EXTERNAL_INFO {
        version: WOF_CURRENT_VERSION,
        provider: WOF_PROVIDER_FILE,
    };

    // 2. Prepare FILE_PROVIDER_EXTERNAL_INFO_V1
    let file_info = FILE_PROVIDER_EXTERNAL_INFO_V1 {
        version: FILE_PROVIDER_CURRENT_VERSION,
        algorithm: algo.to_u32(),
        flags: 0,
    };

    // 3. Combine into a single buffer
    // Layout: [WOF_EXTERNAL_INFO] [FILE_PROVIDER_EXTERNAL_INFO_V1]
    let mut input_buffer = Vec::with_capacity(size_of::<WOF_EXTERNAL_INFO>() + size_of::<FILE_PROVIDER_EXTERNAL_INFO_V1>());
    
    // Safety: Simple POD structs
    unsafe {
        let wof_ptr = &wof_info as *const _ as *const u8;
        let wof_slice = std::slice::from_raw_parts(wof_ptr, size_of::<WOF_EXTERNAL_INFO>());
        input_buffer.extend_from_slice(wof_slice);

        let file_ptr = &file_info as *const _ as *const u8;
        let file_slice = std::slice::from_raw_parts(file_ptr, size_of::<FILE_PROVIDER_EXTERNAL_INFO_V1>());
        input_buffer.extend_from_slice(file_slice);
    }

    let mut bytes_returned = 0u32;
    
    unsafe {
        let win_api = crate::engine::dynamic_import::WinApi::get();
        let result = (win_api.DeviceIoControl.unwrap())(
            handle,
            FSCTL_SET_EXTERNAL_BACKING,
            input_buffer.as_ptr() as *const c_void,
            input_buffer.len() as u32,
            std::ptr::null_mut(),
            0,
            &mut bytes_returned,
            std::ptr::null_mut(),
        );

        if result == 0 {
             let err = GetLastError();
             // Handle specific errors that aren't fatal "failures" but just "Can't compress this"
             // ERROR_COMPRESSION_NOT_BENEFICIAL (344)
             if err == 344 { 
                 if force {
                     // Fallback to NTFS Compression (LZNT1)
                     let compression_state: u16 = COMPRESSION_FORMAT_DEFAULT;
                     let _ = (crate::engine::dynamic_import::WinApi::get().DeviceIoControl.unwrap())(
                        handle,
                        FSCTL_SET_COMPRESSION,
                        &compression_state as *const _ as *const c_void,
                        std::mem::size_of::<u16>() as u32,
                        std::ptr::null_mut(),
                        0,
                        &mut bytes_returned,
                        std::ptr::null_mut(),
                    );
                    // We assume if this succeeds/fails, we did our best.
                    return Ok(true);
                 }
                 return Ok(false);
             }
             return Err(err);
        }
    }

    Ok(true)
}


pub fn uncompress_file(path: &str) -> Result<(), u32> {
    // Requires Write permission for FSCTL_DELETE_EXTERNAL_BACKING
    // Use permissive sharing (Read|Write|Delete = 7) to allow processing locked files
    let file = std::fs::OpenOptions::new()
        .read(true)
        .write(true)
        .share_mode(7)
        .open(path)
        .map_err(|e| e.raw_os_error().unwrap_or(0) as u32)?;  
    uncompress_file_handle(&file)
}

pub fn uncompress_file_handle(file: &File) -> Result<(), u32> {
    let handle = file.as_raw_handle() as HANDLE;
    let mut bytes_returned = 0u32;

    unsafe {
        let win_api = crate::engine::dynamic_import::WinApi::get();
        if (win_api.DeviceIoControl.unwrap())(
            handle,
            FSCTL_DELETE_EXTERNAL_BACKING,
            std::ptr::null(),
            0,
            std::ptr::null_mut(),
            0,
            &mut bytes_returned,
            std::ptr::null_mut(),
        ) == 0 {
            let err = GetLastError();
             // ERROR_INVALID_FUNCTION (1) or ERROR_NOT_SUPPORTED (50) might happen if not compressed
             if err == 346 { // ERROR_NOT_CAPABLE? Or some specific WOF error? 
                // Don't return yet, try NTFS decompression too!
            } else {
                 // We might want to just proceed to NTFS decompression anyway
            }
        }
        
        // ALSO try to remove NTFS compression (Blue files)
        // FSCTL_SET_COMPRESSION(COMPRESSION_FORMAT_NONE)
        let compression_state: u16 = COMPRESSION_FORMAT_NONE; 
        
        let _ = (win_api.DeviceIoControl.unwrap())(
            handle,
            FSCTL_SET_COMPRESSION,
            &compression_state as *const _ as *const c_void,
            std::mem::size_of::<u16>() as u32,
            std::ptr::null_mut(),
            0,
            &mut bytes_returned,
            std::ptr::null_mut(),
        );
    }
    Ok(())
}