I am trying to create a file with GENERIC_WRITE permission with a path entered by the user.
To get user input, I am using fwgets function.
VOID DoCreateFile() {
SIZE_T sAlloc = sizeof(WCHAR) * (MAX_WPATH + 1); // allocation size
// allocating space and checking if actually allocated
LPWSTR lpPath = (LPWSTR)malloc(sAlloc);
LPWSTR lpContent = (LPWSTR)malloc(sAlloc);
if (lpPath == NULL || lpContent == NULL) {
PrintLastError(L"malloc()", TRUE);
}
wprintf(L"Enter path of file: ");
fgetws(lpPath, sAlloc, stdin); // read the contents of stdin with space
wprintf(L"Enter content (max 256 chars): ");
fgetws(lpContent, sAlloc, stdin);
/*
Documentation: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
*/
HANDLE hFile = CreateFileW(lpPath, // path of file
GENERIC_WRITE, // creating file with write permission
FILE_SHARE_READ, // allow other process to open file for reading
NULL, // disallow handle inheritance
CREATE_ALWAYS, // overwrite file if exists, otherwise create a new one
FILE_ATTRIBUTE_NORMAL, // do not set any file attributes
NULL // not using any file template
);
if (hFile == INVALID_HANDLE_VALUE) {
PrintLastError(L"CreateFileW()", TRUE);
}
CloseHandle(hFile);
}
Error message printed by PrintLastError function: CreateFileW() Failed! The filename, directory name, or volume label syntax is incorrect.
The input I have entered on the console is
Enter path of file: c:\file.txt
Enter content (max 256 chars): s
I have also tried file path \\.\C:\file.txt.
FYI, when I replace lpPath with a wide string literal L"C:\\Files.txt", the function succeeds.
Related
New to C programming.
The following section of code attempts to read a tab-separated list of MD5 (32 chars) and corresponding description (up to 128 chars) from a text file (utf-8), but is causing the application to crash:
HANDLE hFile = CreateFileW(good_path, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return FALSE;
}
LPWSTR md5 = malloc(sizeof(wchar_t) * 32);
LPWSTR desc = malloc(sizeof(wchar_t) * 128);
int i;
while((i = fwscanf(hFile, L"%ls %ls", md5, desc)) != EOF)
{
if (i == 2) // OK
{
}
else // Something went wrong
{
}
}
CloseHandle(hFile);
return TRUE;
Few questions:
Is my use of malloc(...) correct?
What might be causing the crash?
Update 1
I've taken this code and made it into a standalone exe (rather than a DLL). Still crashes.
Update 2
Updated to fwscanf as per Chris's comment. Still crashes. If I comment out the while...fwscanf... line it exits properly.
CreateFileW() returns a Windows handle, which is sort of like a file number but different somehow. fwscanf() expects a FILE* not a Windows handle; to get a FILE* open your file with fopen() or _wfopen().
%s stores a null terminator. Malloc 33 and 129 chars.
%s stores a nul-terminated string under the address your provide. To store n significant characters without buffer overflow, you need to provide an address of n+1 long buffer.
This question already has answers here:
Returning a string from function
(3 answers)
Closed 7 years ago.
I'm currently using Code::Blocks 13.12 (compiler: GNU GCC) under Windows 10.
I'm trying to open a file and load its content, but fopen gives me troubles. The 'input.txt' exists in the same directory as my executable. I've already checked the permissions.
Function for getting the path:
char* getFileName()
{
char *fileName; /* the path of the .txt file */
char path[MAX_PATH];
/* get the path of the executable */
GetModuleFileName(NULL, path, MAX_PATH);
/* remove the name of the executable from the path */
PathRemoveFileSpec(path);
/* check case where path is directory root */
if(PathIsRoot(path))
strcat(path, "\\*");
/* add the name of the .txt file to the path */
strcat(path, "\\input.txt");
/* not sure if needed */
path[strlen(path)] = '\0';
fileName = strdup((char *) path);
return fileName;
}
Function for loading the contents of the file:
bool loadDict(char *fileName)
{
FILE *fp; /* file stream */
char line[LINE_SIZE]; /* each line of the file */
// other variables
/* try to open file for reading */
if((fp = fopen(fileName, "r")) == NULL)
{
fprintf(stderr, "Error: Could not open the file '%s' to read\n", fileName);
return false;
}
// stuff done
/* file is no longer needed, close it */
if(fclose(fp))
{
fprintf(stderr, "Error: Could not close the file '%s' to read\n", fileName);
return false;
}
return true; /* in case no problem has occured */
}
Main:
int main()
{
char *fileName;
fileName = getFileName();
/* try to load the dictionary into memory */
if(!loadDict(fileName))
{
fprintf(stderr, "Error: The dictionary could be not loaded into memory.\nProgram terminating...\n");
return 1;
}
// other stuff
return 0;
}
I'm getting both errors (could not open the file, could not load). I've already tried replacing '\' with '/' or using double slashes without success.
FILE *fp = fopen("path\\input.txt", "r");
Any help would be appreciated.
You're returning the address of a local variable in getFileName, which results in undefined behavior. This is a common pitfall in C.
You need to either: A) Allocate the string on the heap (using e.g. malloc) and return it.B) Have getFileName take a pointer to a caller-allocated buffer which it then populates.
Also, when debugging problems like this, don't just assume everything is working. Use printf to see what the value of filename is before you try to fopen it.
Your array path is a local variable whose scope is limited to function getFileName. Don't return its address .
Instead pass it from the calling function.
i am trying to open a file handler to a path i got from file,
i have input file which has a full path in it for example :
c:\def\es1.txt
i replaced the "\" char to double "\" so it will fit string format and then i am using :
myfile = fopen("temp.txt", "r");
while (fgets(line, line_size, myfile) != NULL){
printf("==============================\n");
printf(line);
system("PAUSE\n");
mbstowcs(wtext, line, strlen(line) + 1);//Plus null
_tprintf(wtext);
LPWSTR ptr = wtext;
hFile = CreateFile(wtext, // name of the write
GENERIC_WRITE, // open for writing
0, // do not share
NULL, // default security
OPEN_EXISTING, // create new file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attr. template
if (hFile == INVALID_HANDLE_VALUE)
{
DisplayError(TEXT("CreateFile"));
_tprintf(TEXT("Terminal failure: Unable to open file \"%s\" for write.\n"), wtext);
return;
}
else {
printf("yes!!!!!!!\n");
}
when the command _tprintf(wtext); occurs i see the string as it should be:
"c:\def\es1.txt"
but the CreateFile command fails:
FATAL ERROR: Unable to output error code.
ERROR: CreateFile failed with error code 123 as follows:
The filename, directory name, or volume label syntax is incorrect.
Terminal failure: Unable to open file "c:\\def\\es1.txt
" for write.
when i replace the wtext variable in CreateFile with :L"c:\\def\\es1.txt"
it works fine, what is the problem?
Are you sure that your file which contains the path doesn't contains any special char at the end ? Like a \r or \n ?
You can print the strlen and know if your string contains only classic char.
I replaced the "\" char to double "\" so it will fit string format
A backslash in a string is a backslash. That they must be escaped in string literals doesn't mean they must be doubled in every string you process. In other words, "\\" is a string literal containing exactly one backslash.
A file named c:\\def\\es1.txt with double-backslashes doesn't seem to exist, so opening fails. At least that's what I'm guessing. I'm not familiar with Windows; under Linux, double-slashes in file names are interpreted as one slash.
Thank you all, it was the newline and the need to clear the char var:
while (fgets(line, line_size, myfile) != NULL){
printf("==============================\n");
printf(line);
//solution
char deststring[BUFFER];
memset(deststring, '\0', sizeof deststring);
strncpy(deststring, line, strlen(line) - 1);
mbstowcs(wtext, deststring, strlen(deststring) + 1);//Plus null
_tprintf(wtext);
HANDLE hFile = CreateFile(LPCTSTR("filename"), // name of the write
GENERIC_READ | GENERIC_WRITE, // open for writing and reading
0, // do not share
NULL, // default security
OPEN_ALWAYS, // create new file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL);
if(hFile != INVALID_HANDLE_VALUE)
{
printf("Success.\n");
}
CloseHandle(hFile);
The operation succeeds but i can't find 'filename' on the disk.
Does CreateFile() actually creates file on the disk?
I tried a minimal program containing only your code and ... the file was correctly created in current directory ! But only if the program is compiled in ANSI mode, because the LPCTSTR only converts the pointer to be a LPCTSTR but does not convert from ANSI to UNICODE. Only the _T macro does that.
You should use GetCurrentDirectory to control where you try to write the file, and use TCHAR to be UNICODE compatible :
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
int main() {
LPTSTR dir;
DWORD cr = ::GetCurrentDirectory(0, NULL);
cr += 1;
dir = (LPTSTR) malloc(cr * sizeof(TCHAR));
cr = ::GetCurrentDirectory(cr, dir);
/* ::MessageBox(NULL, dir, _T("Current dir"), MB_OK); */
_tprintf(_T("Current dir : %s\n"), dir); // note the _tprintf and _T macro
free(dir);
HANDLE hFile = CreateFile(_T("filename"), // name of the write - _T
GENERIC_READ | GENERIC_WRITE, // open for writing and reading
0, // do not share
NULL, // default security
OPEN_ALWAYS, // create new file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL);
if(hFile != INVALID_HANDLE_VALUE)
{
printf("Success.\n");
}
CloseHandle(hFile);
return 0;
}
If I compile in UNICODE mode without the _T macro around "filename", the program does create a file, but its name is simply garbage
There is not much information, but here is a blind guess : your file is redirected to the VirtualStore.
Some locations, like "Program Files", are protected on the latest versions of Windows.
If your program is in a protected location and is not run as administrator, the read/write operations will be redirected to C:\Users\MYNAME\AppData\Local\VirtualStore\MYFOLDER.
Running your program as admin should correct this wherever it is located.
I have written a function as follows to read a text file and write the content into another text file with a different file name:
The read file function:
char *getFileContent (const char *fileName)
{
char errorBuffer[50];
//Prepare read file
FILE *pReadFile;
long bufferReadSize;
char *bufferReadFile; //This variable is going to be returned as file content
size_t readFileSize;
pReadFile = fopen (fileName, "rb");
if (pReadFile != NULL)
{
// Get file size.
fseek (pReadFile , 0 , SEEK_END);
bufferReadSize = ftell (pReadFile);
rewind (pReadFile);
// Allocate RAM to contain the whole file:
bufferReadFile = (char*) malloc (sizeof(char) * bufferReadSize);
if (bufferReadFile != NULL)
{
// Copy the file into the buffer:
readFileSize = fread (bufferReadFile, sizeof(char), bufferReadSize, pReadFile);
if (readFileSize == bufferReadSize)
{
return bufferReadFile;
fclose (pReadFile);
free (bufferReadFile);
} else {
//fread failed
sprintf (errorBuffer, "File reading failed for file:\n%s", fileName);
MessageBox (NULL, errorBuffer, "Error file reading", MB_ICONERROR | MB_OK);
}
} else {
//malloc failed
sprintf (errorBuffer, "Memory allocation failed for file:\n%s", fileName);
MessageBox (NULL, errorBuffer, "Error memory allocation", MB_ICONERROR | MB_OK);
}
} else {
//fopen failed
sprintf (errorBuffer, "File opening failed for file:\n%s", fileName);
MessageBox (NULL, errorBuffer, "Error file opening", MB_ICONERROR | MB_OK);
}
}
The write file code:
//Get file content from read file
char *fileContent = getFileContent (readFileName);
FILE *pWriteFile = fopen (writeFileName, "wb");
fwrite (fileContent, sizeof (char), strlen (fileContent), pWriteFile);
fclose (pWriteFile);
They successfully work together to read and write files. However, in the written file, at the end of it, some strange characters come out like this:
ýýýý««««««««îþîþîþ
Please kindly help me solve this problem. How can I avoid the final strange characters in the written file when they were not there in the original file?
fwrite (fileContent, sizeof (char), strlen (fileContent), pWriteFile);
strlen() doesn't work here because fileContent contains binary data. The binary data could contain a null byte which would mean strlen() would be too short, or it may not contain a null byte which means strlen() would read past fileContent until it finds a null byte. This would be a reason why you see garbage at the end.
Note also, in your read routine, that the fclose() and the free() never happen because they come after the return statement. But, note that you can't free() the data until after you write it.
On the other hand, if it's not a binary file, all you need is a terminating 0 at the end of the data and then strlen() would work. So in your read, you need to alloc another byte and make sure that byte is zero:
bufferReadFile = (char*) malloc (sizeof(char) * bufferReadSize + 1); // note the + 1
bufferReadFile[bufferReadSize] = 0; // the terminating null byte.