Ejemplo n.º 1
0
DEBUG_LOCAL OSStatus	EnableNSP( const char *inGUID, BOOL inEnable )
{
	OSStatus		err;
	WSADATA			wsd;
	GUID			guid;
	
	require_action( inGUID && ( *inGUID != '\0' ), exit, err = kParamErr );
	
	err = StringToGUID( inGUID, &guid );
	require_noerr( err, exit );
	
	err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
	require_noerr( err, exit );
	
	err = WSCEnableNSProvider( &guid, inEnable );
	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
	WSACleanup();
	require_noerr( err, exit );
	
	if (!gToolQuietMode)
	{
		fprintf( stderr, "Removed NSP %s\n", inGUID );
	}
		
exit:
	if( err != kNoErr )
	{
		fprintf( stderr, "### FAILED (%d) to remove %s Name Space Provider\n", err, inGUID );
	}
	return( err );
}
Ejemplo n.º 2
0
OSStatus
CSecondPage::LoadPrinterNames()
{
	PBYTE		buffer	=	NULL;
	OSStatus	err		= 0;

	//
	// rdar://problem/3701926 - Printer can't be installed twice
	//
	// First thing we want to do is make sure the printer isn't already installed.
	// If the printer name is found, we'll try and rename it until we
	// find a unique name
	//
	DWORD dwNeeded = 0, dwNumPrinters = 0;

	BOOL ok = EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, NULL, 0, &dwNeeded, &dwNumPrinters);
	err = translate_errno( ok, errno_compat(), kUnknownErr );

	if ((err == ERROR_INSUFFICIENT_BUFFER) && (dwNeeded > 0))
	{
		try
		{
			buffer = new unsigned char[dwNeeded];
		}
		catch (...)
		{
			buffer = NULL;
		}
	
		require_action( buffer, exit, kNoMemoryErr );
		ok = EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, buffer, dwNeeded, &dwNeeded, &dwNumPrinters);
		err = translate_errno( ok, errno_compat(), kUnknownErr );
		require_noerr( err, exit );

		for (DWORD index = 0; index < dwNumPrinters; index++)
		{
			PRINTER_INFO_4 * lppi4 = (PRINTER_INFO_4*) (buffer + index * sizeof(PRINTER_INFO_4));

			m_printerNames[lppi4->pPrinterName] = lppi4->pPrinterName;
		}
	}

