I want to delete all the files which begin with sub string.
CString Formatter = _T("C:\\logs\\test\\test_12-12-2018_1*.*");
DeleteFile(Formatter);
I intend to delete following files with above code
C:\logs\test\test_12-12-2018_1_G1.txt
C:\logs\test\test_12-12-2018_1_G2.txt
C:\logs\test\test_12-12-2018_1_G3.txt
C:\logs\test\test_12-12-2018_1_G4.txt
When I check error from GetLastError, I get ERROR_INVALID_NAME.
Any idea how to fix this?
DeleteFile doesn't take wildcards. It looks like what you need is a FindFirstFile/FindNextFile/FindClose loop to turn your wildcard into a list of full file names.
#include <windows.h>
#include <pathcch.h>
#pragma comment(lib, "pathcch.lib")
// (In a function now)
WIN32_FIND_DATAW wfd;
WCHAR wszPattern[MAX_PATH];
HANDLE hFind;
INT nDeleted = 0;
PathCchCombine(wszPattern, MAX_PATH, L"C:\\Logs\\Test", L"test_12-12-2018_1*.*");
SetCurrentDirectoryW(L"C:\\Logs\\Test");
hFind = FindFirstFileW(wszPattern, &wfd);
if(hFind == INVALID_HANDLE_VALUE)
{
// Handle error & exit
}
do
{
DeleteFileW(wfd.cFileName);
nDeleted++;
}
while (FindNextFileW(hFind, &wfd));
FindClose(hFind);
wprintf(L"Deleted %d files.\n", nDeleted);
Note that PathCchCombine, FindFirstFileW, and DeleteFileW can all fail, and robust code would check their return values and handle failures appropriately. Also, if FindNextFileW returns 0 and the last error code is not ERROR_NO_MORE_FILES, then it failed because of an actual error (not because there was nothing left to find), and that needs to be handled as well.
Also, if speed is a concern of yours (your example in your post about deleting four files in the same directory doesn't seem like it needs it), replace the line hFind = FindFirstFileW(...) with:
hFind = FindFirstFileExW(wszPattern, FindExInfoBasic, (LPVOID)&wfd, FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH);
Although you can search for the file names, and then call DeleteFile individually for each, my advice would be to use one of the Windows shell functions to do the job instead.
For example, you could use code something like this:
#define _WIN32_IE 0x500
#include <windows.h>
#include <shellapi.h>
#include <shlobj.h>
#include <iostream>
#include <string>
static char const *full_path(std::string const &p) {
static char path[MAX_PATH+2] = {0};
char *ignore;
GetFullPathName(p.c_str(), sizeof(path), path, &ignore);
return path;
}
static int shell_delete(std::string const &name) {
SHFILEOPSTRUCT op = { 0 };
op.wFunc = FO_DELETE;
op.pFrom = full_path(name);
op.fFlags = FOF_ALLOWUNDO | FOF_SILENT | FOF_WANTNUKEWARNING | FOF_NOCONFIRMATION;
return !SHFileOperation(&op);
}
int main(int argc, char **argv) {
if ( argc < 2) {
fprintf(stderr, "Usage: delete <filename> [filename ...]");
return 1;
}
for (int i=1; i<argc; i++)
shell_delete(argv[i]);
}
One obvious advantage to this is that you can pass the FOF_ALLOWUNDO flag (as I have in the code above), which moves the files to the recycle bin instead of removing it permanently. Of course, you can omit that flag if you want to the files nuked.
Depending on what you're doing, there are a few other flags that might be handy, such as FOF_FILESONLY, to delete only files, not directories that might match the wildcard you specify, and FOF_NORECURSION to have it not recurse into subdirectories at all.
Microsoft considers SHFileOperation obsolescent, and has (in Windows Vista, if memory serves) "replaced" it with IFileOperation. IFileOperation is a COM interface though, so unless you're using COM elsewhere in your code, chances are pretty good that using it will add a fair amount of extra work for (at least in this case) little or no real advantage. Especially you're already using COM, however, this might be worth considering.
Related
I found this in another forum that is supposed to give it to you. But I think this may not be the best way, also I think it results in a memory leak due to the array not being deleted. Is this true?
Also is this the best way? Best way being a cross platform command (if it doesn't exist then use Windows) that gives the folder directory directly.
std::string ExePath()
{
using namespace std;
char buffer[MAX_PATH];
GetModuleFileName(NULL, buffer, MAX_PATH);
string::size_type pos = string(buffer).find_last_of("\\/");
if (pos == string::npos)
{
return "";
}
else
{
return string(buffer).substr(0, pos);
}
}
There is no memory leak in your code, but there are some issues with it:
it is Windows-specific,
it works with local code-page and does not support arbitrary Unicode files names.
Unfortunately, there is no standard way of accomplishing this task just with C++ library, but here is a code that will work on Windows and Linux, and support Unicode paths as well. Also it utilizes std::filesystem library from C++17:
#include <filesystem>
#ifdef _WIN32
#include <windows.h>
#elif
#include <unistd.h>
#endif
std::filesystem::path GetExeDirectory()
{
#ifdef _WIN32
// Windows specific
wchar_t szPath[MAX_PATH];
GetModuleFileNameW( NULL, szPath, MAX_PATH );
#else
// Linux specific
char szPath[PATH_MAX];
ssize_t count = readlink( "/proc/self/exe", szPath, PATH_MAX );
if( count < 0 || count >= PATH_MAX )
return {}; // some error
szPath[count] = '\0';
#endif
return std::filesystem::path{ szPath }.parent_path() / ""; // to finish the folder path with (back)slash
}
I would like to log every syscall of a specified directory and I've found this repository https://github.com/rflament/loggedfs
It creates a virtual filesystem with fuse and log everything in it, just like I want.
I tried to port it on mac but it uses a "trick" that doesn't works on osx. The lstat is stuck 10s and crash.
I would like to understand why ?
This is a main part of my code :
// g++ -Wall main.cpp `pkg-config fuse --cflags --libs` -o hello
#define FUSE_USE_VERSION 26
#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
static char *path;
static int savefd;
static int getattr(const char *path, struct stat *stbuf)
{
int res;
char rPath[1024];
strcpy(rPath, "."); strcat(rPath, path);
res = lstat(rPath, stbuf); // Mac stuck here
return (res == -1 ? -errno : 0);
}
static void* loggedFS_init(struct fuse_conn_info* info)
{
fchdir(savefd); close(savefd); return NULL;
}
int main(int argc, char *argv[])
{
struct fuse_operations oper;
bzero(&oper, sizeof(fuse_operations));
oper.init = loggedFS_init;
oper.getattr = getattr;
path = strdup(argv[argc - 1]);
printf("chdir to %s\n", path);
chdir(path);
savefd = open(".", 0);
return fuse_main(argc, argv, &oper, NULL);
}
I had a very close look at LoggedFS and tested it for POSIX compliance using pjdfstest, resulting in 3 issues (or groups of issues). I ended up re-implementing it in Python, fully POSIX compliant. I have not tested it on OS X yet, so I'd be happy to receive some feedback ;)
The "trick" you are mentioning could be the root cause of your issue, although I am not entirely sure. It causes a fundamental problem by adding another character to the path, which leads to issues when the length of path gets close to PATH_MAX. libfuse already passes paths with a leading / into FUSE operations. The additional . plus the "misleading" / (root of the mounted filesystem, not the "global" root folder) are two characters "too many", effectively reducing the maximum allowed path length to PATH_MAX minus 2. I explored options of altering PATH_MAX and informing user land software about a smaller PATH_MAX, which turned out to be impossible.
There is a way around, however. Do not close the file descriptor savefd in the init routine. Keep it open and instead close it in the destroy routine, which will be called by FUSE when the filesystem is unmounted. You can actually use savefd for specifying paths relative to it. You can then use fstatat (Linux, OS X / BSD) instead of lstat. Its prototype looks like this:
int fstatat(int dirfd, const char *pathname, struct stat *buf,
int flags);
You have to pass savefd into dirfd and remove the leading / from the content of path before passing it into pathname.
So, code I can't change calls an executable, and I need to give it different commandline args than what the black box code calls. I was figuring I could make an executable to serve as a proxy. proc.exe sits where the black box section is expecting, takes the commandline arguments, modifies them, then calls procReal.exe, the original file.
Unfortunately CreateProcess seems to fail to start, returning status 183. I've looked up everything I can and can't find out much about this. Have tried flipping things around, setting the handle inheritance to true, manually specifying the working directory, not doing either of those things. No luck. I assume there's something going on here with inheriting the proper security context of the calling application so the wrapper works as a proper passthrough, but I can't figure out how to do it...
Code below, irrelevant sections pruned.
EDIT Put the full code here after request. This isn't making any sense anymore. It now will partially work, but only if the fopen section for traceFile isn't there. Not even the fprintfs removed, specifically the whole section has to be cut out.
I've tried to respond to everyone's comments and I think I've ruled out most of those things as an issue, but am left with the current anomalous behavior. What little more I could read up on this says that some forms of copying the strings around could lead to memory overflows, is that possible at all?
#include <iostream>
#include <fstream>
#include <windows.h>
#include <string>
#include <vector>
#include <stdio.h>
#include <tchar.h>
#include <algorithm>
#include <string>
using namespace std;
bool caseInsensitiveStringCompare( const std::string& str1, const std::string& str2 );
int main(int argc, char* argv[]) {
const string path = "E:\\util\\bin\\";
const string procName = "procReal.exe";
const string argToFilter = "-t";
string origValue;
string passedValue;
for(int i = 1; i < argc; i++)
{
origValue.append(" ").append(argv[i]);
}
for(int i = 1; i < argc; i++)
{
if (!caseInsensitiveStringCompare(argv[i],argToFilter))
{
passedValue.append(" ").append(argv[i]);
}
else
{
i++; // skip over argument and it's value
}
}
const LPCTSTR exeModule = (path+procName).c_str();
std::vector<char> chars(passedValue.c_str(), passedValue.c_str() + passedValue.size() + 1u);
LPTSTR exeArgs = &chars[0];
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
GetStartupInfo(&si);
FILE* traceFile;
traceFile = fopen ((path+"lastRun.txt").c_str(), "w"); // This causes exeModule to change value for unknown reasons???
fprintf(traceFile, "orig: %s%s\n", exeModule, origValue.c_str());
fprintf(traceFile, "%s%s\n", exeModule, exeArgs);
SetLastError(0);
// Start the child process.
if( !CreateProcess( exeModule, // use module name with args for exeArgs
exeArgs, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
TRUE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
FILE* myfile;
myfile = fopen ((path+"error.txt").c_str(), "w");
fprintf(myfile, "CreateProcess failed (%d).\n", int(GetLastError()));
fclose(myfile);
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
DWORD exit_code;
GetExitCodeProcess(pi.hProcess, &exit_code);
fprintf(traceFile, "Exit Code: %d\n", int(exit_code));
fclose(traceFile);
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
return exit_code;
}
bool caseInsensitiveStringCompare( const std::string& str1, const std::string& str2 ) {
std::string str1Cpy( str1 );
std::string str2Cpy( str2 );
std::transform( str1Cpy.begin(), str1Cpy.end(), str1Cpy.begin(), ::tolower );
std::transform( str2Cpy.begin(), str2Cpy.end(), str2Cpy.begin(), ::tolower );
return ( str1Cpy == str2Cpy );
}
The most obvious problem is that you can't say (path+procName).c_str() because the temporary string object it builds is discarded immediately, invalidating the returned pointer. I'm also very dubious about assuming that the elements of a vector are necessarily consecutive.
The corrected string handling code should look something like this:
string passedValue(procName); // First element of command line MUST be module name
...
const string exeModuleString(path + procName);
const LPCTSTR exeModule = exeModuleString.c_str();
LPTSTR exeArgs = new char[passedValue.size() + 1];
passedValue.copy(exeArgs, passedValue.size());
exeArgs[passedValue.size()] = '\0';
(That might not be the best way to do it; I don't use C++ often. But it should work correctly.)
The corrected error handling code, ensuring that the last error code is read immediately, should look something like this:
{
DWORD err = GetLastError();
FILE* myfile;
myfile = fopen ((path+"error.txt").c_str(), "w");
fprintf(myfile, "CreateProcess failed (%d).\n", int(err));
fclose(myfile);
}
Your code was reporting the wrong error code, because calling fopen() changes it. (When a new file is created that overwrites an existing file, the last error code is set to ERROR_ALREADY_EXISTS.)
There are two broader issues, which may or may not matter in your context. Firstly, you're using argv[] to build the command line for the new process; that means that the command line parsing (as described in Parsing C Command-Line Arguments) will be applied twice (once by your process and once by the child) which may cause trouble if the command line contains any special characters such as quote marks or backslashes. Ideally, in the general case, you would call GetCommandLine() instead. (Granted, this makes parsing the string to remove the extra argument quite a bit harder.)
Secondly, you're obviously building the code in ANSI mode. This may cause problems if the command line ever contains any wide ("Unicode") characters. It is generally accepted that best practice is to always build in Unicode mode. The only major change you'll need to make to the code is to replace string with wstring, so it should be straightforward enough.
I have the same problem.
The problem seems to be there when i call executables with no window.
I found 2 solutions:
1.
Create a bat file with the name of thet exe, followed by the arguments,
and then execute the bat file:
CreateProcess( "temp.bat" , NULL , ....etc
2.
use _spawnl
I am trying get path of the exe file at the same folder where this program will been. but i couldnt figure out how to do, i did something like this but it only gets the current programs path, and i dont know how to replace filenames between my program and the program i want to get path.
so simply can you help me about get the path of an exe (i know the name of that exe ) at the same folder where this program will been...
char fullp[MAX_PATH];
char selfp[MAX_PATH] = "..//myprogram.exe";
char otherprogram[MAX_PATH] = "//test.exe";
DWORD szPath;
szPath = GetModuleFileName(NULL, selfp, sizeof(selfp));
The Win32 API has a whole bunch of Path Handling functions available.
For instance, once you have obtained the calling process's full path from GetModuleFileName(), you can use PathRemoveFileSpec() to remove the filename leaving just the folder path:
char selfdir[MAX_PATH] = {0};
GetModuleFileNameA(NULL, selfdir, MAX_PATH);
PathRemoveFileSpecA(selfdir);
And then use either PathAppend() or PathCombine() to append a different filename to that path:
char otherprogram[MAX_PATH] = {0};
lstrcpyA(otherprogram, selfdir);
PathAppendA(otherprogram, "test.exe");
char otherprogram[MAX_PATH] = {0};
PathCombineA(otherprogram, selfdir, "test.exe");
OP is most of the way there. Here is an example of how to get the rest of the way.
To simplify the solution, I'm leaving char arrays as far behind as possible and using std::string.
#include <iostream>
#include <string>
#include <windows.h>
int main()
{
char selfp[MAX_PATH];
std::string otherprogram = "Failed to get path";
DWORD szPath;
szPath = GetModuleFileName(NULL, selfp, MAX_PATH);
if (szPath != 0) // successfully got path of current program
{
// helper string to make life much, much easier
std::string helper = selfp;
//find last backslash in current program path
size_t pos = helper.find_last_of( "\\" );
if (pos != std::string::npos) // found last backslash
{
// remove everything after last backslash. This should remove
// the current program's name.
otherprogram = helper.substr( 0, pos+1);
// append new program name
otherprogram += "test.exe";
}
}
std::cout << otherprogram << std::endl;
}
I'm trying to get the filesize of a large file (12gb+) and I don't want to open the file to do so as I assume this would eat a lot of resources. Is there any good API to do so with? I'm in a Windows environment.
You should call GetFileSizeEx which is easier to use than the older GetFileSize. You will need to open the file by calling CreateFile but that's a cheap operation. Your assumption that opening a file is expensive, even a 12GB file, is false.
You could use the following function to get the job done:
__int64 FileSize(const wchar_t* name)
{
HANDLE hFile = CreateFile(name, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile==INVALID_HANDLE_VALUE)
return -1; // error condition, could call GetLastError to find out more
LARGE_INTEGER size;
if (!GetFileSizeEx(hFile, &size))
{
CloseHandle(hFile);
return -1; // error condition, could call GetLastError to find out more
}
CloseHandle(hFile);
return size.QuadPart;
}
There are other API calls that will return you the file size without forcing you to create a file handle, notably GetFileAttributesEx. However, it's perfectly plausible that this function will just open the file behind the scenes.
__int64 FileSize(const wchar_t* name)
{
WIN32_FILE_ATTRIBUTE_DATA fad;
if (!GetFileAttributesEx(name, GetFileExInfoStandard, &fad))
return -1; // error condition, could call GetLastError to find out more
LARGE_INTEGER size;
size.HighPart = fad.nFileSizeHigh;
size.LowPart = fad.nFileSizeLow;
return size.QuadPart;
}
If you are compiling with Visual Studio and want to avoid calling Win32 APIs then you can use _wstat64.
Here is a _wstat64 based version of the function:
__int64 FileSize(const wchar_t* name)
{
__stat64 buf;
if (_wstat64(name, &buf) != 0)
return -1; // error, could use errno to find out more
return buf.st_size;
}
If performance ever became an issue for you then you should time the various options on all the platforms that you target in order to reach a decision. Don't assume that the APIs that don't require you to call CreateFile will be faster. They might be but you won't know until you have timed it.
I've also lived with the fear of the price paid for opening a file and closing it just to get its size. And decided to ask the performance counter^ and see how expensive the operations really are.
This is the number of cycles it took to execute 1 file size query on the same file with the three methods. Tested on 2 files: 150 MB and 1.5 GB. Got +/- 10% fluctuations so they don't seem to be affected by actual file size. (obviously this depend on CPU but it gives you a good vantage point)
190 cycles - CreateFile, GetFileSizeEx, CloseHandle
40 cycles - GetFileAttributesEx
150 cycles - FindFirstFile, FindClose
The GIST with the code used^ is available here.
As we can see from this highly scientific :) test, slowest is actually the file opener. 2nd slowest is the file finder while the winner is the attributes reader. Now, in terms of reliability, CreateFile should be preferred over the other 2. But I still don't like the concept of opening a file just to read its size... Unless I'm doing size critical stuff, I'll go for the Attributes.
PS: When I'll have time I'll try to read sizes of files that are opened and am writing to. But not right now...
Another option using the FindFirstFile function
#include "stdafx.h"
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
int _tmain(int argc, _TCHAR* argv[])
{
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
LPCTSTR lpFileName = L"C:\\Foo\\Bar.ext";
hFind = FindFirstFile(lpFileName , &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
{
printf ("File not found (%d)\n", GetLastError());
return -1;
}
else
{
ULONGLONG FileSize = FindFileData.nFileSizeHigh;
FileSize <<= sizeof( FindFileData.nFileSizeHigh ) * 8;
FileSize |= FindFileData.nFileSizeLow;
_tprintf (TEXT("file size is %u\n"), FileSize);
FindClose(hFind);
}
return 0;
}
As of C++17, there is file_size as part of the standard library. (Then the implementor gets to decide how to do it efficiently!)
What about GetFileSize function?