예제 #1
0
파일: fakesign.c 프로젝트: MP2E/Gecko-OS
//---------------------------------------------------------------------------------
s32 install(const signed_blob *s_tmd, const signed_blob *s_certs, u32 certs_len){
//---------------------------------------------------------------------------------
  u32 ret, i;
  tmd *p_tmd = SIGNATURE_PAYLOAD(s_tmd);

  ret = ES_AddTitleStart(s_tmd, SIGNED_TMD_SIZE(s_tmd), s_certs, certs_len, NULL, 0);

  if(ret < 0) {
    ES_AddTitleCancel();
    return ret;
  }

  for(i=0; i<p_tmd->num_contents; i++) {
	currentfile = i+1;
	filecount = p_tmd->num_contents;
	installios_thread_state = 1;
    ret = install_nus_object((tmd *)SIGNATURE_PAYLOAD(s_tmd), i);
    if (ret) return ret;
  }

  ret = ES_AddTitleFinish();
  if(ret < 0) {
    ES_AddTitleCancel();
    return ret;
  }

  return 0;
}
예제 #2
0
파일: wad.cpp 프로젝트: gnils/usbloader-gx
s32 Wad_Install(FILE *fp)
{
	//////start the gui shit
	GuiWindow promptWindow(472,320);
	promptWindow.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE);
	promptWindow.SetPosition(0, -10);

	GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, Settings.sfxvolume);
	// because destroy GuiSound must wait while sound playing is finished, we use a global sound
	if(!btnClick2) btnClick2=new GuiSound(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume);
	//	GuiSound btnClick(button_click2_pcm, button_click2_pcm_size, Settings.sfxvolume);

	char imgPath[100];
	snprintf(imgPath, sizeof(imgPath), "%sbutton_dialogue_box.png", CFG.theme_path);
	GuiImageData btnOutline(imgPath, button_dialogue_box_png);
	snprintf(imgPath, sizeof(imgPath), "%sdialogue_box.png", CFG.theme_path);
	GuiImageData dialogBox(imgPath, dialogue_box_png);
	GuiTrigger trigA;
	trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);

	GuiImage dialogBoxImg(&dialogBox);
	if (Settings.wsprompt == yes){
	dialogBoxImg.SetWidescreen(CFG.widescreen);}

	GuiText btn1Txt(tr("OK"), 22, THEME.prompttext);
	GuiImage btn1Img(&btnOutline);
	if (Settings.wsprompt == yes){
	btn1Txt.SetWidescreen(CFG.widescreen);
	btn1Img.SetWidescreen(CFG.widescreen);}
	GuiButton btn1(&btn1Img,&btn1Img, 2, 4, 0, -35, &trigA, &btnSoundOver, btnClick2,1);
	btn1.SetLabel(&btn1Txt);
	btn1.SetState(STATE_SELECTED);

	snprintf(imgPath, sizeof(imgPath), "%sprogressbar_outline.png", CFG.theme_path);
	GuiImageData progressbarOutline(imgPath, progressbar_outline_png);
	GuiImage progressbarOutlineImg(&progressbarOutline);
	if (Settings.wsprompt == yes){
	progressbarOutlineImg.SetWidescreen(CFG.widescreen);}
	progressbarOutlineImg.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
	progressbarOutlineImg.SetPosition(25, 50);

	snprintf(imgPath, sizeof(imgPath), "%sprogressbar_empty.png", CFG.theme_path);
	GuiImageData progressbarEmpty(imgPath, progressbar_empty_png);
	GuiImage progressbarEmptyImg(&progressbarEmpty);
	progressbarEmptyImg.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
	progressbarEmptyImg.SetPosition(25, 50);
	progressbarEmptyImg.SetTile(100);

	snprintf(imgPath, sizeof(imgPath), "%sprogressbar.png", CFG.theme_path);
	GuiImageData progressbar(imgPath, progressbar_png);
	GuiImage progressbarImg(&progressbar);
	progressbarImg.SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
	progressbarImg.SetPosition(25, 50);

    char title[50];
   sprintf(title, "%s", tr("Installing wad"));
	GuiText titleTxt(title, 26, THEME.prompttext);
	titleTxt.SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
	titleTxt.SetPosition(0,40);
    char msg[50];
    sprintf(msg, " ");
	// sprintf(msg, "%s", tr("Initializing Network"));
	GuiText msg1Txt(NULL, 20, THEME.prompttext);
	msg1Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP);
	msg1Txt.SetPosition(50,75);