exit:

	if (buffer != NULL)
	{
		delete [] buffer;
	}

	return err;
}
OSStatus
CPrinterSetupWizardSheet::InstallPrinterIPP(Printer * printer, Service * service)
{
	DEBUG_UNUSED( service );

	HANDLE			hPrinter = NULL;
	PRINTER_INFO_2	pInfo;
	OSStatus		err;
	
	//
	// add the printer
	//
	ZeroMemory(&pInfo, sizeof(PRINTER_INFO_2));
	
	pInfo.pPrinterName		= printer->actualName.GetBuffer();
	pInfo.pPortName			= printer->portName.GetBuffer();
	pInfo.pDriverName		= printer->model.GetBuffer();
	pInfo.pPrintProcessor	= L"winprint";
	pInfo.pLocation			= service->location.GetBuffer();
	pInfo.Attributes		= PRINTER_ATTRIBUTE_NETWORK | PRINTER_ATTRIBUTE_LOCAL;
	
	hPrinter = AddPrinter(NULL, 2, (LPBYTE)&pInfo);
	err = translate_errno( hPrinter, errno_compat(), kUnknownErr );
	require_noerr( err, exit );

exit:

	if ( hPrinter != NULL )
	{
		ClosePrinter(hPrinter);
	}

	return err;
}
Ejemplo n.º 4
0
OSStatus	InstallNSP( const char *inName, const char *inGUID, const char *inPath )
{
	OSStatus		err;
	size_t			size;
	WSADATA			wsd;
	WCHAR			name[ 256 ];
	GUID			guid;
	WCHAR			path[ MAX_PATH ];
	
	require_action( inName && ( *inName != '\0' ), exit, err = kParamErr );
	require_action( inGUID && ( *inGUID != '\0' ), exit, err = kParamErr );
	require_action( inPath && ( *inPath != '\0' ), exit, err = kParamErr );
	
	size = strlen( inName );
	require_action( size < sizeof_array( name ), exit, err = kSizeErr );
	CharToWCharString( inName, name );
	
	err = StringToGUID( inGUID, &guid );
	require_noerr( err, exit );
	
	size = strlen( inPath );
	require_action( size < sizeof_array( path ), exit, err = kSizeErr );
	CharToWCharString( inPath, path );
	
	err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
	require_noerr( err, exit );
	
	err = WSCInstallNameSpace( name, path, NS_DNS, 1, &guid );
	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
	WSACleanup();
	require_noerr( err, exit );
	
	if (!gToolQuietMode)
	{
		fprintf( stderr, "Installed NSP \"%s\" (%s) at %s\n", inName, inGUID, inPath );
	}
	
exit:
	if( err != kNoErr )
	{
		fprintf( stderr, "### FAILED (%d) to install \"%s\" (%s) Name Space Provider at %s\n", err, inName, inGUID, inPath );
	}
	return( err );
}
Ejemplo n.º 5
0
unsigned WINAPI
CPrinterSetupWizardSheet::InstallDriverThread( LPVOID inParam )
{	
	Printer			*	printer = (Printer*) inParam;
	DWORD				exitCode = 0;
	DWORD				dwResult;
	OSStatus			err;
	STARTUPINFO			si;
	PROCESS_INFORMATION pi;
	BOOL				ok;

	check( printer );
	check( m_self );

	//
	// because we're calling endthreadex(), C++ objects won't be cleaned up
	// correctly.  we'll nest the CString 'command' inside a block so
	// that it's destructor will be invoked.
	//
	{
		CString command;

		ZeroMemory( &si, sizeof(si) );
		si.cb = sizeof(si);
		ZeroMemory( &pi, sizeof(pi) );

		command.Format(L"rundll32.exe printui.dll,PrintUIEntry /ia /m \"%s\" /f \"%s\"", (LPCTSTR) printer->modelName, (LPCTSTR) printer->infFileName );

		ok = CreateProcess(NULL, command.GetBuffer(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
		err = translate_errno( ok, errno_compat(), kUnknownErr );
		require_noerr( err, exit );

		dwResult = WaitForSingleObject( pi.hProcess, INFINITE );
		translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr );
		require_noerr( err, exit );

		ok = GetExitCodeProcess( pi.hProcess, &exitCode );
		err = translate_errno( ok, errno_compat(), kUnknownErr );
		require_noerr( err, exit );
	}

exit:

	//
	// Close process and thread handles. 
	//
	if ( pi.hProcess )
	{
		CloseHandle( pi.hProcess );
	}

	if ( pi.hThread )
	{
		CloseHandle( pi.hThread );
	}

	//
	// alert the main thread
	//
	m_self->PostMessage( WM_PROCESS_EVENT, err, exitCode );

	_endthreadex_compat( 0 );

	return 0;
}
Ejemplo n.º 6
0
OSStatus
CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * service, DWORD protocol )
{
	PRINTER_DEFAULTS	printerDefaults =	{ NULL,  NULL, SERVER_ACCESS_ADMINISTER };
	DWORD				dwStatus;
	DWORD				cbInputData		=	100;
	PBYTE				pOutputData		=	NULL;
	DWORD				cbOutputNeeded	=	0;
	PORT_DATA_1			portData;
	PRINTER_INFO_2		pInfo;
	HANDLE				hXcv			=	NULL;
	HANDLE				hPrinter		=	NULL;
	Queue			*	q;
	BOOL				ok;
	OSStatus			err;

	check(printer != NULL);
	check(printer->installed == false);

	q = service->queues.front();
	check( q );

	ok = OpenPrinter(L",XcvMonitor Standard TCP/IP Port", &hXcv, &printerDefaults);
	err = translate_errno( ok, errno_compat(), kUnknownErr );
	require_noerr( err, exit );

	//
	// BUGBUG: MSDN said this is not required, but my experience shows it is required
	//
	try
	{
		pOutputData = new BYTE[cbInputData];
	}
	catch (...)
	{
		pOutputData = NULL;
	}

	require_action( pOutputData, exit, err = kNoMemoryErr );
	
	//
	// setup the port
	//
	ZeroMemory(&portData, sizeof(PORT_DATA_1));
	wcscpy(portData.sztPortName, printer->portName);
    	
	portData.dwPortNumber	=	service->portNumber;
	portData.dwVersion		=	1;
    	
	portData.dwProtocol	= protocol;
	portData.cbSize		= sizeof PORT_DATA_1;
	portData.dwReserved	= 0L;
    	
	wcscpy(portData.sztQueue, q->name);
	wcscpy(portData.sztIPAddress, service->hostname); 
	wcscpy(portData.sztHostAddress, service->hostname);

	ok = XcvData(hXcv, L"AddPort", (PBYTE) &portData, sizeof(PORT_DATA_1), pOutputData, cbInputData,  &cbOutputNeeded, &dwStatus);
	err = translate_errno( ok, errno_compat(), kUnknownErr );
	require_noerr( err, exit );

	//
	// add the printer
	//
	ZeroMemory(&pInfo, sizeof(pInfo));
		
	pInfo.pPrinterName			=	printer->actualName.GetBuffer();
	pInfo.pServerName			=	NULL;
	pInfo.pShareName			=	NULL;
	pInfo.pPortName				=	printer->portName.GetBuffer();
	pInfo.pDriverName			=	printer->modelName.GetBuffer();
	pInfo.pComment				=	printer->displayModelName.GetBuffer();
	pInfo.pLocation				=	q->location.GetBuffer();
	pInfo.pDevMode				=	NULL;
	pInfo.pDevMode				=	NULL;
	pInfo.pSepFile				=	L"";
	pInfo.pPrintProcessor		=	L"winprint";
	pInfo.pDatatype				=	L"RAW";
	pInfo.pParameters			=	L"";
	pInfo.pSecurityDescriptor	=	NULL;
	pInfo.Attributes			=	PRINTER_ATTRIBUTE_QUEUED;
	pInfo.Priority				=	0;
	pInfo.DefaultPriority		=	0;
	pInfo.StartTime				=	0;
	pInfo.UntilTime				=	0;

	hPrinter = AddPrinter(NULL, 2, (LPBYTE) &pInfo);
	err = translate_errno( hPrinter, errno_compat(), kUnknownErr );
	require_noerr( err, exit );

exit:

	if (hPrinter != NULL)
	{
		ClosePrinter(hPrinter);
	}

	if (hXcv != NULL)
	{
		ClosePrinter(hXcv);
	}

	if (pOutputData != NULL)
	{
		delete [] pOutputData;
	}

	return err;
}
Ejemplo n.º 7
0
OSStatus
CPrinterSetupWizardSheet::InstallPrinter(Printer * printer)
{
	Service	*	service;
	BOOL		ok;
	OSStatus	err;

	service = printer->services.front();
	check( service );

	//
	// if the driver isn't installed, then install it
	//

	if ( !printer->driverInstalled )
	{
		DWORD		dwResult;
		HANDLE		hThread;
		unsigned	threadID;

		m_driverThreadFinished = false;
	
		//
		// create the thread
		//
		hThread = (HANDLE) _beginthreadex_compat( NULL, 0, InstallDriverThread, printer, 0, &threadID );
		err = translate_errno( hThread, (OSStatus) GetLastError(), kUnknownErr );
		require_noerr( err, exit );
			
		//
		// go modal
		//
		while (!m_driverThreadFinished)
		{
			MSG msg;
	
			GetMessage( &msg, m_hWnd, 0, 0 );
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	
		//
		// Wait until child process exits.
		//
		dwResult = WaitForSingleObject( hThread, INFINITE );
		err = translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr );
		require_noerr( err, exit );

		//
		// check the return value of thread
		//
		require_noerr( m_driverThreadExitCode, exit );

		//
		// now we know that the driver was successfully installed
		//
		printer->driverInstalled = true;
	}

	if ( service->type == kPDLServiceType )
	{
		err = InstallPrinterPDLAndLPR( printer, service, PROTOCOL_RAWTCP_TYPE );
		require_noerr( err, exit );
	}
	else if ( service->type == kLPRServiceType )
	{
		err = InstallPrinterPDLAndLPR( printer, service, PROTOCOL_LPR_TYPE );
		require_noerr( err, exit );
	}
	else if ( service->type == kIPPServiceType )
	{
		err = InstallPrinterIPP( printer, service );
		require_noerr( err, exit );
	}
	else
	{
		err = kUnknownErr;
		require_noerr( err, exit );
	}

	printer->installed = true;

	//
	// if the user specified a default printer, set it
	//
	if (printer->deflt)
	{
		ok = SetDefaultPrinter( printer->actualName );
		err = translate_errno( ok, errno_compat(), err = kUnknownErr );
		require_noerr( err, exit );
	}

exit:

	return err;
}
Ejemplo n.º 8
0
CThirdPage::CThirdPage()
    : CPropertyPage(CThirdPage::IDD),
      m_manufacturerSelected( NULL ),
      m_modelSelected( NULL ),
      m_genericPostscript( NULL ),
      m_genericPCL( NULL ),
      m_initialized(false),
      m_printerImage( NULL )
{
    static const int	bufferSize	= 32768;
    TCHAR				windowsDirectory[bufferSize];
    CString				header;
    WIN32_FIND_DATA		findFileData;
    HANDLE				findHandle;
    CString				prnFiles;
    CString				ntPrint;
    OSStatus			err;
    BOOL				ok;

    m_psp.dwFlags &= ~(PSP_HASHELP);
    m_psp.dwFlags |= PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE;

    m_psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_INSTALL_TITLE);
    m_psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_INSTALL_SUBTITLE);

    //
    // load printers from ntprint.inf
    //
    ok = GetWindowsDirectory( windowsDirectory, bufferSize );
    err = translate_errno( ok, errno_compat(), kUnknownErr );
    require_noerr( err, exit );

    //
    // <rdar://problem/4826126>
    //
    // If there are no *prn.inf files, we'll assume that the information
    // is in ntprint.inf
    //
    prnFiles.Format( L"%s\\%s", windowsDirectory, kVistaPrintFiles );
    findHandle = FindFirstFile( prnFiles, &findFileData );

    if ( findHandle != INVALID_HANDLE_VALUE )
    {
        CString absolute;

        absolute.Format( L"%s\\inf\\%s", windowsDirectory, findFileData.cFileName );
        err = LoadPrintDriverDefsFromFile( m_manufacturers, absolute, false );
        require_noerr( err, exit );

        while ( FindNextFile( findHandle, &findFileData ) )
        {
            absolute.Format( L"%s\\inf\\%s", windowsDirectory, findFileData.cFileName );
            err = LoadPrintDriverDefsFromFile( m_manufacturers, absolute, false );
            require_noerr( err, exit );
        }

        FindClose( findHandle );
    }
    else
    {
        ntPrint.Format(L"%s\\%s", windowsDirectory, kNTPrintFile);
        err = LoadPrintDriverDefsFromFile( m_manufacturers, ntPrint, false );
        require_noerr(err, exit);
    }

    //
    // load printer drivers that have been installed on this machine
    //
    err = LoadPrintDriverDefs( m_manufacturers );
    require_noerr(err, exit);

    //
    // load our own special generic printer defs
    //
    err = LoadGenericPrintDriverDefs( m_manufacturers );
    require_noerr( err, exit );

