{"id":21522032,"url":"https://github.com/sstock2005/calcslackspace","last_synced_at":"2025-03-17T17:22:47.630Z","repository":{"id":217541895,"uuid":"744230342","full_name":"sstock2005/CalcSlackSpace","owner":"sstock2005","description":"A program written in C++ to calculate the slack space of a given file on Windows.","archived":false,"fork":false,"pushed_at":"2024-01-16T21:57:47.000Z","size":23,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-24T04:51:56.927Z","etag":null,"topics":["cpp"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sstock2005.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2024-01-16T21:51:27.000Z","updated_at":"2024-01-16T21:53:14.000Z","dependencies_parsed_at":"2024-01-17T03:44:39.147Z","dependency_job_id":null,"html_url":"https://github.com/sstock2005/CalcSlackSpace","commit_stats":null,"previous_names":["sstock2005/calcslackspace"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sstock2005%2FCalcSlackSpace","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sstock2005%2FCalcSlackSpace/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sstock2005%2FCalcSlackSpace/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sstock2005%2FCalcSlackSpace/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sstock2005","download_url":"https://codeload.github.com/sstock2005/CalcSlackSpace/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244075657,"owners_count":20393980,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp"],"created_at":"2024-11-24T01:09:03.820Z","updated_at":"2025-03-17T17:22:47.607Z","avatar_url":"https://github.com/sstock2005.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# CalcSlackSpace\n\nA simple calculator program written in C++ with the goal to calculate a file's slack space on Windows.\n\nNote: This will only work on Windows\n\nTry it out: [Releases Page](https://github.com/sstock2005/CalcSlackSpace/releases/latest)\n## TL;DR\n\nI am going to give a decently detailed explanation of how this program works not only for you but for myself, I am learning C++ so some of the functions used (especially WinAPI) seemed advanced to me and I want to document how to use them in the future.\n\n### Utils.h\nThis is the header file for the Utils class. It contains the following:\n\n| Type | Name | Parameter | Returns |\n|---|---|---|---|\n| Unsigned Long | getLogicalSize | std::string filename| Logical Size of File  |\n| Unsigned Long | getSizeonDisk | std::string filename | Physical Size of File |\n| std::string | wPrefix | unsigned long bytes | Formatted Storage String |\n| bool | error | None | Whether or not there has been an error |\n\n**getLogicalSize**  \nReturns the logical size of the file.  \n\n**getSizeonDisk**  \nReturns the physical size or the size on disk of the file.\n\n**wPrefix**  \nReturns a formatted string representing the given bytes.\n\n**error**  \nStores whether or not the program has had an error while running.\n\n\n### Utils.cpp\nThis is the real part of the Utils class, it contains the logic behind the Utils functions.  \n\n```cpp\nunsigned long Utils::getLogicalSize(std::string filename) \n{\n    std::ifstream file(filename, std::ifstream::ate | std::ifstream::binary);\n    if (!file) {\n        std::cerr \u003c\u003c \"Failed to open file\\n\";\n        Utils::error = true;\n        return 1;\n    }\n    return static_cast\u003cunsigned long\u003e(file.tellg());\n}\n```\n\n**What does this do?**  \nThis function intakes an std::string named filename. On line 1, the function creates an `std::ifstream` object named file. `std::ifstream` is a class in C++ used for reading from files. The constructor takes two arguments: the name of the file to open and the mode to open the file in. `std::ifstream::ate` opens the file and seeks to the end of the file, and `std::ifstream::binary` opens the file in binary mode.  \n\nThe function then checks if the object could not be created. If the file object could not be created, the function reports the error and returns.\n\nFinally, the function returns the static casted unsigned long from `file.tellg()`. `file.tellg()` is the current file pointer. Because the file object was created with `std::ifstream::ate`, the current file pointer is the logical size of the file.\n\n```cpp\nunsigned long Utils::getSizeonDisk(std::string filename)\n{\n    std::wstring wfilename(filename.begin(), filename.end());\n\n    WIN32_FILE_ATTRIBUTE_DATA fad;\n    if (!GetFileAttributesEx(wfilename.c_str(), GetFileExInfoStandard, \u0026fad))\n    {\n        std::cerr \u003c\u003c \"Failed to get file attributes\\n\";\n        Utils::error = true;\n        return 0;\n    }\n\n    if (fad.dwFileAttributes \u0026 FILE_ATTRIBUTE_COMPRESSED || fad.dwFileAttributes \u0026 FILE_ATTRIBUTE_SPARSE_FILE)\n    {\n        std::cerr \u003c\u003c \"File is compressed or sparse, physical size might not be accurate\\n\";\n    }\n\n    HANDLE hFile = CreateFile(wfilename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\n    if (hFile == INVALID_HANDLE_VALUE)\n    {\n        std::cerr \u003c\u003c \"Failed to open file\\n\";\n        Utils::error = true;\n        return 0;\n    }\n\n    BY_HANDLE_FILE_INFORMATION info;\n    if (!GetFileInformationByHandle(hFile, \u0026info))\n    {\n        std::cerr \u003c\u003c \"Failed to get file information\\n\";\n        Utils::error = true;\n        CloseHandle(hFile);\n        return 0;\n    }\n\n    DWORD sectorsPerCluster, bytesPerSector, numberOfFreeClusters, totalNumberOfClusters;\n    if (!GetDiskFreeSpace(L\"C:\\\\\", \u0026sectorsPerCluster, \u0026bytesPerSector, \u0026numberOfFreeClusters, \u0026totalNumberOfClusters))\n    {\n        std::cerr \u003c\u003c \"Failed to get disk information\\n\";\n        Utils::error = true;\n        CloseHandle(hFile);\n        return 0;\n    }\n\n    unsigned long physicalSize = info.nFileSizeHigh * (MAXDWORD)+info.nFileSizeLow;\n    physicalSize = ((physicalSize + bytesPerSector - 1) / bytesPerSector) * bytesPerSector;\n\n    CloseHandle(hFile);\n    return physicalSize;\n}\n```\n\n**Oh Boy..**  \nThis is the real meat of the program. This calculates the physical size of a file or the size of the file on disk. This interacts heavily with the Windows API so it can be confusing to understand.\n\n**What does this do?**  \n`std::wstring wfilename(filename.begin(), filename.end());`  \nConverts the given filename to wide character string because the Windows API requires weird things.  \n\n`WIN32_FILE_ATTRIBUTE_DATA fad;`  \nDeclares a `WIN32_FILE_ATTRIBUTE_DATA` structure that will hold file attribute data.  \n\n`if (!GetFileAttributesEx(wfilename.c_str(), GetFileExInfoStandard, \u0026fad)) { ... }`  \nThis calls the `GetFileAttributesEx` function to get the attributes of the file. If the function fails, it prints an error message, sets `Utils::error` to `true`, and returns `0`.  \n\n`if (fad.dwFileAttributes \u0026 FILE_ATTRIBUTE_COMPRESSED || fad.dwFileAttributes \u0026 FILE_ATTRIBUTE_SPARSE_FILE) { ... }`  \nThis checks if the file is compressed or sparse. If it is, it prints a warning message because the physical size might not be accurate for these types of files.  \n\n`HANDLE hFile = CreateFile(wfilename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);`  \nThis calls the `CreateFile` function to open the file and get a handle to it.  \n\n`if (hFile == INVALID_HANDLE_VALUE) { ... }`  \nThis checks if the `CreateFile` function succeeded. If it failed, it prints an error message, sets `Utils::error` to `true`, and returns `0`.  \n\n`BY_HANDLE_FILE_INFORMATION info;`  \nThis declares a `BY_HANDLE_FILE_INFORMATION` structure that will hold file information.  \n\n`if (!GetFileInformationByHandle(hFile, \u0026info)) { ... }`  \nThis calls the `GetFileInformationByHandle` function to get information about the file. If the function fails, it prints an error message, sets `Utils::error` to `true`, closes the file handle, and returns `0`.  \n\n`DWORD sectorsPerCluster, bytesPerSector, numberOfFreeClusters, totalNumberOfClusters;`  \nThis declares several `DWORD` variables that will hold disk information.  \n\n`if (!GetDiskFreeSpace(L\"C:\\\\\", \u0026sectorsPerCluster, \u0026bytesPerSector, \u0026numberOfFreeClusters, \u0026totalNumberOfClusters)) { ... }`  \nThis line calls the `GetDiskFreeSpace` function to get information about the disk. If the function fails, it prints an error message, sets `Utils::error` to `true`, closes the file handle, and returns `0`.  \n\n`unsigned long physicalSize = info.nFileSizeHigh * (MAXDWORD)+info.nFileSizeLow;`  \nThis calculates the size of the file in bytes.  \n\n`physicalSize = ((physicalSize + bytesPerSector - 1) / bytesPerSector) * bytesPerSector;`  \nThis rounds the size of the file up to the nearest multiple of the sector size. This is the physical size of the file on disk.  \n\n`CloseHandle(hFile);`  \nCloses the file handle.  \n\n`return physicalSize;`  \nReturns the physical size of the file or the size on disk.  \n\n### Main.cpp\nThis is the main function of the program, it is pretty straightforward.  \n\n```cpp\nint main(int argc, char * argv[])\n{\n\tstd::string filename;\n\tunsigned long logicalSize;\n\tunsigned long sizeOnDisk;\n\tunsigned long slackSpace;\n\n\tif (argv[1] == NULL)\n\t{\n\t\tstd::cout \u003c\u003c \"File: \";\n\t\tstd::getline(std::cin, filename);\n\t\tstd::cout \u003c\u003c \"\\n\";\n\t}\n\telse \n\t{\n\t\tfilename = argv[1];\n\t}\n\n\tif (filename.find(\"\\\"\") != std::string::npos) \n\t{\n\t\tfilename.erase(std::remove(filename.begin(), filename.end(), '\\\"'), filename.end());\n\t}\n\n\tlogicalSize = Utils::getLogicalSize(filename);\n\tsizeOnDisk = Utils::getSizeonDisk(filename);\n\n\tif (Utils::error == true) \n\t{\n\t\treturn 0;\n\t}\n\n\tslackSpace = sizeOnDisk - logicalSize;\n\n\tstd::cout \u003c\u003c \"Logical Size: \" \u003c\u003c Utils::wPrefix(logicalSize) \u003c\u003c \" (\" \u003c\u003c logicalSize \u003c\u003c \" bytes)\\n\";\n\tstd::cout \u003c\u003c \"Physical Size (size on disk): \" \u003c\u003c Utils::wPrefix(sizeOnDisk) \u003c\u003c \" (\" \u003c\u003c sizeOnDisk \u003c\u003c \" bytes)\\n\";\n\tstd::cout \u003c\u003c \"Slack Space: \" \u003c\u003c Utils::wPrefix(slackSpace) \u003c\u003c \" (\" \u003c\u003c slackSpace \u003c\u003c \" bytes)\\n\";\n\treturn 0;\n}\n```\n\n**What does this do?**  \nThis function creates an `std::string filename`, and 3 `unsigned long` variables named `logicalSize`, `sizeOnDisk`, and `slackSpace`. It then checks if an argument was passed when the program was executed, if there was no argument passed, the program then asks for user input and assigns that to the filename, otherwise if there was, the program assigns the value of the first argument to the `filename` variable. \n\nThe program then removes any \" from the filename because of the way dropping a file with spaces work on Windows. The program then assigns `localSize` and `sizeOnDisk` to the calculates values from `Utils::getLogicalSize` and `Utils::getSizeonDisk`. It then calculates the `slackSpace` by subtracting the physical size of the file by the logical size of the file. \n\nThe program then checks if the `Utils::error` bool is set to `true`, the program exists if it is. Then the program prints out the formatted strings of `logicalSize`, `sizeOnDisk`, and `slackSpace`.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsstock2005%2Fcalcslackspace","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsstock2005%2Fcalcslackspace","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsstock2005%2Fcalcslackspace/lists"}