Esempio n. 1
0
//
// Corvus_Format_Drive (Prep Mode Only)
//
// Write the pattern provided across the entire disk
//
// Pass:
//      pattern: 512-byte buffer containing the pattern to write to the whole drive
//
// Returns:
//      Status of command
//
UINT8 corvus_hdc_t::corvus_format_drive(UINT8 *pattern, UINT16 len) {
	UINT32  sector;
	UINT32  max_sector;
	UINT8   status = 0;
	UINT8   tbuffer[512];

	// Set up m_tracks_per_cylinder and m_sectors_per_track
	corvus_hdc_file(m_prep_drv);

	max_sector = m_sectors_per_track * m_tracks_per_cylinder * m_cylinders_per_drive;

	//
	// If we were passed less than 512 bytes, fill the buffer up with the first byte passed (for Omnidrive Format command)
	//
	if(len < 512) {
		memset(tbuffer, *pattern, 512);
		pattern = tbuffer;
	}

	LOG(("corvus_format_drive: Formatting drive with 0x%5.5x sectors, pattern buffer (passed length: %d) follows\n", max_sector, 512));
	LOG_BUFFER(pattern, 512);

	for(sector = 0; sector <= max_sector; sector++) {
		status = corvus_write_sector(m_prep_drv, sector, pattern, 512);
		if(status != STAT_SUCCESS) {
			logerror("corvus_format_drive: Error while formatting drive in corvus_write_sector--sector: 0x%5.5x, status: 0x%x2.2x\n",
				sector, status);
			break;
		}
	}

	return status;
}
Esempio n. 2
0
//
// Corvus_Read_Sector
//
// Read a variably-sized chunk of data from the CHD file
//
// Pass:
//      drv:    Corvus drive id (1..15)
//      sector: Physical sector number to read from
//      buffer: Buffer to hold the data read from the disk
//      len:    Length of the buffer
//
// Returns:
//      status: Corvus status
//
UINT8 corvus_hdc_t::corvus_read_sector(UINT8 drv, UINT32 sector, UINT8 *buffer, int len) {
	hard_disk_file
			*disk;              // Structures for interface to CHD routines
	UINT8   tbuffer[512];       // Buffer to store full sector results in
	UINT16  cylinder;

	LOG(("corvus_read_sector: Read Drive: %d, physical sector: 0x%5.5x\n", drv, sector));

	disk = corvus_hdc_file(drv);
	if(!disk) {
		logerror("corvus_read_sector: Failure returned by corvus_hdc_file(%d)\n", drv);
		return STAT_FATAL_ERR | STAT_DRIVE_NOT_ONLINE;
	}

	//
	// Calculate what cylinder the sector resides on for timing purposes
	//
	cylinder = (double) sector / (double) m_sectors_per_track / (double) m_tracks_per_cylinder;
	m_delay = abs(m_last_cylinder - cylinder) * TRACK_SEEK_TIME + INTERSECTOR_DELAY;

	hard_disk_read(disk, sector, tbuffer);

	memcpy(buffer, tbuffer, len);

	m_last_cylinder = cylinder;

	LOG(("corvus_read_sector: Data read follows:\n"));
	LOG_BUFFER(tbuffer, len);

	return STAT_SUCCESS;
}
Esempio n. 3
0
//
// Corvus_Write_Sector
//
// Write a variably-sized chunk of data to the CHD file
//
// Pass:
//      drv:    Corvus drive id (1..15)
//      sector: Physical sector number to write to
//      buffer: Buffer to write
//      len:    Length of the buffer (amount of data to write)
//
// Returns:
//      status: Command status
//
UINT8 corvus_hdc_t::corvus_write_sector(UINT8 drv, UINT32 sector, UINT8 *buffer, int len) {
	hard_disk_file
			*disk;              // Structures for interface to CHD routines
	UINT8   tbuffer[512];       // Buffer to hold an entire sector
	UINT16  cylinder;           // Cylinder this sector resides on

	LOG(("corvus_write_sector: Write Drive: %d, physical sector: 0x%5.5x\n", drv, sector));

	disk = corvus_hdc_file(drv);
	if(!disk) {
		logerror("corvus_write_sector: Failure returned by corvus_hdc_file(%d)\n", drv);
		return STAT_FATAL_ERR | STAT_DRIVE_NOT_ONLINE;
	}

	//
	// Calculate what cylinder the sector resides on for timing purposes
	//
	cylinder = (double) sector / (double) m_sectors_per_track / (double) m_tracks_per_cylinder;
	m_delay = abs(m_last_cylinder - cylinder) * TRACK_SEEK_TIME + INTERSECTOR_DELAY;

	//
	// Corvus supports write sizes of 128, 256 and 512 bytes.  In the case of a write smaller than
	// the sector size of 512 bytes, the sector is read, the provided data is overlayed and then the
	// sector is written back out.  See pp. 5 of the Mass Storage Systems GTI for the details of this
	// wonderful functionality.
	//
	if(len == 512) {
		hard_disk_write(disk, sector, buffer);
	} else {
		hard_disk_read(disk, sector, tbuffer);      // Read the existing data into our temporary buffer
		memcpy(tbuffer, buffer, len);                   // Overlay the data with the buffer passed
		m_delay += INTERSECTOR_DELAY;                  // Add another delay because of the Read / Write
		hard_disk_write(disk, sector, tbuffer);     // Re-write the data
	}

	m_last_cylinder = cylinder;

	LOG(("corvus_write_sector: Full sector dump on a write of %d bytes follows:\n", len));
	LOG_BUFFER(len == 512 ? buffer : tbuffer, 512);

	return STAT_SUCCESS;
}
Esempio n. 4
0
//
// corvus_enter_prep_mode
//
// Enter prep mode.  In prep mode, only prep mode commands may be executed.
//
// A "prep block" is 512 bytes of machine code that the host sends to the
// controller.  The controller will jump to this code after receiving it,
// and it is what actually implements prep mode commands.  This HLE ignores
// the prep block from the host.
//
// On the Rev B/H drives (which we emulate), a prep block is Z80 machine
// code and only one prep block can be sent.  Sending the "put drive into
// prep mode" command (0x11) when already in prep mode is an error.  The
// prep block sent by the Corvus program DIAG.COM on the SSE SoftBox
// distribution disk returns error 0x8f (unrecognized command) for this case.
//
// On the OmniDrive and Bank, a prep block is 6801 machine code.  These
// controllers allow multiple prep blocks to be sent.  The first time the
// "put drive into prep mode" command is sent puts the drive into prep mode.
// The command can then be sent again up to 3 times with more prep blocks.
// (Mass Storage GTI, pages 50-51)
//
// Pass:
//      drv:        Corvus drive id (1..15) to be prepped
//      prep_block: 512 bytes of machine code, contents ignored
//
// Returns:
//      Status of command
//
UINT8 corvus_hdc_t::corvus_enter_prep_mode(UINT8 drv, UINT8 *prep_block) {
	// on rev b/h drives, sending the "put drive into prep mode"
	// command when already in prep mode is an error.
	if (m_prep_mode) {
		logerror("corvus_enter_prep_mode: Attempt to enter prep mode while in prep mode\n");
		return STAT_FATAL_ERR | STAT_ILL_CMD_OP_CODE;
	}

	// check if drive is valid
	if (!corvus_hdc_file(drv)) {
		logerror("corvus_enter_prep_mode: Failure returned by corvus_hdc_file(%d)\n", drv);
		return STAT_FATAL_ERR | STAT_DRIVE_NOT_ONLINE;
	}

	LOG(("corvus_enter_prep_mode: Prep mode entered for drive %d, prep block follows:\n", drv));
	LOG_BUFFER(prep_block, 512);

	m_prep_mode = true;
	m_prep_drv = drv;
	return STAT_SUCCESS;
}
Esempio n. 5
0
//
// Corvus_Process_Command_Packet
//
// Having received a complete packet from the host, process it
//
// Pass:
//      Invalid_Command_Flag:   Invalid command flag responses are handled in this routine
//
// Returns:
//      Nothing
//
void corvus_hdc_t::corvus_process_command_packet(bool invalid_command_flag) {
	if (VERBOSE_RESPONSES)
	{
		LOG(("corvus_hdc_data_w: Complete packet received.  Dump follows:\n"));
		LOG_BUFFER(m_buffer.raw_data, m_offset);
	}

	if(!invalid_command_flag) {
		if(!m_prep_mode) {
			switch(m_buffer.command.code) {
				//
				// Read / Write Chunk commands
				//
				case READ_CHUNK_128:
					m_buffer.read_128_response.status =
						corvus_read_logical_sector(&m_buffer.read_sector_command.dadr, m_buffer.read_128_response.data, 128);
					break;
				case READ_SECTOR_256:
				case READ_CHUNK_256:
					m_buffer.read_256_response.status =
						corvus_read_logical_sector(&m_buffer.read_sector_command.dadr, m_buffer.read_256_response.data, 256);
					break;
				case READ_CHUNK_512:
					m_buffer.read_512_response.status =
						corvus_read_logical_sector(&m_buffer.read_sector_command.dadr, m_buffer.read_512_response.data, 512);
					break;
				case WRITE_CHUNK_128:
					m_buffer.single_byte_response.status =
						corvus_write_logical_sector(&m_buffer.write_128_command.dadr, m_buffer.write_128_command.data, 128);
					break;
				case WRITE_SECTOR_256:
				case WRITE_CHUNK_256:
					m_buffer.single_byte_response.status =
						corvus_write_logical_sector(&m_buffer.write_256_command.dadr, m_buffer.write_256_command.data, 256);
					break;
				case WRITE_CHUNK_512:
					m_buffer.single_byte_response.status =
						corvus_write_logical_sector(&m_buffer.write_512_command.dadr, m_buffer.write_512_command.data, 512);
					break;
				//
				// Semaphore commands
				//
				case SEMAPHORE_LOCK_CODE:
			//  case SEMAPHORE_UNLOCK_CODE:
				case SEMAPHORE_INIT_CODE:
			//  case SEMAPHORE_STATUS_CODE:
					switch(m_buffer.command.modifier) {
						case SEMAPHORE_LOCK_MOD:
							m_buffer.semaphore_locking_response.status = corvus_lock_semaphore(m_buffer.lock_semaphore_command.name);
							break;
						case SEMAPHORE_UNLOCK_MOD:
							m_buffer.semaphore_locking_response.status =
								corvus_unlock_semaphore(m_buffer.unlock_semaphore_command.name);
							break;
						case SEMAPHORE_INIT_MOD:
							m_buffer.single_byte_response.status = corvus_init_semaphore_table();
							break;
						case SEMAPHORE_STATUS_MOD:
							m_buffer.semaphore_status_response.status =
								corvus_read_sector(1, 7, m_buffer.semaphore_status_response.table, 256);
							break;
						default:
							invalid_command_flag = true;
					}
					break;
				//
				// Miscellaneous commands
				//
				case BOOT:
					m_buffer.read_512_response.status =
						corvus_read_boot_block(m_buffer.old_boot_command.boot_block);
					break;
				case GET_DRIVE_PARAMETERS:
					m_buffer.drive_param_response.status =
						corvus_get_drive_parameters(m_buffer.get_drive_parameters_command.drive);
					break;
				case PREP_MODE_SELECT:
					m_buffer.single_byte_response.status =
						corvus_enter_prep_mode(m_buffer.prep_mode_command.drive,
							m_buffer.prep_mode_command.prep_block);
					break;
				default:
					m_xmit_bytes = 1;                      // Return a fatal status
					m_buffer.single_byte_response.status = STAT_FAULT | STAT_FATAL_ERR;
					logerror("corvus_hdc_data_w: Unimplemented command, returning FATAL FAULT status!\n");
					break;
			}
		} else {    // In Prep mode
			switch(m_buffer.command.code) {
				case PREP_MODE_SELECT:
					// when already in prep mode, some drives allow this command to
					// be sent again.  see corvus_enter_prep_mode() for details.
					m_buffer.single_byte_response.status =
						corvus_enter_prep_mode(m_buffer.prep_mode_command.drive,
							m_buffer.prep_mode_command.prep_block);
					break;
				case PREP_RESET_DRIVE:
					m_buffer.single_byte_response.status =
						corvus_exit_prep_mode();
					break;
				case PREP_READ_FIRMWARE:
					m_buffer.drive_param_response.status =
						corvus_read_firmware_block((m_buffer.read_firmware_command.encoded_h_s & 0xe0) >> 5,
							m_buffer.read_firmware_command.encoded_h_s & 0x1f);
					break;
				case PREP_WRITE_FIRMWARE:
					m_buffer.drive_param_response.status =
						corvus_write_firmware_block((m_buffer.write_firmware_command.encoded_h_s & 0xe0) >> 5,
							m_buffer.write_firmware_command.encoded_h_s & 0x1f, m_buffer.write_firmware_command.data);
					break;
				case PREP_FORMAT_DRIVE:
					m_buffer.drive_param_response.status =
						corvus_format_drive(m_buffer.format_drive_revbh_command.pattern, m_offset - 512);
					break;
				case PREP_VERIFY:
					m_buffer.verify_drive_response.status = STAT_SUCCESS;
					m_buffer.verify_drive_response.bad_sectors = 0;
					break;
				default:
					m_xmit_bytes = 1;
					m_buffer.single_byte_response.status = STAT_FAULT | STAT_FATAL_ERR;
					logerror("corvus_hdc_data_w: Unimplemented Prep command %02x, returning FATAL FAULT status!\n", m_buffer.command.code);
			}
		}
		if (VERBOSE_RESPONSES)
		{
			LOG(("corvus_hdc_data_w: Command execution complete, status: 0x%2.2x.  Response dump follows:\n",
				m_buffer.single_byte_response.status));
			LOG_BUFFER(m_buffer.raw_data, m_xmit_bytes);
		}

	} // if(!invalid_command_flag)

	//
	// Use a separate "if" in case the Invalid Command Flag was set as a result of a two-byte command
	//
	if(invalid_command_flag) {
		//
		// An Illegal command was detected (Truly invalid, not just unimplemented)
		//
		m_buffer.single_byte_response.status =
			STAT_FATAL_ERR | STAT_ILL_CMD_OP_CODE;      // Respond with an Illegal Op Code

		logerror("corvus_hdc_data_w: Illegal command 0x%2.2x, status: 0x%2.2x\n", m_buffer.command.code, m_buffer.single_byte_response.status);
	}
	//
	// Command execution complete, free up the controller
	//
	m_offset = 0;                                  // Point to beginning of buffer for response

	LOG(("corvus_hdc_data_w: Setting one-time mame timer of %d microseconds to simulate disk function\n", m_delay));

	//
	// Set up timers for command completion and timeout from host
	//
	//machine.scheduler().timer_set(attotime::from_usec(m_delay), FUNC(corvus_hdc_callback), CALLBACK_CTH_MODE);
	m_cmd_timer->adjust(attotime::from_usec(m_delay), CALLBACK_CTH_MODE);
	m_timeout_timer->enable(0);            // We've received enough data, disable the timeout timer

	m_delay = 0;                                   // Reset delay for next function
}
Esempio n. 6
0
//
// Corvus_Get_Drive_Parameters
//
// Fills in the Drive Parameter packet based on the opened CHD file
//
// Pass:
//      drv:    Corvus drive id (1..15)
//
// Returns:
//      Status of command
//
UINT8 corvus_hdc_t::corvus_get_drive_parameters(UINT8 drv) {
	UINT16  capacity;                           // Number of usable 512-byte blocks
	UINT16  raw_capacity;                       // Number of actual 512-byte blocks
	union {
		UINT8
			buffer[512];
		disk_parameter_block_t
			dpb;
	} raw_disk_parameter_block;                 // Buffer for the Disk Parameter Block
	union {
		UINT8
			buffer[512];
		constellation_parameter_block_t
			cpb;
	} raw_constellation_parameter_block;        // Buffer for the Constellation Parameter Block
	UINT8   status;                             // Status to return

	//
	// Make sure a valid drive is being accessed
	//
	if ( ! corvus_hdc_file( drv ) )
	{
		logerror("corvus_get_drive_parameters: Attempt to retrieve parameters from non-existant drive: %d\n", drv);
		m_xmit_bytes = 1;
		return STAT_FATAL_ERR | STAT_DRIVE_NOT_ONLINE;
	}

	//
	// Read the Disk Parameter Block (Sector 1) from the drive
	//
	status = corvus_read_sector(drv, 1, raw_disk_parameter_block.buffer, 512);
	if(status != STAT_SUCCESS) {
		logerror("corvus_get_drive_parameters: Error status returned reading Disk Parameter Block -- status: 0x%2.2x\n", status);
		m_xmit_bytes = 1;
		return status;
	}

	//
	// Read the Constellation Parameter Block (Sector 3) from the drive
	//
	status = corvus_read_sector(drv, 3, raw_constellation_parameter_block.buffer, 512);
	if(status != STAT_SUCCESS) {
		logerror("corvus_get_drive_parameters: Error status returned reading Constellation Parameter Block -- status: 0x%2.2x\n", status);
		m_xmit_bytes = 1;
		return status;
	}

	//
	// Build up the parameter packet
	//

	// This firmware string and revision were taken from the Corvus firmware
	// file CORVB184.CLR found on the SSE SoftBox distribution disk.
	strncpy((char *) m_buffer.drive_param_response.firmware_desc, "V18.4     -- CONST II - 11/82  ", sizeof(m_buffer.drive_param_response.firmware_desc));
	m_buffer.drive_param_response.firmware_rev = 37;

	// Controller ROM version
	m_buffer.drive_param_response.rom_version = ROM_VERSION;

	//
	// Track information
	//
	m_buffer.drive_param_response.track_info.sectors_per_track = m_sectors_per_track;
	m_buffer.drive_param_response.track_info.tracks_per_cylinder = m_tracks_per_cylinder;
	m_buffer.drive_param_response.track_info.cylinders_per_drive.msb = (m_cylinders_per_drive & 0xff00) >> 8;
	m_buffer.drive_param_response.track_info.cylinders_per_drive.lsb = (m_cylinders_per_drive & 0x00ff);

	//
	// Calculate the user capacity of the drive based on total capacity less spare tracks and firmware tracks
	//
	raw_capacity = m_tracks_per_cylinder * m_cylinders_per_drive * m_sectors_per_track; // Total capacity
	capacity = raw_capacity - ((m_tracks_per_cylinder * m_sectors_per_track * 2) + (SPARE_TRACKS * m_sectors_per_track));
	m_buffer.drive_param_response.capacity.msb = (capacity & 0xff0000) >> 16;
	m_buffer.drive_param_response.capacity.midb = (capacity & 0x00ff00) >> 8;
	m_buffer.drive_param_response.capacity.lsb = (capacity & 0x0000ff);

	//
	// Fill in the information from the Disk Parameter Block and Constellation Parameter Block
	//
	m_buffer.drive_param_response.interleave = raw_disk_parameter_block.dpb.interleave;
	memcpy(m_buffer.drive_param_response.table_info.mux_parameters, raw_constellation_parameter_block.cpb.mux_parameters, 12);
	memcpy(m_buffer.drive_param_response.table_info.pipe_name_table_ptr,
		raw_constellation_parameter_block.cpb.pipe_name_table_ptr, 2);
	memcpy(m_buffer.drive_param_response.table_info.pipe_ptr_table_ptr,
		raw_constellation_parameter_block.cpb.pipe_ptr_table_ptr, 2);
	memcpy(m_buffer.drive_param_response.table_info.pipe_area_size, raw_constellation_parameter_block.cpb.pipe_area_size, 2);
	memcpy(m_buffer.drive_param_response.table_info.vdo_table, raw_disk_parameter_block.dpb.vdo_table, 14);
	memcpy(m_buffer.drive_param_response.table_info.lsi11_vdo_table, raw_disk_parameter_block.dpb.lsi11_vdo_table, 8);
	memcpy(m_buffer.drive_param_response.table_info.lsi11_spare_table, raw_disk_parameter_block.dpb.lsi11_spare_table, 8);

	m_buffer.drive_param_response.drive_number = drv;
	m_buffer.drive_param_response.physical_capacity.msb = (raw_capacity & 0xff0000) >> 16;
	m_buffer.drive_param_response.physical_capacity.midb = (raw_capacity & 0x00ff00) >> 8;
	m_buffer.drive_param_response.physical_capacity.lsb = (raw_capacity & 0x0000ff);

	LOG(("corvus_get_drive_parameters: Drive Parameter packet follows:\n"));
	LOG_BUFFER(m_buffer.raw_data, 110);

	return STAT_SUCCESS;
}
Esempio n. 7
0
long
LWIAttrValDataQuery::Run(sDoAttrValueSearchWithData* pAttrValueSearchWithData, LWE_DS_FLAGS Flags, PNETADAPTERINFO pNetAdapterList)
{
    long macError = eDSNoErr;
    long macError_userQuery = eDSNoErr;
    long macError_groupQuery = eDSNoErr;
    unsigned long bytesWritten = 0;
    unsigned long nRecordsWritten = 0;
    unsigned long TotalRecords = 0;
    LWIQuery* pQuery = NULL;
    int recordTypeCount;
    int recordAttributeCount;
    bool isWithData = (kDoAttributeValueSearchWithData == pAttrValueSearchWithData->fType);
    tContextData HandleId = 0;
 
    LOG_ENTER("LWIAttrValDataQuery::Run - fType = %d, fResult = %d, fInNodeRef = %d, fInAttrType = %s, fInPattMatchType = 0x%04X, fInPatt2Match = %s, fInAttrInfoOnly = %s, fIOContinueData = %d, fOutDataBuff => { size = %d }",
              pAttrValueSearchWithData->fType,
              pAttrValueSearchWithData->fResult,
              pAttrValueSearchWithData->fInNodeRef,
              pAttrValueSearchWithData->fInAttrType->fBufferData,
              pAttrValueSearchWithData->fInPattMatchType,
              pAttrValueSearchWithData->fInPatt2Match->fBufferData,
              BOOL_STRING(isWithData && pAttrValueSearchWithData->fInAttrInfoOnly),
              pAttrValueSearchWithData->fIOContinueData,
              pAttrValueSearchWithData->fOutDataBuff->fBufferSize);

    recordTypeCount = dsDataListGetNodeCount(pAttrValueSearchWithData->fInRecTypeList);
    recordAttributeCount = isWithData ? dsDataListGetNodeCount(pAttrValueSearchWithData->fInAttrTypeRequestList) : 0;

    LOG_PARAM("fInRecTypeList.count = %d, fInAttrTypeRequestList.count = %d",
              recordTypeCount,
              recordAttributeCount);

    if (pAttrValueSearchWithData->fIOContinueData != 0)
    {
        macError = GetQueryFromContextList(pAttrValueSearchWithData->fIOContinueData, &pQuery);
        if (macError == eDSNoErr)
        {
            LOG("Already processed this query, handling IO continuation for result record data");
            goto HandleResponse;
        }
    }

    macError = LWIQuery::Create(!isWithData || !pAttrValueSearchWithData->fInAttrInfoOnly,
                                true, // The query results will support fIOContinue (split large results over many calls)
                                pAttrValueSearchWithData->fInNodeRef,
                                Flags,
                                pNetAdapterList,
                                &pQuery);
    GOTO_CLEANUP_ON_MACERROR(macError);

    macError = LWIRecTypeLookup::GetVector(pAttrValueSearchWithData->fInRecTypeList, &pQuery->_recTypeSet);
    GOTO_CLEANUP_ON_MACERROR(macError);

    if (isWithData)
    {
        macError = LWIAttrLookup::GetVector(pAttrValueSearchWithData->fInAttrTypeRequestList, &pQuery->_attributeSet);
        GOTO_CLEANUP_ON_MACERROR(macError);
    }
    else
    {
        macError = LWIAttrLookup::GetVector(kDSAttributesAll, &pQuery->_attributeSet);
        GOTO_CLEANUP_ON_MACERROR(macError);
    }

    // We support only exact (including case-insensitive) matches
    switch (pAttrValueSearchWithData->fInPattMatchType)
    {
        case eDSExact:
        case eDSiExact:
            // These are fine
            break;

        default:
            LOG("Unsupported pattern match type: 0x%04X", pAttrValueSearchWithData->fInPattMatchType);
            macError = eDSRecordNotFound;
            GOTO_CLEANUP_ON_MACERROR(macError);
    }

    macError = eDSInvalidRecordType;

    if (pQuery->ShouldQueryUserInformation())
    {
        macError_userQuery = QueryUserInformation(pQuery,
                                                  pAttrValueSearchWithData->fInAttrType->fBufferData,
                                                  pAttrValueSearchWithData->fInPatt2Match->fBufferData);
        if (macError_userQuery != eDSNoErr)
        {
            LOG("User query failed [Error: %d]", macError_userQuery);
        }
    }

    if (pQuery->ShouldQueryGroupInformation())
    {
        macError_groupQuery = QueryGroupInformation(pQuery,
                                                    pAttrValueSearchWithData->fInAttrType->fBufferData,
                                                    pAttrValueSearchWithData->fInPatt2Match->fBufferData);
        if (macError_groupQuery != eDSNoErr)
        {
            LOG("Group query failed [Error: %d]", macError_groupQuery);
        }
    }
    
    if (pQuery->ShouldQueryComputerListInformation())
    {
        macError_groupQuery = QueryComputerListInformation(pQuery,
                                                           pAttrValueSearchWithData->fInAttrType->fBufferData,
                                                           pAttrValueSearchWithData->fInPatt2Match->fBufferData);
        if (macError_groupQuery != eDSNoErr)
        {
            LOG("Computer List query failed [Error: %d]", macError_groupQuery);
        }
    }

    if (pQuery->ShouldQueryComputerGroupInformation())
    {
        macError_groupQuery = QueryComputerGroupInformation(pQuery,
                                                            pAttrValueSearchWithData->fInAttrType->fBufferData,
                                                            pAttrValueSearchWithData->fInPatt2Match->fBufferData);
        if (macError_groupQuery != eDSNoErr)
        {
            LOG("Computer Group query failed [Error: %d]", macError_groupQuery);
        }
    }

    if (pQuery->ShouldQueryComputerInformation())
    {
        macError_groupQuery = QueryComputerInformation(pQuery,
                                                       pAttrValueSearchWithData->fInAttrType->fBufferData,
                                                       pAttrValueSearchWithData->fInPatt2Match->fBufferData);
        if (macError_groupQuery != eDSNoErr)
        {
            LOG("Computer query failed [Error: %d]", macError_groupQuery);
        }
    }

    // If both queries failed, it is a problem
    if ((macError_userQuery != eDSNoErr) && (macError_groupQuery != eDSNoErr))
    {
       macError = (pQuery->ShouldQueryUserInformation() ? macError_userQuery : macError_groupQuery);
       GOTO_CLEANUP_ON_MACERROR(macError);
    }
    else
       macError = eDSNoErr;

HandleResponse:

    // Write the results
    macError = pQuery->WriteResponse(pAttrValueSearchWithData->fOutDataBuff->fBufferData,
                                     pAttrValueSearchWithData->fOutDataBuff->fBufferSize,
                                     bytesWritten,
                                     nRecordsWritten,
                                     TotalRecords);
    GOTO_CLEANUP_ON_MACERROR(macError);

    if (TotalRecords > nRecordsWritten)
    {
        macError = AddQueryToContextList(pQuery, &HandleId);
        GOTO_CLEANUP_ON_MACERROR(macError);

        pQuery = NULL;
  
        pAttrValueSearchWithData->fIOContinueData = HandleId;
    }
    else
    {
        pAttrValueSearchWithData->fIOContinueData = 0;
    }

    pAttrValueSearchWithData->fOutDataBuff->fBufferLength = bytesWritten;
    pAttrValueSearchWithData->fOutMatchRecordCount = nRecordsWritten;

    if ( bytesWritten > 0 )
    {
#ifdef SHOW_ALL_DEBUG_SPEW
        LOG_BUFFER(pAttrValueSearchWithData->fOutDataBuff->fBufferData, bytesWritten);
#endif
    }

cleanup:

    if (pQuery)
    {
        delete pQuery;
    }

    LOG_LEAVE("fOutMatchRecordCount = %d, fIOContinueData = %d --> %d", pAttrValueSearchWithData->fOutMatchRecordCount, pAttrValueSearchWithData->fIOContinueData, macError);

    return macError;
}
long
LWIRecordListQuery::Test(
    IN const char* DsPath,
    IN tDataListPtr RecNameList,
    IN tDirPatternMatch PatternMatch,
    IN tDataListPtr RecTypeList,
    IN tDataListPtr AttribTypeList,
    IN dsBool AttribInfoOnly,
    IN unsigned long Size
    )
{
    long macError = eDSNoErr;
    tDirReference dirRef = 0;
    tDirNodeReference dirNode = 0;
    tDataListPtr dirNodeName = NULL;
    tDataBufferPtr pData = NULL;
    UInt32 outCount;
    tContextData continueData = NULL;

    LOG_ENTER("");

    macError = dsOpenDirService( &dirRef );
    GOTO_CLEANUP_ON_MACERROR( macError );

    pData = dsDataBufferAllocate(dirRef, Size);
    if (!pData)
    {
        macError = eDSAllocationFailed;
        GOTO_CLEANUP();
    }

    dirNodeName = dsBuildFromPath( dirRef, DsPath, "/" );
    if (!dirNodeName)
    {
        macError = eDSAllocationFailed;
        GOTO_CLEANUP();
    }

    macError = dsOpenDirNode( dirRef, dirNodeName, &dirNode );
    GOTO_CLEANUP_ON_MACERROR( macError );

    macError = dsGetRecordList( dirNode,
                                pData,
                                RecNameList,
                                PatternMatch,
                                RecTypeList,
                                AttribTypeList,
                                AttribInfoOnly,
                                &outCount,
                                &continueData);
    GOTO_CLEANUP_ON_MACERROR( macError );

    LOG("Got %d records", outCount);

    if (pData->fBufferLength > 0)
    {
        LOG_BUFFER(pData->fBufferData, pData->fBufferLength);
    }

cleanup:

    if ( pData )
    {
        dsDataBufferDeAllocate( dirRef, pData );
    }

    if ( dirNodeName )
    {
        dsDataListDeallocate( dirRef, dirNodeName );
    }

    if ( dirNode )
    {
        dsCloseDirNode( dirNode );
    }

    if ( dirRef )
    {
        dsCloseDirService( dirRef );
    }

    LOG_LEAVE("--> %d", macError);

    return macError;
}
long
LWIRecordListQuery::Run(IN OUT sGetRecordList* pGetRecordList, LWE_DS_FLAGS Flags, PNETADAPTERINFO pNetAdapterList)
{
    long macError = eDSNoErr;
    long macError_userQuery = eDSNoErr;
    long macError_groupQuery = eDSNoErr;
    long macError_computerQuery = eDSNoErr;
    long macError_computergroupQuery = eDSNoErr;
    long macError_computerlistQuery = eDSNoErr;
    tDataNodePtr pDataNode = NULL;
    const char* szNames = NULL;
    unsigned long bytesWritten = 0;
    unsigned long nRecordsWritten = 0;
    unsigned long TotalRecords = 0;
    LWIQuery* pQuery = NULL;
    int iter = 0;
    int resultCount = 0;
    int recordNameCount;
    int recordTypeCount;
    int recordAttributeCount;
    tContextData HandleId = 0;

    LOG_ENTER("LWIRecordListQuery::Run - fType = %d, fResult = %d, fInNodeRef = %d, "
              "fInDataBuf = @%p { len = %d, size = %d }, fInPatternMatch = 0x%04X, "
              "fIOContinueData = %d",
              pGetRecordList->fType,
              pGetRecordList->fResult,
              pGetRecordList->fInNodeRef,
              pGetRecordList->fInDataBuff,
              pGetRecordList->fInDataBuff->fBufferLength,
              pGetRecordList->fInDataBuff->fBufferSize,
              pGetRecordList->fInPatternMatch,
              pGetRecordList->fIOContinueData);

    recordNameCount = dsDataListGetNodeCount(pGetRecordList->fInRecNameList);
    recordTypeCount = dsDataListGetNodeCount(pGetRecordList->fInRecTypeList);
    recordAttributeCount = dsDataListGetNodeCount(pGetRecordList->fInAttribTypeList);

    LOG_PARAM("fInRecNameList.count = %d, fInRecTypeList.count = %d, "
              "fInAttribTypeList.count = %d",
              recordNameCount,
              recordTypeCount,
              recordAttributeCount);

    /* Initialize the out parameters in case we return with error */
    pGetRecordList->fInDataBuff->fBufferLength = 0;
    pGetRecordList->fOutRecEntryCount = 0;

    if ((UInt32)pGetRecordList->fIOContinueData != 0 &&
        (UInt32)pGetRecordList->fIOContinueData != SPECIAL_DS_CONTINUE_HANDLE)
    {
        macError = GetQueryFromContextList(pGetRecordList->fIOContinueData, &pQuery);
        if (macError == eDSNoErr)
        {
            LOG("Already processed this query, handling IO continuation for result record data");
            goto HandleResponse;
        }
    }

    macError = LWIQuery::Create(!pGetRecordList->fInAttribInfoOnly,
                                true, // The query results will support fIOContinue (split large results over many calls)
                                pGetRecordList->fInNodeRef,
                                Flags,
                                pNetAdapterList,
                                &pQuery);
    GOTO_CLEANUP_ON_MACERROR(macError);

    macError = LWIRecTypeLookup::GetVector(pGetRecordList->fInRecTypeList, &pQuery->_recTypeSet);
    GOTO_CLEANUP_ON_MACERROR(macError);

    macError = LWIAttrLookup::GetVector(pGetRecordList->fInAttribTypeList, &pQuery->_attributeSet);
    GOTO_CLEANUP_ON_MACERROR(macError);

    for (iter = 0; iter < recordNameCount; iter++)
    {
        macError = dsDataListGetNodeAlloc( pGetRecordList->fInNodeRef,
                                           pGetRecordList->fInRecNameList,
                                           iter+1,
                                           &pDataNode );
        GOTO_CLEANUP_ON_MACERROR( macError );
        szNames = pDataNode->fBufferData;

        macError = eDSInvalidRecordType;

        if (pQuery->ShouldQueryUserInformation())
        {
            macError_userQuery = pQuery->QueryUserInformationByName(szNames);
            if (macError_userQuery != eDSNoErr)
            {
               LOG("User query failed [Error: %d]", macError_userQuery);
            }
            else
            {
                resultCount++;
            }
        }

        if (pQuery->ShouldQueryGroupInformation())
        {
            macError_groupQuery = pQuery->QueryGroupInformationByName(szNames);
            if (macError_groupQuery != eDSNoErr)
            {
               LOG("Group query failed [Error: %d]", macError_groupQuery);
            }
            else
            {
                resultCount++;
            }
        }

        if (pQuery->ShouldQueryComputerInformation())
        {
            macError_computerQuery = pQuery->QueryComputerInformationByName(szNames);
            if (macError_computerQuery != eDSNoErr)
            {
               LOG("Computer query failed [Error: %d]", macError_computerQuery);
            }
            else
            {
                resultCount++;
            }
        }

        if (pQuery->ShouldQueryComputerGroupInformation())
        {
            macError_computergroupQuery = pQuery->QueryComputerGroupInformationByName(szNames);
            if (macError_computergroupQuery != eDSNoErr)
            {
               LOG("Computer group query failed [Error: %d]", macError_computergroupQuery);
            }
            else
            {
                resultCount++;
            }
        }

        if (pQuery->ShouldQueryComputerListInformation())
        {
            macError_computerlistQuery = pQuery->QueryComputerListInformationByName(szNames);
            if (macError_computerlistQuery != eDSNoErr)
            {
               LOG("Computer list query failed [Error: %d]", macError_computerlistQuery);
            }
            else
            {
                resultCount++;
            }
        }

        dsDataNodeDeAllocate(NULL, pDataNode);
        pDataNode = NULL;
    }

    // If both queries failed, it is a problem
    if (resultCount == 0 &&
        (macError_userQuery != eDSNoErr) &&
        (macError_groupQuery != eDSNoErr) &&
        (macError_computerQuery != eDSNoErr) &&
        (macError_computergroupQuery != eDSNoErr) &&
        (macError_computerlistQuery != eDSNoErr))
    {
       macError = (pQuery->ShouldQueryUserInformation() ? macError_userQuery : macError_groupQuery);
       GOTO_CLEANUP_ON_MACERROR(macError);
    }
    else
       macError = eDSNoErr;

HandleResponse:

    // Write the results
    macError = pQuery->WriteResponse(pGetRecordList->fInDataBuff->fBufferData,
                                     pGetRecordList->fInDataBuff->fBufferSize,
                                     bytesWritten,
                                     nRecordsWritten,
                                     TotalRecords);
    GOTO_CLEANUP_ON_MACERROR(macError);

    if (TotalRecords > nRecordsWritten)
    {
        macError = AddQueryToContextList(pQuery, &HandleId);
        GOTO_CLEANUP_ON_MACERROR(macError);

        pQuery = NULL;

        pGetRecordList->fIOContinueData = HandleId;
    }
    else
    {
        pGetRecordList->fIOContinueData = 0;
    }

    pGetRecordList->fInDataBuff->fBufferLength = bytesWritten;
    pGetRecordList->fOutRecEntryCount = nRecordsWritten;

    if ( bytesWritten > 0 )
    {
#ifdef SHOW_ALL_DEBUG_SPEW
        LOG_BUFFER(pGetRecordList->fInDataBuff->fBufferData, bytesWritten);
#endif
    }

cleanup:

    if (pDataNode)
    {
        dsDataNodeDeAllocate(0, pDataNode);
    }

    if (pQuery)
    {
        delete pQuery;
    }

    if (macError == eDSBufferTooSmall)
    {
        pGetRecordList->fIOContinueData = (tContextData)SPECIAL_DS_CONTINUE_HANDLE;
    }

    LOG_LEAVE("fOutRecEntryCount = %d, fInDataBuff = { length = %d, size = %d }, fIOContinueData = %d, macError = %d",
              pGetRecordList->fOutRecEntryCount,
              pGetRecordList->fInDataBuff->fBufferLength,
              pGetRecordList->fInDataBuff->fBufferSize,
              pGetRecordList->fIOContinueData,
              macError);

    return macError;
}