FOSSology  3.2.0rc1
Open Source License Compliance by Open Source Software
utils.c
Go to the documentation of this file.
1 /*******************************************************************
2  Copyright (C) 2011-2013 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  *******************************************************************/
22 #include "ununpack.h"
23 #include "externs.h"
24 #include "regex.h"
25 
29 enum BITS {
30  BITS_PROJECT = 27,
31  BITS_ARTIFACT = 28,
32  BITS_CONTAINER = 29
33 };
34 
38 const char* SCM_REGEX = "/\\.git|\\.hg|\\.bzr|CVS/ROOT|\\.svn/";
39 
40 
41 
51 int IsInflatedFile(char *FileName, int InflateSize)
52 {
53  int result = 0;
54  char FileNameParent[PATH_MAX];
55  struct stat st, stParent;
56  memcpy(FileNameParent, FileName, sizeof(FileNameParent));
57  FileNameParent[PATH_MAX-1] = 0;
58  char *lastSlashPos = strrchr(FileNameParent, '/');
59  if (NULL != lastSlashPos)
60  {
61  /* get the parent container,
62  e.g. for the file ./10g.tar.bz.dir/10g.tar, partent file is ./10g.tar.bz.dir
63  */
64  FileNameParent[lastSlashPos - FileNameParent] = '\0';
65  if (!strcmp(FileNameParent + strlen(FileNameParent) - 4, ".dir"))
66  {
67  /* get the parent file, must be one file
68  e.g. for the file ./10g.tar.bz.dir/10g.tar, partent file is ./10g.tar.bz
69  */
70  FileNameParent[strlen(FileNameParent) - 4] = '\0';
71  stat(FileNameParent, &stParent);
72  stat(FileName, &st);
73  if(S_ISREG(stParent.st_mode) && (st.st_size/stParent.st_size > InflateSize))
74  {
75  result = 1;
76  }
77  }
78  }
79  return result;
80 }
81 
82 
88 void SafeExit (int rc)
89 {
90  if (pgConn) PQfinish(pgConn);
92  exit(rc);
93 } /* SafeExit() */
94 
101 void RemovePostfix(char *Name)
102 {
103  if (NULL == Name) return; // exception
104  // keep the part before the last dot
105  char *LastDot = strrchr(Name, '.');
106  if (LastDot == NULL) return;
107  // if the part after the last dot is number, do not get rid of the postfix
108  if ((LastDot[1]>='0')&&(LastDot[1]<='9')) return;
109  if (LastDot) *LastDot = 0;
110 }
111 
119 void InitCmd ()
120 {
121  int i;
122  PGresult *result;
123 
124  /* clear existing indexes */
125  for(i=0; CMD[i].Magic != NULL; i++)
126  {
127  CMD[i].DBindex = -1; /* invalid value */
128  }
129 
130  if (!pgConn) return; /* DB must be open */
131 
132  /* Load them up! */
133  for(i=0; CMD[i].Magic != NULL; i++)
134  {
135  if (CMD[i].Magic[0] == '\0') continue;
136  ReGetCmd:
137  memset(SQL,'\0',MAXSQL);
138  snprintf(SQL,MAXSQL,"SELECT mimetype_pk FROM mimetype WHERE mimetype_name = '%s';",CMD[i].Magic);
139  result = PQexec(pgConn, SQL); /* SELECT */
140  if (fo_checkPQresult(pgConn, result, SQL, __FILE__, __LINE__)) SafeExit(1);
141  else if (PQntuples(result) > 0) /* if there is a value */
142  {
143  CMD[i].DBindex = atol(PQgetvalue(result,0,0));
144  PQclear(result);
145  }
146  else /* No value, so add it */
147  {
148  PQclear(result);
149  memset(SQL,'\0',MAXSQL);
150  snprintf(SQL,MAXSQL,"INSERT INTO mimetype (mimetype_name) VALUES ('%s');",CMD[i].Magic);
151  result = PQexec(pgConn, SQL); /* INSERT INTO mimetype */
152  if (fo_checkPQcommand(pgConn, result, SQL, __FILE__ ,__LINE__)) SafeExit(2);
153  else
154  {
155  PQclear(result);
156  goto ReGetCmd;
157  }
158  }
159  }
160 } /* InitCmd() */
161 
162 
176 int TaintString (char *Dest, int DestLen,
177  char *Src, int ProtectQuotes, char *Replace)
178 {
179  int i,d;
180  char Temp[FILENAME_MAX];
181 
182  memset(Dest,'\0',DestLen);
183  i=0;
184  d=0;
185  while((Src[i] != '\0') && (d < DestLen))
186  {
187  /* save */
188  if (ProtectQuotes && (Src[i]=='\''))
189  {
190  if (d+4 >= DestLen) return(1);
191  strcpy(Dest+d,"'\\''"); /* unquote, raw quote, requote (for shells) */
192  d+=4;
193  i++;
194  }
195  else if (!ProtectQuotes && strchr("\\",Src[i]))
196  {
197  if (d+2 >= DestLen) return(1);
198  Dest[d] = '\\'; d++;
199  Dest[d] = Src[i]; d++;
200  i++;
201  }
202  else if (Replace && (Src[i]=='%') && (Src[i+1]=='s'))
203  {
204  TaintString(Temp,sizeof(Temp),Replace,1,NULL);
205  if (d+strlen(Temp) >= DestLen) return(1);
206  strcpy(Dest+d,Temp);
207  d = strlen(Dest);
208  i += 2;
209  }
210  else
211  {
212  Dest[d] = Src[i];
213  d++;
214  i++;
215  }
216  }
217  return(0);
218 } /* TaintString() */
219 
228 int Prune (char *Fname, struct stat Stat)
229 {
230  if (!Fname || (Fname[0]=='\0')) return(1); /* not a good name */
231  /* check file type */
232  if (S_ISLNK(Stat.st_mode) || S_ISCHR(Stat.st_mode) ||
233  S_ISBLK(Stat.st_mode) || S_ISFIFO(Stat.st_mode) ||
234  S_ISSOCK(Stat.st_mode))
235  {
236  unlink(Fname);
237  return(1);
238  }
239  /* check hard-link count */
240  if (S_ISREG(Stat.st_mode) && (Stat.st_nlink > 1))
241  {
242  unlink(Fname);
243  return(1);
244  }
245  /* check zero-length files */
246  if (S_ISREG(Stat.st_mode) && (Stat.st_size == 0))
247  {
248  unlink(Fname);
249  return(1);
250  }
251  return(0);
252 } /* Prune() */
253 
259 int MkDirs (char *Fname)
260 {
261  char Dir[FILENAME_MAX+1];
262  int i;
263  int rc=0;
264  struct stat Status;
265 
266  memset(Dir,'\0',sizeof(Dir));
267  strcpy(Dir,Fname);
268  for(i=1; Dir[i] != '\0'; i++)
269  {
270  if (Dir[i] == '/')
271  {
272  Dir[i]='\0';
273  /* Only mkdir if it does not exist */
274  if (stat(Dir,&Status) == 0)
275  {
276  if (!S_ISDIR(Status.st_mode))
277  {
278  LOG_FATAL("'%s' is not a directory.",Dir);
279  SafeExit(3);
280  }
281  }
282  else /* else, it does not exist */
283  {
284  rc=mkdir(Dir,0770); /* create this path segment + Setgid */
285  if (rc && (errno == EEXIST)) rc=0;
286  if (rc)
287  {
288  LOG_FATAL("mkdir %s' failed, error: %s",Dir,strerror(errno));
289  SafeExit(4);
290  }
291  chmod(Dir,02770);
292  } /* else */
293  Dir[i]='/';
294  }
295  }
296  rc = mkdir(Dir,0770); /* create whatever is left */
297  if (rc && (errno == EEXIST)) rc=0;
298  if (rc)
299  {
300  LOG_FATAL("mkdir %s' failed, error: %s",Dir,strerror(errno));
301  SafeExit(5);
302  }
303  chmod(Dir,02770);
304  return(rc);
305 } /* MkDirs() */
306 
314 int MkDir (char *Fname)
315 {
316  if (mkdir(Fname,0770))
317  {
318  if (errno == EEXIST) return(0); /* failed because it exists is ok */
319  return(MkDirs(Fname));
320  }
321  chmod(Fname,02770);
322  return(0);
323 } /* MkDir() */
324 
330 int IsDir (char *Fname)
331 {
332  struct stat Stat;
333  int rc;
334  if (!Fname || (Fname[0]=='\0')) return(0); /* not a directory */
335  rc = lstat(Fname,&Stat);
336  if (rc != 0) return(0); /* bad name */
337  return(S_ISDIR(Stat.st_mode));
338 } /* IsDir() */
339 
346 int IsFile (char *Fname, int Link)
347 {
348  struct stat Stat;
349  int rc;
350  if (!Fname || (Fname[0]=='\0')) return(0); /* not a directory */
351  if (Link) rc = stat(Fname,&Stat);
352  else rc = lstat(Fname,&Stat);
353  if (rc != 0) return(0); /* bad name */
354  return(S_ISREG(Stat.st_mode));
355 } /* IsFile() */
356 
357 
367 int ReadLine (FILE *Fin, char *Line, int MaxLine)
368 {
369  int C;
370  int i;
371 
372  if (!Fin) return(-1);
373  if (feof(Fin)) return(-1);
374  memset(Line,'\0',MaxLine);
375  i=0;
376  C=fgetc(Fin);
377  if (C<0) return(-1);
378  while(!feof(Fin) && (C>=0) && (i<MaxLine))
379  {
380  if (C=='\n')
381  {
382  if (i > 0) return(i);
383  /* if it is a blank line, then ignore it. */
384  }
385  else
386  {
387  Line[i]=C;
388  i++;
389  }
390  C=fgetc(Fin);
391  }
392  return(i);
393 } /* ReadLine() */
394 
404 int IsExe (char *Exe, int Quiet)
405 {
406  char *Path;
407  int i,j;
408  char TestCmd[FILENAME_MAX];
409 
410  Path = getenv("PATH");
411  if (!Path) return(0); /* nope! */
412 
413  memset(TestCmd,'\0',sizeof(TestCmd));
414  j=0;
415  for(i=0; (j<FILENAME_MAX-1) && (Path[i] != '\0'); i++)
416  {
417  if (Path[i]==':')
418  {
419  if ((j>0) && (TestCmd[j-1] != '/')) strcat(TestCmd,"/");
420  strcat(TestCmd,Exe);
421  if (IsFile(TestCmd,1)) return(1); /* found it! */
422  /* missed */
423  memset(TestCmd,'\0',sizeof(TestCmd));
424  j=0;
425  }
426  else
427  {
428  TestCmd[j]=Path[i];
429  j++;
430  }
431  }
432 
433  /* check last path element */
434  if (j>0)
435  {
436  if (TestCmd[j-1] != '/') strcat(TestCmd,"/");
437  strcat(TestCmd,Exe);
438  if (IsFile(TestCmd,1)) return(1); /* found it! */
439  }
440  if (!Quiet) LOG_WARNING("%s not found in $PATH",Exe);
441  return(0); /* not in path */
442 } /* IsExe() */
443 
451 int CopyFile (char *Src, char *Dst)
452 {
453  int Fin, Fout;
454  unsigned char * Mmap;
455  int LenIn, LenOut, Wrote;
456  struct stat Stat;
457  int rc=0;
458  char *Slash;
459 
460  if (lstat(Src,&Stat) == -1) return(1);
461  LenIn = Stat.st_size;
462  if (!S_ISREG(Stat.st_mode)) return(1);
463 
464  Fin = open(Src,O_RDONLY);
465  if (Fin == -1)
466  {
467  LOG_FATAL("Unable to open source '%s'",Src);
468  SafeExit(22);
469  }
470 
471  /* Make sure the directory exists for copying */
472  Slash = strrchr(Dst,'/');
473  if (Slash && (Slash != Dst))
474  {
475  Slash[0]='\0';
476  MkDir(Dst);
477  Slash[0]='/';
478  }
479 
480  Fout = open(Dst,O_WRONLY|O_CREAT|O_TRUNC,Stat.st_mode);
481  if (Fout == -1)
482  {
483  LOG_FATAL("Unable to open target '%s'",Dst);
484  close(Fin);
485  SafeExit(23);
486  }
487 
488  /* load the source file */
489  Mmap = mmap(0,LenIn,PROT_READ,MAP_PRIVATE,Fin,0);
490  if (Mmap == NULL)
491  {
492  LOG_FATAL("pfile %s Unable to process file.",Pfile_Pk);
493  LOG_WARNING("pfile %s Mmap failed during copy.",Pfile_Pk);
494  rc=1;
495  goto CopyFileEnd;
496  }
497 
498  /* write file at maximum speed */
499  LenOut=0;
500  Wrote=0;
501  while((LenOut < LenIn) && (Wrote >= 0))
502  {
503  Wrote = write(Fout,Mmap+LenOut,LenIn-LenOut);
504  LenOut += Wrote;
505  }
506 
507  /* clean up */
508  munmap(Mmap,LenIn);
509  CopyFileEnd:
510  close(Fout);
511  close(Fin);
512  return(rc);
513 } /* CopyFile() */
514 
515 
521 {
522  int i;
523  int Pid;
524  int Status;
525 
526  Pid = wait(&Status);
527  if (Pid <= 0) return(-1); /* no pending children, or call failed */
528 
529  /* find the child! */
530  for(i=0; (i<MAXCHILD) && (Queue[i].ChildPid != Pid); i++) ;
531  if (Queue[i].ChildPid != Pid)
532  {
533  /* child not found */
534  return(-1);
535  }
536 
537  /* check if the child had an error */
538  if (!WIFEXITED(Status))
539  {
540  if (!ForceContinue)
541  {
542  LOG_FATAL("Child had unnatural death");
543  SafeExit(6);
544  }
545  Queue[i].ChildCorrupt=1;
546  Status = -1;
547  }
548  else Status = WEXITSTATUS(Status);
549  if (Status != 0)
550  {
551  if (!ForceContinue)
552  {
553  LOG_FATAL("Child had non-zero status: %d",Status);
554  LOG_FATAL("Child was to recurse on %s",Queue[i].ChildRecurse);
555  SafeExit(10);
556  }
557  Queue[i].ChildCorrupt=1;
558  }
559 
560  /* Finish record */
561  Queue[i].ChildStatus = Status;
562  Queue[i].ChildPid = 0;
563  Queue[i].PI.EndTime = time(NULL);
564  return(i);
565 } /* ParentWait() */
566 
567 /***************************************************************************/
568 /***************************************************************************/
569 /*** Command Processing ***/
570 /***************************************************************************/
571 /***************************************************************************/
572 
578 void CheckCommands (int Show)
579 {
580  int i;
581  int rc;
582 
583  /* Check for CMD_PACK and CMD_ARC tools */
584  for(i=0; CMD[i].Cmd != NULL; i++)
585  {
586  if (CMD[i].Cmd[0] == '\0') continue; /* no command to check */
587  switch(CMD[i].Type)
588  {
589  case CMD_PACK:
590  case CMD_RPM:
591  case CMD_DEB:
592  case CMD_ARC:
593  case CMD_AR:
594  case CMD_PARTITION:
595  CMD[i].Status = IsExe(CMD[i].Cmd,Quiet);
596  break;
597  default:
598  ; /* do nothing */
599  }
600  }
601 
602  /* Check for CMD_ISO */
603  rc = ( IsExe("isoinfo",Quiet) && IsExe("grep",Quiet) );
604  for(i=0; CMD[i].Cmd != NULL; i++)
605  {
606  if (CMD[i].Type == CMD_ISO) CMD[i].Status = rc;
607  }
608 
609  /* Check for CMD_DISK */
610  rc = ( IsExe("icat",Quiet) && IsExe("fls",Quiet) );
611  for(i=0; CMD[i].Cmd != NULL; i++)
612  {
613  if (CMD[i].Type == CMD_DISK) CMD[i].Status = rc;
614  }
615 } /* CheckCommands() */
616 
631 int RunCommand (char *Cmd, char *CmdPre, char *File, char *CmdPost,
632  char *Out, char *Where)
633 {
634  char Cmd1[FILENAME_MAX * 5];
635  char CWD[FILENAME_MAX];
636  int rc;
637  char TempPre[FILENAME_MAX];
638  char TempFile[FILENAME_MAX];
639  char TempCwd[FILENAME_MAX];
640  char TempPost[FILENAME_MAX];
641 
642  if (!Cmd) return(0); /* nothing to do */
643 
644  if (Verbose)
645  {
646  if (Where && Out)
647  {
648  LOG_DEBUG("Extracting %s: %s > %s",Cmd,File,Out);
649  }
650  else
651  {
652  if (Where)
653  {
654  LOG_DEBUG("Extracting %s in %s: %s\n",Cmd,Where,File);
655  }
656  else
657  {
658  LOG_DEBUG("Testing %s: %s\n",Cmd,File);
659  }
660  }
661  }
662 
663  if (getcwd(CWD,sizeof(CWD)) == NULL)
664  {
665  LOG_FATAL("directory name longer than %d characters",(int)sizeof(CWD));
666  SafeExit(24);
667  }
668  if (Verbose > 1){ LOG_DEBUG("CWD: %s\n",CWD);}
669  if ((Where != NULL) && (Where[0] != '\0'))
670  {
671  if (chdir(Where) != 0)
672  {
673  MkDir(Where);
674  if (chdir(Where) != 0)
675  {
676  LOG_FATAL("Unable to access directory '%s'",Where);
677  SafeExit(25);
678  }
679  }
680  if (Verbose > 1) LOG_DEBUG("CWD: %s",Where);
681  }
682 
683  /* CMD: Cmd CmdPre 'CWD/File' CmdPost */
684  /* CmdPre and CmdPost may contain a "%s" */
685  memset(Cmd1,'\0',sizeof(Cmd1));
686  if (TaintString(TempPre,FILENAME_MAX,CmdPre,0,Out) ||
687  TaintString(TempFile,FILENAME_MAX,File,1,Out) ||
688  TaintString(TempPost,FILENAME_MAX,CmdPost,0,Out))
689  {
690  return(-1);
691  }
692  if (File[0] != '/')
693  {
694  TaintString(TempCwd,FILENAME_MAX,CWD,1,Out);
695  snprintf(Cmd1,sizeof(Cmd1),"%s %s '%s/%s' %s",
696  Cmd,TempPre,TempCwd,TempFile,TempPost);
697  }
698  else
699  {
700  snprintf(Cmd1,sizeof(Cmd1),"%s %s '%s' %s",
701  Cmd,TempPre,TempFile,TempPost);
702  }
703  rc = system(Cmd1);
704  if (WIFSIGNALED(rc))
705  {
706  LOG_ERROR("Process killed by signal (%d): %s",WTERMSIG(rc),Cmd1);
707  SafeExit(8);
708  }
709  if (WIFEXITED(rc)) rc = WEXITSTATUS(rc);
710  else rc=-1;
711  if (Verbose) LOG_DEBUG("in %s -- %s ; rc=%d",Where,Cmd1,rc);
712 
713  if(chdir(CWD) != 0)
714  LOG_ERROR("Unable to change directory to %s", CWD);
715  if (Verbose > 1) LOG_DEBUG("CWD: %s",CWD);
716  return(rc);
717 } /* RunCommand() */
718 
719 
726 {
727  MagicCookie = magic_open(MAGIC_MIME);
728  if (MagicCookie == NULL)
729  {
730  LOG_FATAL("Failed to initialize magic cookie");
731  SafeExit(9);
732  }
733  return magic_load(MagicCookie,NULL);
734 }
735 
744 {
745  /* Set .dsc file magic as application/x-debian-source */
746  char *pExt;
747  FILE *fp;
748  char line[500];
749  int j;
750  char c;
751 
752  pExt = strrchr(Filename, '.');
753  if ( pExt != NULL)
754  {
755  if (strcmp(pExt, ".dsc")==0)
756  {
757  /* read the first 500 characters of the file to verify that
758  * it really is a debian source file
759  */
760  if ((fp = fopen(Filename, "r")) == NULL) return 0;
761  j=0;
762  while ((c = fgetc(fp)) != EOF && j < 500 ){
763  line[j]=c;
764  j++;
765  }
766  fclose(fp);
767  if ((strstr(line, "-----BEGIN PGP SIGNED MESSAGE-----") && strstr(line,"Source:")) ||
768  (strstr(line, "Format:") && strstr(line, "Source:") && strstr(line, "Version:")))
769  {
770  return 1;
771  }
772  }
773  }
774  return 0;
775 }
776 
782 void OctetType(char *Filename, char *TypeBuf)
783 {
784  int rc1, rc2, rc3;
785  char *Type;
786 
787  /* Get more information from magic */
788  magic_setflags(MagicCookie, MAGIC_NONE);
789  Type = (char *)magic_file(MagicCookie, Filename);
790  /* reset magic flags */
791  magic_setflags(MagicCookie, MAGIC_MIME);
792 
793  /* .deb and .udeb as application/x-debian-package*/
794  if (strstr(Type, "Debian binary package"))
795  {
796  strcpy(TypeBuf,"application/x-debian-package");
797  return;
798  }
799 
800  if (strstr(Type, "ISO 9660"))
801  {
802  strcpy(TypeBuf,"application/x-iso9660-image");
803  return;
804  }
805 
806  /* 7zr can handle many formats (including isos), so try this first */
807  rc1 = RunCommand("7z","l -y ",Filename,">/dev/null 2>&1",NULL,NULL);
808  rc2 = RunCommand("7z","t -y -pjunk",Filename,">/dev/null 2>&1",NULL,NULL);
809  if(rc2!=0)
810  {
811  rc3 = RunCommand("7z","t -y -pjunk",Filename,"|grep 'Wrong password' >/dev/null 2>&1",NULL,NULL);
812  if(rc3==0)
813  {
814  LOG_ERROR("'%s' cannot be unpacked, password required.",Filename);
815  return;
816  }
817  }
818  if ((rc1 || rc2)==0)
819  {
820  strcpy(TypeBuf,"application/x-7z-w-compressed");
821  return;
822  }
823 
824  if (strstr(Type, " ext2 "))
825  {
826  strcpy(TypeBuf,"application/x-ext2");
827  return;
828  }
829 
830  if (strstr(Type, " ext3 "))
831  {
832  strcpy(TypeBuf,"application/x-ext3");
833  return;
834  }
835 
836  if (strstr(Type, "x86 boot sector, mkdosfs")) /* the file type is FAT */
837  {
838  strcpy(TypeBuf,"application/x-fat");
839  return;
840  }
841 
842  if (strstr(Type, "NTFS")) /* the file type is NTFS */
843  {
844  strcpy(TypeBuf,"application/x-ntfs");
845  return;
846  }
847 
848  if (strstr(Type, "x86 boot")) /* the file type is boot partition */
849  {
850  strcpy(TypeBuf,"application/x-x86_boot");
851  return;
852  }
853 }
854 
860 int FindCmd (char *Filename)
861 {
862  char *Type;
863  char TypeBuf[256];
864  int Match;
865  int i;
866  int rc;
867 
868  if (!MagicCookie) InitMagic();
869  TypeBuf[0] = 0;
870 
871  Type = (char *)magic_file(MagicCookie,Filename);
872  if (Type == NULL) return(-1);
873 
874  /* Windows executables look like archives and 7z will attempt to unpack them.
875  * If that happens there will be a .bss file representing the .bss segment.
876  * 7z will try to unpack this further, potentially getting into an infinite
877  * unpack loop. So if you see an octet type .bss file, consider it text
878  * to avoid this problem. This problem was first noticed on papi-4.1.3-3.el6.src.rpm
879  */
880  if ((strcmp(basename(Filename), ".bss") == 0) && (strstr(Type, "octet")))
881  {
882  Type = strdup("text/plain");
883  }
884 
885  /* The Type returned by magic_file needs to be verified and possibly rewritten.
886  * So save it in a static buffer.
887  */
888  strncpy(TypeBuf, Type, sizeof(TypeBuf));
889  TypeBuf[255] = 0; /* make sure TypeBuf is null terminated */
890 
891  if (strstr(Type, "octet" ))
892  {
893  OctetType(Filename, TypeBuf);
894  }
895  else
896  if (IsDebianSourceFile(Filename)) strcpy(TypeBuf,"application/x-debian-source");
897  else
898  if (strstr(Type, "msword") || strstr(Type, "vnd.ms"))
899  strcpy(TypeBuf, "application/x-7z-w-compressed");
900  else
901  /* some files you just have to try to verify their type */
902  if (strstr(Type, "application/x-exe") ||
903  strstr(Type, "application/x-shellscript"))
904  {
905  rc = RunCommand("unzip","-q -l",Filename,">/dev/null 2>&1",NULL,NULL);
906  if ((rc==0) || (rc==1) || (rc==2) || (rc==51))
907  {
908  strcpy(TypeBuf,"application/x-zip");
909  }
910  } /* if was x-exe */
911  else if (strstr(Type, "application/x-tar"))
912  {
913  if (RunCommand("tar","-tf",Filename,">/dev/null 2>&1",NULL,NULL) != 0)
914  return(-1); /* bad tar! (Yes, they do happen) */
915  } /* if was x-tar */
916 
917  /* Match Type (mimetype from magic or from special processing above to determine
918  * the command for Filename
919  */
920  Match=-1;
921  for(i=0; (CMD[i].Cmd != NULL) && (Match == -1); i++)
922  {
923  if (CMD[i].Status == 0) continue; /* cannot check */
924  if (CMD[i].Type == CMD_DEFAULT)
925  {
926  Match=i; /* done! */
927  }
928  else
929  if (!strstr(TypeBuf, CMD[i].Magic))
930  {
931  continue; /* not a match */
932  }
933  Match=i;
934  }
935 
936  if (Verbose > 0)
937  {
938  /* no match */
939  if (Match == -1)
940  {
941  LOG_DEBUG("MISS: Type=%s %s",TypeBuf,Filename);
942  }
943  else
944  {
945  LOG_DEBUG("MATCH: Type=%d %s %s %s %s",CMD[Match].Type,CMD[Match].Cmd,CMD[Match].CmdPre,Filename,CMD[Match].CmdPost);
946  }
947  }
948  return(Match);
949 } /* FindCmd() */
950 
951 /***************************************************************************/
952 /***************************************************************************/
953 /*** File Processing ***/
954 /***************************************************************************/
955 /***************************************************************************/
956 
962 {
963  dirlist *d;
964  /* free records */
965  while(DL)
966  {
967  d=DL; /* grab the head */
968  DL=DL->Next; /* increment new head */
969  /* free old head */
970  if (d->Name) free(d->Name);
971  free(d);
972  }
973 } /* FreeDirList() */
974 
980 dirlist * MakeDirList (char *Fullname)
981 {
982  dirlist *dlist=NULL, *dhead=NULL;
983  DIR *Dir;
984  struct dirent *Entry;
985 
986  /* no effort is made to sort since all records need to be processed anyway */
987  /* Current order is "reverse inode order" */
988  Dir = opendir(Fullname);
989  if (Dir == NULL) return(NULL);
990 
991  Entry = readdir(Dir);
992  while(Entry != NULL)
993  {
994  if (!strcmp(Entry->d_name,".")) goto skip;
995  if (!strcmp(Entry->d_name,"..")) goto skip;
996  dhead = (dirlist *)malloc(sizeof(dirlist));
997  if (!dhead)
998  {
999  LOG_FATAL("Failed to allocate dirlist memory");
1000  SafeExit(10);
1001  }
1002  dhead->Name = (char *)malloc(strlen(Entry->d_name)+1);
1003  if (!dhead->Name)
1004  {
1005  LOG_FATAL("Failed to allocate dirlist.Name memory");
1006  SafeExit(11);
1007  }
1008  memset(dhead->Name,'\0',strlen(Entry->d_name)+1);
1009  strcpy(dhead->Name,Entry->d_name);
1010  /* add record to the list */
1011  dhead->Next = dlist;
1012  dlist = dhead;
1013 #if 0
1014  {
1015  /* bubble-sort name -- head is out of sequence */
1017  char *Name;
1018  dhead = dlist;
1019  while(dhead->Next && (strcmp(dhead->Name,dhead->Next->Name) > 0))
1020  {
1021  /* swap names */
1022  Name = dhead->Name;
1023  dhead->Name = dhead->Next->Name;
1024  dhead->Next->Name = Name;
1025  dhead = dhead->Next;
1026  }
1027  }
1028 #endif
1029 
1030  skip:
1031  Entry = readdir(Dir);
1032  }
1033  closedir(Dir);
1034 
1035 #if 0
1036  /* debug: List the directory */
1037  printf("Directory: %s\n",Fullname);
1038  for(dhead=dlist; dhead; dhead=dhead->Next)
1039  {
1040  printf(" %s\n",dhead->Name);
1041  }
1042 #endif
1043 
1044  return(dlist);
1045 } /* MakeDirList() */
1046 
1057 void SetDir (char *Dest, int DestLen, char *Smain, char *Sfile)
1058 {
1059  int i;
1060 
1061  memset(Dest,'\0',DestLen);
1062  if (Smain)
1063  {
1064  strcpy(Dest,Smain);
1065  /* remove absolute path (stay in destination) */
1066  if (Sfile && (Sfile[0]=='/')) Sfile++;
1067  /* skip "../" */
1070  i=1;
1071  while(i && Sfile)
1072  {
1073  i=0;
1074  if (!memcmp(Sfile,"../",3)) { Sfile+=3; i=1; }
1075  else if (!memcmp(Sfile,"./",2)) { Sfile+=2; i=1; }
1076  }
1077  while(Sfile && !memcmp(Sfile,"../",3)) Sfile+=3;
1078  }
1079 
1080  if ((strlen(Dest) > 0) && (Last(Smain) != '/') && (Sfile[0] != '/'))
1081  strcat(Dest,"/");
1082  if (Sfile) strcat(Dest,Sfile);
1083  /* remove terminating file */
1084  for(i=strlen(Dest)-1; (i>=0) && (Dest[i] != '/'); i--)
1085  {
1086  Dest[i]='\0';
1087  }
1088 } /* SetDir() */
1089 
1090 
1096 {
1097  LOG_DEBUG("Container:");
1098  printf(" Source: %s\n",CI->Source);
1099  printf(" Partdir: %s\n",CI->Partdir);
1100  printf(" Partname: %s\n",CI->Partname);
1101  printf(" PartnameNew: %s\n",CI->PartnameNew);
1102  printf(" TopContainer: %d\n",CI->TopContainer);
1103  printf(" HasChild: %d\n",CI->HasChild);
1104  printf(" Pruned: %d\n",CI->Pruned);
1105  printf(" Corrupt: %d\n",CI->Corrupt);
1106  printf(" Artifact: %d\n",CI->Artifact);
1107  printf(" IsDir: %d\n",CI->IsDir);
1108  printf(" IsCompressed: %d\n",CI->IsCompressed);
1109  printf(" uploadtree_pk: %ld\n",CI->uploadtree_pk);
1110  printf(" pfile_pk: %ld\n",CI->pfile_pk);
1111  printf(" ufile_mode: %ld\n",CI->ufile_mode);
1112  printf(" Parent Cmd: %d\n",CI->PI.Cmd);
1113  printf(" Parent ChildRecurseArtifact: %d\n",CI->PI.ChildRecurseArtifact);
1114  printf(" Parent uploadtree_pk: %ld\n",CI->PI.uploadtree_pk);
1115 } /* DebugContainerInfo() */
1116 
1124 int DBInsertPfile (ContainerInfo *CI, char *Fuid)
1125 {
1126  PGresult *result;
1127  char *Val; /* string result from SQL query */
1128  long tempMimeType;
1129  char *tempSha256;
1130 
1131  /* idiot checking */
1132  if (!Fuid || (Fuid[0] == '\0')) return(1);
1133 
1134  /* Check if the pfile exists */
1135  memset(SQL,'\0',MAXSQL);
1136  snprintf(SQL,MAXSQL,"SELECT pfile_pk,pfile_mimetypefk,pfile_sha256 FROM pfile "
1137  "WHERE pfile_sha1 = '%.40s' AND pfile_md5 = '%.32s' AND pfile_size = '%s';",
1138  Fuid,Fuid+41,Fuid+140);
1139  result = PQexec(pgConn, SQL); /* SELECT */
1140  if (fo_checkPQresult(pgConn, result, SQL, __FILE__, __LINE__)) SafeExit(12);
1141 
1142  /* add it if it was not found */
1143  if (PQntuples(result) == 0)
1144  {
1145  /* blindly insert to pfile table in database (don't care about dups) */
1146  /* If TWO ununpacks are running at the same time, they could both
1147  create the same pfile at the same time. Ignore the dup constraint. */
1148  PQclear(result);
1149  memset(SQL,'\0',MAXSQL);
1150  if (CMD[CI->PI.Cmd].DBindex > 0)
1151  {
1152  snprintf(SQL,MAXSQL,"INSERT INTO pfile (pfile_sha1,pfile_md5,pfile_sha256,pfile_size,pfile_mimetypefk) "
1153  "VALUES ('%.40s','%.32s','%.64s','%s','%ld');",
1154  Fuid,Fuid+41,Fuid+74,Fuid+140,CMD[CI->PI.Cmd].DBindex);
1155  }
1156  else
1157  {
1158  snprintf(SQL,MAXSQL,"INSERT INTO pfile (pfile_sha1,pfile_md5,pfile_sha256,pfile_size) VALUES ('%.40s','%.32s','%.64s','%s');",
1159  Fuid,Fuid+41,Fuid+74,Fuid+140);
1160  }
1161  result = PQexec(pgConn, SQL); /* INSERT INTO pfile */
1162  // ignore duplicate constraint failure (23505), report others
1163  if ((result==0) || ((PQresultStatus(result) != PGRES_COMMAND_OK) &&
1164  (strncmp("23505", PQresultErrorField(result, PG_DIAG_SQLSTATE),5))))
1165  {
1166  LOG_ERROR("Error inserting pfile, %s.", SQL);
1167  SafeExit(13);
1168  }
1169  PQclear(result);
1170 
1171  /* Now find the pfile_pk. Since it might be a dup, we cannot rely
1172  on currval(). */
1173  memset(SQL,'\0',MAXSQL);
1174  snprintf(SQL,MAXSQL,"SELECT pfile_pk,pfile_mimetypefk,pfile_sha256 FROM pfile "
1175  "WHERE pfile_sha1 = '%.40s' AND pfile_md5 = '%.32s' AND pfile_sha256 = '%.64s' AND pfile_size = '%s';",
1176  Fuid,Fuid+41,Fuid+74,Fuid+140);
1177  result = PQexec(pgConn, SQL); /* SELECT */
1178  if (fo_checkPQresult(pgConn, result, SQL, __FILE__, __LINE__)) SafeExit(14);
1179  }
1180 
1181  /* Now *DB contains the pfile_pk information */
1182  Val = PQgetvalue(result,0,0);
1183  if (Val)
1184  {
1185  CI->pfile_pk = atol(Val);
1186  if (Verbose) LOG_DEBUG("pfile_pk = %ld",CI->pfile_pk);
1187  tempMimeType = atol(PQgetvalue(result,0,1));
1188  tempSha256 = PQgetvalue(result,0,2);
1189  /* For backwards compatibility... Do we need to update the mimetype? */
1190  if ((CMD[CI->PI.Cmd].DBindex > 0) &&
1191  ((tempMimeType != CMD[CI->PI.Cmd].DBindex)))
1192  {
1193  PQclear(result);
1194  memset(SQL,'\0',MAXSQL);
1195  snprintf(SQL,MAXSQL,"UPDATE pfile SET pfile_mimetypefk = '%ld' WHERE pfile_pk = '%ld';",
1196  CMD[CI->PI.Cmd].DBindex, CI->pfile_pk);
1197  result = PQexec(pgConn, SQL); /* UPDATE pfile */
1198  if (fo_checkPQcommand(pgConn, result, SQL, __FILE__ ,__LINE__)) SafeExit(16);
1199  }
1200  /* Update the SHA256 for the pfile if it does not exists */
1201  if (strncasecmp(tempSha256, Fuid+74, 64) != 0)
1202  {
1203  PQclear(result);
1204  memset(SQL,'\0',MAXSQL);
1205  snprintf(SQL,MAXSQL,"UPDATE pfile SET pfile_sha256 = '%.64s' WHERE pfile_pk = '%ld';",
1206  Fuid+74, CI->pfile_pk);
1207  result = PQexec(pgConn, SQL); /* UPDATE pfile */
1208  if (fo_checkPQcommand(pgConn, result, SQL, __FILE__ ,__LINE__)) SafeExit(16);
1209  }
1210  PQclear(result);
1211  }
1212  else
1213  {
1214  PQclear(result);
1215  CI->pfile_pk = -1;
1216  return(0);
1217  }
1218 
1219  return(1);
1220 } /* DBInsertPfile() */
1221 
1234 int TestSCMData(char *sourcefilename)
1235 {
1236  regex_t preg;
1237  int err;
1238  int found=0;
1239 
1240  err = regcomp (&preg, SCM_REGEX, REG_NOSUB | REG_EXTENDED);
1241  if (err == 0)
1242  {
1243  int match;
1244 
1245  match = regexec (&preg, sourcefilename, 0, NULL, 0);
1246  regfree (&preg);
1247  if(match == 0)
1248  {
1249  found = 1;
1250  if (Verbose) LOG_DEBUG("match found %s",sourcefilename);
1251  }
1252  else if(match == REG_NOMATCH)
1253  {
1254  found = 0;
1255  if (Verbose) LOG_DEBUG("match not found %s",sourcefilename);
1256  }
1257  else
1258  {
1259  char *text;
1260  size_t size;
1261  size = regerror (err, &preg, NULL, 0);
1262  text = malloc (sizeof (*text) * size);
1263  if(text)
1264  {
1265  regerror (err, &preg, text, size);
1266  LOG_ERROR("Error regexc '%s' '%s' return %d, error %s",SCM_REGEX,sourcefilename,match,text);
1267  }
1268  else
1269  {
1270  LOG_ERROR("Not enough memory (%lu)",sizeof (*text) * size);
1271  SafeExit(127);
1272  }
1273  found = 0;
1274  }
1275  }
1276  else
1277  {
1278  LOG_ERROR("Error regcomp(%d)",err);
1279  SafeExit(127);
1280  }
1281 
1282 
1283  return(found);
1284 } /* TestSCMData() */
1285 
1297 {
1298  char UfileName[1024];
1299  char *cp;
1300  PGresult *result;
1301  char EscBuf[1024];
1302  int error;
1303 
1304  if (!Upload_Pk) return(-1); /* should never happen */
1305  // printf("=========== BEFORE ==========\n"); DebugContainerInfo(CI);
1306 
1307  /* Find record's mode */
1308  CI->ufile_mode = CI->Stat.st_mode & Mask;
1309  if (!CI->TopContainer && CI->Artifact) CI->ufile_mode |= (1 << BITS_ARTIFACT);
1310  if (CI->HasChild) CI->ufile_mode |= (1 << BITS_CONTAINER);
1311 
1312  /* Find record's name */
1313  memset(UfileName,'\0',sizeof(UfileName));
1314  if (CI->TopContainer)
1315  {
1316  char *ufile_name;
1317  snprintf(UfileName,sizeof(UfileName),"SELECT upload_filename FROM upload WHERE upload_pk = %s;",Upload_Pk);
1318  result = PQexec(pgConn, UfileName);
1319  if (fo_checkPQresult(pgConn, result, UfileName, __FILE__, __LINE__)) SafeExit(17);
1320  memset(UfileName,'\0',sizeof(UfileName));
1321  ufile_name = PQgetvalue(result,0,0);
1322  PQclear(result);
1323  if (strchr(ufile_name,'/')) ufile_name = strrchr(ufile_name,'/')+1;
1324  strncpy(CI->Partname,ufile_name,sizeof(CI->Partname)-1);
1325  }
1326  else if (CI->Artifact)
1327  {
1328  int Len;
1329  Len = strlen(CI->Partname);
1330  /* determine type of artifact */
1331  if ((Len > 4) && !strcmp(CI->Partname+Len-4,".dir"))
1332  strcpy(UfileName,"artifact.dir");
1333  else if ((Len > 9) && !strcmp(CI->Partname+Len-9,".unpacked"))
1334  strcpy(UfileName,"artifact.unpacked");
1335  else if ((Len > 5) && !strcmp(CI->Partname+Len-5,".meta"))
1336  strcpy(UfileName,"artifact.meta");
1337  else /* Don't know what it is */
1338  strcpy(UfileName,"artifact");
1339  strncpy(CI->Partname,UfileName,sizeof(CI->Partname)-1);
1340  }
1341 
1342  PQescapeStringConn(pgConn, EscBuf, CI->Partname, strlen(CI->Partname), &error);
1343  if (error)
1344  {
1345  LOG_WARNING("Error escaping filename with multibyte character set (%s).", CI->Partname);
1346  }
1347  else
1348  {
1349  strncpy(UfileName, EscBuf, sizeof(UfileName));
1350  }
1351 
1352  /*
1353  * Tests for SCM Data: IgnoreSCMData is global and defined in ununpack_globals.h with false value
1354  * and pass to true if ununpack is called with -I option to ignore SCM data.
1355  * So if IgnoreSCMData is false the right test is true.
1356  * Otherwise if IgnoreSCMData is true and CI->Source is not a SCM data then add it in database.
1357  */
1358  if(ReunpackSwitch && ((IgnoreSCMData && !TestSCMData(CI->Source)) || !IgnoreSCMData))
1359  {
1360  /* postgres 8.3 seems to have a problem escaping binary characters
1361  * (it works in 8.4). So manually substitute '~' for any unprintable and slash chars.
1362  */
1363  for (cp=UfileName; *cp; cp++) if (!isprint(*cp) || (*cp=='/') || (*cp=='\\')) *cp = '~';
1364 
1365  /* Get the parent ID */
1366  /* Two cases -- depending on if the parent exists */
1367  memset(SQL,'\0',MAXSQL);
1368  if (CI->PI.uploadtree_pk > 0) /* This is a child */
1369  {
1370  /* Prepare to insert child */
1371  snprintf(SQL,MAXSQL,"INSERT INTO %s (parent,pfile_fk,ufile_mode,ufile_name,upload_fk) VALUES (%ld,%ld,%ld,E'%s',%s);",
1373  UfileName, Upload_Pk);
1374  result = PQexec(pgConn, SQL); /* INSERT INTO uploadtree */
1375  if (fo_checkPQcommand(pgConn, result, SQL, __FILE__ ,__LINE__))
1376  {
1377  SafeExit(18);
1378  }
1379  PQclear(result);
1380  }
1381  else /* No parent! This is the first upload! */
1382  {
1383  snprintf(SQL,MAXSQL,"INSERT INTO %s (upload_fk,pfile_fk,ufile_mode,ufile_name) VALUES (%s,%ld,%ld,E'%s');",
1384  uploadtree_tablename, Upload_Pk, CI->pfile_pk, CI->ufile_mode, UfileName);
1385  result = PQexec(pgConn, SQL); /* INSERT INTO uploadtree */
1386  if (fo_checkPQcommand(pgConn, result, SQL, __FILE__ ,__LINE__)) SafeExit(19);
1387  PQclear(result);
1388  }
1389  /* Find the inserted child */
1390  memset(SQL,'\0',MAXSQL);
1391  snprintf(SQL,MAXSQL,"SELECT currval('uploadtree_uploadtree_pk_seq');");
1392  result = PQexec(pgConn, SQL);
1393  if (fo_checkPQresult(pgConn, result, SQL, __FILE__, __LINE__)) SafeExit(20);
1394  CI->uploadtree_pk = atol(PQgetvalue(result,0,0));
1395  PQclear(result);
1396  }
1397  TotalItems++;
1398  fo_scheduler_heart(1);
1399  return(0);
1400 } /* DBInsertUploadTree() */
1401 
1412 int AddToRepository (ContainerInfo *CI, char *Fuid, int Mask)
1413 {
1414  int IsUnique = 1; /* is it a DB replica? */
1415 
1416  /*****************************************/
1417  /* populate repository (include artifacts) */
1418  /* If we ever want to skip artifacts, use && !CI->Artifact */
1419  if ((Fuid[0]!='\0') && UseRepository)
1420  {
1421  /* Translate the new Fuid into old Fuid */
1422  char FuidNew[1024];
1423  memset(FuidNew, '\0', sizeof(FuidNew));
1424  // Copy the value till md5
1425  strncpy(FuidNew, Fuid, 74);
1426  // Copy the size of the file
1427  strcat(FuidNew,Fuid+140);
1428 
1429  /* put file in repository */
1430  if (!fo_RepExist(REP_FILES,Fuid))
1431  {
1432  if (fo_RepImport(CI->Source,REP_FILES,FuidNew,1) != 0)
1433  {
1434  LOG_ERROR("Failed to import '%s' as '%s' into the repository",CI->Source,FuidNew);
1435  SafeExit(21);
1436  }
1437  }
1438  if (Verbose) LOG_DEBUG("Repository[%s]: insert '%s' as '%s'",
1439  REP_FILES,CI->Source,FuidNew);
1440  }
1441 
1442  /* PERFORMANCE NOTE:
1443  I used to use and INSERT and an UPDATE.
1444  Turns out, INSERT is fast, UPDATE is *very* slow (10x).
1445  Now I just use an INSERT.
1446  */
1447 
1448  /* Insert pfile record */
1449  if (pgConn && Upload_Pk)
1450  {
1451  if (!DBInsertPfile(CI,Fuid)) return(0);
1452  /* Update uploadtree table */
1453  IsUnique = !DBInsertUploadTree(CI,Mask);
1454  }
1455 
1456  if (ForceDuplicate) IsUnique=1;
1457  return(IsUnique);
1458 } /* AddToRepository() */
1459 
1468 {
1469  int i;
1470  int Mask=0177000; /* used for XML modemask */
1471  char Fuid[1024];
1472 
1473  if (CI->Source[0] == '\0') return(0);
1474  memset(Fuid,0,sizeof(Fuid));
1475  /* TotalItems++; */
1476 
1477  /* list source */
1478  if (ListOutFile)
1479  {
1480  fputs("<item source=\"",ListOutFile);
1481  for(i=0; CI->Source[i] != '\0'; i++)
1482  {
1483  if (isalnum(CI->Source[i]) ||
1484  strchr(" `~!@#$%^*()-=_+[]{}\\|;:',./?",CI->Source[i]))
1485  fputc(CI->Source[i],ListOutFile);
1486  else fprintf(ListOutFile,"&#x%02x;",(int)(CI->Source[i])&0xff);
1487  }
1488  fputs("\" ",ListOutFile);
1489 
1490  /* list file names */
1491  if (CI->Partname[0] != '\0')
1492  {
1493  fputs("name=\"",ListOutFile);
1494  /* XML taint-protect name */
1495  for(i=0; CI->Partname[i] != '\0'; i++)
1496  {
1497  if (isalnum(CI->Partname[i]) ||
1498  strchr(" `~!@#$%^*()-=_+[]{}\\|;:',./?",CI->Partname[i]))
1499  fputc(CI->Partname[i],ListOutFile);
1500  else fprintf(ListOutFile,"&#x%02x;",(int)(CI->Partname[i])&0xff);
1501  }
1502  fputs("\" ",ListOutFile);
1503  }
1504 
1505  /* list mime info */
1506  if ((CI->PI.Cmd >= 0) && (CMD[CI->PI.Cmd].Type != CMD_DEFAULT))
1507  {
1508  fprintf(ListOutFile,"mime=\"%s\" ",CMD[CI->PI.Cmd].Magic);
1509  TotalFiles++;
1510  }
1511  else if (S_ISDIR(CI->Stat.st_mode))
1512  {
1513  fprintf(ListOutFile,"mime=\"directory\" ");
1514  TotalDirectories++;
1515  }
1516  else TotalFiles++;
1517 
1518  /* identify compressed files */
1519  if (CMD[CI->PI.Cmd].Type == CMD_PACK)
1520  {
1521  fprintf(ListOutFile,"compressed=\"1\" ");
1523  }
1524  /* identify known artifacts */
1525  if (CI->Artifact)
1526  {
1527  fprintf(ListOutFile,"artifact=\"1\" ");
1528  TotalArtifacts++;
1529  }
1530 
1531  if (CI->HasChild) fprintf(ListOutFile,"haschild=\"1\" ");
1532  } /* if ListOutFile */
1533 
1534  if (!CI->TopContainer)
1535  {
1536  /* list mode */
1537  Mask=0177000;
1538  if (Cmd >= 0)
1539  {
1540  if (S_ISDIR(CI->Stat.st_mode))
1541  {
1542  Mask = CMD[Cmd].ModeMaskDir;
1543  }
1544  else if (S_ISREG(CI->Stat.st_mode))
1545  {
1546  Mask = CMD[Cmd].ModeMaskReg;
1547  }
1548  }
1549 
1550  if (ListOutFile)
1551  {
1552  if (!CI->Artifact) /* no masks for an artifact */
1553  {
1554  fprintf(ListOutFile,"mode=\"%07o\" ",CI->Stat.st_mode & Mask);
1555  fprintf(ListOutFile,"modemask=\"%07o\" ",Mask);
1556  }
1557 
1558  /* identify known corrupted files */
1559  if (CI->Corrupt) fprintf(ListOutFile,"error=\"%d\" ",CI->Corrupt);
1560 
1561  /* list timestamps */
1562  if (CI->Stat.st_mtime)
1563  {
1564  if ((CI->Stat.st_mtime < CI->PI.StartTime) || (CI->Stat.st_mtime > CI->PI.EndTime))
1565  fprintf(ListOutFile,"mtime=\"%d\" ",(int)(CI->Stat.st_mtime));
1566  }
1567 #if 0
1568  /* commented out since almost anything can screw this up. */
1569  if (CI->Stat.st_ctime)
1570  {
1571  if ((CI->Stat.st_ctime < CI->PI.StartTime) || (CI->Stat.st_ctime > CI->PI.EndTime))
1572  fprintf(ListOutFile,"ctime=\"%d\" ",(int)(CI->Stat.st_ctime));
1573  }
1574 #endif
1575  } /* if ListOutFile */
1576  } /* if not top container */
1577 
1578  /* list checksum info for files only! */
1579  if (S_ISREG(CI->Stat.st_mode) && !CI->Pruned)
1580  {
1581  CksumFile *CF;
1582  Cksum *Sum;
1583  char SHA256[65];
1584 
1585  memset(SHA256, '\0', sizeof(SHA256));
1586 
1587  CF = SumOpenFile(CI->Source);
1588  if(calc_sha256sum(CI->Source, SHA256))
1589  {
1590  LOG_FATAL("Unable to calculate SHA256 of %s\n", CI->Source);
1591  SafeExit(56);
1592  }
1593 
1594  if (CF)
1595  {
1596  Sum = SumComputeBuff(CF);
1597  SumCloseFile(CF);
1598 
1599  if (Sum)
1600  {
1601  for(i=0; i<20; i++) { sprintf(Fuid+0+i*2,"%02X",Sum->SHA1digest[i]); }
1602  Fuid[40]='.';
1603  for(i=0; i<16; i++) { sprintf(Fuid+41+i*2,"%02X",Sum->MD5digest[i]); }
1604  Fuid[73]='.';
1605  for(i=0; i<64; i++) { sprintf(Fuid+74+i,"%c",SHA256[i]); }
1606  Fuid[139]='.';
1607  snprintf(Fuid+140,sizeof(Fuid)-140,"%Lu",(long long unsigned int)Sum->DataLen);
1608  if (ListOutFile) fprintf(ListOutFile,"fuid=\"%s\" ",Fuid);
1609  free(Sum);
1610  } /* if Sum */
1611  } /* if CF */
1612  else /* file too large to mmap (probably) */
1613  {
1614  FILE *Fin;
1615  Fin = fopen(CI->Source,"rb");
1616  if (Fin)
1617  {
1618  Sum = SumComputeFile(Fin);
1619  if (Sum)
1620  {
1621  for(i=0; i<20; i++) { sprintf(Fuid+0+i*2,"%02X",Sum->SHA1digest[i]); }
1622  Fuid[40]='.';
1623  for(i=0; i<16; i++) { sprintf(Fuid+41+i*2,"%02X",Sum->MD5digest[i]); }
1624  Fuid[73]='.';
1625  for(i=0; i<64; i++) { sprintf(Fuid+74+i,"%c",SHA256[i]); }
1626  Fuid[139]='.';
1627  snprintf(Fuid+140,sizeof(Fuid)-140,"%Lu",(long long unsigned int)Sum->DataLen);
1628  if (ListOutFile) fprintf(ListOutFile,"fuid=\"%s\" ",Fuid);
1629  free(Sum);
1630  }
1631  fclose(Fin);
1632  }
1633  }
1634  } /* if is file */
1635 
1636  /* end XML */
1637  if (ListOutFile)
1638  {
1639  if (CI->HasChild) fputs(">\n",ListOutFile);
1640  else fputs("/>\n",ListOutFile);
1641  } /* if ListOutFile */
1642 
1643  return(AddToRepository(CI,Fuid,Mask));
1644 } /* DisplayContainerInfo() */
1645 
1651 int RemoveDir(char *dirpath)
1652 {
1653  char RMcmd[FILENAME_MAX];
1654  int rc;
1655  memset(RMcmd, '\0', sizeof(RMcmd));
1656  snprintf(RMcmd, FILENAME_MAX -1, "rm -rf '%s' ", dirpath);
1657 // nokill = fo_scheduler_get_special(SPECIAL_NOKILL);
1658  rc = system(RMcmd);
1659 // fo_scheduler_set_special(SPECIAL_NOKILL, nokill);
1660  return rc;
1661 } /* RemoveDir() */
1662 
1663 
1672 char *PathCheck(char *DirPath)
1673 {
1674  char *NewPath;
1675  char *subs;
1676  char TmpPath[2048];
1677  char HostName[2048];
1678  struct timeval time_st;
1679 
1680  NewPath = strdup(DirPath);
1681 
1682  if ((subs = strstr(NewPath,"%U")) )
1683  {
1684  /* dir substitution */
1685  if (gettimeofday(&time_st, 0))
1686  {
1687  /* gettimeofday failure */
1688  LOG_WARNING("gettimeofday() failure.");
1689  time_st.tv_usec = 999999;
1690  }
1691 
1692  *subs = 0;
1693  snprintf(TmpPath, sizeof(TmpPath), "%s%ul", NewPath, (unsigned)time_st.tv_usec);
1694  free(NewPath);
1695  NewPath = strdup(TmpPath);
1696  }
1697 
1698  if ((subs = strstr(NewPath,"%H")) )
1699  {
1700  /* hostname substitution */
1701  gethostname(HostName, sizeof(HostName));
1702 
1703  *subs = 0;
1704  snprintf(TmpPath, sizeof(TmpPath), "%s%s%s", NewPath, HostName, subs+2);
1705  free(NewPath);
1706  NewPath = strdup(TmpPath);
1707  }
1708 
1709  if ((subs = strstr(NewPath, "%R")) )
1710  {
1711  /* repo location substitution */
1712  *subs = 0;
1713 
1714  snprintf(TmpPath, sizeof(TmpPath), "%s%s%s", NewPath, fo_config_get(sysconfig, "FOSSOLOGY", "path", NULL), subs+2);
1715  free(NewPath);
1716  NewPath = strdup(TmpPath);
1717  }
1718 
1719  return(NewPath);
1720 }
1721 
1722 void deleteTmpFiles(char *dir)
1723 {
1724  if (strcmp(dir, ".")) RemoveDir(dir);
1725 }
1726 
1727 
1733 void Usage (char *Name, char *Version)
1734 {
1735  fprintf(stderr,"Universal Unpacker, %s, compiled %s %s\n",
1736  Version,__DATE__,__TIME__);
1737  fprintf(stderr,"Usage: %s [options] file [file [file...]]\n",Name);
1738  fprintf(stderr," Extracts each file.\n");
1739  fprintf(stderr," If filename specifies a directory, then extracts everything in it.\n");
1740  fprintf(stderr," Unpack Options:\n");
1741  fprintf(stderr," -h :: help (print this message), then exit.\n");
1742  fprintf(stderr," -C :: force continue when unpack tool fails.\n");
1743  fprintf(stderr," -d dir :: specify alternate extraction directory. %%U substitutes a unique ID.\n");
1744  fprintf(stderr," Default is the same directory as file (usually not a good idea).\n");
1745  fprintf(stderr," -m # :: number of CPUs to use (default: 1).\n");
1746  fprintf(stderr," -P :: prune files: remove links, >1 hard links, zero files, etc.\n");
1747  fprintf(stderr," -R :: recursively unpack (same as '-r -1')\n");
1748  fprintf(stderr," -r # :: recurse to a specified depth (0=none/default, -1=infinite)\n");
1749  fprintf(stderr," -X :: remove recursive sources after unpacking.\n");
1750  fprintf(stderr," -x :: remove ALL unpacked files when done (clean up).\n");
1751  fprintf(stderr," I/O Options:\n");
1752  fprintf(stderr," -L out :: Generate a log of files extracted (in XML) to out.\n");
1753  fprintf(stderr," -F :: Using files from the repository.\n");
1754  fprintf(stderr," -i :: Initialize the database queue system, then exit.\n");
1755  fprintf(stderr," -I :: Ignore SCM Data.\n");
1756  fprintf(stderr," -Q :: Using scheduler queue system. (Includes -F)\n");
1757  fprintf(stderr," If -L is used, unpacked files are placed in 'files'.\n");
1758  fprintf(stderr," -T rep :: Set gold repository name to 'rep' (for testing)\n");
1759  fprintf(stderr," -t rep :: Set files repository name to 'rep' (for testing)\n");
1760  fprintf(stderr," -A :: do not set the initial DB container as an artifact.\n");
1761  fprintf(stderr," -f :: force processing files that already exist in the DB.\n");
1762  fprintf(stderr," -q :: quiet (generate no output).\n");
1763  fprintf(stderr," -U upload_pk :: upload to unpack (implies -RQ). Writes to db.\n");
1764  fprintf(stderr," -v :: verbose (-vv = more verbose).\n");
1765  fprintf(stderr," -V :: print the version info, then exit.\n");
1766  fprintf(stderr,"Currently identifies and processes:\n");
1767  fprintf(stderr," Compressed files: .Z .gz .bz .bz2 upx\n");
1768  fprintf(stderr," Archives files: tar cpio zip jar ar rar cab\n");
1769  fprintf(stderr," Data files: pdf\n");
1770  fprintf(stderr," Installer files: rpm deb\n");
1771  fprintf(stderr," File images: iso9660(plain/Joliet/Rock Ridge) FAT(12/16/32) ext2/ext3 NTFS\n");
1772  fprintf(stderr," Boot partitions: x86, vmlinuz\n");
1774 } /* Usage() */
1775 
1782  void SQLNoticeProcessor(void *arg, const char *message)
1783  {
1784  }
PGconn * pgConn
Database connection.
Definition: adj2nest.c:98
int CopyFile(char *Src, char *Dst)
Copy a file. For speed: mmap and save.
Definition: utils.c:451
char * PathCheck(char *DirPath)
Check if path contains a "%U" or "%H". If so, substitute a unique ID for U.
Definition: utils.c:1672
int fo_checkPQresult(PGconn *pgConn, PGresult *result, char *sql, char *FileID, int LineNumb)
Check the result status of a postgres SELECT.
Definition: libfossdb.c:181
int Quiet
Run in quiet mode?
int TotalFiles
Number of regular files.
Definition: match.h:31
int ParentWait()
Wait for a child. Sets child status.
Definition: utils.c:520
Structure for storing information about a particular file.
Definition: ununpack.h:120
fo_conf * sysconfig
unpackqueue Queue[MAXCHILD+1]
Manage children.
CksumFile * SumOpenFile(char *Fname)
Open and mmap a file.
Definition: checksum.c:38
Store the results of a regex match.
Definition: scanners.hpp:39
Definition: monk.h:72
char Partname[FILENAME_MAX]
Definition: ununpack.h:124
int RemoveDir(char *dirpath)
Remove all files under dirpath (rm -rf)
Definition: utils.c:1651
int DisplayContainerInfo(ContainerInfo *CI, int Cmd)
Print what can be printed in XML.
Definition: utils.c:1467
int IsDir(char *Fname)
Given a filename, is it a directory?
Definition: utils.c:330
int Verbose
Verbose level.
Definition: util.c:28
int TotalCompressedFiles
Number of compressed files.
FILE * ListOutFile
File to store unpack list.
const char * SCM_REGEX
Definition: utils.c:38
char * Pfile_Pk
Pfile pk in DB.
ParentInfo PI
Definition: ununpack.h:131
void fo_scheduler_disconnect(int retcode)
Disconnect the scheduler connection.
char * fo_config_get(fo_conf *conf, const char *group, const char *key, GError **error)
Gets an element based on its group name and key name. If the group or key is not found, the error object is set and NULL is returned.
Definition: fossconfig.c:341
int IsInflatedFile(char *FileName, int InflateSize)
Test if the file is a compression bomb.
Definition: utils.c:51
long uploadtree_pk
Definition: ununpack.h:135
BITS
File mode BITS.
Definition: utils.c:29
Cksum * SumComputeFile(FILE *Fin)
Compute the checksum, allocate and return a string containing the sum value.
Definition: checksum.c:127
int TotalArtifacts
Number of artifacts.
long DBindex
Definition: ununpack.h:158
int IsDebianSourceFile(char *Filename)
Read file to see if it is a Debian source file.
Definition: utils.c:743
int IgnoreSCMData
1: Ignore SCM data, 0: dont ignore it.
int MkDir(char *Fname)
Smart mkdir.
Definition: utils.c:314
int FindCmd(char *Filename)
Given a file name, determine the type of extraction command. This uses Magic.
Definition: utils.c:860
int ModeMaskDir
Definition: ununpack.h:156
int Status
Definition: ununpack.h:155
int TestSCMData(char *sourcefilename)
Search for SCM data in the filename.
Definition: utils.c:1234
void SetDir(char *Dest, int DestLen, char *Smain, char *Sfile)
Set a destination directory name.
Definition: utils.c:1057
int ModeMaskReg
Definition: ununpack.h:157
cmdlist CMD[]
Global command table.
static char * Src
Souce location.
Definition: test_CopyFile.c:24
ParentInfo PI
Definition: ununpack.h:102
int ChildCorrupt
Definition: ununpack.h:98
void RemovePostfix(char *Name)
get rid of the postfix
Definition: utils.c:101
char * Cmd
Definition: ununpack.h:150
int IsCompressed
Definition: ununpack.h:134
uint8_t SHA1digest[20]
SHA1 digest of the file.
Definition: checksum.h:42
void SQLNoticeProcessor(void *arg, const char *message)
Dummy postgresql notice processor. This prevents Notices from being written to stderr.
Definition: utils.c:1782
long ufile_mode
Definition: ununpack.h:137
int ReunpackSwitch
Set if the uploadtree records are missing from db.
time_t EndTime
Definition: ununpack.h:84
int IsExe(char *Exe, int Quiet)
Check if the executable exists.
Definition: utils.c:404
static char * Dst
Destination location.
Definition: test_CopyFile.c:25
char Partdir[FILENAME_MAX]
Definition: ununpack.h:123
int fo_checkPQcommand(PGconn *pgConn, PGresult *result, char *sql, char *FileID, int LineNumb)
Check the result status of a postgres commands (not select) If an error occured, write the error to s...
Definition: libfossdb.c:215
uint8_t MD5digest[16]
MD5 digest of the file.
Definition: checksum.h:41
dirlist * MakeDirList(char *Fullname)
Create a list of files in a directory.
Definition: utils.c:980
int ChildRecurseArtifact
Definition: ununpack.h:85
long uploadtree_pk
Definition: ununpack.h:86
char SQL[256]
SQL query to execute.
Definition: adj2nest.c:90
int ForceDuplicate
When using db, should it process duplicates?
int UseRepository
Using files from the repository?
struct stat Stat
Definition: ununpack.h:130
void CheckCommands(int Show)
Make sure all commands are usable.
Definition: utils.c:578
int ReadLine(FILE *Fin, char *Line, int MaxLine)
Read a command from a stream.
Definition: utils.c:367
int Prune(char *Fname, struct stat Stat)
Given a filename and its stat, prune it.
Definition: utils.c:228
Stores all extern variables used by the agent.
char * uploadtree_tablename
upload.uploadtree_tablename
Definition: adj2nest.c:112
int TaintString(char *Dest, int DestLen, char *Src, int ProtectQuotes, char *Replace)
Protect strings intelligently.
Definition: utils.c:176
Store check sum of a file.
Definition: checksum.h:39
uint64_t DataLen
Size of the file.
Definition: checksum.h:43
void OctetType(char *Filename, char *TypeBuf)
Figure out the real type of "octet" files in case we can unarchive them.
Definition: utils.c:782
int AddToRepository(ContainerInfo *CI, char *Fuid, int Mask)
Add a ContainerInfo record to the repository AND to the database.
Definition: utils.c:1412
char * Upload_Pk
Upload pk in DB.
int TopContainer
Definition: ununpack.h:126
time_t StartTime
Definition: ununpack.h:83
void fo_scheduler_heart(int i)
This function must be called by agents to let the scheduler know they are alive and how many items th...
magic_t MagicCookie
for Magic
Definition: finder.c:34
void FreeDirList(dirlist *DL)
Free a list of files in a directory list.
Definition: utils.c:961
char REP_FILES[16]
Files repository name.
int RunCommand(char *Cmd, char *CmdPre, char *File, char *CmdPost, char *Out, char *Where)
Try a command and return command code.
Definition: utils.c:631
int TotalDirectories
Number of directories.
void Usage(char *Name, char *Version)
Display program usage.
Definition: utils.c:1733
int fo_RepImport(char *Source, char *Type, char *Filename, int Link)
Import a file into the repository.
Definition: libfossrepo.c:824
char * Filename
Filename.
Definition: run_tests.c:28
int MkDirs(char *Fname)
Same as command-line "mkdir -p".
Definition: utils.c:259
cmdtype Type
Definition: ununpack.h:154
int DBInsertUploadTree(ContainerInfo *CI, int Mask)
Insert an UploadTree record.
Definition: utils.c:1296
void SumCloseFile(CksumFile *CF)
Close a file that was opened with SumOpenFile()
Definition: checksum.c:95
long TotalItems
Number of records inserted.
struct dirlist * Next
Definition: ununpack.h:112
void InitCmd()
Initialize the metahandler CMD table.
Definition: utils.c:119
Cksum * SumComputeBuff(CksumFile *CF)
Compute the checksum, allocate and return a Cksum containing the sum value.
Definition: checksum.c:194
Directory linked list.
Definition: ununpack.h:109
void SafeExit(int rc)
Close scheduler and database connections, then exit.
Definition: utils.c:88
int InitMagic()
Open and load Magic file Initializes global MagicCookie.
Definition: utils.c:725
int ForceContinue
Force continue when unpack tool fails?
int ChildStatus
Definition: ununpack.h:97
void DebugContainerInfo(ContainerInfo *CI)
Print a ContainerInfo structure.
Definition: utils.c:1095
int IsFile(char *Fname, int Link)
Given a filename, is it a file?
Definition: utils.c:346
long pfile_pk
Definition: ununpack.h:136
Store file handler and mmap of a file.
Definition: checksum.h:50
char PartnameNew[FILENAME_MAX]
Definition: ununpack.h:125
int fo_RepExist(char *Type, char *Filename)
Determine if a file exists.
Definition: libfossrepo.c:498
int DBInsertPfile(ContainerInfo *CI, char *Fuid)
Insert a Pfile record. Sets the pfile_pk in CI.
Definition: utils.c:1124