Example #1
0
IO_METHOD(IoDirectory, createSubdirectory)
{
    /*doc Directory createSubdirectory(name)
    Create a subdirectory with the specified name.
    */

    IoState *state = IOSTATE;
    IoSymbol *subfolderName = IoMessage_locals_symbolArgAt_(m, locals, 0);
    IoObject *currentItem = IoDirectory_justAt(self, subfolderName);

    if (ISDIRECTORY(currentItem))
    {
        return currentItem;
    }

    if (ISFILE(currentItem))
    {
        IoState_error_(IOSTATE, m, "Attempt to create directory %s on top of existing file",
                       CSTRING(subfolderName));
    }
    else
    {
        IoSymbol *fullPath = IoDirectory_justFullPath(self, subfolderName);

        MKDIR(CSTRING(fullPath), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
        return IoDirectory_newWithPath_(state, fullPath);
    }

    return IONIL(self);
}
Example #2
0
File: IoFile.c Project: achoy/io
IO_METHOD(IoFile, reopen)
{
	/*doc File reopen(otherFile, mode)
	Reopens otherFile and redirects its stream to this file's path using mode.
	If mode is omitted, it is copied from otherFile.
	Returns self or raises a File exception on error.
	*/

	IoFile *otherFile;
	IoSeq *mode;

	DATA(self)->flags = IOFILE_FLAGS_NONE;

	IoMessage_assertArgCount_receiver_(m, 1, self);
	
	otherFile = IoMessage_locals_valueArgAt_(m, locals, 0);
	IOASSERT(ISFILE(otherFile), "arg must be a File");
	
	mode = IoMessage_locals_valueArgAt_(m, locals, 1);
	if(ISSEQ(mode))
	{
		DATA(self)->mode = IOREF(mode);
	}
	else
	{
		DATA(self)->mode = IOREF(IoSeq_newWithUArray_copy_(IOSTATE, (UArray *)DATA(DATA(otherFile)->mode), 1));
	}

	if (!DATA(self)->stream)
	{
		FILE *fp = freopen(UTF8CSTRING(DATA(self)->path), CSTRING(DATA(self)->mode), DATA(otherFile)->stream);

		if (fp)
		{
			DATA(self)->stream = fp;
		}
		else
		{
			printf("%i:%s\n", errno, strerror(errno));
			IoState_error_(IOSTATE, m, "unable to reopen to file '%s' with mode %s.", UTF8CSTRING(DATA(self)->path), CSTRING(DATA(self)->mode));
			fclose(fp);
		}
	}

	return self;
}
Example #3
0
// ----------------------------------------------------------------------
// Get file snap shot
// ----------------------------------------------------------------------
VOID GetFilesSnap(LPSNAPSHOT lpShot, LPTSTR lpszFullName, LPFILECONTENT lpFatherFC, LPFILECONTENT *lplpCaller) 
{
	LPFILECONTENT lpFC;
	HANDLE hFile;
	BOOL calculateHash = TRUE;
	BOOL found = FALSE;

	// Full dir/file name is already given
	// Extra local block to reduce stack usage due to recursive calls
	{
		LPTSTR lpszFindFileName;
		lpszFindFileName = NULL;
		// Get father file data if not already provided (=called from FileShot)
		// lpFatherFC only equals "C:\" and is called once at start
		if (NULL == lpFatherFC) 
		{
			// Check if file is to be GENERIC excluded
			if ((NULL == lpszFullName)
				|| (((TCHAR)'.' == lpszFullName[0])  // fast exclusion for 99% of the cases
				&& ((0 == _tcscmp(lpszFullName, TEXT(".")))
				|| (0 == _tcscmp(lpszFullName, TEXT("..")))))) {
				return;
			}
			// Create new file content
			lpFatherFC = MYALLOC0(sizeof(FILECONTENT));

			// Set file name length
			lpFatherFC->cchFileName = _tcslen(lpszFullName);
			// Copy file name to new buffer for directory search and more
			lpszFindFileName = MYALLOC((lpFatherFC->cchFileName + 4 + 1) * sizeof(TCHAR));  // +4 for "\*.*" search when directory (later in routine)
			_tcscpy(lpszFindFileName, lpszFullName);
			// Special case if root dir of a drive was specified, needs trailing backslash otherwise current dir of that drive is used
			if ((TCHAR)':' == lpszFindFileName[lpFatherFC->cchFileName - 1]) {
				lpszFindFileName[lpFatherFC->cchFileName] = (TCHAR)'\\';
				lpszFindFileName[lpFatherFC->cchFileName + 1] = (TCHAR)'\0';
			}
			//printf("lpszFullName: %ws\n", lpszFullName);
			//printf("lpszFindFileName: %ws\n", lpszFindFileName);

			hFile = FindFirstFile(lpszFullName, &FindData);
			if (INVALID_HANDLE_VALUE != hFile) {
				FindClose(hFile);
			}
			else {
				// Workaround for some cases in Windows Vista and later
				ZeroMemory(&FindData, sizeof(FindData));
				
				hFile = CreateFile(lpszFullName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
				if (INVALID_HANDLE_VALUE != hFile) {
					BY_HANDLE_FILE_INFORMATION FileInformation;
					BOOL bResult;

					bResult = GetFileInformationByHandle(hFile, &FileInformation);
					if (bResult) {
						FindData.dwFileAttributes = FileInformation.dwFileAttributes;
						FindData.ftCreationTime = FileInformation.ftCreationTime;
						FindData.ftLastAccessTime = FileInformation.ftLastAccessTime;
						FindData.ftLastWriteTime = FileInformation.ftLastWriteTime;
						FindData.nFileSizeHigh = FileInformation.nFileSizeHigh;
						FindData.nFileSizeLow = FileInformation.nFileSizeLow;
					}
					else {
						FindData.dwFileAttributes = GetFileAttributes(lpszFullName);
						if (INVALID_FILE_ATTRIBUTES == FindData.dwFileAttributes) {
							FindData.dwFileAttributes = 0;
						}
						bResult = GetFileTime(hFile, &FindData.ftCreationTime, &FindData.ftLastAccessTime, &FindData.ftLastWriteTime);
						if (!bResult) {
							FindData.ftCreationTime.dwLowDateTime = 0;
							FindData.ftCreationTime.dwHighDateTime = 0;
							FindData.ftLastAccessTime.dwLowDateTime = 0;
							FindData.ftLastAccessTime.dwHighDateTime = 0;
							FindData.ftLastWriteTime.dwLowDateTime = 0;
							FindData.ftLastWriteTime.dwHighDateTime = 0;
						}
						FindData.nFileSizeLow = GetFileSize(hFile, &FindData.nFileSizeHigh);
						if (INVALID_FILE_SIZE == FindData.nFileSizeLow) {
							FindData.nFileSizeHigh = 0;
							FindData.nFileSizeLow = 0;
						}
					}
					CloseHandle(hFile);
				}
			}

			// Remove previously added backslash (if any)
			lpszFindFileName[lpFatherFC->cchFileName] = (TCHAR)'\0';

			// Copy pointer to current file into caller's pointer
			if (NULL != lplpCaller) {
				*lplpCaller = lpFatherFC;
			}
			          
			// Increase dir/file count
			if (ISFILE(FindData.dwFileAttributes)) {
				lpShot->stCounts.cFiles++;
			}
			else {
				lpShot->stCounts.cDirs++;
			}

			// Copy file name
			lpFatherFC->lpszFileName = MYALLOC((lpFatherFC->cchFileName + 1) * sizeof(TCHAR));
			_tcscpy(lpFatherFC->lpszFileName, lpszFullName);

			// Copy file data
			lpFatherFC->nWriteDateTimeLow = FindData.ftLastWriteTime.dwLowDateTime;
			lpFatherFC->nWriteDateTimeHigh = FindData.ftLastWriteTime.dwHighDateTime;
			lpFatherFC->nAccessDateTimeLow = FindData.ftLastWriteTime.dwLowDateTime;
			lpFatherFC->nAccessDateTimeHigh = FindData.ftLastWriteTime.dwHighDateTime;
			lpFatherFC->nFileSizeLow = FindData.nFileSizeLow;
			lpFatherFC->nFileSizeHigh = FindData.nFileSizeHigh;
			lpFatherFC->nFileAttributes = FindData.dwFileAttributes;

			// Set "lpFirstSubFC" pointer for storing the first child's pointer
			lplpCaller = &lpFatherFC->lpFirstSubFC;
		}

		// If father is a file, then leave (=special case when called from FileShot)
		if (ISFILE(lpFatherFC->nFileAttributes)) {
			if (NULL != lpszFindFileName) {
				MYFREE(lpszFindFileName);
			}
			return;
		}

		// Process all entries of directory
		// a) Create search pattern and start search
		if (NULL == lpszFindFileName) {
			lpszFindFileName = lpszFullName;
		}
		_tcscat(lpszFindFileName, TEXT("\\*.*"));
		hFile = FindFirstFile(lpszFindFileName, &FindData);
		if (lpszFindFileName != lpszFullName) {
			MYFREE(lpszFindFileName);
		}
	}  // End of extra local block
	if (INVALID_HANDLE_VALUE == hFile) {  
		// error: nothing in dir, no access, etc.
		//printf(">>> ERROR: fileshot.c: getFileSnap: INVALID_HANDLE_VALUE: %ws\n", lpszFullName);
		return;
	}
	// b) process entry then find next
	do {
		lpszFullName = NULL;
		//BOOL calculateHash = TRUE;
		//BOOL found = FALSE;

		// Check if file is to be GENERIC excluded (dot dirs)
		if ((NULL == FindData.cFileName)
			|| (((TCHAR)'.' == FindData.cFileName[0])  // fast exclusion for 99% of the cases
			&& ((0 == _tcscmp(FindData.cFileName, TEXT(".")))
			|| (0 == _tcscmp(FindData.cFileName, TEXT("..")))))) {
			continue;  // ignore this entry and continue with next file
		}

		// Create new file content
		lpFC = MYALLOC0(sizeof(FILECONTENT));
		// Set father of current key
		lpFC->lpFatherFC = lpFatherFC;
		// Set file name length
		lpFC->cchFileName = _tcslen(FindData.cFileName);

		// Allocate memory copy file name to FILECONTENT
		lpFC->lpszFileName = MYALLOC0((lpFC->cchFileName + 1) * sizeof(TCHAR));
		_tcscpy(lpFC->lpszFileName, FindData.cFileName);

		// Static blacklist for directories
		if (ISDIR(FindData.dwFileAttributes))
		{
			if (performStaticBlacklisting)
			{
				LPTSTR lpszFullPath;
				lpszFullPath = GetWholeFileName(lpFC, 4);

				found = TrieSearchPath(blacklistDIRS->children, lpszFullPath);
				if (found)
				{
					lpShot->stCounts.cFilesBlacklist++;
					MYFREE(lpszFullPath);
					FreeAllFileContents(lpFC);

					// Increase value count for display purposes
					lpShot->stCounts.cDirsBlacklist++;
					
					// Ignore this entry and continue with next brother value
					continue;  
				}
				else
				{
					MYFREE(lpszFullPath);
				}
			}
		}

		// Check if the file system entry is a symbolic link
		// If so, skip as it actually resides somewhere else on the file system!
		if (ISSYM(FindData.dwFileAttributes)) {
			if (ISFILE(FindData.dwFileAttributes)) {
				lpShot->stCounts.cFilesBlacklist++;
			}
			else {
				lpShot->stCounts.cDirsBlacklist++;
			}
			continue;
		}

		// Blacklisting implementation for files		
		if (ISFILE(FindData.dwFileAttributes))
		{
			if (dwBlacklist == 1)
			{
				// First snapshot, therefore populate the Trie (Prefix Tree)
				// Get the full file path
				LPTSTR lpszFullPath;
				lpszFullPath = GetWholeFileName(lpFC, 4);

				// Add full path to file blacklist prefix tree, then free path
				TrieAdd(&blacklistFILES, lpszFullPath);
				MYFREE(lpszFullPath);

				// Increase value count for display purposes
				lpShot->stCounts.cFiles++;

				// Ignore this entry and continue with next brother value
				//continue;  
			}
			else if (dwBlacklist == 2)
			{
				// Not the first snapshot, so either:
				// 1) If blacklisting enabled: Ignore file if its in the blacklist
				// 2) If hashing enabled (and not blacklisting): Mark file as not to be hashed
				LPTSTR lpszFullPath;
				lpszFullPath = GetWholeFileName(lpFC, 4);
				found = TrieSearchPath(blacklistFILES->children, lpszFullPath);
				if (found)
				{
					if (performDynamicBlacklisting)
					{
						MYFREE(lpszFullPath);
						FreeAllFileContents(lpFC);

						// Increase value count for display purposes
						lpShot->stCounts.cFilesBlacklist++;

						// Ignore this entry and continue with next brother value
						continue;  
					}
					if (performSHA1Hashing || performMD5Hashing)
					{
						lpShot->stCounts.cFiles++;
						MYFREE(lpszFullPath);
						calculateHash = FALSE;
					}
				}
				else
				{
					MYFREE(lpszFullPath);
				}
			}
		}
					
		// Copy pointer to current file into caller's pointer
		if (NULL != lplpCaller) {
			*lplpCaller = lpFC;
		}

		// Increase dir/file count
		if (ISFILE(FindData.dwFileAttributes)) {
			lpShot->stCounts.cFiles++;
		}
		else {
			lpShot->stCounts.cDirs++;
		}

		// Copy file data
		lpFC->nWriteDateTimeLow = FindData.ftLastWriteTime.dwLowDateTime;
		lpFC->nWriteDateTimeHigh = FindData.ftLastWriteTime.dwHighDateTime;
		lpFC->nAccessDateTimeLow = FindData.ftLastWriteTime.dwLowDateTime;
		lpFC->nAccessDateTimeHigh = FindData.ftLastWriteTime.dwHighDateTime;
		lpFC->nFileSizeLow = FindData.nFileSizeLow;
		lpFC->nFileSizeHigh = FindData.nFileSizeHigh;
		lpFC->nFileAttributes = FindData.dwFileAttributes;

		// Calculate file hash (computationally intensive!)
		// This should only be executed in the following scenarios:
		// 1) If the file system entry is a data file 
		// 2) If the data file is not blacklisted (previously known)
		if (ISFILE(FindData.dwFileAttributes))
		{
			if (dwBlacklist == 2 && calculateHash) {
			    if (performSHA1Hashing)
			    {
				    lpFC->cchSHA1 = 40;
				    lpFC->lpszSHA1 = MYALLOC((lpFC->cchSHA1 + 1) * sizeof(TCHAR));
				    _tcscpy(lpFC->lpszSHA1, CalculateSHA1(GetWholeFileName(lpFC, 4)));
                }
                if (performMD5Hashing)
                {
				    lpFC->cchMD5 = 32;
				    lpFC->lpszMD5 = MYALLOC((lpFC->cchMD5 + 1) * sizeof(TCHAR));
				    _tcscpy(lpFC->lpszMD5, CalculateMD5(GetWholeFileName(lpFC, 4)));
				}
				if (performMD5BlockHashing)
				{
					LPMD5BLOCK theMD5Block = CalculateMD5Blocks(GetWholeFileName(lpFC, 4), dwHashBlockSize);
					lpFC->lpMD5Block = MYALLOC0(sizeof(MD5BLOCK));
					lpFC->lpMD5Block = theMD5Block;
				}
			}
		}

		// Print file system shot status
		if ((dwBlacklist == 2 && performDynamicBlacklisting) || (performStaticBlacklisting)) {
			printf("  > Dirs: %d  Files: %d  Blacklisted Dirs: %d  Blacklisted Files: %d\r", lpShot->stCounts.cDirs, 
				lpShot->stCounts.cFiles,
				lpShot->stCounts.cDirsBlacklist,
				lpShot->stCounts.cFilesBlacklist);
		}
		else {
			printf("  > Dirs: %d  Files: %d\r", lpShot->stCounts.cDirs, lpShot->stCounts.cFiles);
		}

		// ATTENTION!!! FindData will be INVALID from this point on, due to recursive calls
		// If the entry is a directory, then do a recursive call for it
		// Pass this entry as father and "lpFirstSubFC" pointer for storing the first child's pointer
		if (ISDIR(lpFC->nFileAttributes)) {
			if (NULL == lpszFullName) {
				lpszFullName = GetWholeFileName(lpFC, 4);  // +4 for "\*.*" search (in recursive call)
			}
			GetFilesSnap(lpShot, lpszFullName, lpFC, &lpFC->lpFirstSubFC);
		}

		if (NULL != lpszFullName) {
			MYFREE(lpszFullName);
		}

		// Set "lpBrotherFC" pointer for storing the next brother's pointer
		lplpCaller = &lpFC->lpBrotherFC;
	} while (FindNextFile(hFile, &FindData));
	FindClose(hFile);
}
Example #4
0
//-------------------------------------------------------------
// File comparison engine
//-------------------------------------------------------------
VOID CompareFiles(LPFILECONTENT lpStartFC1, LPFILECONTENT lpStartFC2)
{
	LPFILECONTENT lpFC1;
	LPFILECONTENT lpFC2;

	// Compare dirs/files
	for (lpFC1 = lpStartFC1; NULL != lpFC1; lpFC1 = lpFC1->lpBrotherFC) {
		if (ISFILE(lpFC1->nFileAttributes)) {
			CompareResult.stcCompared.cFiles++;
		}
		else {
			CompareResult.stcCompared.cDirs++;
		}

		// Find a matching dir/file for FC1
		for (lpFC2 = lpStartFC2; NULL != lpFC2; lpFC2 = lpFC2->lpBrotherFC) {
			// skip FC2 if already matched
			if (NOMATCH != lpFC2->fFileMatch) {
				continue;
			}

			// skip FC2 if types do *not* match (even if same name then interpret as deleted+added)
			if (ISFILE(lpFC1->nFileAttributes) != ISFILE(lpFC2->nFileAttributes)) {
				continue;
			}

			// skip FC2 if names do *not* match
			if ((NULL == lpFC1->lpszFileName) || (NULL == lpFC2->lpszFileName) || (0 != _tcsicmp(lpFC1->lpszFileName, lpFC2->lpszFileName))) { // 1.8.2 from lstrcmp to strcmp  // 1.9.0 to _tcsicmp
				continue;
			}

			// Same file type and (case-insensitive) name of FC1 found in FC2, so compare their attributes and if applicable their dates and sizes
			if (ISFILE(lpFC1->nFileAttributes)) 
			{
				// Both are files
				if ((lpFC1->nWriteDateTimeLow == lpFC2->nWriteDateTimeLow)
					&& (lpFC1->nWriteDateTimeHigh == lpFC2->nWriteDateTimeHigh)
					&& (lpFC1->nFileSizeLow == lpFC2->nFileSizeLow)
					&& (lpFC1->nFileSizeHigh == lpFC2->nFileSizeHigh)
					&& (lpFC1->nFileAttributes == lpFC2->nFileAttributes)) 
				{
					// Same file of FC1 found in FC2
					lpFC2->fFileMatch = ISMATCH;
				}
				else 
				{
					// File data differ, so file is modified
					lpFC2->fFileMatch = ISMODI;
					CompareResult.stcChanged.cFiles++;
					CompareResult.stcModified.cFiles++;
					CreateNewResult(FILEMODI, lpFC1, lpFC2);
				}
			}
			else
			{
				// Both are dirs
				if (lpFC1->nFileAttributes == lpFC2->nFileAttributes) {
					// Same dir of FC1 found in FC2
					lpFC2->fFileMatch = ISMATCH;
				}
				else 
				{
					// Dir data differ, so dir is modified
					lpFC2->fFileMatch = ISMODI;
					CompareResult.stcChanged.cDirs++;
					CompareResult.stcModified.cDirs++;
					CreateNewResult(DIRMODI, lpFC1, lpFC2);
				}
				// Compare sub files if any
				if ((NULL != lpFC1->lpFirstSubFC) || (NULL != lpFC2->lpFirstSubFC)) {
					CompareFiles(lpFC1->lpFirstSubFC, lpFC2->lpFirstSubFC);
				}
			}

			break;
		}
		if (NULL == lpFC2) 
		{
			// FC1 has no matching FC2, so FC1 is a deleted dir/file
			if (ISFILE(lpFC1->nFileAttributes)) 
			{
				CompareResult.stcChanged.cFiles++;
				CompareResult.stcDeleted.cFiles++;
				CreateNewResult(FILEDEL, lpFC1, NULL);
			}
			else 
			{
				CompareResult.stcChanged.cDirs++;
				CompareResult.stcDeleted.cDirs++;
				CreateNewResult(DIRDEL, lpFC1, NULL);

				// "Compare"/Log sub files if any
				if (NULL != lpFC1->lpFirstSubFC) {
					CompareFiles(lpFC1->lpFirstSubFC, NULL);
				}
			}
		}
	}

	// After looping all FC1 files, do an extra loop over all FC2 files and check previously set match flags to determine added dirs/files
	for (lpFC2 = lpStartFC2; NULL != lpFC2; lpFC2 = lpFC2->lpBrotherFC) 
	{
		// skip FC2 if already matched
		if (NOMATCH != lpFC2->fFileMatch) {
			continue;
		}

		// FC2 has no matching FC1, so FC2 is an added dir/file
		if (ISFILE(lpFC2->nFileAttributes)) 
		{
			CompareResult.stcCompared.cFiles++;
			CompareResult.stcChanged.cFiles++;
			CompareResult.stcAdded.cFiles++;
			CreateNewResult(FILEADD, NULL, lpFC2);
		}
		else 
		{
			CompareResult.stcCompared.cDirs++;
			CompareResult.stcChanged.cDirs++;
			CompareResult.stcAdded.cDirs++;
			CreateNewResult(DIRADD, NULL, lpFC2);

			// "Compare"/Log sub files if any
			if (NULL != lpFC2->lpFirstSubFC) {
				CompareFiles(NULL, lpFC2->lpFirstSubFC);
			}
		}
	}
}