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