News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

CreateFile returns ERROR_NOACCESS

Started by sys64738, October 26, 2013, 09:35:44 PM

Previous topic - Next topic

sys64738

I don't really understand this. I have written a small helperfunction which gets a pathname and a pointer with size to save it to a file. I used this function in the maincode and it worked. Now I moved it to a separate function and suddenly CreateFile returns INVALID_HANDLE_VALUE and GetLastError() returns ERROR_NOACCESS (3E6h).

The only thing I changed was that now I put the filename on the stack (because I didn't want to bother with malloc/free). So I thought, maybe the adress must be aligned, or it doesn't accept filenames on the stack, so I copied the filename for testing into a variable in .data? but this also doesn't help.

Any ideas whats wrong?

This is the version with the pointer in a stackvariable


_writeFile proc pFilename: PTR byte, pData: PTR byte, nDataLen: DWORD

LOCAL BytesWritten:DWORD

invoke CreateFile, pFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL


And this is where I added code to make the pointer aligned and not on the stack:

_writeFile proc pFilename: PTR byte, pData: PTR byte, nDataLen: DWORD

LOCAL BytesWritten:DWORD

mov eax, pFilename
lea edx, BufferMem
call strcpy
lea eax, BufferMem

invoke CreateFile, eax, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL


The filepath is correct. I copied it directly from the variable in a shell and when I create the file from the shell, the file is created.


echo > c:\mypath.txt


dedndave

what you are not showing us is the code that worked   :(

but - that's ok
it's possible that some other program has the file opened
for example - a previous instance of your program did not terminate or close the handle
because you are using FILE_SHARE_READ, the only mode it may then be opened is read
make sure you close the handle when you are done

when i create a file for write-only operations, i generally use
    INVOKE  CreateFile,lpFileName,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL
which appears to be what you have

so - that means that the OS has a lock on the file for some reason
or - you aren't getting a valid name to it

lea eax, BufferMem
this line may be a problem
i take it that BufferMem is a variable with a pointer to the buffer
in that case, use it directly...
...CreateFile,BufferMem,GENERIC_WRITE....
the way it looks, you are passing the address of the BufferMem variable - not the string address

the CreateFile function does not care what kind of buffer you have
it does want a valid path/file name string - with a null terminator
i don't think it has to be aligned
except the UNICODE version - some UNICODE functions require 16-aligned string buffers

to test the file name pointer, just temporarily replace the CreateFile call with MessageBox
use the same pointer you are passing to CreateFile
if it doesn't display the path/file string - you have found the problem
    INVOKE  MessageBox,0,BufferMem,0,MB_OK

sys64738

Thanks for oyur reply. The OS doesn't have a lock. I also though of this, and even rebooted, to make sure that this is not happening. As I said, when I create the file in a shell, it works.

But looking at this in the meantime, I found out what the problem is, though I still don't understand it.
If the filename is not exactly 12 characters long, then it works. If the filename is longer or shorter it fails????

So this works:

FileName db '123456789012', 0


But this not:

FileName db '12345678901', 0
or
FileName db '1234567890123', 0



BufferMem is a byte array, just like in the above example. I also traced throug hthe create file function. The first thing it does is to call a function that converst my path to UNICODE and this path is definitely correct, as well as the pointer.

dedndave

you have something odd going on there - lol
i have never heard of anything like that

but - we need more complete code to be much help
post a complete source, and i will have a look

sys64738

I see if I can create a small sample that demonstrates it. Maybe this wil help me to find the problem, and if not then I can post it. I sure don't understand this either, as I have never seen such a strange problem. :)

The Messagebox is a good idea, I'll test this.

dedndave


dedndave

this seems to work ok...
    push    0
    push    'eliF'
    push    'tseT'
    mov     edx,esp
    INVOKE  CreateFile,edx,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL
    add     esp,12
    INVOKE  CloseHandle,eax

an empty file named "TestFile" is created
and - the second time - the file is overwritten with a new one

sys64738

I'm not using UNICODE, but CreateFileA converts the path to a UNICODE string and forwards the parameters to CreateFileW. Most of the ANSI functions in Windows simply convert to UNICODE and then call the W version.

The messagebox shows exactly what it should, so that works fine, as expected. I also checked the stack for corruption and this also looks good.

dedndave

then you aren't doing it right   :biggrin:
post some code

sys64738

I finally found the problem. The funny thing is that it was a problem I already anticipated but fixed in the wrong position. :)

I figured that the stack should be aligned on an even address, so I added a check for the pathname to make the stack aligned. However, I did it in the wrong position, so it was NOT aligned when calling CreateFile(). That was the reason why it worked with 12 character filenames, because in this case it happend to be aligned correct.

Now I moved the alignment check after constructing the full path (where it belongs), and now it works. :)

Thanks for your help!


To make it more understandable:

The function takes a directory and a file as two arguments. It calulates the total length of the path and checks if the directory has a `\` so it will yield a valid path when concatenating. My alignment check aligned only the directory path, instead of the full path, so the stackpointer became uneven when the filename was of a different size.


SaveToFile proc pBasepath: PTR byte, pFilename: PTR byte, pData: PTR byte, nMemSize:DWORD

LOCAL pPath: PTR byte
LOCAL StackPathlen:DWORD
LOCAL Path:byte

; Calculate the stringlength of the path plus the filename, plus a missing backslash
; and 0-Byte. We copy the path on the stack, so we wont have to malloc
mov eax, pBasepath
mov esi, eax
call strlen
mov edx, eax

inc eax ; Room for the 0-Byte
inc eax ; If the '\' is missing we need another character
mov edi, eax

; alignment check was here so it could become missaligned.

mov ebx, eax
mov eax, pFilename
call strlen
add ebx, eax

; Check if the stack will be aligned
test ebx, 1
je @@Aligned

inc ebx

@@Aligned:
sub esp, ebx
mov StackPathlen, ebx
mov ebx, eax

; Copy the basepath
mov ecx, edx
mov eax, esi
mov edx, esp
call memcpy

; Append the filename to the path.
; If the path is given without a '\' at the end, we have to append it.
lea edx, [esp+edx-1]
cmp byte ptr [edx], '\'
je @@AppendFile

inc edx
mov byte ptr [edx], '\'

@@AppendFile:
inc ebx ; include the 0-Byte
inc edx
mov ecx, ebx
mov eax, pFilename
call memcpy

mov eax, esp
invoke writeFile, eax, pData, nMemSize

add esp, StackPathlen
ret

SaveToFile endp


dedndave