FOSSology  3.2.0rc1
Open Source License Compliance by Open Source Software
departition.c
Go to the documentation of this file.
1 /******************************************************************
2  Copyright (C) 2007-2011 Hewlett-Packard Development Company, L.P.
3 
4  This program is free software; you can redistribute it and/or
5  modify it under the terms of the GNU General Public License
6  version 2 as published by the Free Software Foundation.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License along
14  with this program; if not, write to the Free Software Foundation, Inc.,
15  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16  ******************************************************************/
17 
23 #define _LARGEFILE64_SOURCE
24 
25 #include <stdlib.h>
26 #include <errno.h>
27 
28 /* specify support for files > 2G */
29 #ifndef __USE_LARGEFILE64
30 #define __USE_LARGEFILE64
31 #endif
32 #ifndef __USE_FILE_OFFSET64
33 #define __USE_FILE_OFFSET64
34 #endif
35 
36 #include <stdio.h>
37 #include <stdint.h>
38 #include <unistd.h>
39 #include <limits.h>
40 #include <string.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 
45 #ifdef COMMIT_HASH
46 char BuildVersion[]="Build version: " COMMIT_HASH ".\n";
47 char Version[]=COMMIT_HASH;
48 #endif
49 
50 int Test=0;
51 int Verbose=0;
52 
72 void ExtractKernel (int Fin)
73 {
74  long Hold;
75  off_t ReadSize,WriteSize;
76  unsigned char Buffer[655360], *Bp;
77  /* file name */
78  static int Counter=0;
79  char Name[256];
80  int Fout=-1;
81  /* gz headers */
82  unsigned char GZHead[2][4]={ {0x1f,0x8b,0x08,0x00},{0x1f,0x8b,0x08,0x08} };
83  int GZindex=0;
84 
85  if (Test) return;
86 
87  /* save position */
88  Hold = lseek(Fin,0,SEEK_CUR);
89 
90  /* seek header */
91  GZindex=0;
92  while(GZindex < 4)
93  {
94  ReadSize = read(Fin,Buffer+GZindex,1);
95  if (ReadSize <= 0)
96  {
97  /* this will fall out */
98  GZindex=0;
99  break;
100  }
101  /* make sure I match the header! */
102  if (!memcmp(Buffer,GZHead[0],GZindex+1) ||
103  !memcmp(Buffer,GZHead[1],GZindex+1))
104  {
105  GZindex++;
106  }
107  else
108  {
109  GZindex=0;
110  }
111  }
112  ReadSize=GZindex;
113 
114  if (ReadSize == 0) return; /* nothing to extract */
115  if (ReadSize > 0)
116  {
117  /* prepare file for writing */
118  memset(Name,0,sizeof(Name));
119  snprintf(Name,250,"Kernel_%04d",Counter);
120 #ifdef O_LARGEFILE
121  Fout = open(Name,O_CREAT | O_LARGEFILE | O_WRONLY | O_TRUNC, 0644);
122 #else
123 
124  Fout = open(Name,O_CREAT | O_WRONLY | O_TRUNC, 0644);
125 #endif
126  }
127 
128  if (Fout == -1)
129  {
130  perror("ERROR: Unable to create output file for kernel");
131  exit(-1);
132  }
133 
134  /* Copy file */
136  while(ReadSize > 0)
137  {
138  Bp=Buffer;
139  while(ReadSize > 0)
140  {
141  WriteSize = write(Fout,Bp,ReadSize);
142  Bp += WriteSize;
143  ReadSize = ReadSize - WriteSize;
144  if (WriteSize <= 0) { break; } /* abort! */
145  }
146  ReadSize = read(Fin,Buffer,sizeof(Buffer));
147  }
148 
149  /* close file */
150  close(Fout);
151  Counter++;
152 
153  /* reset position */
154  lseek(Fin,Hold,SEEK_SET); /* rewind file */
155 } /* ExtractKernel() */
156 
166 void ExtractPartition (int Fin, uint64_t Start, uint64_t Size)
167 {
168  off64_t Hold;
169  off_t ReadSize,WriteSize;
170  unsigned char Buffer[655360], *Bp;
171  /* file name */
172  static int Counter=0;
173  char Name[256];
174  int Fout=-1;
175  struct stat64 Stat;
176 
177  if (Test) return;
178 
179  /* Basic idiot test */
180  if (Size <= 0)
181  {
182  /* invalid */
183  if (Verbose) fprintf(stderr,"ERROR: Partition size is <= 0.\n");
184  return;
185  }
186 
187  /* save position */
188  Hold = lseek64(Fin,0,SEEK_CUR);
189  if (Start < Hold)
190  {
191  /* invalid */
192  if (Verbose) fprintf(stderr,"ERROR: Start is before the starting area.\n");
193  lseek64(Fin,Hold,SEEK_SET); /* rewind file */
194  return;
195  }
196 
197  /* Don't go beyond the end of file */
198  fstat64(Fin,&Stat);
199  if (Start > Stat.st_size)
200  {
201  /* invalid */
202  if (Verbose) fprintf(stderr,"ERROR: Partition start is after then end of file.\n");
203  lseek64(Fin,Hold,SEEK_SET); /* rewind file */
204  return;
205  }
206  if (Start + Size > Stat.st_size)
207  {
208  /* permit partial files */
209  if (Verbose) fprintf(stderr,"WARNING: Partition end is after then end of file; partition is truncated.\n");
210  Size = Stat.st_size - Start;
211  }
212 
213  /* prepare file for writing */
214  memset(Name,0,sizeof(Name));
215  snprintf(Name,250,"Partition_%04d",Counter);
216 #ifdef O_LARGEFILE
217  Fout = open(Name,O_CREAT | O_LARGEFILE | O_WRONLY | O_TRUNC, 0644);
218 #else
219  /* BSD does not use nor need O_LARGEFILE */
220  Fout = open(Name,O_CREAT | O_WRONLY | O_TRUNC, 0644);
221 #endif
222  if (Fout == -1)
223  {
224  perror("ERROR: Unable to create output file for partition");
225  exit(-1);
226  }
227 
228  /* Copy file */
229  /*** Support very large disk space ***/
230  lseek64(Fin,(off64_t)Start,SEEK_SET);
231 
232  while(Size > 0)
233  {
234  if (Size > sizeof(Buffer))
235  {
236  ReadSize = read(Fin,Buffer,sizeof(Buffer));
237  }
238  else
239  {
240  ReadSize = read(Fin,Buffer,Size);
241  }
242  if (ReadSize <= 0) Size=0; /* abort! */
243  Bp = Buffer;
244  while(ReadSize > 0)
245  {
246  WriteSize = write(Fout,Bp,ReadSize);
247  Size = Size - WriteSize;
248  Bp += WriteSize;
249  ReadSize = ReadSize - WriteSize;
250  if (WriteSize <= 0) {ReadSize=0; Size=0;} /* abort! */
251  }
252  }
253 
254  /* close file */
255  close(Fout);
256  Counter++;
257 
258  /* reset position */
259  lseek64(Fin,Hold,SEEK_SET); /* rewind file */
260 } /* ExtractPartition() */
261 
271 int ReadMBR (int Fin, uint64_t MBRStart)
272 {
273  unsigned char MBR[0x200]; /* master boot record sector */
274  int i;
275  /* extended partitions */
276  off_t Offset;
277  /* partition descriptions */
278  int ActiveFlag,Type;
279  int Head[2],Sec[2],Cyl[2];
280  uint64_t Start,Size;
281  /* disk descriptions */
282  uint64_t SectorSize;
283  //uint64_t SectorPerCluster;
284  //uint64_t SectorPerCylinder;
285 
286  lseek(Fin,MBRStart,SEEK_SET); /* rewind file */
287  for(i=0; i<0x200; i++)
288  {
289  if(read(Fin,MBR+i,1) < 0)
290  {
291  fprintf(stderr, "ERROR %s.%d: unable to perform read", __FILE__, __LINE__);
292  fprintf(stderr, "ERROR errno is: %s\n", strerror(errno));
293  }
294  }
295 
296  /* check if it really is a MBR */
297  if ((MBR[0x1fe] != 0x55) || (MBR[0x1ff] != 0xaa))
298  {
299  fprintf(stderr,"ERROR: No master boot record\n");
300  return(0);
301  }
302 
303  /* 512 bytes per sector is pretty much standard.
304  Apparently IBM's AS/400 systems use disks with 520 bytes/sector.
305  MFM/RLL disks didn't have a native sector size.
306  Some SCSI disks use 2048 bytes.
307  But IDE uses 512.
308  */
309  SectorSize = 512;
310  //SectorPerCluster = 0; /* does not matter for extraction */
311  //SectorPerCylinder = 0; /* does not matter for extraction */
312 
313  /* process each partition table */
314  for(i=446; i<510; i+=16)
315  {
316  /* 16 bytes describe each partition */
317  ActiveFlag=MBR[i]; /* 0x1BE */
318  Head[0]=MBR[i+1];
319  Sec[0]=(MBR[i+2] >> 2) & 0xcf;
320  Cyl[0]=MBR[i+3] + (MBR[i+2] & 0x3)*16;
321  Type=MBR[i+4];
322  Head[1]=MBR[i+5];
323  Sec[1]=(MBR[i+6] >> 2) & 0xcf;
324  Cyl[1]=MBR[i+7] + (MBR[i+6] & 0x3)*16;
325  /* Starting sector number, size of the sector */
326  Start=MBR[i+ 8] + MBR[i+ 9]*256 + MBR[i+10]*256*256 + MBR[i+11]*256*256*256;
327  Size= MBR[i+12] + MBR[i+13]*256 + MBR[i+14]*256*256 + MBR[i+15]*256*256*256;
328  if (Type != 0) /* Type 0 is unused */
329  {
330  printf("Partition: (Active=%d,Type=%x)\n",ActiveFlag & 0x80,Type);
331  printf(" HSC Start=%d,%d,%d\n",Head[0],Sec[0],Cyl[0]);
332  printf(" HSC End =%d,%d,%d\n",Head[1],Sec[1],Cyl[1]);
333  printf(" Sector: Start=%llu (%08llx) End=%llu (%08llx)\n",
334  (unsigned long long)Start,(unsigned long long)Start,
335  (unsigned long long)Start+Size,(unsigned long long)Start+Size);
336  printf(" Byte: Logical start= %llu (%08llx)\n",
337  (unsigned long long)MBRStart+(Start)*SectorSize,
338  (unsigned long long)MBRStart+(Start)*SectorSize);
339  printf(" Byte: Logical end = %llu (%08llx)\n",
340  (unsigned long long)MBRStart+(Size+Start)*SectorSize,
341  (unsigned long long)MBRStart+(Size+Start)*SectorSize);
342 
343  if (Start == 0) /* if it is a Linux kernel */
344  {
345  ExtractKernel(Fin);
346  break;
347  }
348  }
349 
350  /* check for extended partitions */
352  switch(Type)
353  {
354  case 0x00: /* unused */
355  break;
356  case 0x05: /* extended partition */
357  case 0x0f: /* Win95 extended partition */
358  Offset = lseek(Fin,0,SEEK_CUR);
359  ReadMBR(Fin,MBRStart+(Start)*SectorSize);
360  Offset = lseek(Fin,Offset,SEEK_CUR);
361  break;
362  case 0x06: /* FAT (DOS 3.3+) */
363  case 0x07: /* OS/2 HPFS, Windows NTFS, Advanced Unix */
364  case 0x0b: /* Win95 OSR2 FAT32 */
365  case 0x0c: /* Win95 OSR2 FAT32, LBA-mapped */
366  case 0x82: /* Linux swap */
367  case 0x83: /* Linux partition */
368  default:
369  /* extract partition */
370  {
371  long S,E;
372  S=MBRStart+(Start)*SectorSize;
373  E=MBRStart+(Size)*SectorSize;
374  if (Verbose)
375  fprintf(stderr,"Extracting type %02x: start=%04llx size=%llu\n",
376  Type,(unsigned long long)S,(unsigned long long)E);
377  ExtractPartition(Fin,S,E);
378  }
379  }
380  } /* for MBR */
381  return(1);
382 } /* ReadMBR() */
383 
388 void Usage (char *Filename)
389 {
390  fprintf(stderr,"Usage: %s [-t] diskimage\n",Filename);
391  fprintf(stderr," -t = test -- do not actually extract.\n");
392  fprintf(stderr," -v = Verbose.\n");
393 } /* Usage() */
394 
398 int main (int argc, char *argv[])
399 {
400  int Fin;
401  int c;
402 
403  if ((argc < 2) || (argc > 3))
404  {
405  Usage(argv[0]);
406  exit(-1);
407  }
408 
409  while((c = getopt(argc,argv,"tv")) != -1)
410  {
411  switch(c)
412  {
413  case 't': Test=1; break;
414  case 'v': Verbose++; break;
415  default:
416  Usage(argv[0]);
417  exit(-1);
418  break;
419  }
420  }
421  if (optind != argc-1)
422  {
423  Usage(argv[0]);
424  exit(-1);
425  }
426 
427 #ifdef O_LARGEFILE
428  Fin = open(argv[optind],O_RDONLY | O_LARGEFILE);
429 #else
430  /* BSD does not use nor need O_LARGEFILE */
431  Fin = open(argv[optind],O_RDONLY);
432 #endif
433  if (Fin == -1)
434  {
435  perror("ERROR: Unable to open diskimage");
436  exit(-1);
437  }
438 
439  ReadMBR(Fin,0);
440  close(Fin);
441  return(0);
442 } /* main() */
443 
char BuildVersion[]
Definition: buckets.c:79
int ReadMBR(int Fin, uint64_t MBRStart)
Read a master boot record (first 0x200 bytes).
Definition: departition.c:271
int Test
Set to 0 to extract, 1 to just be verbose.
Definition: departition.c:50
int Verbose
Verbose level for log.
Definition: departition.c:51
void Usage(char *Filename)
Usage.
Definition: departition.c:388
void ExtractPartition(int Fin, uint64_t Start, uint64_t Size)
Dump a partition to a file.
Definition: departition.c:166
int main(int argc, char *argv[])
Main for departition.
Definition: departition.c:398
void ExtractKernel(int Fin)
Extract a kernel file system and copy it to a new file called "Kernel_%04d",Counter.
Definition: departition.c:72
char * Filename
Filename.
Definition: run_tests.c:28