[cvsnt] Problem with NTFS-Extended Attributes

Andreas Winter awinter at codewrights.biz
Fri Dec 3 13:16:37 GMT 2004


Community technical support mailing list was retired 2010 and replaced with a professional technical support team. For assistance please contact: Pre-sales Technical support via email to sales@march-hare.com.


Hello,

we run a CVSNT-Client on Windows-2000 and XP (2.0.58d) using a 
Standard-CVS Server on Linux.

Whenever a file is produced from the CVSNT-Client 
(checkout/update/export) this file has so called Extended-Attributes 
which are only defined in NTFS. These EAs are not set prior checkin by 
us. These EAs are not visible using Explorer and we dont know the 
meaning of it. The effect is that such files can not be copied into our 
samba fileserver. It creates an empty file on the target dir but stops 
with an error about "source may be in use" - which is wrong of course.
They can be copied when the destination is using NTFS or FAT.
When the files are zipped/unzipped the EAs are deleted and the file then 
can be copied everywhere.
The question is - is that a bug or a feature of CVSNT?
Can anybody reproduce the behaviour?
Is the EA using configurable (switch off)?
Which information is stored into the EA?
Do we have maybe misconfigured our samba (running unchanged since years)?

Best regards,
	Andreas Winter

PS:
Below is the output of a tool showing the attributes (source below)
for a fresh file produced from cvsnt.

stream [0] "":
   type: security
   size: 176

stream [0] "":
   type: data
   size: 469

stream [0] "":
   type: extended attributes
   size: 22

After zipping/unzipping the part with type: extended attributes is missing.

Below is a source we found - which can display the EA in a file.
We found that source during a google session - it is not from us.

---------------------------------------

// ntfsstream.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

typedef unsigned char byte;


#pragma hdrstop



#define err doerr( __FILE__, __LINE__ )


void doerr( const char *file, int line )
{
	DWORD e;

	e = GetLastError();
	if ( e == 0 )
		return;

	printf( "%s(%d): gle = %lu\n", file, line, e );
	exit( 2 );
}

void enableprivs()
{
	HANDLE hToken;
	byte buf[sizeof TOKEN_PRIVILEGES * 2];
	TOKEN_PRIVILEGES & tkp = *( (TOKEN_PRIVILEGES *) buf );

	if ( ! OpenProcessToken( GetCurrentProcess(),
		TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) )
		err;

	// enable SeBackupPrivilege, SeRestorePrivilege

	if ( !LookupPrivilegeValue( NULL, SE_BACKUP_NAME, 
&tkp.Privileges[0].Luid ) )
		err;

	if ( !LookupPrivilegeValue( NULL, SE_RESTORE_NAME, 
&tkp.Privileges[1].Luid ) )
		err;

	tkp.PrivilegeCount = 2;
	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	tkp.Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;

	AdjustTokenPrivileges( hToken, FALSE, &tkp, sizeof tkp,
		NULL, NULL );
}



void dumphdr( WIN32_STREAM_ID & wsi )
{
	const char *p;

	printf( "\nstream [%lu] \"%S\":\n", wsi.dwStreamNameSize,
		wsi.dwStreamNameSize? wsi.cStreamName: L"" );
	switch ( wsi.dwStreamId )
	{
	case BACKUP_DATA:
		p = "data";
		break;
	case BACKUP_EA_DATA:
		p = "extended attributes";
		break;
	case BACKUP_SECURITY_DATA:
		p = "security";
		break;
	case BACKUP_ALTERNATE_DATA:
		p = "other streams";
		break;
	case BACKUP_LINK:
		p = "link";
		break;
	default:
		p = "unknown";
		break;
	}
	printf( "  type: %s\n", p );
	printf( "  size: %I64d\n", wsi.Size.QuadPart );
}



int main( int argc, char *argv[] )
{
	HANDLE fh;

	if ( argc != 2 )
	{
		printf( "usage: dump_ntfs_streams {file}\n" );
		return 1;
	}

	// SeBackupPrivilege is not necessary to enumerate streams --
	// but it helps if you are an admin/backup-operator and need
	// to scan files to which you have no permissions
	enableprivs();

	fh = CreateFile( argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING,
		FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, NULL );
	if ( fh == INVALID_HANDLE_VALUE || fh == NULL )
		err;

	byte buf[4096];
	DWORD numread, numtoskip;
	void *ctx = NULL;
	WIN32_STREAM_ID & wsi = *( (WIN32_STREAM_ID *) buf );

	numtoskip = 0;
	while ( 1 )
	{
		// we are at the start of a stream header. read it.
		if ( ! BackupRead( fh, buf, 20, &numread, FALSE, TRUE, &ctx ) )
			err;

		if ( numread == 0 )
			break;

		if ( wsi.dwStreamNameSize > 0 )
		{
			if ( ! BackupRead( fh, buf + 20, wsi.dwStreamNameSize, &numread, 
FALSE, TRUE, &ctx ) )
				err;

			if ( numread != wsi.dwStreamNameSize )
				break;
		}

		dumphdr( wsi );

		// skip stream data
		if ( wsi.Size.QuadPart > 0 )
		{
			DWORD lo, hi;
			BackupSeek( fh, 0xffffffffL, 0x7fffffffL, &lo, &hi, &ctx );
		}
	}

	// make NT release the context
	BackupRead( fh, buf, 0, &numread, TRUE, FALSE, &ctx );

	CloseHandle( fh );

	return 0;
}

---------------------------
Best regards,
	Andreas Winter




More information about the cvsnt mailing list
Download the latest CVSNT, TortosieCVS, WinCVS etc. for Windows 8 etc.
@CVSNT on Twitter   CVSNT on Facebook