XADMaster/XADPlatformWindows.m
2018-03-21 14:24:50 +02:00

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