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