Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added Distributed File Sync.exe
Binary file not shown.
238 changes: 113 additions & 125 deletions Distributed File Sync/Distributed File Sync/DirectoryMonitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,139 +4,127 @@ std::vector<sf::Packet> packetBuf;

void WatchDirectory(LPTSTR lpDir, std::mutex& dirLock)
{

//Status on the directory watch waiting, ie if a directory has been changed the wait status will free
DWORD dirWaitStatus;
//The handles to the windows Directory Change Notification
HANDLE dirChangeHandle;
//Name of the drive the directory is located on.
TCHAR dirDrive[4];


//Micrsoft stdlib function that the lpDir (pointer to the string with the directory path)
//https://titanwolf.org/Network/Articles/Article?AID=7d033004-eb4a-4d38-b335-0ed45c948f2e#gsc.tab=0 explains the function better than what I could find from microsoft.
_tsplitpath_s(lpDir, dirDrive, 4, NULL, 0, NULL, 0, NULL, 0);

//No idea why this is here or what it does not documented at all on Microsofts website. Could be adding a null terminator? No idea.
dirDrive[2] = (TCHAR)'\\';
dirDrive[3] = (TCHAR)'\0';

// Watch the directory for file creation and deletion editing and directory changes.
//Microsoft has 6 different ways to look for file or directory updates, we watch them all besides security changes.
dirChangeHandle = FindFirstChangeNotification(
lpDir, // directory to watch
TRUE, // watch subtree
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_LAST_WRITE); // watch file name changes


// Make a final validation check on our handles.



auto fileHashes = CreateFileHashes(lpDir);


for (auto iter = fileHashes.begin(); iter != fileHashes.end(); ++iter) {
std::wcout << iter->first << std::endl;
}
// Change notification is set. Now wait on both notification
// handles and refresh accordingly.

while (TRUE)
{
// Wait for notification.
if ((dirChangeHandle == NULL))
{
printf("\n ERROR: Unexpected NULL from FindFirstChangeNotification.\n");
ExitProcess(GetLastError());
}
printf("\nWaiting for notification...\n");
//function sets the wait status
dirWaitStatus = WaitForSingleObject(dirChangeHandle, INFINITE);
if (!FindNextChangeNotification(dirChangeHandle)) {
printf("\n File Next File change Failed.");
}

dirLock.lock();
std::cout << "locking dirLock" << std::endl;
auto dirChanges = getDirectoryChanges(lpDir, fileHashes);
sf::Packet dirChangesPacket;

packetBuf.push_back(dirChangesPacket << dirChanges);
std::cout << "unlocking dirLock" << std::endl;
dirLock.unlock();
}
//Status on the directory watch waiting, ie if a directory has been changed the wait status will free
DWORD dirWaitStatus;
//The handles to the windows Directory Change Notification
HANDLE dirChangeHandle;
//Name of the drive the directory is located on.
TCHAR dirDrive[4];

//Micrsoft stdlib function that the lpDir (pointer to the string with the directory path)
//https://titanwolf.org/Network/Articles/Article?AID=7d033004-eb4a-4d38-b335-0ed45c948f2e#gsc.tab=0 explains the function better than what I could find from microsoft.
_tsplitpath_s(lpDir, dirDrive, 4, NULL, 0, NULL, 0, NULL, 0);

//No idea why this is here or what it does not documented at all on Microsofts website. Could be adding a null terminator? No idea.
dirDrive[2] = (TCHAR)'\\';
dirDrive[3] = (TCHAR)'\0';

// Watch the directory for file creation and deletion editing and directory changes.
//Microsoft has 6 different ways to look for file or directory updates, we watch them all besides security changes.
dirChangeHandle = FindFirstChangeNotification(
lpDir, // directory to watch
TRUE, // watch subtree
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_LAST_WRITE); // watch file name changes

// Make a final validation check on our handles.

auto fileHashes = CreateFileHashes(lpDir);

for (auto iter = fileHashes.begin(); iter != fileHashes.end(); ++iter) {
std::wcout << iter->first << std::endl;
}
// Change notification is set. Now wait on both notification
// handles and refresh accordingly.

while (TRUE)
{
// Wait for notification.
if ((dirChangeHandle == NULL))
{
printf("\n ERROR: Unexpected NULL from FindFirstChangeNotification.\n");
ExitProcess(GetLastError());
}
printf("\nWaiting for notification...\n");
//function sets the wait status
dirWaitStatus = WaitForSingleObject(dirChangeHandle, INFINITE);
if (!FindNextChangeNotification(dirChangeHandle)) {
printf("\n File Next File change Failed.");
}

dirLock.lock();
std::cout << "locking dirLock" << std::endl;
auto dirChanges = getDirectoryChanges(lpDir, fileHashes);
sf::Packet dirChangesPacket;

packetBuf.push_back(dirChangesPacket << dirChanges);
std::cout << "unlocking dirLock" << std::endl;
dirLock.unlock();
}
}
// Creates a map of all filePaths to their hash.
std::map<std::wstring, uint64_t> CreateFileHashes(const std::wstring dirPath) {
std::map<std::wstring, uint64_t> pathToHash;

std::vector<std::wstring> filepaths = getFilepaths(dirPath);
std::map<std::wstring, uint64_t> pathToHash;

//Inserts all the hashes using getFileHash
for (std::wstring path : filepaths) {
pathToHash.insert(pathToHash.end(),{ path, getFileHash(path)});
}
return pathToHash;
std::vector<std::wstring> filepaths = getFilepaths(dirPath);

//Inserts all the hashes using getFileHash
for (std::wstring path : filepaths) {
pathToHash.insert(pathToHash.end(), { path, getFileHash(path) });
}
return pathToHash;
}

