gpk_create_file(sc_card_t *card, sc_file_t *file)
{
	struct gpk_private_data *priv = DRVDATA(card);
	sc_apdu_t	apdu;
	u8		data[28+3], crycks[3], resp[3];
	size_t		datalen, namelen;
	int		r;

	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
		"gpk_create_file(0x%04X)\n", file->id);

	/* Prepare APDU */
	memset(&apdu, 0, sizeof(apdu));
	apdu.cla = 0x80;	/* assume no secure messaging */
	apdu.cse = SC_APDU_CASE_3_SHORT;
	apdu.ins = 0xE0;
	apdu.p2  = 0x00;

	/* clear data */
	memset(data, 0, sizeof(data));
	datalen = 12;

	/* FID */
	data[0] = file->id >> 8;
	data[1] = file->id & 0xFF;

	/* encode ACLs */
	if (file->type == SC_FILE_TYPE_DF) {
		/* The GPK4000 has separate AC bits for
		 * creating sensitive files and creating
		 * data files. Since OpenSC has just the notion
		 * of "file" we use the same ACL for both AC words
		 */
		apdu.p1 = 0x01; /* create DF */
		data[2] = 0x38;
		acl_to_ac(file, SC_AC_OP_CREATE, data + 6);
		acl_to_ac(file, SC_AC_OP_CREATE, data + 8);
		if ((namelen = file->namelen) != 0) {
			if (namelen > 16)
				return SC_ERROR_INVALID_ARGUMENTS;
			memcpy(data+datalen, file->name, namelen);
			data[5] = namelen;
			datalen += namelen;
		}
	} else {
		apdu.p1 = 0x02; /* create EF */
		data[2] = file->ef_structure;
		data[3] = file->record_length;
		data[4] = file->size >> 8;
		data[5] = file->size & 0xff;
		acl_to_ac(file, SC_AC_OP_UPDATE, data + 6);
		acl_to_ac(file, SC_AC_OP_WRITE, data + 8);
		acl_to_ac(file, SC_AC_OP_READ, data + 10);
	}

	apdu.data = data;
	apdu.datalen = datalen;
	apdu.lc = datalen;

	if (priv->key_set) {
		apdu.cla = 0x84;
		apdu.cse = SC_APDU_CASE_4_SHORT;
		r = gpk_compute_crycks(card, &apdu, crycks);
		if (r)
			return r;
		apdu.resp = resp;
		apdu.resplen = sizeof(resp); /* XXX? */
	}

	r = sc_transmit_apdu(card, &apdu);
	SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
	SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Card returned error");

	/* verify secure messaging response */
	if (priv->key_set)
		r = gpk_verify_crycks(card, &apdu, crycks);

	return r;
}
gpk_create_file(sc_card_t *card, sc_file_t *file)
{
	struct gpk_private_data *priv = DRVDATA(card);
	sc_apdu_t	apdu;
	u8		data[28+3], crycks[3], resp[3];
	size_t		datalen, namelen;
	int		r;

	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
		"gpk_create_file(0x%04X)\n", file->id);

	 
	memset(&apdu, 0, sizeof(apdu));
	apdu.cla = 0x80;	 
	apdu.cse = SC_APDU_CASE_3_SHORT;
	apdu.ins = 0xE0;
	apdu.p2  = 0x00;

	 
	memset(data, 0, sizeof(data));
	datalen = 12;

	 
	data[0] = file->id >> 8;
	data[1] = file->id & 0xFF;

	 
	if (file->type == SC_FILE_TYPE_DF) {
		 
		apdu.p1 = 0x01;  
		data[2] = 0x38;
		acl_to_ac(file, SC_AC_OP_CREATE, data + 6);
		acl_to_ac(file, SC_AC_OP_CREATE, data + 8);
		if ((namelen = file->namelen) != 0) {
			if (namelen > 16)
				return SC_ERROR_INVALID_ARGUMENTS;
			memcpy(data+datalen, file->name, namelen);
			data[5] = namelen;
			datalen += namelen;
		}
	} else {
		apdu.p1 = 0x02;  
		data[2] = file->ef_structure;
		data[3] = file->record_length;
		data[4] = file->size >> 8;
		data[5] = file->size & 0xff;
		acl_to_ac(file, SC_AC_OP_UPDATE, data + 6);
		acl_to_ac(file, SC_AC_OP_WRITE, data + 8);
		acl_to_ac(file, SC_AC_OP_READ, data + 10);
	}

	apdu.data = data;
	apdu.datalen = datalen;
	apdu.lc = datalen;

	if (priv->key_set) {
		apdu.cla = 0x84;
		apdu.cse = SC_APDU_CASE_4_SHORT;
		r = gpk_compute_crycks(card, &apdu, crycks);
		if (r)
			return r;
		apdu.resp = resp;
		apdu.resplen = sizeof(resp);  
	}

	r = sc_transmit_apdu(card, &apdu);
	SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
	SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Card returned error");

	 
	if (priv->key_set)
		r = gpk_verify_crycks(card, &apdu, crycks);

	return r;
}