//	char msg2[50] = " ";
	GuiText msg2Txt(NULL, 20, THEME.prompttext);
	msg2Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP);
	msg2Txt.SetPosition(50, 98);

	GuiText msg3Txt(NULL, 20, THEME.prompttext);
	msg3Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP);
	msg3Txt.SetPosition(50, 121);

	GuiText msg4Txt(NULL, 20, THEME.prompttext);
	msg4Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP);
	msg4Txt.SetPosition(50, 144);

	GuiText msg5Txt(NULL, 20, THEME.prompttext);
	msg5Txt.SetAlignment(ALIGN_LEFT, ALIGN_TOP);
	msg5Txt.SetPosition(50, 167);

	GuiText prTxt(NULL, 26, THEME.prompttext);
	prTxt.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE);
	prTxt.SetPosition(0, 50);


	if ((Settings.wsprompt == yes) && (CFG.widescreen)){/////////////adjust for widescreen
		progressbarOutlineImg.SetAlignment(ALIGN_CENTRE, ALIGN_MIDDLE);
		progressbarOutlineImg.SetPosition(0, 50);
		progressbarEmptyImg.SetPosition(80,50);
		progressbarEmptyImg.SetTile(78);
		progressbarImg.SetPosition(80, 50);

		msg1Txt.SetPosition(90,75);
		msg2Txt.SetPosition(90, 98);
		msg3Txt.SetPosition(90, 121);
		msg4Txt.SetPosition(90, 144);
		msg5Txt.SetPosition(90, 167);

	}
	promptWindow.Append(&dialogBoxImg);
	promptWindow.Append(&titleTxt);
	promptWindow.Append(&msg5Txt);
	promptWindow.Append(&msg4Txt);
	promptWindow.Append(&msg3Txt);
	promptWindow.Append(&msg1Txt);
	promptWindow.Append(&msg2Txt);

   //promptWindow.SetEffect(EFFECT_SLIDE_TOP | EFFECT_SLIDE_IN, 50);

	HaltGui();
	mainWindow->SetState(STATE_DISABLED);
	mainWindow->Append(&promptWindow);
	mainWindow->ChangeFocus(&promptWindow);
	//sleep(1);


	///start the wad shit
	bool fail = false;
	wadHeader   *header  = NULL;
	void		*pvoid;
	signed_blob *p_certs = NULL, *p_crl = NULL, *p_tik = NULL, *p_tmd = NULL;

	tmd *tmd_data  = NULL;

	u32 cnt, offset = 0;
	s32 ret = 666;


	ResumeGui();
	msg1Txt.SetText(tr(">> Reading WAD data..."));
	HaltGui();
