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