FOSSology  4.4.0
Open Source License Compliance by Open Source Software
finder.c
Go to the documentation of this file.
1 /*
2  SPDX-FileCopyrightText: © 2011-2012 Hewlett-Packard Development Company, L.P.
3 
4  SPDX-License-Identifier: GPL-2.0-only
5 */
6 
12 #include "finder.h"
13 
14 char SQL[MAXCMD];
15 
16 PGresult *DBMime = NULL;
17 int MaxDBMime=0;
18 PGconn *pgConn;
19 int Agent_pk=-1;
20 
21 FILE *FMimetype=NULL;
22 
23 magic_t MagicCookie;
24 
25 int Akey = 0;
26 char A[MAXCMD];
27 
35 char * TaintString(char *S)
36 {
37  static char String[4096];
38  int i;
39 
40  memset(String,'\0',sizeof(String));
41  if (!S) return(String);
42  for(i=0; (S[0]!='\0') && (i < sizeof(String)-1); S++)
43  {
44  if (S[0]=='\n') { String[i++]='\\'; String[i++]='n'; }
45  else if (S[0]=='\r') { String[i++]='\\'; String[i++]='r'; }
46  else if (S[0]=='\a') { String[i++]='\\'; String[i++]='a'; }
47  else if (S[0]=='\'') { String[i++]='\\'; String[i++]='\''; }
48  else if (S[0]=='\"') { String[i++]='\\'; String[i++]='"'; }
49  else if (S[0]=='\\') { String[i++]='\\'; String[i++]='\\'; }
50  else String[i++]=S[0];
51  }
52  return(String);
53 } /* TaintString() */
54 
58 void DBLoadMime()
59 {
60  if (DBMime) PQclear(DBMime);
61  memset(SQL, 0, MAXCMD);
62  snprintf(SQL, MAXCMD-1, "SELECT mimetype_pk,mimetype_name FROM mimetype ORDER BY mimetype_pk ASC;");
63  DBMime = PQexec(pgConn, SQL); /* SELECT */
64  if (fo_checkPQresult(pgConn, DBMime, SQL, __FILE__, __LINE__))
65  {
66  PQfinish(pgConn);
67  exit(-1);
68  }
69  MaxDBMime = PQntuples(DBMime);
70 } /* DBLoadMime() */
71 
81 int DBFindMime(char *Mimetype)
82 {
83  int i;
84  PGresult *result;
85 
86  if (!Mimetype || (Mimetype[0]=='\0')) return(-1);
87  if (!DBMime) DBLoadMime();
88  for(i=0; i < MaxDBMime; i++)
89  {
90  if (!strcmp(Mimetype,PQgetvalue(DBMime,i,1)))
91  {
92  return(atoi(PQgetvalue(DBMime,i,0))); /* return mime type */
93  }
94  }
95 
96  /* If it got here, then the mimetype is unknown. Add it! */
97  memset(SQL,'\0',sizeof(SQL));
98  snprintf(SQL,sizeof(SQL)-1,"INSERT INTO mimetype (mimetype_name) VALUES ('%s');",TaintString(Mimetype));
99  /* The insert will fail if it already exists. This is good. It will
100  prevent multiple mimetype agents from inserting the same data at the
101  same type. */
102  result = PQexec(pgConn, SQL);
103  if ((result==0) || ((PQresultStatus(result) != PGRES_COMMAND_OK) &&
104  (strncmp("23505", PQresultErrorField(result, PG_DIAG_SQLSTATE),5))))
105  {
106  PQfinish(pgConn);
107  exit(-1);
108  }
109  PQclear(result);
110 
111  /* Now reload the mimetype table */
112  DBLoadMime();
113  /* And re-process the request... */
114  return(DBFindMime(Mimetype));
115 } /* DBFindMime() */
116 
127 int CheckMimeTypes(char *Ext)
128 {
129  char Line[MAXCMD];
130  int i;
131  int ExtLen;
132 
133  if (!FMimetype) return(-1);
134  if (!Ext || (Ext[0] == '\0')) return(-1);
135  ExtLen = strlen(Ext);
136  rewind(FMimetype);
137  LOG_VERBOSE0("Looking for mimetype based on extension: '%s'",Ext);
138 
139  while(ReadLine(FMimetype,Line,MAXCMD) > 0)
140  {
141  if (Line[0] == '#') continue; /* skip comments */
142  /* find the extension */
143  for(i=0; (Line[i] != '\0') && !isspace(Line[i]); i++);
144  if (Line[i] == '\0') continue; /* no file types */
145  Line[i]='\0'; /* terminate the metatype */
146  i++;
147 
148  /* Now find the extensions and see if any match */
149 #if 0
150  printf("CheckMimeTypes(%s) in '%s' from '%s\n",Ext,Line+i,Line);
151 #endif
152  for( ; Line[i] != '\0'; i++)
153  {
154  /* Line[i-1] is always valid */
155  /* if the previous character is not a word-space, then skip */
156  if ((Line[i-1] != '\0') && !isspace(Line[i-1]))
157  continue; /* not start of a type */
158  /* if the first character does not match is a shortcut.
159  if the string matches AND the next character is a word-space,
160  then match. */
161  if ((Line[i] == Ext[0]) && !strncasecmp(Line+i,Ext,ExtLen) &&
162  ( (Line[i+ExtLen] == '\0') || isspace(Line[i+ExtLen]) )
163  )
164  {
165  /* it matched! */
166  LOG_VERBOSE0("Found mimetype by extension: '%s' = '%s'",Ext,Line);
167  return(DBFindMime(Line)); /* return metatype id */
168  }
169  }
170  }
171 
172  /* For specagent (used because the DB query 'like %.spec' is slow) */
173  if (!strcasecmp(Ext,"spec")) return(DBFindMime("application/x-rpm-spec"));
174 
175  return(-1);
176 } /* CheckMimeTypes() */
177 
186 {
187  int u, Maxu;
188  char *Ext;
189  int rc;
190  PGresult *result;
191 
192  if (!FMimetype) return(-1);
193 
194  if (Akey >= 0)
195  {
196  memset(SQL,'\0',sizeof(SQL));
197  snprintf(SQL,sizeof(SQL)-1,"SELECT distinct(ufile_name) FROM uploadtree WHERE pfile_fk = %d",Akey);
198  result = PQexec(pgConn, SQL);
199  if (fo_checkPQresult(pgConn, result, SQL, __FILE__, __LINE__))
200  {
201  PQfinish(pgConn);
202  exit(-1);
203  }
204 
205  Maxu = PQntuples(result);
206  for(u=0; u<Maxu; u++)
207  {
208  Ext = strrchr(PQgetvalue(result,u,0),'.'); /* find the extention */
209  if (Ext)
210  {
211  Ext++; /* move past period */
212  rc = CheckMimeTypes(Ext);
213  if (rc >= 0) return(rc);
214  }
215  }
216  PQclear(result);
217  } /* if using DB */
218  else
219  {
220  /* using command-line */
221  Ext = strrchr(A,'.'); /* find the extention */
222  if (Ext)
223  {
224  Ext++; /* move past period */
225  rc = CheckMimeTypes(Ext);
226  if (rc >= 0) return(rc);
227  }
228  }
229  return(-1);
230 } /* DBCheckFileExtention() */
231 
247 int GetDefaultMime(char *MimeType, char *Filename)
248 {
249  int i;
250  FILE *Fin;
251  int C;
252 
253  /* the common case: the default mime type is known already */
254  if (MimeType) return(DBFindMime(MimeType));
255 
256  /* unknown mime, so find out what it is... */
257  Fin = fopen(Filename,"rb");
258  if (!Fin) return(-1);
259 
260  i=0;
261  C=fgetc(Fin);
262  while(!feof(Fin) && isprint(C) && (i < 100))
263  {
264  C=fgetc(Fin);
265  i++;
266  }
267  fclose(Fin);
268 
269  if (i==0) return(DBFindMime("application/x-empty"));
270  if ((C >= 0) && !isprint(C)) return(DBFindMime("application/octet-stream"));
271  return(DBFindMime("text/plain"));
272 } /* GetDefaultMime() */
273 
282 {
283  char MimeType[MAXCMD];
284  char *MagicType;
285  int MimeTypeID;
286  int i;
287  PGresult *result;
288 
289  if (Akey >= 0)
290  {
291  memset(SQL,'\0',sizeof(SQL));
292  snprintf(SQL,sizeof(SQL)-1,"SELECT pfile_mimetypefk FROM pfile WHERE pfile_pk = %d AND pfile_mimetypefk is not null;",Akey);
293  result = PQexec(pgConn, SQL);
294  if (fo_checkPQresult(pgConn, result, SQL, __FILE__, __LINE__))
295  {
296  PQfinish(pgConn);
297  exit(-1);
298  }
299 
300  if (PQntuples(result) > 0)
301  {
302  PQclear(result);
303  return;
304  }
305  PQclear(result);
306  } /* if using DB */
307 
308  /* Not in DB, so find out what it is... */
309  /* Check using Magic */
310  MagicType = (char *)magic_file(MagicCookie,Filename);
311  memset(MimeType,'\0',MAXCMD);
312  if (MagicType)
313  {
314  LOG_VERBOSE0("Found mimetype by magic: '%s'",MagicType);
315  /* Magic contains additional data after a ';' */
316  for(i=0;
317  (i<MAXCMD) && (MagicType[i] != '\0') &&
318  !isspace(MagicType[i]) && !strchr(",;",MagicType[i]);
319  i++)
320  {
321  MimeType[i] = MagicType[i];
322  }
323  if (!strchr(MimeType,'/')) { memset(MimeType,'\0',MAXCMD); }
324  }
325 
326  /* If there is no mimetype, or there is one but it is a default value,
327  then determine based on extension */
328  if (!strcmp(MimeType,"text/plain") || !strcmp(MimeType,"application/octet-stream") || (MimeType[0]=='\0'))
329  {
330  /* unknown type... Guess based on file extention */
331  MimeTypeID = DBCheckFileExtention();
332  /* not known? */
333  if (MimeTypeID < 0) MimeTypeID = GetDefaultMime(MimeType,Filename);
334  }
335  else
336  {
337  /* We have a mime-type! Update the database */
338  MimeTypeID = DBFindMime(MimeType);
339  }
340 
341  /* Make sure there is a mime-type */
342  if (MimeTypeID < 0)
343  {
344  /* This should never happen; give it a default. */
345  MimeTypeID = DBFindMime("application/octet-stream");
346  }
347 
348  /* Update pfile record */
349  if (Akey >= 0)
350  {
351  result = PQexec(pgConn, "BEGIN;");
352  if (fo_checkPQcommand(pgConn, result, SQL, __FILE__, __LINE__))
353  {
354  PQfinish(pgConn);
355  exit(-1);
356  }
357 
358  memset(SQL,'\0',sizeof(SQL));
359  snprintf(SQL,sizeof(SQL)-1,"SELECT * FROM pfile WHERE pfile_pk = %d FOR UPDATE;",Akey);
360  PQclear(result);
361  result = PQexec(pgConn, SQL);
362  if (fo_checkPQresult(pgConn, result, SQL, __FILE__, __LINE__))
363  {
364  PQfinish(pgConn);
365  exit(-1);
366  }
367 
368  memset(SQL,'\0',sizeof(SQL));
369  snprintf(SQL,sizeof(SQL)-1,"UPDATE pfile SET pfile_mimetypefk = %d WHERE pfile_pk = %d;",MimeTypeID,Akey);
370  PQclear(result);
371  result = PQexec(pgConn, SQL);
372  if (fo_checkPQcommand(pgConn, result, SQL, __FILE__, __LINE__))
373  {
374  PQfinish(pgConn);
375  exit(-1);
376  }
377 
378  PQclear(result);
379  result = PQexec(pgConn, "COMMIT;");
380  if (fo_checkPQcommand(pgConn, result, SQL, __FILE__, __LINE__))
381  {
382  PQfinish(pgConn);
383  exit(-1);
384  }
385  PQclear(result);
386  }
387  else
388  {
389  /* IF no Akey, then display to stdout */
390  int i;
391  for(i=0; i < MaxDBMime; i++)
392  {
393  if (MimeTypeID == atoi(PQgetvalue(DBMime,i,0)))
394  {
395  printf("%s : mimetype_pk=%d : ",PQgetvalue(DBMime,i,1),MimeTypeID);
396  }
397  }
398  printf("%s\n",Filename);
399  }
400 } /* DBCheckMime() */
401 
414 char * GetFieldValue (char *Sin, char *Field, int FieldMax,
415  char *Value, int ValueMax)
416 {
417  int s,f,v;
418  int GotQuote;
419 
420  memset(Field,0,FieldMax);
421  memset(Value,0,ValueMax);
422 
423  while(isspace(Sin[0])) Sin++; /* skip initial spaces */
424  if (Sin[0]=='\0') return(NULL);
425  f=0; v=0;
426 
427  for(s=0; (Sin[s] != '\0') && !isspace(Sin[s]) && (Sin[s] != '='); s++)
428  {
429  Field[f++] = Sin[s];
430  }
431  while(isspace(Sin[s])) s++; /* skip spaces after field name */
432  if (Sin[s] != '=') /* if it is not a field, then just return it. */
433  {
434  return(Sin+s);
435  }
436  if (Sin[s]=='\0') return(NULL);
437  s++; /* skip '=' */
438  while(isspace(Sin[s])) s++; /* skip spaces after '=' */
439  if (Sin[s]=='\0') return(NULL);
440 
441  GotQuote='\0';
442  if ((Sin[s]=='\'') || (Sin[s]=='"'))
443  {
444  GotQuote = Sin[s];
445  s++; /* skip quote */
446  if (Sin[s]=='\0') return(NULL);
447  }
448  if (GotQuote)
449  {
450  for( ; (Sin[s] != '\0') && (Sin[s] != GotQuote); s++)
451  {
452  if (Sin[s]=='\\') Value[v++]=Sin[++s];
453  else Value[v++]=Sin[s];
454  }
455  }
456  else
457  {
458  /* if it gets here, then there is no quote */
459  for( ; (Sin[s] != '\0') && !isspace(Sin[s]); s++)
460  {
461  if (Sin[s]=='\\') Value[v++]=Sin[++s];
462  else Value[v++]=Sin[s];
463  }
464  }
465  while(isspace(Sin[s])) s++; /* skip spaces */
466  return(Sin+s);
467 } /* GetFieldValue() */
468 
478 int ReadLine(FILE *Fin, char *Line, int MaxLine)
479 {
480  int C;
481  int i;
482 
483  memset(Line,'\0',MaxLine);
484  if (feof(Fin)) return(-1);
485  i=0;
486  C=fgetc(Fin);
487  if (C<0) return(-1);
488  while(!feof(Fin) && (C>=0) && (i<MaxLine))
489  {
490  if (C=='\n')
491  {
492  if (i > 0) return(i);
493  /* if it is a blank line, then ignore it. */
494  }
495  else
496  {
497  Line[i]=C;
498  i++;
499  }
500  C=fgetc(Fin);
501  }
502  return(i);
503 } /* ReadLine() */
504 
510 void Usage(char *Name)
511 {
512  printf("Usage: %s [options] [file [file [...]]\n",Name);
513  printf(" -h :: help (print this message), then exit.\n");
514  printf(" -i :: initialize the database, then exit.\n");
515  printf(" -v :: verbose (-vv = more verbose)\n");
516  printf(" -c :: Specify the directory for the system configuration.\n");
517  printf(" -C :: run from command line.\n");
518  printf(" -V :: print the version info, then exit.\n");
519  printf(" file :: if files are listed, display their mimetype.\n");
520  printf(" no file :: process data from the scheduler.\n");
521 } /* Usage() */
void DBLoadMime()
Populate the DBMime table.
Definition: finder.c:58
FILE * FMimetype
for /etc/mime.types
Definition: finder.c:21
char * GetFieldValue(char *Sin, char *Field, int FieldMax, char *Value, int ValueMax)
Given a string that contains field='value' pairs, save the items.
Definition: finder.c:414
void Usage(char *Name)
Here are some suggested options.
Definition: finder.c:510
int CheckMimeTypes(char *Ext)
Given an extension, see if extension exists in the /etc/mime.types.
Definition: finder.c:127
char SQL[MAXCMD]
For DB.
Definition: finder.c:14
char * TaintString(char *S)
Create a string with taint quoting.
Definition: finder.c:35
int GetDefaultMime(char *MimeType, char *Filename)
Get the ID for the default mimetype.
Definition: finder.c:247
int DBFindMime(char *Mimetype)
Find a mime type in the DBMime table.
Definition: finder.c:81
char A[MAXCMD]
input for this system
Definition: finder.c:26
PGconn * pgConn
Database connection.
Definition: finder.c:18
magic_t MagicCookie
for Magic
Definition: finder.c:23
int MaxDBMime
how many rows in DBMime
Definition: finder.c:17
void DBCheckMime(char *Filename)
Given a file, check if it has a mime type in the DB.
Definition: finder.c:281
int DBCheckFileExtention()
Given a pfile, identify any filenames and see if any of them have a known extension based on /etc/mim...
Definition: finder.c:185
int Agent_pk
agent identifier
Definition: finder.c:19
PGresult * DBMime
contents of mimetype table
Definition: finder.c:16
int ReadLine(FILE *Fin, char *Line, int MaxLine)
Read a line each time from one file.
Definition: finder.c:478
int s
The socket that the CLI will use to communicate.
Definition: fo_cli.c:37
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
char * Filename
Filename.
Definition: run_tests.c:17