exit:

    return;
}
Ejemplo n.º 9
0
// -------------------------------------------------------
// LoadPrintDriverDefs
//
// This function is responsible for loading the print driver
// definitions of all print drivers that have been installed
// on this machine.
// -------------------------------------------------------
OSStatus
CThirdPage::LoadPrintDriverDefs( Manufacturers & manufacturers )
{
    BYTE	*	buffer			=	NULL;
    DWORD		bytesReceived	=	0;
    DWORD		numPrinters		=	0;
    OSStatus	err				=	0;
    BOOL		ok;

    //
    // like a lot of win32 calls, we call this first to get the
    // size of the buffer we need.
    //
    EnumPrinterDrivers(NULL, L"all", 6, NULL, 0, &bytesReceived, &numPrinters);

    if (bytesReceived > 0)
    {
        try
        {
            buffer = new BYTE[bytesReceived];
        }
        catch (...)
        {
            buffer = NULL;
        }

        require_action( buffer, exit, err = kNoMemoryErr );

        //
        // this call gets the real info
        //
        ok = EnumPrinterDrivers(NULL, L"all", 6, buffer, bytesReceived, &bytesReceived, &numPrinters);
        err = translate_errno( ok, errno_compat(), kUnknownErr );
        require_noerr( err, exit );

        DRIVER_INFO_6 * info = (DRIVER_INFO_6*) buffer;

        for (DWORD i = 0; i < numPrinters; i++)
        {
            Manufacturer	*	manufacturer;
            Model			*	model;
            CString				name;

            //
            // skip over anything that doesn't have a manufacturer field.  This
            // fixes a bug that I noticed that occurred after I installed
            // ProComm.  This program add a print driver with no manufacturer
            // that screwed up this wizard.
            //
            if (info[i].pszMfgName == NULL)
            {
                continue;
            }

            //
            // look for manufacturer
            //
            Manufacturers::iterator iter;

            //
            // save the name
            //
            name = NormalizeManufacturerName( info[i].pszMfgName );

            iter = manufacturers.find(name);

            if (iter != manufacturers.end())
            {
                manufacturer = iter->second;
            }
            else
            {
                try
                {
                    manufacturer = new Manufacturer;
                }
                catch (...)
                {
                    manufacturer = NULL;
                }

                require_action( manufacturer, exit, err = kNoMemoryErr );

                manufacturer->name	=	name;

                manufacturers[name]	=	manufacturer;
            }

            //
            // now look to see if we have already seen this guy.  this could
            // happen if we have already installed printers that are described
            // in ntprint.inf.  the extant drivers will show up in EnumPrinterDrivers
            // but we have already loaded their info
            //
            //
            if ( MatchModel( manufacturer, ConvertToModelName( info[i].pName ) ) == NULL )
            {
                try
                {
                    model = new Model;
                }
                catch (...)
                {
                    model = NULL;
                }

                require_action( model, exit, err = kNoMemoryErr );

                model->displayName		=	info[i].pName;
                model->name				=	info[i].pName;
                model->driverInstalled	=	true;

                manufacturer->models.push_back(model);
            }
        }
    }

exit:

    if (buffer != NULL)
    {
        delete [] buffer;
    }

    return err;
}
Ejemplo n.º 10
0
DEBUG_LOCAL OSStatus	ReorderNameSpaces( void )
{
	OSStatus				err;
	WSADATA					wsd;
	bool					started;
	int						n;
	int						i;
	DWORD					size;
	WSANAMESPACE_INFO *		array;
	WCHAR					name[ 256 ];
	WCHAR					path[ MAX_PATH ];
	
	array 	= NULL;
	started	= false;
		
	err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
	require_noerr( err, exit );
	started = true;
	
	// Build an array of all the NSPs. Call it first with NULL to get the size, allocate a buffer, then get them into it.
	
	size = 0;
	n = WSAEnumNameSpaceProviders( &size, NULL );
	err = translate_errno( n != SOCKET_ERROR, (OSStatus) GetLastError(), kUnknownErr );
	require_action( err == WSAEFAULT, exit, err = kUnknownErr );
	
	array = (WSANAMESPACE_INFO *) malloc( size );
	require_action( array, exit, err = kNoMemoryErr );
	
	n = WSAEnumNameSpaceProviders( &size, array );
	err = translate_errno( n != SOCKET_ERROR, (OSStatus) GetLastError(), kUnknownErr );
	require_noerr( err, exit );
	
	// Find the "Tcpip" NSP.
	
	for( i = 0; i < n; ++i )
	{
		if( strcmp( array[ i ].lpszIdentifier, "Tcpip" ) == 0 )
		{
			break;
		}
	}
	require_action( i < n, exit, err = kNotFoundErr );
	
	// Uninstall it then re-install it to move it to the end.
	
	size = (DWORD) strlen( array[ i ].lpszIdentifier );
	require_action( size < sizeof_array( name ), exit, err = kSizeErr );
	CharToWCharString( array[ i ].lpszIdentifier, name );
	
	size = (DWORD) strlen( "%SystemRoot%\\System32\\mswsock.dll" );
	require_action( size < sizeof_array( path ), exit, err = kSizeErr );
	CharToWCharString( "%SystemRoot%\\System32\\mswsock.dll", path );
	
	err = WSCUnInstallNameSpace( &array[ i ].NSProviderId );
	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
	require_noerr( err, exit );
	
	err = WSCInstallNameSpace( name, path, NS_DNS, array[ i ].dwVersion, &array[ i ].NSProviderId );
	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
	require_noerr( err, exit );
		
	// Success!
	
	fprintf( stderr, "Reordered \"Tcpip\" NSP to to the bottom of the NSP chain\n" );	
	err = kNoErr;
	
exit:
	if( array )
	{
		free( array );
	}
	if( started )
	{
		WSACleanup();
	}
	if( err != kNoErr )
	{
		fprintf( stderr, "### FAILED (%d) to reorder Name Space Providers\n", err );
	}
	return( err );
}
Ejemplo n.º 11
0
DEBUG_LOCAL OSStatus	ListNameSpaces( void )
{
	OSStatus				err;
	WSADATA					wsd;
	bool					started;
	int						n;
	int						i;
	DWORD					size;
	WSANAMESPACE_INFO *		array;
	char					s[ 256 ];
	
	array 	= NULL;
	started	= false;
	
	err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
	err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
	require_noerr( err, exit );
	started = true;
	
	// Build an array of all the NSPs. Call it first with NULL to get the size, allocate a buffer, then get them into it.
	
	size = 0;
	n = WSAEnumNameSpaceProviders( &size, NULL );
	err = translate_errno( n != SOCKET_ERROR, (OSStatus) GetLastError(), kUnknownErr );
	require_action( err == WSAEFAULT, exit, err = kUnknownErr );
	
	array = (WSANAMESPACE_INFO *) malloc( size );
	require_action( array, exit, err = kNoMemoryErr );
	
	n = WSAEnumNameSpaceProviders( &size, array );
	err = translate_errno( n != SOCKET_ERROR, (OSStatus) GetLastError(), kUnknownErr );
	require_noerr( err, exit );
	
	fprintf( stdout, "\n" );
	for( i = 0; i < n; ++i )
	{
		fprintf( stdout, "Name Space %d\n", i + 1 );
		fprintf( stdout, "    NSProviderId:   %s\n", GUIDtoString( &array[ i ].NSProviderId, sizeof( s ), s ) );
		fprintf( stdout, "    dwNameSpace:    %d\n", array[ i ].dwNameSpace );
		fprintf( stdout, "    fActive:        %s\n", array[ i ].fActive ? "YES" : "NO" );
		fprintf( stdout, "    dwVersion:      %d\n", array[ i ].dwVersion );
		fprintf( stdout, "    lpszIdentifier: \"%s\"\n", array[ i ].lpszIdentifier );
		fprintf( stdout, "\n" );
	}
	err = kNoErr;
	
exit:
	if( array )
	{
		free( array );
	}
	if( started )
	{
		WSACleanup();
	}
	if( err != kNoErr )
	{
		fprintf( stderr, "### FAILED (%d) to list Name Space Providers\n", err );
	}
	return( err );
}