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