How to fix CopyFile() error 5 - access denied error - c++

I am trying to write a copy file function that can be used on both Linux and Windows. It works on Linux, but on Windows, I get error code 5 when trying to use the WinApi function CopyFile().
In header File.h
This is the custom defined function in the File namespace that I should be able to use on both Linux and windows.
class File
{
public:
static bool copyFile(std::string source, std::string destination);
private:
}
In File.cpp
For Linux it is simple:
#ifdef __unix__
#include "File.h"
bool File::copyFile(std::string source, std::string destination)
{
std::string arg = source + " " + destination;
return launchProcess("cp", arg);
}
#endif
In the Windows specific block of code, I use the WinAPI (#include < windows.h >) function CopyFile(). This accepts LPCWSTR data types instead of strings. To overcome this I have created a function that converts strings to LPCWSTR types.
#ifdef _WIN32
#include "File.h"
#include <Windows.h>
std::wstring strtowstr(const std::string &str)
{
// Convert an ASCII string to a Unicode String
std::wstring wstrTo;
wchar_t *wszTo = new wchar_t[str.length() + 1];
wszTo[str.size()] = L'\0';
MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, wszTo,(int)str.length());
wstrTo = wszTo;
delete[] wszTo;
return wstrTo;
}
bool File::copyFile(std::string source, std::string destination)
{
std::wstring wsource = strtowstr(source);
std::wstring wdestination = strtowstr(destination);
int result = CopyFileW(wsource.c_str(), wdestination.c_str(), TRUE);
//for debugging...
std::wcout << "The error is " << GetLastError() <<std::endl;
std::wcout << wsource.c_str() << std::endl;
std::wcout << wdestination.c_str() << std::endl;
if (result == 0)
{
return false;
}
return true;
}
#endif
In my Test Programme
TEST(all,main_copy_file)
{
std::cout << "Testing copyFile() function..." << std::endl;
std::string srcDir = File::currentWorkingDirectory() + "srcDir";
File::makeDirectory(srcDir);
std::string destDir = File::currentWorkingDirectory() + "destDir/";
File::makeDirectory(destDir);
File::makeFile(srcDir, "testFile", ".txt");
ASSERT_TRUE(File::fileExists(srcDir + "/testFile.txt")) << "Error: Test file has not been generated" << std::endl;
ASSERT_TRUE(File::directoryExists(destDir)) << "Error: Destination directory does not exist" <<std::endl;
ASSERT_TRUE(File::copyFile(srcDir + "/testFile.txt", destDir)) << "Error: Coppy unsucsessfull" << std::endl;
ASSERT_TRUE(File::fileExists(destDir + "/testFile.txt")) << "Error: CoppyFile() flagged as sucsessfull but file does not exist" << std::endl;
}
In the application Output (on Windows)
/*
Testing copyFile() function...
The error is 5
C:\GIT\CorteX\Externals\OSAL\build\Debug/srcDir/testFile.txt
C:\GIT\CorteX\Externals\OSAL\build\Debug/destDir/
error: Value of: File::copyFile(srcDir + "/testFile.txt", destDir)
Actual: false
Expected: true
Error: Coppy unsucsessfull
*/
Error code 5 is an access denied error. I think it gives this error when either the directory does not exist, the directory is open somewhere else, or I do not have permissions.
Since I have tested that the directory does exist, I think it must be one of the latter two. I might only have restricted Admin rights (I don't know), but I can paste into the "destDir" without admin permission. So maybe it thinks the directory is open? Is there a command that exists to make sure the directory is closed?
The test is successful when running on Linux.

The CopyFile API expects file names for both source and destination files. Your code passes a directory name for the destination. This causes the API to fail. You need to append the file name for the destination as well.
Besides that, there are several other issues with your code:
The path separator on Windows is a backslash (\). Your are mixing forward slashes (/) and backslashes. Depending on the arguments passed, the system won't translate forward slashes to backslashes, before passing them on to lower-level file I/O API's.
You are calling GetLastError too late. You need to call it immediately, whenever it is documented to return a meaningful value. Do not intersperse it with any other code, however trivial it may appear to you. That code can modify and invalidate the calling thread's last error code.
Your code assumes ASCII-encoded strings. This will stop working, when dealing with files containing non-ASCII characters. This is quite common.
new wchar_t[...] buys you nothing over std::vector<wchar_t>, except the possibility to introduce bugs.
Your MultiByteToWideChar-based string conversion implementation makes (undue) assumptions about the code unit requirements of different character encodings. Those assumptions may not be true. Have the API calculate and tell you the destination buffer size, by passing 0 for cchWideChar.
Your string conversion routine ignores all return values, making bugs ever so likely, and unnecessarily hard to diagnose.

I know this is an old post, but for anyone who stumbles here needing more help:
CopyFile has the following constraints which if not met can give access denied error:
Insufficient permissions for the current user
File is in use
Filepath is a directory and not a file
File is read-only
In my case all the above were met, still I kept getting the same error. What helped me was a simple
SetFileAttributes(filePath,FILE_ATTRIBUTE_NORMAL)
Retrieving and Changing File Attributes
SetFileAttributes

Related

Windows DLL function behaviour is different if DLL is moved to different location

I'm attempting to debug some very opaque issues with DLLs in Unreal on a CI machine (see Unreal: Diagnosing why Windows cannot load a DLL for more information). glu32.dll seems to be the DLL at which the Unreal process falls over, and as Windows Server doesn't contain all the graphics-related DLLs that normal Windows 10 does, I was recommended to upload certain DLLs from my machine/Microsoft redistributables in order to make sure the Unreal build process could run.
For sanity purposes, I've written a small utility program to test whether glu32.dll on my machine can be dynamically loaded and can have its functions called correctly. I'm planning to run this executable on the troublesome CI machine soon to see what happens.
The code for the program is below:
#include <windows.h>
#include <iostream>
#include <GL/gl.h>
extern "C"
{
typedef const GLubyte* (__stdcall *ErrorStringFunc)(GLenum error);
}
int main(int argc, char** argv)
{
if (argc < 2)
{
std::cerr << "Usage: GLU32Loader.exe <path to glu32.dll>" << std::endl;
return 1;
}
const char* path = argv[1];
std::cout << "Attempting to load: " << path << std::endl;
HMODULE dllHandle = LoadLibraryA(path);
if (!dllHandle)
{
std::cerr << "Could not load " << path << std::endl;
return 1;
}
std::cout << "Successfully loaded DLL: 0x" << dllHandle << std::endl;
const char* funcName = "gluErrorString";
std::cout << "Looking up function: " << funcName << std::endl;
ErrorStringFunc func = reinterpret_cast<ErrorStringFunc>(GetProcAddress(dllHandle, funcName));
if (func)
{
std::cout << "Successfully loaded function: 0x" << func << std::endl;
const GLubyte* str = (*func)(100902);
std::cout << "Error string for value 100902: \"" << str << "\" (0x" << static_cast<const void*>(str) << ")" << std::endl;
}
else
{
std::cerr << "Failed to load function " << funcName << std::endl;
}
FreeLibrary(dllHandle);
return 0;
}
When I run the executable and point it to glu32.dll in the System32 folder, I get expected output:
> GLU32Loader.exe "C:\Windows\System32\glu32.dll"
Attempting to load: C:\Windows\System32\glu32.dll
Successfully loaded DLL: 0x00007FFC7A350000
Looking up function: gluErrorString
Successfully loaded function: 0x00007FFC7A35C650
Error string for value 100902: "out of memory" (0x000001E5757F51D0)
However, if I copy the DLL to my desktop and run the program again, although the DLL and function appear to be loaded, the string returned from the function is empty:
> GLU32Loader.exe "C:\Users\Jonathan\Desktop\glu32.dll"
Attempting to load: C:\Users\Jonathan\Desktop\glu32.dll
Successfully loaded DLL: 0x00007FFC8DDB0000
Looking up function: gluErrorString
Successfully loaded function: 0x00007FFC8DDBC650
Error string for value 100902: "" (0x0000025C5236E520)
Why would this be? It's exactly the same DLL, just in a different folder, and I would have thought that any other dependent DLLs that it references should still be available because they're all in System32. Is there some mystical property of Windows DLLs that I'm not familiar with that might cause this to happen?
This is an example of why one shall not mess around with system DLLs.
The DLL in question, like many Microsoft DLLs, uses MUI (Multilingual User Interface).
If you look at its resources, it has no resources except a MUI type resource, pointing to a folder containing the corresponding .mui file, which contains its actual (internationalized) resources.
So, if you still want to copy it, at least also copy the corresponding .mui file:
System32\glu32.dll → <my_files>\glu32.dll
System32\en-US\glu32.dll.mui → <my_files>\en-US\glu32.dll.mui
The en-US part may be different on your system depending on the default locale.
EDIT: I saw only now from your log that you didn't rename the file. Then I'm not sure what it can be. I'll leave this explanation up anyway because it would also be what happens if one were to rename that file, so maybe it is helpful to someone else...
It seems to me as if you renamed the DLL file (not just loaded it from another location but with another filename as well).
glu32.dll doesn't like to be renamed, because in some places code like GetModuleHandle("glu32.dll") is used instead of saving the hInstance received in DllMain into a global variable and using that handle (which is what should have been done, but unfortunately it isn't what Microsoft did). If you rename the DLL, this call will return NULL. Now unfortunately there also isn't much error handling going on in glu32 in that case.
The error strings are stored in global arrays of some sort, but they are lazy-loaded there from string table resources. The first time you call gluErrorString, the error strings are loaded using LoadString which takes the hInstance of the DLL. With the renamed DLL, this will be the bogus NULL handle, and calling LoadString(NULL, ...) will return 0, indicating an error. Normally the number returned is the length of the string. glu32 doesn't handle the zero case in any special way and just copies the zero characters to the array and happily returns an empty string to you at the end.