#define SetPointer(a, p) a=(typeof(a))p
	// WAD header
	//ret = __Wad_ReadAlloc(fp, (void *)header, offset, sizeof(wadHeader));
	ret = __Wad_ReadAlloc(fp, &pvoid, offset, sizeof(wadHeader));

	if (ret < 0)
		goto err;
	SetPointer(header, pvoid);
	offset += round_up(header->header_len, 64);

	// WAD certificates
	//ret = __Wad_ReadAlloc(fp, (void *)&p_certs, offset, header->certs_len);
	ret = __Wad_ReadAlloc(fp, &pvoid, offset, header->certs_len);
	if (ret < 0)
		goto err;
	SetPointer(p_certs, pvoid);
	offset += round_up(header->certs_len, 64);

	// WAD crl

	if (header->crl_len) {
		//ret = __Wad_ReadAlloc(fp, (void *)&p_crl, offset, header->crl_len);
		ret = __Wad_ReadAlloc(fp, &pvoid, offset, header->crl_len);
		if (ret < 0)
			goto err;
		SetPointer(p_crl, pvoid);
		offset += round_up(header->crl_len, 64);
	}

	// WAD ticket
	//ret = __Wad_ReadAlloc(fp, (void *)&p_tik, offset, header->tik_len);
	ret = __Wad_ReadAlloc(fp, &pvoid, offset, header->tik_len);
	if (ret < 0)
		goto err;
	SetPointer(p_tik, pvoid);
	offset += round_up(header->tik_len, 64);

	// WAD TMD
	//ret = __Wad_ReadAlloc(fp, (void *)&p_tmd, offset, header->tmd_len);
	ret = __Wad_ReadAlloc(fp, &pvoid, offset, header->tmd_len);
	if (ret < 0)
		goto err;
	SetPointer(p_tmd, pvoid);
	offset += round_up(header->tmd_len, 64);

	ResumeGui();
	msg1Txt.SetText(tr("Reading WAD data... Ok!"));
	msg2Txt.SetText(tr(">> Installing ticket..."));
	HaltGui();
	// Install ticket
	ret = ES_AddTicket(p_tik, header->tik_len, p_certs, header->certs_len, p_crl, header->crl_len);
	if (ret < 0)
		goto err;

	ResumeGui();
	msg2Txt.SetText(tr("Installing ticket... Ok!"));
	msg3Txt.SetText(tr(">> Installing title..."));
	//WindowPrompt(">> Installing title...",0,0,0,0,0,200);
	HaltGui();
	// Install title
	ret = ES_AddTitleStart(p_tmd, header->tmd_len, p_certs, header->certs_len, p_crl, header->crl_len);
	if (ret < 0)
		goto err;

	// Get TMD info
	tmd_data = (tmd *)SIGNATURE_PAYLOAD(p_tmd);

	// Install contents
	//ResumeGui();
	//HaltGui();
	promptWindow.Append(&progressbarEmptyImg);
   promptWindow.Append(&progressbarImg);
   promptWindow.Append(&progressbarOutlineImg);
   promptWindow.Append(&prTxt);
	ResumeGui();
	msg3Txt.SetText(tr("Installing title... Ok!"));
	for (cnt = 0; cnt < tmd_data->num_contents; cnt++) {

		tmd_content *content = &tmd_data->contents[cnt];

		u32 idx = 0, len;
		s32 cfd;
		ResumeGui();

		//printf("\r\t\t>> Installing content #%02d...", content->cid);
		// Encrypted content size
		len = round_up(content->size, 64);

		// Install content
		cfd = ES_AddContentStart(tmd_data->title_id, content->cid);
		if (cfd < 0) {
			ret = cfd;
			goto err;
		}
		snprintf(imgPath, sizeof(imgPath), "%s%d...",tr(">> Installing content #"),content->cid);
		msg4Txt.SetText(imgPath);
		// Install content data
		while (idx < len) {

            //VIDEO_WaitVSync ();

			u32 size;

			// Data length
			size = (len - idx);
			if (size > BLOCK_SIZE)
				size = BLOCK_SIZE;

			// Read data
			ret = __Wad_ReadFile(fp, &wadBuffer, offset, size);
			if (ret < 0)
				goto err;

			// Install data
			ret = ES_AddContentData(cfd, wadBuffer, size);
			if (ret < 0)
				goto err;

			// Increase variables
			idx    += size;
			offset += size;
		
		//snprintf(imgPath, sizeof(imgPath), "%s%d (%d)...",tr(">> Installing content #"),content->cid,idx);

		//msg4Txt.SetText(imgPath);

		prTxt.SetTextf("%i%%", 100*(cnt*len+idx)/(tmd_data->num_contents*len));
      if ((Settings.wsprompt == yes) && (CFG.widescreen)) {
         progressbarImg.SetTile(78*(cnt*len+idx)/(tmd_data->num_contents*len));
      } else {
         progressbarImg.SetTile(100*(cnt*len+idx)/(tmd_data->num_contents*len));
      }

		}

		// Finish content installation
		ret = ES_AddContentFinish(cfd);
		if (ret < 0)
			goto err;
	}

	msg4Txt.SetText(tr("Installing content... Ok!"));
	msg5Txt.SetText(tr(">> Finishing installation..."));



	// Finish title install
	ret = ES_AddTitleFinish();
	if (ret >= 0) {
//		printf(" OK!\n");
		goto out;
	}

err:
	//char titties[100];
	ResumeGui();
	prTxt.SetTextf("%s%d", tr("Error..."),ret);
	promptWindow.Append(&prTxt);
	fail = true;
  	//snprintf(titties, sizeof(titties), "%d", ret);
	//printf(" ERROR! (ret = %d)\n", ret);
	//WindowPrompt("ERROR!",titties,"Back",0,0);
	// Cancel install
	ES_AddTitleCancel();
	goto exit;
	//return ret;

