mirror of
https://github.com/MacPaw/XADMaster.git
synced 2025-08-28 19:13:49 +02:00
295 lines
7.8 KiB
Objective-C
295 lines
7.8 KiB
Objective-C
/*
|
|
* XADPlatformWindows.m
|
|
*
|
|
* Copyright (c) 2017-present, MacPaw Inc. All rights reserved.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
* MA 02110-1301 USA
|
|
*/
|
|
#import "XADPlatform.h"
|
|
#import "NSDateXAD.h"
|
|
|
|
#import <windows.h>
|
|
#import <sys/stat.h>
|
|
|
|
|
|
|
|
|
|
// TODO: Implement proper handling of Windows metadata.
|
|
|
|
@implementation XADPlatform
|
|
|
|
//
|
|
// Archive entry extraction.
|
|
//
|
|
|
|
+(XADError)extractResourceForkEntryWithDictionary:(NSDictionary *)dict
|
|
unarchiver:(XADUnarchiver *)unarchiver toPath:(NSString *)destpath
|
|
{
|
|
return XADNotSupportedError;
|
|
}
|
|
|
|
+(XADError)updateFileAttributesAtPath:(NSString *)path
|
|
forEntryWithDictionary:(NSDictionary *)dict parser:(XADArchiveParser *)parser
|
|
preservePermissions:(BOOL)preservepermissions
|
|
{
|
|
#if defined(__COCOTRON__)
|
|
const wchar_t *wpath=[path fileSystemRepresentationW];
|
|
#else
|
|
const wchar_t *wpath=(const wchar_t *)[path fileSystemRepresentation];
|
|
#endif
|
|
|
|
// If the file is read-only, change this temporarily and remember to change back.
|
|
BOOL changedattributes=NO;
|
|
DWORD oldattributes=GetFileAttributesW(wpath);
|
|
if(oldattributes!=INVALID_FILE_ATTRIBUTES&&(oldattributes&FILE_ATTRIBUTE_READONLY))
|
|
{
|
|
SetFileAttributesW(wpath,oldattributes&~INVALID_FILE_ATTRIBUTES);
|
|
changedattributes=YES;
|
|
}
|
|
|
|
NSDate *modification=[dict objectForKey:XADLastModificationDateKey];
|
|
NSDate *creation=[dict objectForKey:XADCreationDateKey];
|
|
NSDate *access=[dict objectForKey:XADLastAccessDateKey];
|
|
|
|
if(modification||creation||access)
|
|
{
|
|
HANDLE handle=CreateFileW(wpath,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
|
|
if(handle==INVALID_HANDLE_VALUE) return XADUnknownError; // TODO: better error
|
|
|
|
FILETIME creationtime,lastaccesstime,lastwritetime;
|
|
|
|
if(creation) creationtime=[creation FILETIME];
|
|
if(access) lastaccesstime=[access FILETIME];
|
|
if(modification) lastwritetime=[modification FILETIME];
|
|
|
|
if(!SetFileTime(handle,
|
|
creation?&creationtime:NULL,
|
|
access?&lastaccesstime:NULL,
|
|
modification?&lastwritetime:NULL))
|
|
{
|
|
CloseHandle(handle);
|
|
return XADUnknownError; // TODO: better error
|
|
}
|
|
|
|
CloseHandle(handle);
|
|
}
|
|
|
|
NSNumber *attributes=[dict objectForKey:XADWindowsFileAttributesKey];
|
|
if(!attributes) attributes=[dict objectForKey:XADDOSFileAttributesKey];
|
|
if(attributes||changedattributes)
|
|
{
|
|
DWORD newattributes=oldattributes;
|
|
if(attributes) newattributes=[attributes intValue];
|
|
SetFileAttributesW(wpath,newattributes);
|
|
}
|
|
|
|
return XADNoError;
|
|
}
|
|
|
|
+(XADError)createLinkAtPath:(NSString *)path withDestinationPath:(NSString *)link
|
|
{
|
|
return XADNotSupportedError;
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Archive post-processing.
|
|
//
|
|
|
|
+(id)readCloneableMetadataFromPath:(NSString *)path { return nil; }
|
|
+(void)writeCloneableMetadata:(id)metadata toPath:(NSString *)path {}
|
|
|
|
+(BOOL)copyDateFromPath:(NSString *)src toPath:(NSString *)dest
|
|
{
|
|
#if defined(__COCOTRON__)
|
|
const wchar_t *wsrc=[src fileSystemRepresentationW];
|
|
#else
|
|
const wchar_t *wsrc=(const wchar_t *)[src fileSystemRepresentation];
|
|
#endif
|
|
|
|
HANDLE srchandle=CreateFileW(wsrc,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
|
|
if(srchandle==INVALID_HANDLE_VALUE) return NO;
|
|
|
|
FILETIME time;
|
|
if(!GetFileTime(srchandle,NULL,NULL,&time)) { CloseHandle(srchandle); return NO; }
|
|
|
|
CloseHandle(srchandle);
|
|
|
|
#if defined(__COCOTRON__)
|
|
const wchar_t *wdest=[dest fileSystemRepresentationW];
|
|
#else
|
|
const wchar_t *wdest=(const wchar_t *)[dest fileSystemRepresentation];
|
|
#endif
|
|
|
|
HANDLE desthandle=CreateFileW(wdest,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
|
|
if(desthandle==INVALID_HANDLE_VALUE) return NO;
|
|
|
|
if(!SetFileTime(desthandle,NULL,NULL,&time)) { CloseHandle(desthandle); return NO; }
|
|
|
|
CloseHandle(desthandle);
|
|
|
|
return YES;
|
|
}
|
|
|
|
+(BOOL)resetDateAtPath:(NSString *)path
|
|
{
|
|
SYSTEMTIME now;
|
|
GetSystemTime(&now);
|
|
|
|
FILETIME time;
|
|
if(!SystemTimeToFileTime(&now,&time)) return NO;
|
|
|
|
#if defined(__COCOTRON__)
|
|
const wchar_t *wpath=[path fileSystemRepresentationW];
|
|
#else
|
|
const wchar_t *wpath=(const wchar_t *)[path fileSystemRepresentation];
|
|
#endif
|
|
|
|
HANDLE handle=CreateFileW(wpath,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
|
|
if(handle==INVALID_HANDLE_VALUE) return NO;
|
|
|
|
if(!SetFileTime(handle,NULL,NULL,&time)) { CloseHandle(handle); return NO; }
|
|
|
|
CloseHandle(handle);
|
|
|
|
return YES;
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Path functions.
|
|
//
|
|
|
|
+(BOOL)fileExistsAtPath:(NSString *)path { return [self fileExistsAtPath:path isDirectory:NULL]; }
|
|
|
|
+(BOOL)fileExistsAtPath:(NSString *)path isDirectory:(BOOL *)isdirptr
|
|
{
|
|
#if defined(__COCOTRON__)
|
|
const wchar_t *wpath=[path fileSystemRepresentationW];
|
|
#else
|
|
const wchar_t *wpath=(const wchar_t *)[path fileSystemRepresentation];
|
|
#endif
|
|
|
|
struct _stat st;
|
|
if(_wstat(wpath,&st)!=0) return NO;
|
|
|
|
if(isdirptr)
|
|
{
|
|
if((st.st_mode&S_IFMT)==S_IFDIR) *isdirptr=YES;
|
|
else *isdirptr=NO;
|
|
}
|
|
|
|
return YES;
|
|
}
|
|
|
|
+(NSString *)uniqueDirectoryPathWithParentDirectory:(NSString *)parent
|
|
{
|
|
NSDate *now=[NSDate date];
|
|
int64_t t=[now timeIntervalSinceReferenceDate]*1000000000;
|
|
|
|
NSString *dirname=[NSString stringWithFormat:@"XADTemp%qd",t];
|
|
|
|
if(parent) return [parent stringByAppendingPathComponent:dirname];
|
|
else return dirname;
|
|
}
|
|
|
|
+(NSString *)sanitizedPathComponent:(NSString *)component
|
|
{
|
|
static NSCharacterSet *charset=nil;
|
|
if(!charset) charset=[[NSCharacterSet characterSetWithCharactersInString:
|
|
@"\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
|
|
@"\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
|
|
@"\"*:<>?\\/|\000"] retain];
|
|
|
|
static XADRegex *regex1=nil;
|
|
if(!regex1) regex1=[[XADRegex regexWithPattern:
|
|
@"^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$" options:REG_ICASE] retain];
|
|
|
|
static XADRegex *regex2=nil;
|
|
if(!regex2) regex2=[[XADRegex regexWithPattern:
|
|
@"^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(\\..*)$" options:REG_ICASE] retain];
|
|
|
|
if([component rangeOfCharacterFromSet:charset].location!=NSNotFound)
|
|
{
|
|
NSMutableString *newstring=[NSMutableString stringWithString:component];
|
|
int length=[newstring length];
|
|
for(int i=0;i<length;i++)
|
|
{
|
|
unichar c=[newstring characterAtIndex:i];
|
|
if([charset characterIsMember:c])
|
|
[newstring replaceCharactersInRange:NSMakeRange(i,1) withString:@"_"];
|
|
}
|
|
component=newstring;
|
|
}
|
|
|
|
if([regex1 matchesString:component])
|
|
{
|
|
return [component stringByAppendingString:@"_"];
|
|
}
|
|
|
|
if([regex2 matchesString:component])
|
|
{
|
|
NSArray *matches=[regex2 capturedSubstringsOfString:component];
|
|
return [NSString stringWithFormat:@"%@_%@",
|
|
[matches objectAtIndex:1],[matches objectAtIndex:2]];
|
|
}
|
|
|
|
return component;
|
|
}
|
|
|
|
+(NSArray *)contentsOfDirectoryAtPath:(NSString *)path
|
|
{
|
|
return [[NSFileManager defaultManager] directoryContentsAtPath:path];
|
|
}
|
|
|
|
+(BOOL)moveItemAtPath:(NSString *)src toPath:(NSString *)dest
|
|
{
|
|
return [[NSFileManager defaultManager] movePath:src toPath:dest handler:nil];
|
|
}
|
|
|
|
+(BOOL)removeItemAtPath:(NSString *)path
|
|
{
|
|
return [[NSFileManager defaultManager] removeFileAtPath:path handler:nil];
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Resource forks
|
|
//
|
|
|
|
+(CSHandle *)handleForReadingResourceForkAtPath:(NSString *)path { return nil; }
|
|
|
|
|
|
|
|
//
|
|
// Time functions.
|
|
//
|
|
|
|
+(double)currentTimeInSeconds
|
|
{
|
|
return (double)timeGetTime()/1000.0;
|
|
}
|
|
|
|
@end
|