std::vector<fileChangeData> getDirectoryChanges(LPTSTR lpDir, std::map<std::wstring, uint64_t> &prevDir)
std::vector<fileChangeData> getDirectoryChanges(LPTSTR lpDir, std::map<std::wstring, uint64_t>& prevDir)
{
//This is probably innefficient most likely I should get filepaths only and hash only as needed.
auto newDir = CreateFileHashes(lpDir);
//Storing the file changes
std::vector<fileChangeData> fileChanges;
//Every file in the directory we want to check if is in the old directory, if it we check if the hashes are the same, if they aren't it the file change was an edit. If the file is in the new directory but not in the old directory the file change is an Addition.
for (auto outerIter = newDir.begin(); outerIter != newDir.end(); ++outerIter) {
auto filePath = outerIter->first;

//If prevDir.count == 1 then the file is in both the prevDir and the newDir
if (prevDir.count(filePath)) {
auto filesDiffer = prevDir[filePath] != newDir[filePath];

//IF the files differ the change was an edit.
if (filesDiffer) {
fileChanges.insert(fileChanges.end(), { filePath,newDir[filePath], fileChangeType::Edit });
}
else {
continue;
}
}
//If there was no matching file in the new directory the change was an additon.
else {
fileChanges.insert(fileChanges.end(), { filePath, newDir[filePath], fileChangeType::Addition });
}



}
//we do one last check for deletions by checking the files that show up in the old directory but not in the new directory.
for (auto outerIter = prevDir.begin(); outerIter != prevDir.end(); ++outerIter) {
auto filePath = outerIter->first;
if (!newDir.count(filePath)) {
fileChanges.insert(fileChanges.end(), { filePath, NULL, fileChangeType::Deletion });
}

}
prevDir = newDir;
return fileChanges;
//This is probably innefficient most likely I should get filepaths only and hash only as needed.
auto newDir = CreateFileHashes(lpDir);
//Storing the file changes
std::vector<fileChangeData> fileChanges;
//Every file in the directory we want to check if is in the old directory, if it we check if the hashes are the same, if they aren't it the file change was an edit. If the file is in the new directory but not in the old directory the file change is an Addition.
for (auto outerIter = newDir.begin(); outerIter != newDir.end(); ++outerIter) {
auto filePath = outerIter->first;

//If prevDir.count == 1 then the file is in both the prevDir and the newDir
if (prevDir.count(filePath)) {
auto filesDiffer = prevDir[filePath] != newDir[filePath];

//IF the files differ the change was an edit.
if (filesDiffer) {
fileChanges.insert(fileChanges.end(), { filePath,newDir[filePath], fileChangeType::Edit });
}
else {
continue;
}
}
//If there was no matching file in the new directory the change was an additon.
else {
fileChanges.insert(fileChanges.end(), { filePath, newDir[filePath], fileChangeType::Addition });
}
}
//we do one last check for deletions by checking the files that show up in the old directory but not in the new directory.
for (auto outerIter = prevDir.begin(); outerIter != prevDir.end(); ++outerIter) {
auto filePath = outerIter->first;
if (!newDir.count(filePath)) {
fileChanges.insert(fileChanges.end(), { filePath, NULL, fileChangeType::Deletion });
}
}
prevDir = newDir;
return fileChanges;
}

void printChanges(std::vector<fileChangeData> fileChanges) {
for (auto fileChange : fileChanges) {
std::wcout << fileChange.filePath;
switch (fileChange.change) {
case fileChangeType::Addition:
std::wcout << L" File Added" << std::endl;
break;
case fileChangeType::Deletion:
std::wcout << L" File Deleted" << std::endl;
break;
case fileChangeType::Edit:
std::wcout << L" File Edit" << std::endl;
break;
}
}
}

for (auto fileChange : fileChanges) {
std::wcout << fileChange.filePath;
switch (fileChange.change) {
case fileChangeType::Addition:
std::wcout << L" File Added" << std::endl;
break;
case fileChangeType::Deletion:
std::wcout << L" File Deleted" << std::endl;
break;
case fileChangeType::Edit:
std::wcout << L" File Edit" << std::endl;
break;
}
}
}
6 changes: 6 additions & 0 deletions Distributed File Sync/Distributed File Sync/FileHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ std::size_t filesize(const std::wstring& absPath) {
return length;
}

bool deleteFile(const std::wstring& absPath) {
return std::filesystem::remove(absPath);
}



//hash is a takes into account absolute path, file size, and file contents
uint64_t getFileHash(const std::wstring& absPath) {
std::vector<uint64_t> multiplands{2,7,17,29,41,53,67,79,97};
Expand Down
2 changes: 2 additions & 0 deletions Distributed File Sync/Distributed File Sync/FileHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ bool filesDiffer(const std::wstring& absPath1, const std::wstring& absPath2);
std::size_t filesize(const std::wstring& absPath);
//hash file into a 64 bit number
uint64_t getFileHash(const std::wstring& absPath);
//Delete file
bool deleteFile(const std::wstring& absPath);
Loading