How to check if a file already exists before creating it? (C++, Unicode, cross platform)

I have the following code which works on Windows:
bool fileExists(const wstring& src)
{
#ifdef PLATFORM_WINDOWS
return (_waccess(src.c_str(), 0) == 0);
#else
// ???? how to make C access() function to accept the wstring on Unix/Linux/MacOS ?
#endif
}
How do I make the code work on *nix platforms the same way as it does on Windows, considering that scr is a Unicode string and might contain file path with Unicode characters?
I have seen various StackOverflow answers which partly answer my question but I have problems to put it all together. My system relies on wide strings, especially on Windows where file names might contain non-ASCII characters. I know that generally it's better to write to the file and check for errors, but my case is the opposite - I need to skip the file if it already exists. I just want to check if the file exists, no matter if I can read/write it or not.
On many filesystems other than FAT and NTFS, filenames aren't exactly well defined as strings. They're technically byte sequences. What those byte sequences mean is a matter of interpretation. A common interpretation is UTF-8-like. Not exact UTF-8, because Unicode specifies string equality regardless of encoding. Most systems use byte equality instead. (Again, FAT and NTFS are exceptions, using case-insensitive comparisons)
A good portable solution I use is to use the following:
ifstream my_file(myFilenameHere);
if (my_file.good())
{
// file exists and do what you need to do when it exists
}
else
{
// the file doesn't exist do what you need to do to create it etc.
}
For example a small file existence checker function could be (this one works in windows, linux and unix):
inline bool doesMyFileExist (const std::string& myFilename)
{
#if defined(__unix__) || defined(__posix__) || defined(__linux__ )
// all UNIXes, POSIX (including OS X I think (cant remember been a while)) and
// all the various flavours of Linus Torvalds digital offspring:)
struct stat buffer;
return (stat (myFilename.c_str(), &buffer) == 0);
#elif defined(__APPLE__)|| defined(_WIN32)
// this includes IOS AND OSX and Windows (x64 and x86)
// note the underscore in the windows define, without it can cause problems
if (FILE *file = fopen(myFilename.c_str(), "r"))
{
fclose(file);
return true;
}
else
{
return false;
}
#else // a catch-all fallback, this is the slowest method, but works on them all:)
ifstream myFile(myFilename.c_str());
if (myFile.good())
{
myFile.close();
return true;
}
else
{
myFile.close();
return false;
}
#endif
}
The function above uses the fastest possible method to check the file for each OS variant, and has a fallback in case you are on an os other than the ones explicitly listed (original Amiga OS for example). This has been used in GCC4.8.x and VS 2010/2012.
The good method will check that everything is as it should be, and this way you actually have the file open.
The only caveat is pay close attention to how the file name is represented in the OS (as mentioned in another answer).
So far this has worked cross platform for me just fine:)
I spent some hours experimenting on my Ubuntu machine. It took many trials and errors but finally I got it working. I'm not sure if it will work on MacOS or even on other *nixes.
As many suspected, direct casting to char* did not work - then I got only the first slash of my test path /home/progmars/абвгдāēī . The trick was to use wcstombs() combined with setlocale() Although I could not get the text to display in console after this conversion, still access() function got it right.
Here is the code which worked for me:
bool fileExists(const wstring& src)
{
#ifdef PLATFORM_WINDOWS
return (_waccess(src.c_str(), 0) == 0);
#else
// hopefully this will work on most *nixes...
size_t outSize = src.size() * sizeof(wchar_t) + 1;// max possible bytes plus \0 char
char* conv = new char[outSize];
memset(conv, 0, outSize);
// MacOS claims to have wcstombs_l which has locale argument,
// but I could not find something similar on Ubuntu
// thus I had to use setlocale();
char* oldLocale = setlocale(LC_ALL, NULL);
setlocale(LC_ALL, "en_US.UTF-8"); // let's hope, most machines will have "en_US.UTF-8" available
// "Works on my machine", that is, Ubuntu 12.04
size_t wcsSize = wcstombs(conv, src.c_str(), outSize);
// we might get an error code (size_t-1) in wcsSize, ignoring for now
// now be good, restore the locale
setlocale(LC_ALL, oldLocale);
return (access(conv, 0) == 0);
#endif
}
And here is some experimental code which led me to the solution:
// this is crucial to output correct unicode characters in console and for wcstombs to work!
// empty string also works instead of en_US.UTF-8
// setlocale(LC_ALL, "en_US.UTF-8");
wstring unicoded = wstring(L"/home/progmars/абвгдāēī");
int outSize = unicoded.size() * sizeof(wchar_t) + 1;// max possible bytes plus \0 char
char* conv = new char[outSize];
memset(conv, 0, outSize);
size_t szt = wcstombs(conv, unicoded.c_str(), outSize); // this needs setlocale - only then it returns 31. else it returns some big number - most likely, an error message
wcout << "wcstombs result " << szt << endl;
int resDirect = access("/home/progmars/абвгдāēī", 0); // works fine always
int resCast = access((char*)unicoded.c_str(), 0);
int resConv = access(conv, 0);
wcout << "Raw " << unicoded.c_str() << endl; // output /home/progmars/абвгдāēī but only if setlocale has been called; else output is /home/progmars/????????
wcout << "Casted " << (char*)unicoded.c_str() << endl; // output /
wcout << "Converted " << conv << endl; // output /home/progmars/ - for some reason, Unicode chars are cut away in the console, but still they are there because access() picks them up correctly
wcout << "resDirect " << resDirect << endl; // gives correct result depending on the file existence
wcout << "resCast " << resCast << endl; // wrong result - always 0 because it looks for / and it's the filesystem root which always exists
wcout << "resConv " << resConv << endl;
// gives correct result but only if setlocale() is present
Of course, I could avoid all that hassle with ifdefs to define my own version of string which would be wstring on Windows and string on *nix because *nix seems to be more liberal about UTF8 symbols and doesn't mind using them in plain strings. Still, I wanted to keep my function declarations consistent for all platforms and also I wanted to learn how Unicode filenames work in Linux.