out:
	// Free memory
	if (header)
		free(header);
	if (p_certs)
		free(p_certs);
	if (p_crl)
		free(p_crl);
	if (p_tik)
		free(p_tik);
	if (p_tmd)
		free(p_tmd);
	goto exit;


exit:
	if (!fail)msg5Txt.SetText(tr("Finishing installation... Ok!"));
	promptWindow.Append(&btn1);
	while(btn1.GetState() != STATE_CLICKED){
	}


	HaltGui();
	mainWindow->Remove(&promptWindow);
	mainWindow->SetState(STATE_DEFAULT);
	ResumeGui();

	return ret;
}
bool NandSave::CheckSave()
{
	/* 10 million variables */
	u32 u8_bin_size = 0;
	u8 *u8_bin = NULL;
	u32 certSize = 0;
	signed_blob *certBuffer = NULL;
	u32 tmd_bin_size = 0;
	const signed_blob *tmd_bin = NULL;
	u32 tik_bin_size = 0;
	const signed_blob *tik_bin = NULL;
	u32 banner_bin_size = 0;
	const u8 *banner_bin = NULL;
	u32 entries = 0;
	/* May our banner already exist */
	memset(&ISFS_Path, 0, ISFS_MAXPATH);
	strcpy(ISFS_Path, BANNER_PATH);
	fd = ISFS_Open(ISFS_Path, ISFS_OPEN_READ);
	if(fd >= 0)
	{
		ISFS_Close(fd);
		gprintf("Found WiiFlow Save\n");
		goto done;
	}
	/* extract our archive */
	u8_bin = DecompressCopy(save_bin, save_bin_size, &u8_bin_size);
	if(u8_bin == NULL || u8_bin_size == 0)
		goto error;
	/* grab cert.sys */
	memset(&ISFS_Path, 0, ISFS_MAXPATH);
	strcpy(ISFS_Path, "/sys/cert.sys");
	certBuffer = (signed_blob*)ISFS_GetFile(ISFS_Path, &certSize, -1);
	if(certBuffer == NULL || certSize == 0)
		goto error;
	/* Install tik and tmd */
	tik_bin = (const signed_blob*)u8_get_file(u8_bin, "tik.bin", &tik_bin_size);
	if(tik_bin == NULL || tik_bin_size == 0)
		goto error;
	ret = ES_AddTicket(tik_bin, tik_bin_size, certBuffer, certSize, NULL, 0);
	if(ret < 0)
		goto error;
	tmd_bin = (const signed_blob*)u8_get_file(u8_bin, "tmd.bin", &tmd_bin_size);
	if(tmd_bin == NULL || tmd_bin_size == 0)
		goto error;
	ret = ES_AddTitleStart(tmd_bin, tmd_bin_size, certBuffer, certSize, NULL, 0);
	if(ret < 0)
		goto error;
	ret = ES_AddTitleFinish();
	if(ret < 0)
		goto error;
	/* WARNING dirty, delete tik again */
	memset(&ISFS_Path, 0, ISFS_MAXPATH);
	strcpy(ISFS_Path, "/ticket/00010000/57465346.tik");
	ret = ISFS_Delete(ISFS_Path);
	if(ret < 0)
		goto error;
	/* Delete the unused ticket folder */
	memset(&ISFS_Path, 0, ISFS_MAXPATH);
	strcpy(ISFS_Path, "/ticket/00010000");
	ret = ISFS_ReadDir(ISFS_Path, NULL, &entries);
	if(ret < 0)
		goto error;
	if(entries == 0)
	{
		ret = ISFS_Delete(ISFS_Path);
		if(ret < 0)
			goto error;
	}
	banner_bin = u8_get_file(u8_bin, "banner.bin", &banner_bin_size);
	if(banner_bin == NULL || banner_bin_size == 0)
		goto error;
	memset(&ISFS_Path, 0, ISFS_MAXPATH);
	strcpy(ISFS_Path, BANNER_PATH);
	/* Write our banner */
	ISFS_CreateFile(ISFS_Path, 0, 3, 3, 3);
	fd = ISFS_Open(ISFS_Path, ISFS_OPEN_WRITE);
	if(fd < 0)
		goto error;
	ret = ISFS_Write(fd, banner_bin, banner_bin_size);
	ISFS_Close(fd);
	if(ret < 0)
	{
		ISFS_Delete(ISFS_Path);
		goto error;
	}
	free(certBuffer);
	if(u8_bin != save_bin)
		free(u8_bin);
	gprintf("Created WiiFlow Save\n");
done:
	loaded = true;
	return loaded;

error:
	gprintf("Error while creating WiiFlow Save\n");
	loaded = false;
	ES_AddTitleCancel();
	if(certBuffer != NULL)
		free(certBuffer);
	certBuffer = NULL;
	if(u8_bin != NULL)
		free(u8_bin);
	u8_bin = NULL;
	tik_bin = NULL;
	tmd_bin = NULL;
	banner_bin = NULL;
	return loaded;
}
예제 #4
0
s32 install_IOS(IOS *ios, bool skipticket)
{
	int ret;
	int cfd;

	if (!skipticket)
	{
		((u8*)(ios->ticket))[0x1F1] = 0x00; /* -1029 fix */
		ret = ES_AddTicket(ios->ticket, ios->ticket_size, ios->certs, ios->certs_size, ios->crl, ios->crl_size);
		if (ret < 0)
		{
			printf("ES_AddTicket returned: %d\n", ret);
			ES_AddTitleCancel();
			return ret;
		}
	}
	printf(".");

	ret = ES_AddTitleStart(ios->tmd, ios->tmd_size, ios->certs, ios->certs_size, ios->crl, ios->crl_size);
	if (ret < 0)
	{
		printf("\nES_AddTitleStart returned: %d\n", ret);
		ES_AddTitleCancel();
		return ret;
	}
	printf(".");

	tmd *tmd_data  = (tmd *)SIGNATURE_PAYLOAD(ios->tmd);

	int i;
	for (i = 0; i < ios->content_count; i++)
	{
		tmd_content *content = &tmd_data->contents[i];

		cfd = ES_AddContentStart(tmd_data->title_id, content->cid);
		if (cfd < 0)
		{
			printf("\nES_AddContentStart for content #%u cid %u returned: %d\n", i, content->cid, cfd);
			ES_AddTitleCancel();
			return cfd;
		}
		
		ret = ES_AddContentData(cfd, ios->encrypted_buffer[i], ios->buffer_size[i]);
		if (ret < 0)
		{
			printf("\nES_AddContentData for content #%u cid %u returned: %d\n", i, content->cid, ret);
			ES_AddTitleCancel();
			return ret;
		}
		
		ret = ES_AddContentFinish(cfd);
		if (ret < 0)
		{
			printf("\nES_AddContentFinish for content #%u cid %u returned: %d\n", i, content->cid, ret);
			ES_AddTitleCancel();
			return ret;
		}
		printf(".");
	}
	
	ret = ES_AddTitleFinish();
	if (ret < 0)
	{
		printf("\nES_AddTitleFinish returned: %d\n", ret);
		ES_AddTitleCancel();
		return ret;
	}
	printf(".\n");
	
	return 0;
}
예제 #5
0
s32 Downgrade_IOS(u32 iosversion, u32 highrevision, u32 lowrevision, bool free)
{
	printf("Preparing downgrade of IOS%u from revison: %u to: %u\n", iosversion, highrevision, lowrevision);

	int ret;
	IOS *highios;
	IOS *lowios;
	
	printf("Getting IOS%u revision %u...\n", iosversion, highrevision);
	ret = get_IOS(&highios, iosversion, highrevision);
	if (ret < 0)
	{
		printf("Error reading IOS into memory\n");
		return ret;
	}
	
	printf("Getting IOS%u revision %u...\n", iosversion, lowrevision);
	ret = get_IOS(&lowios, iosversion, lowrevision);
	if (ret < 0)
	{
		printf("Error reading IOS into memory\n");
		free_IOS(&highios);
		return ret;
	}

	printf("\n");
	printf("Downgrading involves two steps:\n");
	printf("Step 1: Set the revison to 0\n");
	printf("Step 2: Install IOS with low revision\n");
	printf("Preparations complete, step 1...\n");

	u32 pressed;
	u32 pressedGC;	
	waitforbuttonpress(&pressed, &pressedGC);
	if (pressed != WPAD_BUTTON_A && pressedGC != PAD_BUTTON_A)
	{
		printf("Other button pressed\n");
		free_IOS(&highios);
		free_IOS(&lowios);
		return -1;
	}
	
	printf("Installing ticket...\n");
	ret = ES_AddTicket(highios->ticket, highios->ticket_size, highios->certs, highios->certs_size, highios->crl, highios->crl_size);
	if (ret < 0)
	{
		printf("ES_AddTicket returned: %d\n", ret);
		free_IOS(&highios);
		free_IOS(&lowios);
		ES_AddTitleCancel();
		return ret;
	}	

	ret = Downgrade_TMD_Revision(highios->tmd, highios->tmd_size, highios->certs, highios->certs_size);
	if (ret < 0)
	{
		printf("Error: Could not set the revision to 0\n");
		free_IOS(&highios);
		free_IOS(&lowios);
		return ret;
	}

	printf("Revision set to 0, step 1 of downgrade complete.\n");
	printf("\n");
	printf("step 2 of downgrade...\n");

	waitforbuttonpress(&pressed, &pressedGC);
	if (pressed != WPAD_BUTTON_A && pressedGC != PAD_BUTTON_A)
	{
		printf("Other button pressed\n");
		free_IOS(&highios);
		free_IOS(&lowios);
		return -1;
	}
	
	printf("Installing IOS%u Rev %u...\n", iosversion, lowrevision);
	ret = install_IOS(lowios, true);
	if (ret < 0)
	{
		printf("Error: Could not install IOS%u Rev %u\n", iosversion, lowrevision);
		free_IOS(&highios);
		free_IOS(&lowios);
		return ret;
	}

	printf("IOS%u downgrade to revision: %u complete.\n", iosversion, lowrevision);
	if (free) {
		free_IOS(&highios);
		free_IOS(&lowios);
	}

	return 0;
}
예제 #6
0
s32 Downgrade_TMD_Revision(void *ptmd, u32 tmd_size, void *certs, u32 certs_size) 
{
	// The revison of the tmd used as paramter here has to be >= the revision of the installed tmd
	s32 ret;

	printf("Setting the revision to 0...\n");

	ret = ES_AddTitleStart(ptmd, tmd_size, certs, certs_size, NULL, 0);
	if (ret < 0) 
	{
		if (ret == -1035)
		{
			printf("Error: ES_AddTitleStart returned %d, maybe you need an updated Downgrader\n", ret);
		} else
		{
			printf("Error: ES_AddTitleStart returned %d\n", ret);
		}
		ES_AddTitleCancel();
		return ret;
	}

	s32 file;
	char *tmd_path = "/tmp/title.tmd";
	
	ret = ISFS_Delete(tmd_path);	
	if (ret < 0) 
	{
		printf("Error: ISFS_Delete returned %d\n", ret);
		ES_AddTitleCancel();
		ISFS_Deinitialize();
		return ret;
	}
	ret = ISFS_CreateFile(tmd_path, 0, 3, 3, 3);
	if (ret < 0) 
	{
		printf("Error: ISFS_CreateFile returned %d\n", ret);
		ES_AddTitleCancel();
		ISFS_Deinitialize();
		return ret;
	}

	file = ISFS_Open(tmd_path, ISFS_OPEN_RW);
	if (file < 0)
	{
		printf("Error: ISFS_Open returned %d\n", file);
		ES_AddTitleCancel();
		ISFS_Deinitialize();
		return file;
	}
	
	u8 *tmd = (u8 *)ptmd;
	tmd[0x1dc] = 0;
	tmd[0x1dd] = 0;
	
	ret = ISFS_Write(file, (u8 *)ptmd, tmd_size);
	if (ret < 0) 
	{
		printf("Error: ISFS_Write returned %d\n", ret);
		ISFS_Close(file);
		ES_AddTitleCancel();
		ISFS_Deinitialize();
		return ret;
	}

	ISFS_Close(file);
	ISFS_Deinitialize();

	ret = ES_AddTitleFinish();
	if (ret < 0) 
	{
		printf("Error: ES_AddTitleFinish returned %d\n", ret);
		return ret;
	}
	
	return 1;
}