Fix fprintf 64-bit format specifiers
[grub-extras.git] / ntldr-img / utils.c
blobd1f3bfaafbddf13ab808cff72099e340237674d2
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 <string.h>
29 #include <fcntl.h>
31 #include "utils.h"
33 static unsigned char ebuf[512];
35 #if defined(WIN32)
37 #ifdef __GNUC__ // Mingw or Cygwin
39 #define u_off_t off64_t
40 #define u_lseek lseek64
42 #else
44 #define u_off_t __int64
45 #define u_lseek _lseeki64
47 #endif
49 #else
51 #define u_off_t off_t // In FreeBSD, off_t is 64-bit !
52 #define u_lseek lseek
54 #endif
56 int go_sect(int hd,unsigned long sec)
58 // Test if 64-bit seek is supported
59 if (sizeof(u_off_t)>=8)
61 u_off_t bs,rs;
63 bs=sec;
64 bs<<=9;
65 rs=u_lseek(hd,bs,SEEK_SET);
66 return (bs!=rs);
68 else
70 unsigned long bs[2];
72 bs[0]=sec<<9;
73 bs[1]=sec>>23;
74 if (bs[1])
75 return 1;
76 return (lseek(hd,bs[0],SEEK_SET)!=(off_t)bs[0]);
80 // Partition enumerator
81 // xe->cur is the current partition number, before the first call to xd_enum,
82 // it should be set to 0xFF
83 // xe->nxt is the target partition number, if it equals 0xFF, it means enumerate
84 // all partitions, otherwise, it means jump to the specific partition.
85 int xd_enum(int hd,xde_t* xe)
87 int nn=512,kk=1,cc;
89 for (cc=xe->cur;;)
91 if (cc==0xFF)
93 unsigned long pt[4][2];
94 int i,j,np;
96 if (go_sect(hd,0))
97 return 1;
98 if (read(hd,ebuf,nn)!=nn)
99 return 1;
100 if (get16(ebuf,0x1FE)!=0xAA55)
101 return 1;
102 np=0;
103 for (i=0x1BE;i<0x1FE;i+=16)
104 if (ebuf[i+4])
106 if ((pt[np][1]=get32(ebuf,i+12))==0)
107 return 1;
108 pt[np++][0]=get32(ebuf,i+8);
110 if (np==0)
111 return 1;
112 // Sort partition table base on start address
113 for (i=0;i<np-1;i++)
115 int k=i;
116 for (j=i+1;j<np;j++)
117 if (pt[k][0]>pt[j][0]) k=j;
118 if (k!=i)
120 unsigned long tt;
122 tt=pt[i][0];
123 pt[i][0]=pt[k][0];
124 pt[k][0]=tt;
125 tt=pt[i][1];
126 pt[i][1]=pt[k][1];
127 pt[k][1]=tt;
130 // Should have space for MBR
131 if (pt[0][0]==0)
132 return 1;
133 // Check for partition overlap
134 for (i=0;i<np-1;i++)
135 if (pt[i][0]+pt[i][1]>pt[i+1][0])
136 return 1;
137 cc=0;
139 else if (kk)
140 cc++;
141 if ((unsigned char)cc>xe->nxt)
142 return 1;
143 if (cc<4)
145 if (xe->nxt<4)
147 // Empty partition
148 if (! ebuf[xe->nxt*16+4+0x1BE])
149 return 1;
150 xe->cur=xe->nxt;
151 xe->dfs=ebuf[xe->nxt*16+4+0x1BE];
152 xe->bse=get32(ebuf,xe->nxt*16+8+0x1BE);
153 xe->len=get32(ebuf,xe->nxt*16+12+0x1BE);
154 return 0;
156 else if (xe->nxt!=0xFF)
157 cc=4;
158 else while (cc<4)
160 if (ebuf[cc*16+4+0x1BE])
162 xe->cur=cc;
163 xe->dfs=ebuf[cc*16+4+0x1BE];
164 xe->bse=get32(ebuf,cc*16+8+0x1BE);
165 xe->len=get32(ebuf,cc*16+12+0x1BE);
166 return 0;
168 cc++;
171 if ((cc==4) && (kk))
173 int i;
175 // Scan for extended partition
176 for (i=0;i<4;i++)
177 if ((ebuf[i*16+4+0x1BE]==5) || (ebuf[i*16+4+0x1BE]==0xF)) break;
178 if (i==4)
179 return 1;
180 xe->ebs=xe->bse=get32(ebuf,i*16+8+0x1BE);
182 else
184 // Is end of extended partition chain ?
185 if (((ebuf[4+0x1CE]!=0x5) && (ebuf[4+0x1CE]!=0xF)) ||
186 (get32(ebuf,8+0x1CE)==0))
187 return 1;
188 xe->bse=xe->ebs+get32(ebuf,8+0x1CE);
191 while (1)
193 if (go_sect(hd,xe->bse))
194 return 1;
196 if (read(hd,ebuf,nn)!=nn)
197 return 1;
199 if (get16(ebuf,0x1FE)!=0xAA55)
200 return 1;
202 if ((ebuf[4+0x1BE]==5) || (ebuf[4+0x1BE]==0xF))
204 if (get32(ebuf,8+0x1BE)==0)
205 return 1;
206 else
208 xe->bse=xe->ebs+get32(ebuf,8+0x1BE);
209 continue;
212 break;
214 kk=(ebuf[4+0x1BE]!=0);
215 if ((kk) && ((xe->nxt==0xFF) || (cc==xe->nxt)))
217 xe->cur=cc;
218 xe->dfs=ebuf[4+0x1BE];
219 xe->bse+=get32(ebuf,8+0x1BE);
220 xe->len=get32(ebuf,12+0x1BE);
221 return 0;
227 #define EXT2_SUPER_MAGIC 0xEF53
229 int mbr_nhd, mbr_spt;
231 static void split_chs(unsigned char* chs,unsigned long* c,unsigned long* h,unsigned long* s)
233 *h=chs[0];
234 *s=(chs[1] & 0x3F)-1;
235 *c=((unsigned long)(chs[1]>>6))*256+chs[2];
238 static int chk_chs(unsigned long nhd,unsigned long spt,unsigned long lba,unsigned char* chs)
240 unsigned long c,h,s;
242 split_chs(chs,&c,&h,&s);
243 if (c==0x3FF)
244 return ((nhd==h+1) && (spt==s+1));
245 else
246 return (c*nhd*spt+h*spt+s==lba);
249 static int chk_mbr(unsigned char* buf)
251 unsigned long nhd,spt,a1,a2,c2,h2,s2;
252 int i;
254 i=0x1BE;
255 while ((i<0x1FE) && (buf[i+4]==0))
256 i+=16;
257 if (i>=0x1FE)
258 return 0;
259 a1=get32(&buf[i],8);
260 a2=a1+get32(&buf[i],12)-1;
261 if (a1>=a2)
262 return 0;
263 split_chs(buf+i+5,&c2,&h2,&s2);
264 if (c2==0x3FF)
266 nhd=h2+1;
267 spt=s2+1;
268 if (! chk_chs(nhd,spt,a1,buf+i+1))
269 return 0;
271 else
273 unsigned long c1,h1,s1;
274 long n1,n2;
276 split_chs(buf+i+1,&c1,&h1,&s1);
277 if ((c1==0x3FF) || (c1>c2))
278 return 0;
279 n1=(long)(c1*a2)-(long)(c2*a1)-(long)(c1*s2)+(long)(c2*s1);
280 n2=(long)(c1*h2)-(long)(c2*h1);
281 if (n2<0)
283 n2=-n2;
284 n1=-n1;
286 if ((n2==0) || (n1<=0) || (n1 % n2))
287 return 0;
288 spt=(unsigned long)(n1/n2);
289 if (c2)
291 n1=(long)a2-(long)s2-(long)(h2*spt);
292 n2=(long)(c2*spt);
293 if ((n2==0) || (n1<=0) || (n1 % n2))
294 return 0;
295 nhd=(unsigned long)(n1/n2);
297 else
298 nhd=h2+1;
300 if ((nhd==0) || (nhd>255) || (spt==0) || (spt>63))
301 return 0;
302 i+=16;
303 while (i<0x1FE)
305 if (buf[i+4])
307 if ((! chk_chs(nhd,spt,get32(&buf[i],8),buf+i+1)) ||
308 (! chk_chs(nhd,spt,get32(&buf[i],8)+get32(&buf[i],12)-1,buf+i+5)))
309 return 0;
311 i+=16;
313 mbr_nhd=(int)nhd;
314 mbr_spt=(int)spt;
315 return 1;
318 int get_fstype(unsigned char* buf)
320 if (chk_mbr(buf))
321 return FST_MBR;
323 // The first sector of EXT2 might not contain the 0xAA55 signature
324 if (get16(&buf[1024],56)==EXT2_SUPER_MAGIC)
325 return FST_EXT2;
326 if (get16(&buf[0],0x1FE)!=0xAA55)
327 return FST_OTHER;
328 if (! memcmp(&buf[0x36],"FAT",3))
329 return ((buf[0x26]==0x28) || (buf[0x26]==0x29))?FST_FAT16:FST_OTHER;
330 if (! memcmp(&buf[0x52],"FAT32",5))
331 return ((buf[0x42]==0x28) || (buf[0x42]==0x29))?FST_FAT32:FST_OTHER;
332 if (! memcmp(&buf[0x3],"NTFS",4))
333 return ((buf[0]==0xEB) && (buf[1]==0x52))?FST_NTFS:FST_OTHER;
334 return FST_OTHER;
337 const char* fst2str(int fs)
339 switch (fs) {
340 case FST_OTHER:
341 return "Other";
342 case FST_MBR:
343 return "MBR";
344 case FST_FAT16:
345 return "FAT12/FAT16";
346 case FST_FAT32:
347 return "FAT32";
348 case FST_NTFS:
349 return "NTFS";
350 case FST_EXT2:
351 return "EXT2/EXT3";
352 default:
353 return "Unknown";
357 typedef struct {
358 int id;
359 const char* str;
360 } fstab_t;
362 static fstab_t fstab[]= {
363 {0x1,"FAT12"},
364 {0x4,"FAT16"},
365 {0x5,"Extended"},
366 {0x6,"FAT16B"},
367 {0x7,"NTFS"},
368 {0xB,"FAT32"},
369 {0xC,"FAT32X"},
370 {0xE,"FAT16X"},
371 {0xF,"ExtendedX"},
372 {0x11,"(H)FAT12"},
373 {0x14,"(H)FAT16"},
374 {0x16,"(H)FAT16B"},
375 {0x17,"(H)NTFS"},
376 {0x1B,"(H)FAT32"},
377 {0x1C,"(H)FAT32X"},
378 {0x1E,"(H)FAT16X"},
379 {0x82,"Swap"},
380 {0x83,"Ext2"},
381 {0xA5,"FBSD"},
382 {0,"Other"}};
384 const char* dfs2str(int fs)
386 int i;
388 for (i=0;fstab[i].id;i++)
389 if (fs==fstab[i].id)
390 return fstab[i].str;
391 return fstab[i].str;