Listing Folders in a Directory C+

I am aware that this may well be a duplicate. However, I am struggling to actually get a working answer.
What I am trying to do is list all of the folders in the working directory. Below is some code that I have adapted from the MS website (http://msdn.microsoft.com/en-us/library/windows/desktop/aa365200(v=vs.85).aspx)
This gives the output:
Filname:52428
I have checked the folder - and there are three folders that I am wanting to list 'Vidoe' 'John' 'David' I am not sure as to why it is printing out the result above.
I do not want to use Boost - nor to download any third party plugings.
int main(int argc, char** argv)
{
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA ffd;
//The Directory where the .exe is run from.
hFind = FindFirstFile(TEXT(".\\Players\\*"), &ffd);
do
{
Sleep(1000);
bool isDirectory = ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
if(isDirectory)
{
cout << "DirectoryName: " << *ffd.cFileName << endl;
}
else
{
cout << "FileName: " << *ffd.cFileName << endl;
}
}while(FindNextFile(hFind, &ffd) != 0);
FindClose(hFind);
}
EDIT:
I do not have a specific way that I want to do this, all I am wanting to do is output the Folders in the directory - I do not care how it is done.
In …
*ffd.cFileName
remove the *.
Also remove the call to Sleep.
Also remove the silly TEXT macro call, use wide string literals like L"blah".
Oh I forgot, also replace the do loop with a while loop (or for loop), because it's not sure that the FindFirstFile call will succeed.
Oh, and important, for the debug output use wcout, not cout. The latter doesn't know anything about output of Unicode strings. But wcout can handle them.
The output you're getting,
52428
appears to be wchar_t value 0xCCCC, treated as an integer by cout, which value indicates uninitialized storage, which implies that the FindFirstFile call failed.
So, also be sure about the current directory when you run the program. A good idea is to run it from the command line. Then you're sure.

c++, output of FindFirstFile()

I wrote the program of finding file using FindFirstFile(...) function. But when I try to print the output of this function, there is a several strings of unknown characters printed in console windows.
I read some posts, there was written to try using wcout instead of cout. I try it, but it doesn't help. I think, that the problem is in difference between ANSI and UNICODE encodings. Can somebody help me? I will be very thankful for any help!
Here is my code:
#include "FindFile.h"
#include <iostream>
using namespace std;
void FindFileCl::Execute(Input * input, Response * response )
{
WIN32_FIND_DATAA FindFileData;
HANDLE h = FindFirstFileA((input->FileName).c_str(), // name of the file
&FindFileData);
if (h)
{
cout << "Search Results:\n";
cout<<(FindFileData.cFileName);
CloseHandle(h);
}
else
{
cerr << "File is NOT found:" << GetLastError() << "\n";
}
}
If FindFirstFile() fails it returns INVALID_HANDLE_VALUE, not NULL:
If the function fails or fails to locate files from the search string in the lpFileName parameter, the return value is INVALID_HANDLE_VALUE and the contents of lpFindFileData are indeterminate. To get extended error information, call the GetLastError function.
and INVALID_HANDLE_VALUE is #defined as -1 (following macro located in WinBase.h):
#define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1)
Meaning the if (h) will be entered in either success or failure. In the event of failure, cFileName will not be modified resulting in junk being printed as it is not initialized. Change the if condition to explicitly check for INVALID_HANDLE_VALUE:
if (h != INVALID_HANDLE_VALUE)
{
}
One of the "least bad" ways would be to convert the Unicode name to the Console's encoding.
For this, I suggest compiling in Unicode (There's a project option for that in Visual Studio >=8; otherwise you have to define both UNICODE and _UNICODE manually), using the TCHAR version of FindFirstFile(), and then using CharToOem() or CharToOemBuff() (neither is perfect). -- Or alternately, use the W version followed by WideCharToMultiByte(CP_OEMCP).

Create a file at a given path using C++ in Linux

I want to create a file at a given path that is relative to the current directory. The following code behaves erratically. I some times see the file created and some times do not. That may be because of the change in the current directory. Here's the code.
//for appending timestamp
timeval ts;
gettimeofday(&ts,NULL);
std::string timestamp = boost::lexical_cast<std::string>(ts.tv_sec);
//./folder/inner_folder is an existing directory
std::string filename = "./folder/inner_folder/abc_"+timestamp+ ".csv";
std::ofstream output_file(filename);
output_file << "abc,efg";
output_file.close();
Now, the problem is the file is created only in some cases. That is when I have as a command line argument an input file from the current directory, it works fine.
./program input_file
If I have something like this, it does not work
./program ./folder1/input_file
I tried giving the full path as an argument for ofstream, I still don't see the files created.
What is the correct way to do this? Thanks
ofstream will not create missing directories in the file path, you must ensure the directories exist and if not create them using OS specific api or boost's file system library.
Always check the result of IO operations, and query system error code to determine reason for failures:
if (output_ file.is_open())
{
if (!(output_file << "abc,efg"))
{
// report error.
}
}
else
{
const int last_error = errno;
std::cerr << "failed to open "
<< filename
<< ": "
<< strerror(last_error)
<< std::endl;
}