50 lines
2.3 KiB
Dart
50 lines
2.3 KiB
Dart
import 'dart:ffi';
|
|
import 'dart:io';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:ffi/ffi.dart';
|
|
import 'package:path/path.dart' as p;
|
|
|
|
import '../l10n/tr.dart';
|
|
|
|
/// X-plore P3 보충 (관리자 지시 10/18): 파일 · 폴더의 숨김 · 읽기 전용 · 시스템 속성과 만든 때 - 보기만 (바꾸지 않음).
|
|
/// Windows 는 GetFileAttributesExW (kernel32), 그 밖 (Android) 은 이름이 점으로 시작하면 숨김 · 만든 때는 모름.
|
|
class FileAttributes {
|
|
final bool hidden;
|
|
final bool readOnly;
|
|
final bool system;
|
|
|
|
/// 만든 때 (모르면 null)
|
|
final DateTime? created;
|
|
const FileAttributes({this.hidden = false, this.readOnly = false, this.system = false, this.created});
|
|
|
|
/// 화면에 보일 속성 이름들 (없으면 빈 목록)
|
|
List<String> get labels => [if (hidden) tr('숨김'), if (readOnly) tr('읽기 전용'), if (system) tr('시스템')];
|
|
}
|
|
|
|
typedef _GetAttrsExC = Int32 Function(Pointer<Utf16> name, Int32 level, Pointer<Uint8> info);
|
|
typedef _GetAttrsExD = int Function(Pointer<Utf16> name, int level, Pointer<Uint8> info);
|
|
|
|
/// [path] 의 속성 (읽지 못하면 null). 로컬 경로만 (원격은 부르지 않는다)
|
|
FileAttributes? readFileAttributes(String path) {
|
|
if (!Platform.isWindows) return FileAttributes(hidden: p.basename(path).startsWith('.'));
|
|
final name = path.toNativeUtf16();
|
|
// WIN32_FILE_ATTRIBUTE_DATA: DWORD 속성 · FILETIME 만든 · 열어 본 · 바뀐 때 · DWORD 크기 (위 · 아래) = 36 바이트
|
|
final info = calloc<Uint8>(36);
|
|
try {
|
|
final f = DynamicLibrary.open('kernel32.dll').lookupFunction<_GetAttrsExC, _GetAttrsExD>('GetFileAttributesExW');
|
|
if (f(name, 0 /* GetFileExInfoStandard */, info) == 0) return null;
|
|
final b = ByteData.sublistView(info.asTypedList(36));
|
|
final attrs = b.getUint32(0, Endian.little);
|
|
final ft = b.getUint32(4, Endian.little) | (b.getUint32(8, Endian.little) << 32);
|
|
// FILETIME: 1601-01-01 부터 100ns 단위
|
|
final created = ft == 0 ? null : DateTime.fromMicrosecondsSinceEpoch(ft ~/ 10 - 11644473600000000, isUtc: true).toLocal();
|
|
return FileAttributes(hidden: attrs & 0x2 != 0, readOnly: attrs & 0x1 != 0, system: attrs & 0x4 != 0, created: created);
|
|
} catch (_) {
|
|
return null;
|
|
} finally {
|
|
calloc.free(name);
|
|
calloc.free(info);
|
|
}
|
|
}
|