/* * GRUB Utilities -- Utilities for GRUB Legacy, GRUB2 and GRUB for DOS * Copyright (C) 2007 Bean (bean123@126.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef LINUX #define _FILE_OFFSET_BITS 64 // This is required to enable 64-bit off_t #include #endif #include #include #include #include "utils.h" static unsigned char ebuf[512]; #if defined(WIN32) #ifdef __GNUC__ // Mingw or Cygwin #define u_off_t off64_t #define u_lseek lseek64 #else #define u_off_t __int64 #define u_lseek _lseeki64 #endif #else #define u_off_t off_t // In FreeBSD, off_t is 64-bit ! #define u_lseek lseek #endif int go_sect(int hd,unsigned long sec) { // Test if 64-bit seek is supported if (sizeof(u_off_t)>=8) { u_off_t bs,rs; bs=sec; bs<<=9; rs=u_lseek(hd,bs,SEEK_SET); return (bs!=rs); } else { unsigned long bs[2]; bs[0]=sec<<9; bs[1]=sec>>23; if (bs[1]) return 1; return (lseek(hd,bs[0],SEEK_SET)!=(off_t)bs[0]); } } // Partition enumerator // xe->cur is the current partition number, before the first call to xd_enum, // it should be set to 0xFF // xe->nxt is the target partition number, if it equals 0xFF, it means enumerate // all partitions, otherwise, it means jump to the specific partition. int xd_enum(int hd,xde_t* xe) { int nn=512,kk=1,cc; for (cc=xe->cur;;) { if (cc==0xFF) { unsigned long pt[4][2]; int i,j,np; if (go_sect(hd,0)) return 1; if (read(hd,ebuf,nn)!=nn) return 1; if (get16(ebuf,0x1FE)!=0xAA55) return 1; np=0; for (i=0x1BE;i<0x1FE;i+=16) if (ebuf[i+4]) { if ((pt[np][1]=get32(ebuf,i+12))==0) return 1; pt[np++][0]=get32(ebuf,i+8); } if (np==0) return 1; // Sort partition table base on start address for (i=0;ipt[j][0]) k=j; if (k!=i) { unsigned long tt; tt=pt[i][0]; pt[i][0]=pt[k][0]; pt[k][0]=tt; tt=pt[i][1]; pt[i][1]=pt[k][1]; pt[k][1]=tt; } } // Should have space for MBR if (pt[0][0]==0) return 1; // Check for partition overlap for (i=0;ipt[i+1][0]) return 1; cc=0; } else if (kk) cc++; if ((unsigned char)cc>xe->nxt) return 1; if (cc<4) { if (xe->nxt<4) { // Empty partition if (! ebuf[xe->nxt*16+4+0x1BE]) return 1; xe->cur=xe->nxt; xe->dfs=ebuf[xe->nxt*16+4+0x1BE]; xe->bse=get32(ebuf,xe->nxt*16+8+0x1BE); xe->len=get32(ebuf,xe->nxt*16+12+0x1BE); return 0; } else if (xe->nxt!=0xFF) cc=4; else while (cc<4) { if (ebuf[cc*16+4+0x1BE]) { xe->cur=cc; xe->dfs=ebuf[cc*16+4+0x1BE]; xe->bse=get32(ebuf,cc*16+8+0x1BE); xe->len=get32(ebuf,cc*16+12+0x1BE); return 0; } cc++; } } if ((cc==4) && (kk)) { int i; // Scan for extended partition for (i=0;i<4;i++) if ((ebuf[i*16+4+0x1BE]==5) || (ebuf[i*16+4+0x1BE]==0xF)) break; if (i==4) return 1; xe->ebs=xe->bse=get32(ebuf,i*16+8+0x1BE); } else { // Is end of extended partition chain ? if (((ebuf[4+0x1CE]!=0x5) && (ebuf[4+0x1CE]!=0xF)) || (get32(ebuf,8+0x1CE)==0)) return 1; xe->bse=xe->ebs+get32(ebuf,8+0x1CE); } { while (1) { if (go_sect(hd,xe->bse)) return 1; if (read(hd,ebuf,nn)!=nn) return 1; if (get16(ebuf,0x1FE)!=0xAA55) return 1; if ((ebuf[4+0x1BE]==5) || (ebuf[4+0x1BE]==0xF)) { if (get32(ebuf,8+0x1BE)==0) return 1; else { xe->bse=xe->ebs+get32(ebuf,8+0x1BE); continue; } } break; } kk=(ebuf[4+0x1BE]!=0); if ((kk) && ((xe->nxt==0xFF) || (cc==xe->nxt))) { xe->cur=cc; xe->dfs=ebuf[4+0x1BE]; xe->bse+=get32(ebuf,8+0x1BE); xe->len=get32(ebuf,12+0x1BE); return 0; } } } } #define EXT2_SUPER_MAGIC 0xEF53 int mbr_nhd, mbr_spt; static void split_chs(unsigned char* chs,unsigned long* c,unsigned long* h,unsigned long* s) { *h=chs[0]; *s=(chs[1] & 0x3F)-1; *c=((unsigned long)(chs[1]>>6))*256+chs[2]; } static int chk_chs(unsigned long nhd,unsigned long spt,unsigned long lba,unsigned char* chs) { unsigned long c,h,s; split_chs(chs,&c,&h,&s); if (c==0x3FF) return ((nhd==h+1) && (spt==s+1)); else return (c*nhd*spt+h*spt+s==lba); } static int chk_mbr(unsigned char* buf) { unsigned long nhd,spt,a1,a2,c2,h2,s2; int i; i=0x1BE; while ((i<0x1FE) && (buf[i+4]==0)) i+=16; if (i>=0x1FE) return 0; a1=get32(&buf[i],8); a2=a1+get32(&buf[i],12)-1; if (a1>=a2) return 0; split_chs(buf+i+5,&c2,&h2,&s2); if (c2==0x3FF) { nhd=h2+1; spt=s2+1; if (! chk_chs(nhd,spt,a1,buf+i+1)) return 0; } else { unsigned long c1,h1,s1; long n1,n2; split_chs(buf+i+1,&c1,&h1,&s1); if ((c1==0x3FF) || (c1>c2)) return 0; n1=(long)(c1*a2)-(long)(c2*a1)-(long)(c1*s2)+(long)(c2*s1); n2=(long)(c1*h2)-(long)(c2*h1); if (n2<0) { n2=-n2; n1=-n1; } if ((n2==0) || (n1<=0) || (n1 % n2)) return 0; spt=(unsigned long)(n1/n2); if (c2) { n1=(long)a2-(long)s2-(long)(h2*spt); n2=(long)(c2*spt); if ((n2==0) || (n1<=0) || (n1 % n2)) return 0; nhd=(unsigned long)(n1/n2); } else nhd=h2+1; } if ((nhd==0) || (nhd>255) || (spt==0) || (spt>63)) return 0; i+=16; while (i<0x1FE) { if (buf[i+4]) { if ((! chk_chs(nhd,spt,get32(&buf[i],8),buf+i+1)) || (! chk_chs(nhd,spt,get32(&buf[i],8)+get32(&buf[i],12)-1,buf+i+5))) return 0; } i+=16; } mbr_nhd=(int)nhd; mbr_spt=(int)spt; return 1; } int get_fstype(unsigned char* buf) { if (chk_mbr(buf)) return FST_MBR; // The first sector of EXT2 might not contain the 0xAA55 signature if (get16(&buf[1024],56)==EXT2_SUPER_MAGIC) return FST_EXT2; if (get16(&buf[0],0x1FE)!=0xAA55) return FST_OTHER; if (! memcmp(&buf[0x36],"FAT",3)) return ((buf[0x26]==0x28) || (buf[0x26]==0x29))?FST_FAT16:FST_OTHER; if (! memcmp(&buf[0x52],"FAT32",5)) return ((buf[0x42]==0x28) || (buf[0x42]==0x29))?FST_FAT32:FST_OTHER; if (! memcmp(&buf[0x3],"NTFS",4)) return ((buf[0]==0xEB) && (buf[1]==0x52))?FST_NTFS:FST_OTHER; return FST_OTHER; } const char* fst2str(int fs) { switch (fs) { case FST_OTHER: return "Other"; case FST_MBR: return "MBR"; case FST_FAT16: return "FAT12/FAT16"; case FST_FAT32: return "FAT32"; case FST_NTFS: return "NTFS"; case FST_EXT2: return "EXT2/EXT3"; default: return "Unknown"; } } typedef struct { int id; const char* str; } fstab_t; static fstab_t fstab[]= { {0x1,"FAT12"}, {0x4,"FAT16"}, {0x5,"Extended"}, {0x6,"FAT16B"}, {0x7,"NTFS"}, {0xB,"FAT32"}, {0xC,"FAT32X"}, {0xE,"FAT16X"}, {0xF,"ExtendedX"}, {0x11,"(H)FAT12"}, {0x14,"(H)FAT16"}, {0x16,"(H)FAT16B"}, {0x17,"(H)NTFS"}, {0x1B,"(H)FAT32"}, {0x1C,"(H)FAT32X"}, {0x1E,"(H)FAT16X"}, {0x82,"Swap"}, {0x83,"Ext2"}, {0xA5,"FBSD"}, {0,"Other"}}; const char* dfs2str(int fs) { int i; for (i=0;fstab[i].id;i++) if (fs==fstab[i].id) return fstab[i].str; return fstab[i].str; }