Add 'ntldr-img/' from commit '0f07f4f2cfebc14bbf14b0f013c015302b16f70c'
[grub-extras.git] / ntldr-img / utils.c
blob1b68c72d8d228968ea7c5aa41e15181e2d2d670b
1 /*
2 * GRUB Utilities -- Utilities for GRUB Legacy, GRUB2 and GRUB for DOS
3 * Copyright (C) 2007 Bean (bean123@126.com)
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #ifdef LINUX
22 #define _FILE_OFFSET_BITS 64 // This is required to enable 64-bit off_t
23 #include <unistd.h>
25 #endif
27 #include <stdio.h>
28 #include <fcntl.h>
30 #include "utils.h"
32 static unsigned char ebuf[512];
34 #if defined(WIN32)
36 #ifdef __GNUC__ // Mingw or Cygwin
38 #define u_off_t off64_t
39 #define u_lseek lseek64
41 #else
43 #define u_off_t __int64
44 #define u_lseek _lseeki64
46 #endif
48 #else
50 #define u_off_t off_t // In FreeBSD, off_t is 64-bit !
51 #define u_lseek lseek
53 #endif
55 int go_sect(int hd,unsigned long sec)
57 // Test if 64-bit seek is supported
58 if (sizeof(u_off_t)>=8)
60 u_off_t bs,rs;
62 bs=sec;
63 bs<<=9;
64 rs=u_lseek(hd,bs,SEEK_SET);
65 return (bs!=rs);
67 else
69 unsigned long bs[2];
71 bs[0]=sec<<9;
72 bs[1]=sec>>23;
73 if (bs[1])
74 return 1;
75 return (lseek(hd,bs[0],SEEK_SET)!=bs[0]);
79 // Partition enumerator
80 // xe->cur is the current partition number, before the first call to xd_enum,
81 // it should be set to 0xFF
82 // xe->nxt is the target partition number, if it equals 0xFF, it means enumerate
83 // all partitions, otherwise, it means jump to the specific partition.
84 int xd_enum(int hd,xde_t* xe)
86 int nn=512,kk=1,cc;
88 for (cc=xe->cur;;)
90 if (cc==0xFF)
92 unsigned long pt[4][2];
93 int i,j,np;
95 if (go_sect(hd,0))
96 return 1;
97 if (read(hd,ebuf,nn)!=nn)
98 return 1;
99 if (valueat(ebuf,0x1FE,unsigned short)!=0xAA55)
100 return 1;
101 np=0;
102 for (i=0x1BE;i<0x1FE;i+=16)
103 if (ebuf[i+4])
105 if ((pt[np][1]=valueat(ebuf,i+12,unsigned long))==0)
106 return 1;
107 pt[np++][0]=valueat(ebuf,i+8,unsigned long);
109 if (np==0)
110 return 1;
111 // Sort partition table base on start address
112 for (i=0;i<np-1;i++)
114 int k=i;
115 for (j=i+1;j<np;j++)
116 if (pt[k][0]>pt[j][0]) k=j;
117 if (k!=i)
119 unsigned long tt;
121 tt=pt[i][0];
122 pt[i][0]=pt[k][0];
123 pt[k][0]=tt;
124 tt=pt[i][1];
125 pt[i][1]=pt[k][1];
126 pt[k][1]=tt;
129 // Should have space for MBR
130 if (pt[0][0]==0)
131 return 1;
132 // Check for partition overlap
133 for (i=0;i<np-1;i++)
134 if (pt[i][0]+pt[i][1]>pt[i+1][0])
135 return 1;
136 cc=0;
138 else if (kk)
139 cc++;
140 if ((unsigned char)cc>xe->nxt)
141 return 1;
142 if (cc<4)
144 if (xe->nxt<4)
146 // Empty partition
147 if (! ebuf[xe->nxt*16+4+0x1BE])
148 return 1;
149 xe->cur=xe->nxt;
150 xe->dfs=ebuf[xe->nxt*16+4+0x1BE];
151 xe->bse=valueat(ebuf,xe->nxt*16+8+0x1BE,unsigned long);
152 xe->len=valueat(ebuf,xe->nxt*16+12+0x1BE,unsigned long);
153 return 0;
155 else if (xe->nxt!=0xFF)
156 cc=4;
157 else while (cc<4)
159 if (ebuf[cc*16+4+0x1BE])
161 xe->cur=cc;
162 xe->dfs=ebuf[cc*16+4+0x1BE];
163 xe->bse=valueat(ebuf,cc*16+8+0x1BE,unsigned long);
164 xe->len=valueat(ebuf,cc*16+12+0x1BE,unsigned long);
165 return 0;
167 cc++;
170 if ((cc==4) && (kk))
172 int i;
174 // Scan for extended partition
175 for (i=0;i<4;i++)
176 if ((ebuf[i*16+4+0x1BE]==5) || (ebuf[i*16+4+0x1BE]==0xF)) break;
177 if (i==4)
178 return 1;
179 xe->ebs=xe->bse=valueat(ebuf,i*16+8+0x1BE,unsigned long);
181 else
183 // Is end of extended partition chain ?
184 if ((ebuf[4+0x1CE]!=0x5) && (ebuf[4+0x1CE]!=0xF) ||
185 (valueat(ebuf,8+0x1CE,unsigned long)==0))
186 return 1;
187 xe->bse=xe->ebs+valueat(ebuf,8+0x1CE,unsigned long);
190 int r;
192 while (1)
194 if (go_sect(hd,xe->bse))
195 return 1;
197 if (read(hd,ebuf,nn)!=nn)
198 return 1;
200 if (valueat(ebuf,0x1FE,unsigned short)!=0xAA55)
201 return 1;
203 if ((ebuf[4+0x1BE]==5) || (ebuf[4+0x1BE]==0xF))
204 if (valueat(ebuf,8+0x1BE,unsigned long)==0)
205 return 1;
206 else
208 xe->bse=xe->ebs+valueat(ebuf,8+0x1BE,unsigned long);
209 continue;
211 break;
213 kk=(ebuf[4+0x1BE]!=0);
214 if ((kk) && ((xe->nxt==0xFF) || (cc==xe->nxt)))
216 xe->cur=cc;
217 xe->dfs=ebuf[4+0x1BE];
218 xe->bse+=valueat(ebuf,8+0x1BE,unsigned long);
219 xe->len=valueat(ebuf,12+0x1BE,unsigned long);
220 return 0;
226 #define EXT2_SUPER_MAGIC 0xEF53
228 int mbr_nhd, mbr_spt;
230 void split_chs(unsigned char* chs,unsigned long* c,unsigned long* h,unsigned long* s)
232 *h=chs[0];
233 *s=(chs[1] & 0x3F)-1;
234 *c=((unsigned long)(chs[1]>>6))*256+chs[2];
237 int chk_chs(unsigned long nhd,unsigned long spt,unsigned long lba,unsigned char* chs)
239 unsigned long c,h,s;
241 split_chs(chs,&c,&h,&s);
242 if (c==0x3FF)
243 return ((nhd==h+1) && (spt==s+1));
244 else
245 return (c*nhd*spt+h*spt+s==lba);
248 int chk_mbr(unsigned char* buf)
250 unsigned long nhd,spt,a1,a2,c2,h2,s2;
251 int i;
253 i=0x1BE;
254 while ((i<0x1FE) && (buf[i+4]==0))
255 i+=16;
256 if (i>=0x1FE)
257 return 0;
258 a1=valueat(buf[i],8,unsigned long);
259 a2=a1+valueat(buf[i],12,unsigned long)-1;
260 if (a1>=a2)
261 return 0;
262 split_chs(buf+i+5,&c2,&h2,&s2);
263 if (c2==0x3FF)
265 nhd=h2+1;
266 spt=s2+1;
267 if (! chk_chs(nhd,spt,a1,buf+i+1))
268 return 0;
270 else
272 unsigned long c1,h1,s1;
273 long n1,n2;
275 split_chs(buf+i+1,&c1,&h1,&s1);
276 if ((c1==0x3FF) || (c1>c2))
277 return 0;
278 n1=(long)(c1*a2)-(long)(c2*a1)-(long)(c1*s2)+(long)(c2*s1);
279 n2=(long)(c1*h2)-(long)(c2*h1);
280 if (n2<0)
282 n2=-n2;
283 n1=-n1;
285 if ((n2==0) || (n1<=0) || (n1 % n2))
286 return 0;
287 spt=(unsigned long)(n1/n2);
288 if (c2)
290 n1=(long)a2-(long)s2-(long)(h2*spt);
291 n2=(long)(c2*spt);
292 if ((n2==0) || (n1<=0) || (n1 % n2))
293 return 0;
294 nhd=(unsigned long)(n1/n2);
296 else
297 nhd=h2+1;
299 if ((nhd==0) || (nhd>255) || (spt==0) || (spt>63))
300 return 0;
301 i+=16;
302 while (i<0x1FE)
304 if (buf[i+4])
306 if ((! chk_chs(nhd,spt,valueat(buf[i],8,unsigned long),buf+i+1)) ||
307 (! chk_chs(nhd,spt,valueat(buf[i],8,unsigned long)+valueat(buf[i],12,unsigned long)-1,buf+i+5)))
308 return 0;
310 i+=16;
312 mbr_nhd=(int)nhd;
313 mbr_spt=(int)spt;
314 return 1;
317 int get_fstype(unsigned char* buf)
319 if (chk_mbr(buf))
320 return FST_MBR;
322 // The first sector of EXT2 might not contain the 0xAA55 signature
323 if (valueat(buf[1024],56,unsigned short)==EXT2_SUPER_MAGIC)
324 return FST_EXT2;
325 if (valueat(buf[0],0x1FE,unsigned short)!=0xAA55)
326 return FST_OTHER;
327 if (! strncmp(&buf[0x36],"FAT",3))
328 return ((buf[0x26]==0x28) || (buf[0x26]==0x29))?FST_FAT16:FST_OTHER;
329 if (! strncmp(&buf[0x52],"FAT32",5))
330 return ((buf[0x42]==0x28) || (buf[0x42]==0x29))?FST_FAT32:FST_OTHER;
331 if (! strncmp(&buf[0x3],"NTFS",4))
332 return ((buf[0]==0xEB) && (buf[1]==0x52))?FST_NTFS:FST_OTHER;
333 return FST_OTHER;
336 char* fst2str(int fs)
338 switch (fs) {
339 case FST_OTHER:
340 return "Other";
341 case FST_MBR:
342 return "MBR";
343 case FST_FAT16:
344 return "FAT12/FAT16";
345 case FST_FAT32:
346 return "FAT32";
347 case FST_NTFS:
348 return "NTFS";
349 case FST_EXT2:
350 return "EXT2/EXT3";
351 default:
352 return "Unknown";
356 typedef struct {
357 int id;
358 char* str;
359 } fstab_t;
361 static fstab_t fstab[]= {
362 {0x1,"FAT12"},
363 {0x4,"FAT16"},
364 {0x5,"Extended"},
365 {0x6,"FAT16B"},
366 {0x7,"NTFS"},
367 {0xB,"FAT32"},
368 {0xC,"FAT32X"},
369 {0xE,"FAT16X"},
370 {0xF,"ExtendedX"},
371 {0x11,"(H)FAT12"},
372 {0x14,"(H)FAT16"},
373 {0x16,"(H)FAT16B"},
374 {0x17,"(H)NTFS"},
375 {0x1B,"(H)FAT32"},
376 {0x1C,"(H)FAT32X"},
377 {0x1E,"(H)FAT16X"},
378 {0x82,"Swap"},
379 {0x83,"Ext2"},
380 {0xA5,"FBSD"},
381 {0,"Other"}};
383 char* dfs2str(int fs)
385 int i;
387 for (i=0;fstab[i].id;i++)
388 if (fs==fstab[i].id)
389 return fstab[i].str;
390 return fstab[i].str;