动态生成GPT分区表
1. 题目具体要求描述
1) 在硬盘上安装win10 64位系统(GPT分区模式), 硬盘要预留空闲空间; --- 前置部署条件
2) 程序具体功能:
A. check 功能
显示当前硬盘上的已划分空间和剩余空间,显示当前硬盘上的分区位置(起始扇区和结束扇区);
B. Add 功能
在空闲空间上添加指定大小的分区;
C. Del 功能
可以把指定(序号)分区从硬盘上删除掉;
2. 基于 linux 平台开发( 提供开发环境 && 基本的磁盘读写接口 && 简单的程序框架 );
diskop.h
#ifndef _DISKOP_H_
#define _DISKOP_H_
#define DISK_READ 2
#define DISK_WRITE 3
#define RETRYTIMES_READWRITE 5
typedef u_int8_t BYTE;
typedef u_int16_t WORD;
typedef u_int32_t DWORD;
typedef u_int64_t DDWORD;
typedef unsigned long long ULONGLONG;
typedef long long LONGLONG;
typedef unsigned long ULONG;
typedef BYTE* LPBYTE;
typedef DWORD UINT;
typedef WORD USHORT;
typedef BYTE* LPSTR;
typedef unsigned char TCHAR;
typedef long long __int64;
typedef WORD* LPWORD;
typedef BYTE BOOL;
int myreadorwrite(BYTE readorwrite, int fd, BYTE *buf, size_t size)
{
size_t total_written = 0;
ssize_t nwritten = 0;
while(total_written < size)
{
//??д???
if(readorwrite == DISK_WRITE)
nwritten = write(fd, buf + total_written, size - total_written);
else if(readorwrite == DISK_READ)
nwritten = read(fd, buf + total_written, size - total_written);
//?ж??д???
if(nwritten > 0)
total_written += nwritten;
else if(nwritten == 0)
break;
else
return -1;
}
return total_written;
}
/*
* === FUNCTION ======================================================================
* Name: hd_4kblok_readwrite
* Description: ???read/write???????????д???(????)???С???4kb.
* =====================================================================================
*/
static DDWORD
hd_4kblok_readwrite (BYTE readorwrite,int fp_disk,DDWORD logsec,DDWORD blocksize, BYTE * buff)
{
int local_adjust = 0;
DDWORD relogsec = 0;
DDWORD reblocksize = 0;
DDWORD tmp_blockcount = 0;
DDWORD total_size = 0;
BYTE tmpbuffer[4096];
int retry_lseek = 0;
int n;
int ret = 0;
char str[300];
DDWORD lseek_local = 0;
local_adjust = logsec % 8;
relogsec = logsec - local_adjust;
//?????д?????λ??
DDWORD size = (DDWORD)(relogsec * 512);
retry_lseek = 0;
while(retry_lseek < RETRYTIMES_READWRITE)
{
ret = lseek64(fp_disk, size, SEEK_SET);
if(ret == -1)
{
retry_lseek ++;
if(retry_lseek >= 3)//??3?ζ?λ????????????????
{
printf("readorwrite lseek error:%d, disk_fd:%d, relogsec:[%lu].\n", readorwrite, fp_disk, relogsec);
printf("relogsec lseek error! user press cancel ... \n");
}
}
else {
break ;
}
}
tmp_blockcount = blocksize + local_adjust;
// printmsg("tmp_blockcount = %lld\n", tmp_blockcount);
reblocksize = ( tmp_blockcount/8 + 1 ) * 8;
if ( tmp_blockcount % 8 == 0 ) {
reblocksize -= 8;
}
if ( readorwrite == DISK_READ ) {
n = 0;
total_size = 0;
if ( reblocksize / 8 == 1 ) {
if ( read(fp_disk, tmpbuffer, 8 * 512) != 8 * 512 ) {
printf("read type @ 1 read 4k block error :%s\n", strerror(errno));
return -1;
}
memcpy(buff, tmpbuffer + local_adjust * 512, blocksize * 512);
total_size = blocksize * 512;
}
else {
while ( n < reblocksize / 8 ) {
if ( read(fp_disk, tmpbuffer, 8 * 512) != 8 * 512 ) {
printf("read type @ 2 read 4k block error :%s\n", strerror(errno));
return -1;
}
n++;
if ( n == 1 ) {
memcpy(buff, tmpbuffer + local_adjust * 512, (8 - local_adjust) * 512);
total_size += (8-local_adjust) * 512;
buff += (8 - local_adjust) * 512;
}
else if ( n == reblocksize / 8 ) {
if ( tmp_blockcount % 8 == 0 ) {
memcpy(buff, tmpbuffer, 8 * 512);
total_size += 8 *512;
}
else {
memcpy(buff, tmpbuffer, tmp_blockcount % 8 * 512);
total_size += tmp_blockcount % 8 * 512;
}
}
else {
memcpy(buff, tmpbuffer, 8 * 512);
total_size += 8 * 512;
buff += 8 * 512;
}
}
}
}
else if ( readorwrite == DISK_WRITE ) {
n = 0;
total_size = 0;
if ( reblocksize / 8 == 1 ) {
retry_lseek = 0;
while(retry_lseek < RETRYTIMES_READWRITE)
{
lseek_local = lseek64(fp_disk, 0, SEEK_CUR);
if(lseek_local == -1)
{
retry_lseek ++;
if(retry_lseek >= 3)//??3?ζ?λ????????????????
{
printf("seek curren 1 error: n:%d, errno:%s.\n",
n, strerror(errno));
printf("seek curren 1 error! user press cancel ... \n");
}
}
else {
break ;
}
}
if ( read(fp_disk, tmpbuffer, 8 * 512) != 8 * 512 ) {
printf("write type @ 1 read 4k block error :%s\n", strerror(errno));
return -1;
}
memcpy(tmpbuffer + local_adjust * 512, buff, blocksize * 512);
retry_lseek = 0;
while(retry_lseek < RETRYTIMES_READWRITE)
{
ret = lseek64(fp_disk, lseek_local, SEEK_SET);
if(ret == -1)
{
retry_lseek ++;
if(retry_lseek >= 3)//??3?ζ?λ????????????????
{
// printmsg("zfk relogsec = %lld.\n", relogsec);
printf("readorwrite lseek error:%d, n:%d, lseek_local:[%lu], errno:%s.\n",
readorwrite, n, lseek_local, strerror(errno));
printf("write 3 lseek error! user press cancel ... \n");
}
}
else {
break ;
}
}
if ( write(fp_disk, tmpbuffer, 8 * 512) != 8 * 512 ) {
printf("write type @ 1 write 4k block error :%s\n", strerror(errno));
return -1;
}
total_size = blocksize * 512;
}
else {
while ( n < reblocksize / 8 ) {
n++;
if ( n == 1 ) {
retry_lseek = 0;
while(retry_lseek < RETRYTIMES_READWRITE)
{
lseek_local = lseek64(fp_disk, 0, SEEK_CUR);
if(lseek_local == -1)
{
retry_lseek ++;
if(retry_lseek >= 3)//??3?ζ?λ????????????????
{
printf("seek curren 2 error: n:%d, errno:%s.\n",
n, strerror(errno));
printf("seek curren 2 error! user press ok ... \n");
}
}
else {
break ;
}
}
if ( read(fp_disk, tmpbuffer, 8 * 512) != 8 * 512 ) {
printf("write type @ 2 read 4k block error :%s\n", strerror(errno));
return -1;
}
memcpy(tmpbuffer + local_adjust * 512, buff, (8 - local_adjust) * 512);
retry_lseek = 0;
while(retry_lseek < RETRYTIMES_READWRITE)
{
ret = lseek64(fp_disk, lseek_local, SEEK_SET);
if(ret == -1)
{
retry_lseek ++;
if(retry_lseek >= 3)//??3?ζ?λ????????????????
{
// printmsg("zfk relogsec = %lld.\n", relogsec);
printf("readorwrite lseek error:%d, n:%d, lseek_local:[%lu], errno:%s.\n",
readorwrite, n, lseek_local, strerror(errno));
printf("write 4 lseek error! user press ok ... \n");
}
}
else {
break ;
}
}
if ( write(fp_disk, tmpbuffer, 8 * 512) != 8 * 512 ) {
printf("write type @ 2 write 4k block error :%s\n", strerror(errno));
return -1;
}
total_size += (8-local_adjust) * 512;
buff += (8 - local_adjust) * 512;
}
else if ( n == reblocksize / 8 ) {
if ( tmp_blockcount % 8 == 0 ) {
if ( write(fp_disk, buff, 8 * 512) != 8 * 512 ) {
printf("write type @ 3 write 4k block error :%s\n", strerror(errno));
return -1;
}
total_size += 8 *512;
}
else {
retry_lseek = 0;
while(retry_lseek < RETRYTIMES_READWRITE)
{
lseek_local = lseek64(fp_disk, 0, SEEK_CUR);
if(lseek_local == -1)
{
retry_lseek ++;
if(retry_lseek >= 3)//??3?ζ?λ????????????????
{
printf("seek curren 3 error: n:%d, errno:%s.\n",
n, strerror(errno));
printf("seek curren 3 error! user press cancel ... \n");
}
}
else {
break ;
}
}
if ( read(fp_disk, tmpbuffer, 8 * 512) == -1 ) {
printf("write type @ 3 read 4k block error :%s\n", strerror(errno));
return -1;
}
memcpy(tmpbuffer, buff, tmp_blockcount % 8 * 512);
retry_lseek = 0;
while(retry_lseek < RETRYTIMES_READWRITE)
{
ret = lseek64(fp_disk, lseek_local, SEEK_SET);
if(ret == -1)
{
retry_lseek ++;
if(retry_lseek >= 3)//??3?ζ?λ????????????????
{
// printmsg("zfk relogsec = %lld.\n", relogsec);
printf("readorwrite lseek error:%d, n:%d, lseek_local:[%lu], errno:%s.\n",
readorwrite, n, lseek_local, strerror(errno));
printf("write 5 lseek error! user press cancel ... \n");
}
}
else {
break ;
}
}
if ( write(fp_disk, tmpbuffer, 8 * 512) == -1 ) {
printf("write type @ 4 write 4k block error :%s\n", strerror(errno));
return -1;
}
total_size += tmp_blockcount % 8 *512;
}
}
else {
if ( write(fp_disk, buff, 8 * 512) != 8 * 512 ) {
printf("write type @ 5 write 4k block error :%s\n", strerror(errno));
return -1;
}
total_size += 8 *512;
buff += 8 * 512;
}
}
}
}
else {
printf("read write type error!\n");
}
return total_size;
} /* ----- end of function hd_4kblok_readwrite ----- */
//??д????????????????д5??
WORD readwriteblocktohd(BYTE readorwrite,int fp_disk,DDWORD logsec,DDWORD blocksize, BYTE * buff)
{
int readwritenbyte = 0;
// int ret = 0;
char str[300];
int retry = 0;
// int retry_lseek = 0;
while(retry < RETRYTIMES_READWRITE)
{
readwritenbyte = hd_4kblok_readwrite(readorwrite, fp_disk, logsec, blocksize, buff);
if ( readwritenbyte == -2 )
return 1;
//??д????????
if(readwritenbyte == blocksize*512)
return 0;
//?????д???????????????
printf("Disk read write error sector:%ld, retrytime:%d.\n", logsec, retry);
retry++;
if (retry >= 3) //?????3?ζ?д???????????????????
{
printf("read or write disk error !user press cancel ... \n");
}
}
return 1;
}
DWORD mCrcTable[256];
DWORD ReverseBits(DWORD Value)
{
DDWORD Index;
DWORD NewValue;
NewValue = 0;
for (Index=0;Index<32;Index++)
{
if ((Value & (1 << Index)) != 0)
{
NewValue = NewValue | (1 << (31 - Index));
}
}
return NewValue;
}
void InitializeCrc32Table()
{
DDWORD TableEntry;
DDWORD Index;
DWORD Value;
for(TableEntry=0;TableEntry<256;TableEntry++)
{
Value = ReverseBits((DWORD)TableEntry);
for(Index=0;Index<8;Index++)
{
if ((Value & 0x80000000) != 0)
{
Value = (Value << 1) ^ 0x04c11db7;
}
else
{
Value = Value << 1;
}
}
mCrcTable[TableEntry] = ReverseBits(Value);
}
}
int CalculateCrc32 (void *Data, DDWORD DataSize,DWORD *CrcOut)
{
DWORD Crc;
DDWORD Index;
BYTE *Ptr = NULL;
if(Data == NULL || DataSize == 0 || CrcOut == NULL)
return 1;
Ptr = (BYTE *)Data;
Crc = 0xffffffff;
for(Index=0;Index<DataSize;Index++)
{
Crc = (Crc >> 8) ^ mCrcTable[(BYTE) Crc ^ *Ptr];
Ptr++;
}
*CrcOut = Crc ^ 0xffffffff;
return 0;
}
#endif
#define SIMPLE_CHINESE
#define _LARGEFILE64_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <ctype.h>
#include <linux/hdreg.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <uuid/uuid.h>
#include "diskop.h"
#pragma pack(4)
struct gpthead
{
BYTE Signature[8];
DWORD Revision;
DWORD HeaderSize;
DWORD HeaderCRC32;
DWORD Reserved;
DDWORD MyLBA;
DDWORD AlternateLBA;
DDWORD FirstUsableLBA;
DDWORD LastUsableLBA;
BYTE DiskGUID[16];
DDWORD PartitionEntryLBA;
DWORD NumberOfPartitionEntries;
DWORD SizeOfPartitionEntry;
DWORD PartitionEntryArrayCRC32;
BYTE Other[512-92];//保留区
}head;
struct gptpartition
{
BYTE PartitionTypeGUID[16];
BYTE UniquePartitionGUID[16];
DDWORD StartingLBA;
DDWORD EndingLBA;
BYTE Attributes[8];
BYTE PartitionName[72];
//BYTE Reserved[];
}GPT[128];//128个gpt分区表
#pragma pack()
int read_gpthead()
{
int fd;
int i=0;
WORD ret=0;
fd=open("/dev/sda", O_RDONLY);
if(fd<0)
{
printf("open dev error\n");
return -1;
}
ret=readwriteblocktohd(DISK_READ,fd,1,1,(BYTE*)&head);
if(ret)
{
printf("read patition 2-23 error\n");
return -1;
}
close(fd);
}
int read_table()
{
int fd;
WORD ret=0;
fd=open("/dev/sda", O_RDONLY);
if(fd<0)
{
printf("open dev error\n");
return -1;
}
ret=readwriteblocktohd(DISK_READ,fd,2,32,(BYTE*)&GPT);
if(ret)
{
printf("read patition 2-23 error\n");
return -1;
}
close(fd);
}
void show_table()
{
WORD count=0;
DDWORD gptsize=0;
DDWORD gptstart=0;
DDWORD gptend=0;
read_table();
printf("当前分区表信息如下:\n");
for(int i=0; i<128; i++)
{
if(GPT[i].EndingLBA==0 && GPT[i].StartingLBA==0)
continue;
gptend=ReverseBitsDD(GPT[i].EndingLBA);
gptstart=ReverseBitsDD(GPT[i].StartingLBA);
gptsize=gptend-gptstart;
printf("GPT%d:\n",count);
printf("gptstart:%08lx \ngptend: %08lx \ngptsize:%09lx=%ldMB\n",gptstart,gptend,gptsize+1,(gptsize+1)*512>>20);
count++;
printf("\n");
}
}
int check()
{
int fd;
WORD ret=0;
DDWORD allsize=0;
DDWORD alluse=0;
DDWORD allnotuse=0;
DDWORD gptsize=0;
DDWORD gptstart=0;
DDWORD gptend=0;
BYTE buff[512]={0};
system("clear");
fd = open("/dev/sda", O_RDONLY);
if (fd < 0)
{
printf("open dev error\n");
return 0;
}
ioctl(fd, BLKGETSIZE, &allsize);
allsize=allsize<<9;
read_table(); //读取gpt分区表
close(fd);
for(int i=0; i<128; i++)
{
gptend=ReverseBitsDD(GPT[i].EndingLBA);
gptstart=ReverseBitsDD(GPT[i].StartingLBA);
gptsize=gptend-gptstart;
if(gptend!=0 && gptstart!=0 && gptsize!=0)
{
printf("GPT%d: gptstart:%08lx gptend:%08lx gptsize:%016ldbyte= %ldMB\n\n",i,gptstart,gptend,(gptsize+1)*512,(gptsize+1)*512>>20);
alluse=alluse+gptsize;
}
}
//显示信息
allnotuse=allsize-(alluse<<9);
printf("allsize=%lx %ldbyte= %ldKB= %ldMB= %ldGB\n",allsize>>9,allsize,allsize>>10,allsize>>20,allsize>>30);
printf("alluse=%ldbyte= %ldKB= %ldMB= %ldGB\n",alluse<<9,alluse<<9>>10,alluse<<9>>20,alluse<<9>>30);
printf("allnotuse=%ldbyte= %ldKB= %ldMB= %ldGB\n\n",allnotuse,allnotuse>>10,allnotuse>>20,allnotuse>>30);
}
int del()
{
int fd=0;
int ret=0;
int tag=0;
int count=0;
BYTE buff[512]={0};
DWORD senderCRC32_0;
read_gpthead();//读取gpt头的信息
show_table();//显示当前信息
printf("delete num:");
scanf("%d", &tag);
for(int i=0; i<128; i++)//找到要删除的分区表
{
if(GPT[i].StartingLBA==GPT[tag].StartingLBA&&GPT[i].EndingLBA==GPT[tag].EndingLBA)
{
count = i;
break;
}
}
for(int i=count; i<(127-count); i++)//将要删除分区表后面的128个字节的分区表前移
{
memcpy((BYTE*)&GPT[i],(BYTE*)&GPT[i+1],128);
}
//最后一个数组清0
memset((BYTE*)&GPT[127],0,128);
//写入备份分区
fd = open("/dev/sda", O_RDWR);
if (fd < 0)
{
printf("open dev error\n");
return 0;
}
ret=readwriteblocktohd(DISK_WRITE,fd,head.AlternateLBA-32,32,(BYTE*)&GPT);
if(ret)
{
printf("write sector error\n");
return -1;
}
ret=readwriteblocktohd(DISK_WRITE,fd,head.PartitionEntryLBA,32,(BYTE*)&GPT);
if(ret)
{
printf("write sector error\n");
return -1;
}
//===========计算出CRC32后写入gpt头和备份区
senderCRC32_0=0;
InitializeCrc32Table();
ret = CalculateCrc32((void *)&GPT,128*128,&senderCRC32_0);
if(ret)
{
printf("cal the sender backup CRC32_0 error\n");
return 0;
}
printf("%x \n",senderCRC32_0);
//=====
ret=readwriteblocktohd(DISK_READ,fd,head.MyLBA,1,(BYTE*)&head);
if(ret)
{
printf("read error\n");
return -1;
}
head.PartitionEntryArrayCRC32=ReverseBitsD(senderCRC32_0);
head.HeaderCRC32=0;
printf("aaaa%x \n",head.PartitionEntryArrayCRC32);
ret = CalculateCrc32((void *)&head,head.HeaderSize,&senderCRC32_0);
if(ret)
{
printf("cal the sender backup CRC32_0 error\n");
return 0;
}
printf("%x \n",senderCRC32_0);
//=============
head.HeaderCRC32=ReverseBitsD(senderCRC32_0);
//=========写入gpt备份区
ret = readwriteblocktohd(DISK_WRITE,fd,head.AlternateLBA,1, (BYTE*)&head);
if(ret)
{
printf("read/write error%d\n",ret);
}
//=========写入gpt头
ret = readwriteblocktohd(DISK_WRITE,fd,head.MyLBA,1, (BYTE*)&head);
if(ret)
{
printf("read/write error%d\n",ret);
}
close(fd);
//============
show_table();
}
int add()
{
int fd=0;
int ret=0;
int count=0;
BYTE _PartitionTypeGUID[16]={0xeb,0xd0,0xa0,0xa2,0xb9,0xe5,0x44,0x33,0x87,0xc0,0x68,0xb6,0xb7,0x26,0x99,0xc7}
uuid_t uu;
DWORD senderCRC32_0=0;
DWORD gpt_temp=0;
DDWORD EX_sector=0;
read_gpthead();//读取gpt头信息
read_table();//读取gpt分区表信息到结构体
printf("add size(MB):");
scanf("%ld",&EX_sector);
EX_sector=(EX_sector<<20)/512;
printf("addsize: %lx\n%ldB= %ldKB= %ldMB= %ldGB\n",EX_sector,EX_sector*512,EX_sector*512>>10,EX_sector*512>>20,EX_sector*512>>30);
for(int i=0; i<128; i++)//找到最后一个分区表的结束位置
{
if(gpt_temp<=ReverseBitsDD(GPT[i].EndingLBA))
gpt_temp=ReverseBitsDD(GPT[i].EndingLBA);
}
uuid_generate_time(uu);//计算GUID
for(int i=0;i<128;i++)
{
if(GPT[i].StartingLBA==0&&GPT[i].EndingLBA==0)
{
count=i;
break;
}
}
for(int i=0; i<16; i++)
{
GPT[count].PartitionTypeGUID[i]=_PartitionTypeGUID[i];
GPT[count].UniquePartitionGUID[i]=uu[i];
}
//起点终点
GPT[count].StartingLBA=ReverseBitsDD(gpt_temp+1);
GPT[count].EndingLBA=ReverseBitsDD(gpt_temp+1+EX_sector);
memset(GPT[count].Attributes,0,8);
for(int i=0; i<72; i++)
{
GPT[count].PartitionName[i]=GPT[count-1].PartitionName[i];
}
//写入备份分区
fd = open("/dev/sda", O_RDWR);
if (fd < 0)
{
printf("open dev error\n");
return 0;
}
ret=readwriteblocktohd(DISK_WRITE,fd,head.AlternateLBA-32,32,(BYTE*)&GPT);
if(ret)
{
printf("write sector error\n");
return -1;
}
ret=readwriteblocktohd(DISK_WRITE,fd,head.PartitionEntryLBA,32,(BYTE*)&GPT);
if(ret)
{
printf("write sector error\n");
return -1;
}
//===========计算出CRC32后写入gpt头和备份区
senderCRC32_0=0;
InitializeCrc32Table();
ret = CalculateCrc32((void *)&GPT,128*128,&senderCRC32_0);
if(ret)
{
printf("cal the sender backup CRC32_0 error\n");
return 0;
}
printf("%x \n",senderCRC32_0);
//=====
ret=readwriteblocktohd(DISK_READ,fd,head.MyLBA,1,(BYTE*)&head);
if(ret)
{
printf("read error\n");
return -1;
}
head.PartitionEntryArrayCRC32=ReverseBitsD(senderCRC32_0);
head.HeaderCRC32=0;
printf("aaaa%x \n",head.PartitionEntryArrayCRC32);
ret = CalculateCrc32((void *)&head,head.HeaderSize,&senderCRC32_0);
if(ret)
{
printf("cal the sender backup CRC32_0 error\n");
return 0;
}
printf("%x \n",senderCRC32_0);
//=============
head.HeaderCRC32=ReverseBitsD(senderCRC32_0);
//=========写入gpt备份区
ret = readwriteblocktohd(DISK_WRITE,fd,head.AlternateLBA,1, (BYTE*)&head);
if(ret)
{
printf("read/write error%d\n",ret);
}
//=========写入gpt头
ret = readwriteblocktohd(DISK_WRITE,fd,head.MyLBA,1, (BYTE*)&head);
if(ret)
{
printf("read/write error%d\n",ret);
}
close(fd);
//============
show_table();
}
int main()
{
int fd = 0;
WORD ret = 0;
BYTE buff[512];
int i = 0;
BYTE buff_parttable[32*512];
fd = open("/dev/sda", O_RDWR);
if (fd < 0)
{
printf("open dev error\n");
return 0;
}
add();
ret = readwriteblocktohd(DISK_READ,fd,1,1, buff);
if(ret)
{
printf("read/write error%d\n",ret);
}
for(i = 0; i < 512; i++)
{
printf("%02x ",buff[i]);
if((i+1)%16 == 0)
{
printf("\n");
}
if((i+1)%128 == 0)
{
printf("\n");
}
}
/*
int fd = 0;
int tag = 1;
WORD ret = 0;
system("clear");
//
while(tag)
{
printf("// /dev/sda\n//=========================\n");
printf(" 1.check\n 2.add\n 3.del\n 4.quit\n");
printf("type in the number:");
scanf("%d", &tag);
switch(tag)
{
case 1:
{
check();
show_table();
break;
}
case 2:
{
add();
break;
}
case 3:
{
del();
break;
}
case 4:
{
return 0;
break;
}
default:
{
printf("input error\n");
return 0;
}
}
}
*/
return 0;
}