File Pointers and File Attributes in win32

Windows keeps a file pointer for each open file handle, indicating the current position in the file. When we open the file with CreateFile(), the pointer is set to the start of the file. The WriteFile() and ReadFile() functions transfer data to or from that position and increment the file pointer by the number of bytes processed. We can move the file pointer around the file using the SetFilePointerEx() function, which can handle 64-bit pointers.

The SetFilePointerEx() function uses the LARGE_INTEGER union, which is a 64-bit data type, for both the requested position and the actual position reached. The return value is a Boolean value that indicates success or failure. The function takes four parameters. The first parameter is the handle to the file. The second and third parameters are of type LARGE_INTEGER; the third parameter is a pointer to a LARGE_INTEGER. The final parameter is a DWORD value, which can be set to one of three named constants, FILE_BEGIN, FILE_CURRENT, and FILE_END.

#include "stdafx.h"

#include <Windows.h>

int main()
{
 HANDLE hFile;
 LARGE_INTEGER liMoveTo;
 LARGE_INTEGER liNewLocation;
 DWORD dwBytesWritten, dwBytesRead;
 TCHAR *tszText = _T("The President has been kidnapped by ninjas. Are you a bad enough dude to rescue the President?");
 TCHAR tszBuffer[256];

 hFile = CreateFile(_T("test.txt"), GENERIC_ALL, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

 if (hFile == INVALID_HANDLE_VALUE) {
 printf("Error creating file.\n");
 exit(EXIT_FAILURE);
 }

 if (WriteFile(hFile, tszText, _tcsclen(tszText) * sizeof(TCHAR), &dwBytesWritten, 0)) {
 printf("%d bytes written to the file.\n", dwBytesWritten);
 }
 else {
 printf("Error writting to the file.\n");
 exit(EXIT_FAILURE);
 }

 //for the union LARGE_INTEGER
 //we only need to set the field 'QuadPart'
 //let's jump ahead 44 characters
 liMoveTo.QuadPart = 44 * sizeof(TCHAR);

 SetFilePointerEx(hFile, liMoveTo, &liNewLocation, FILE_BEGIN);

 if (ReadFile(hFile, tszBuffer, 256, &dwBytesRead, 0)) {
 printf("File read from successfully.\n");
 printf("%d bytes read.\n", dwBytesRead);
 }

 tszBuffer[(dwBytesRead / sizeof(TCHAR))] = '';

 _tprintf(_T("%s\n"), tszBuffer);

 return 0;
}

We can get the file size via the GetFileSizeEx() function. Like SetFilePointerEx(), the GetFileSizeEx() function uses the LARGE_INTEGER union.

#include "stdafx.h"

#include <Windows.h>

int main()
{
 HANDLE hFile;
 LARGE_INTEGER liLength;
 

 hFile = CreateFile(_T("test.txt"), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

 if (hFile == INVALID_HANDLE_VALUE) {
 printf("Error acquiring file handle.");
 exit(EXIT_FAILURE);
 }

 GetFileSizeEx(hFile, &liLength);

 printf("The file size is %lld bytes\n", liLength.QuadPart);


 return 0;
}

File have attribute bits that store special information about the file. We can examine attribute bits with the GetFileAttributes() function. The GetFileAttributes() function returns a DWORD value that stores the attribute bits.

#include <Windows.h>

int main()
{
 DWORD dwValue = GetFileAttributes(_T("test.txt"));

 if (dwValue == INVALID_FILE_ATTRIBUTES) {
 printf("Error retrieving the file attribtues for the file.\n");
 exit(EXIT_FAILURE);
 }

 if (dwValue & FILE_ATTRIBUTE_ARCHIVE) {
 printf("Archive.\n");
 }
 if (dwValue & FILE_ATTRIBUTE_DIRECTORY) {
 printf("Directory.\n");
 }
 if (dwValue & FILE_ATTRIBUTE_HIDDEN) {
 printf("File is hidden.\n");
 }
 if (dwValue & FILE_ATTRIBUTE_NORMAL) {
 printf("File is normal.\n");
 }
 if (dwValue & FILE_ATTRIBUTE_ENCRYPTED) {
 printf("File is encrypted.\n");
 }
 if (dwValue & FILE_ATTRIBUTE_TEMPORARY) {
 printf("File is temporary.\n")
 }

 return 0;
}

It is also possible to set the file attributes using the SetFileAttributes() function. The SetFileAttributes() function accepts a file name and a DWORD value that represents a set of attribute bits to be set.

#include "stdafx.h"

#include <Windows.h>

int main()
{
 DWORD dwFileAttributes = FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN;

 if (SetFileAttributes(_T("test.txt"), dwFileAttributes)) {
 printf("File attributes altered.\n");
 }

 return 0;
}

Note that we combine multiple attributes with the binary or operator, |.

Getting Windows File Attributes

The GetFileAttributes() function retrieves the attribute settings for a file. It returns a DWORD value that can be AND-ed using the << operator to extract information.

Note that the GetFileAttributes() function takes a string filename and not a handle.

int _tmain(int argc, _TCHAR* argv[])
{
	char *file = "C:";
	DWORD dwAttrib;

	dwAttrib = GetFileAttributes(file);

	if(dwAttrib == 0xFFFFFFFF){
		printf("Error getting attributes.\n");
		exit(EXIT_FAILURE);
	}

	if(dwAttrib & FILE_ATTRIBUTE_NORMAL){
		printf("File is a normal file.\n");
	} 
	if(dwAttrib & FILE_ATTRIBUTE_DIRECTORY){
		printf("File is a directory.\n") ;
	} 
	if (dwAttrib & FILE_ATTRIBUTE_DEVICE){
		printf("File is a device.\n");
	} 
	if(dwAttrib & FILE_ATTRIBUTE_ARCHIVE){
		printf("File is an archive.\n");
	} 
	if(dwAttrib & FILE_ATTRIBUTE_COMPRESSED){
		printf("File is compressed.\n");
	} 
	if(dwAttrib & FILE_ATTRIBUTE_HIDDEN){
		printf("File is hidden.\n");
	} 
	if(dwAttrib & FILE_ATTRIBUTE_ENCRYPTED){
		printf("File is encrypted.\n");
	} 

	return 0;
}

The GetFileAttributes() function has a corresponding SetFileAttributes() function that can be used to set the attributes for a file. The SetFileAttributes() function takes two arguments, the first is the file name, and the second is a DWORD value that specifies the new attributes.

#include "windows.h"

void printAttributes(DWORD fileAttributes);

int _tmain(int argc, _TCHAR* argv[])
{
	char *filename = "test.txt";
	DWORD dwCurrentAttrib, dwNewAttrib;

	HANDLE hwFile = CreateFile(
		filename,
		GENERIC_READ | GENERIC_WRITE,
		0,
		NULL,
		CREATE_ALWAYS,
		FILE_ATTRIBUTE_NORMAL,
		NULL
		);

	if(hwFile==INVALID_HANDLE_VALUE){
		printf("Error opening/creating file.\n");
		exit(EXIT_FAILURE);
	} else {
		CloseHandle(hwFile);
	}

	dwCurrentAttrib = GetFileAttributes(filename);
	printAttributes(dwCurrentAttrib);

	dwNewAttrib = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY;
	if(SetFileAttributes(filename, dwNewAttrib)){
		printf("File attributes modified successfully.\n");
	} else {
		printf("File attributes could not be modified.\n");
		exit(EXIT_FAILURE);
	}

	dwCurrentAttrib = GetFileAttributes(filename);
	printAttributes(dwCurrentAttrib);

	if(SetFileAttributes(filename, FILE_ATTRIBUTE_NORMAL)){
		printf("File attributes modified successfully.\n");
	}

	printAttributes(GetFileAttributes(filename));
	

	return 0;
}

void printAttributes(DWORD fileAttributes){
	printf("Attributes: ");
	if(fileAttributes == INVALID_FILE_ATTRIBUTES){
		printf("File attribute is invalid.\n");
		return;
	}
	if(fileAttributes & FILE_ATTRIBUTE_NORMAL){
		printf("Normal file. ");
	}
	if(fileAttributes & FILE_ATTRIBUTE_DIRECTORY){
		printf("Directory. ");
	}
	if(fileAttributes & FILE_ATTRIBUTE_HIDDEN){
		printf("File is hidden. ");
	}
	if(fileAttributes & FILE_ATTRIBUTE_READONLY){
		printf("File is read only. ");
	}
	if(fileAttributes & FILE_ATTRIBUTE_ARCHIVE){
		printf("Archive. ");
	}
	if(fileAttributes & FILE_ATTRIBUTE_TEMPORARY){
		printf("Temporary. ");	
	}
	printf("\n");
}

Note that the SetFileAttributes() function returns a Boolean value.