FOSSology  3.2.0rc1
Open Source License Compliance by Open Source Software
finder.c
Go to the documentation of this file.
1 /***************************************************************
2  Copyright (C) 2011-2012 Hewlett-Packard Development Company, L.P.
3 
4  This program is free software; you can redistribute it and/or
5  modify it under the terms of the GNU General Public License
6  version 2 as published by the Free Software Foundation.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License along
14  with this program; if not, write to the Free Software Foundation, Inc.,
15  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16  ***************************************************************/
17 
23 #include "finder.h"
24 
25 char SQL[MAXCMD];
26 
27 PGresult *DBMime = NULL;
28 int MaxDBMime=0;
29 PGconn *pgConn;
30 int Agent_pk=-1;
31 
32 FILE *FMimetype=NULL;
33 
34 magic_t MagicCookie;
35 
36 int Akey = 0;
37 char A[MAXCMD];
38 
46 char * TaintString(char *S)
47 {
48  static char String[4096];
49  int i;
50 
51  memset(String,'\0',sizeof(String));
52  if (!S) return(String);
53  for(i=0; (S[0]!='\0') && (i < sizeof(String)-1); S++)
54  {
55  if (S[0]=='\n') { String[i++]='\\'; String[i++]='n'; }
56  else if (S[0]=='\r') { String[i++]='\\'; String[i++]='r'; }
57  else if (S[0]=='\a') { String[i++]='\\'; String[i++]='a'; }
58  else if (S[0]=='\'') { String[i++]='\\'; String[i++]='\''; }
59  else if (S[0]=='\"') { String[i++]='\\'; String[i++]='"'; }
60  else if (S[0]=='\\') { String[i++]='\\'; String[i++]='\\'; }
61  else String[i++]=S[0];
62  }
63  return(String);
64 } /* TaintString() */
65 
69 void DBLoadMime()
70 {
71  if (DBMime) PQclear(DBMime);
72  memset(SQL, 0, MAXCMD);
73  snprintf(SQL, MAXCMD-1, "SELECT mimetype_pk,mimetype_name FROM mimetype ORDER BY mimetype_pk ASC;");
74  DBMime = PQexec(pgConn, SQL); /* SELECT */
75  if (fo_checkPQresult(pgConn, DBMime, SQL, __FILE__, __LINE__))
76  {
77  PQfinish(pgConn);
78  exit(-1);
79  }
80  MaxDBMime = PQntuples(DBMime);
81 } /* DBLoadMime() */
82 
92 int DBFindMime(char *Mimetype)
93 {
94  int i;
95  PGresult *result;
96 
97  if (!Mimetype || (Mimetype[0]=='\0')) return(-1);
98  if (!DBMime) DBLoadMime();
99  for(i=0; i < MaxDBMime; i++)
100  {
101  if (!strcmp(Mimetype,PQgetvalue(DBMime,i,1)))
102  {
103  return(atoi(PQgetvalue(DBMime,i,0))); /* return mime type */
104  }
105  }
106 
107  /* If it got here, then the mimetype is unknown. Add it! */
108  memset(SQL,'\0',sizeof(SQL));
109  snprintf(SQL,sizeof(SQL)-1,"INSERT INTO mimetype (mimetype_name) VALUES ('%s');",TaintString(Mimetype));
110  /* The insert will fail if it already exists. This is good. It will
111  prevent multiple mimetype agents from inserting the same data at the
112  same type. */
113  result = PQexec(pgConn, SQL);
114  if ((result==0) || ((PQresultStatus(result) != PGRES_COMMAND_OK) &&
115  (strncmp("23505", PQresultErrorField(result, PG_DIAG_SQLSTATE),5))))
116  {
117  PQfinish(pgConn);
118  exit(-1);
119  }
120  PQclear(result);
121 
122  /* Now reload the mimetype table */
123  DBLoadMime();
124  /* And re-process the request... */
125  return(DBFindMime(Mimetype));
126 } /* DBFindMime() */
127 
138 int CheckMimeTypes(char *Ext)
139 {
140  char Line[MAXCMD];
141  int i;
142  int ExtLen;
143 
144  if (!FMimetype) return(-1);
145  if (!Ext || (Ext[0] == '\0')) return(-1);
146  ExtLen = strlen(Ext);
147  rewind(FMimetype);
148  LOG_VERBOSE0("Looking for mimetype based on extension: '%s'",Ext);
149 
150  while(ReadLine(FMimetype,Line,MAXCMD) > 0)
151  {
152  if (Line[0] == '#') continue; /* skip comments */
153  /* find the extension */
154  for(i=0; (Line[i] != '\0') && !isspace(Line[i]); i++);
155  if (Line[i] == '\0') continue; /* no file types */
156  Line[i]='\0'; /* terminate the metatype */
157  i++;
158 
159  /* Now find the extensions and see if any match */
160 #if 0
161  printf("CheckMimeTypes(%s) in '%s' from '%s\n",Ext,Line+i,Line);
162 #endif
163  for( ; Line[i] != '\0'; i++)
164  {
165  /* Line[i-1] is always valid */
166  /* if the previous character is not a word-space, then skip */
167  if ((Line[i-1] != '\0') && !isspace(Line[i-1]))
168  continue; /* not start of a type */
169  /* if the first character does not match is a shortcut.
170  if the string matches AND the next character is a word-space,
171  then match. */
172  if ((Line[i] == Ext[0]) && !strncasecmp(Line+i,Ext,ExtLen) &&
173  ( (Line[i+ExtLen] == '\0') || isspace(Line[i+ExtLen]) )
174  )
175  {
176  /* it matched! */
177  LOG_VERBOSE0("Found mimetype by extension: '%s' = '%s'",Ext,Line);
178  return(DBFindMime(Line)); /* return metatype id */
179  }
180  }
181  }
182 
183  /* For specagent (used because the DB query 'like %.spec' is slow) */
184  if (!strcasecmp(Ext,"spec")) return(DBFindMime("application/x-rpm-spec"));
185 
186  return(-1);
187 } /* CheckMimeTypes() */
188 
197 {
198  int u, Maxu;
199  char *Ext;
200  int rc;
201  PGresult *result;
202 
203  if (!FMimetype) return(-1);
204 
205  if (Akey >= 0)
206  {
207  memset(SQL,'\0',sizeof(SQL));
208  snprintf(SQL,sizeof(SQL)-1,"SELECT distinct(ufile_name) FROM uploadtree WHERE pfile_fk = %d",Akey);
209  result = PQexec(pgConn, SQL);
210  if (fo_checkPQresult(pgConn, result, SQL, __FILE__, __LINE__))
211  {
212  PQfinish(pgConn);
213  exit(-1);
214  }
215 
216  Maxu = PQntuples(result);
217  for(u=0; u<Maxu; u++)
218  {
219  Ext = strrchr(PQgetvalue(result,u,0),'.'); /* find the extention */
220  if (Ext)
221  {
222  Ext++; /* move past period */
223  rc = CheckMimeTypes(Ext);
224  if (rc >= 0) return(rc);
225  }
226  }
227  PQclear(result);
228  } /* if using DB */
229  else
230  {
231  /* using command-line */
232  Ext = strrchr(A,'.'); /* find the extention */
233  if (Ext)
234  {
235  Ext++; /* move past period */
236  rc = CheckMimeTypes(Ext);
237  if (rc >= 0) return(rc);
238  }
239  }
240  return(-1);
241 } /* DBCheckFileExtention() */
242 
258 int GetDefaultMime(char *MimeType, char *Filename)
259 {
260  int i;
261  FILE *Fin;
262  int C;
263 
264  /* the common case: the default mime type is known already */
265  if (MimeType) return(DBFindMime(MimeType));
266 
267  /* unknown mime, so find out what it is... */
268  Fin = fopen(Filename,"rb");
269  if (!Fin) return(-1);
270 
271  i=0;
272  C=fgetc(Fin);
273  while(!feof(Fin) && isprint(C) && (i < 100))
274  {
275  C=fgetc(Fin);
276  i++;
277  }
278  fclose(Fin);
279 
280  if (i==0) return(DBFindMime("application/x-empty"));
281  if ((C >= 0) && !isprint(C)) return(DBFindMime("application/octet-stream"));
282  return(DBFindMime("text/plain"));
283 } /* GetDefaultMime() */
284 
293 {
294  char MimeType[MAXCMD];
295  char *MagicType;
296  int MimeTypeID;
297  int i;
298  PGresult *result;
299 
300  if (Akey >= 0)
301  {
302  memset(SQL,'\0',sizeof(SQL));
303  snprintf(SQL,sizeof(SQL)-1,"SELECT pfile_mimetypefk FROM pfile WHERE pfile_pk = %d AND pfile_mimetypefk is not null;",Akey);
304  result = PQexec(pgConn, SQL);
305  if (fo_checkPQresult(pgConn, result, SQL, __FILE__, __LINE__))
306  {
307  PQfinish(pgConn);
308  exit(-1);
309  }
310 
311  if (PQntuples(result) > 0)
312  {
313  PQclear(result);
314  return;
315  }
316  PQclear(result);
317  } /* if using DB */
318 
319  /* Not in DB, so find out what it is... */
320  /* Check using Magic */
321  MagicType = (char *)magic_file(MagicCookie,Filename);
322  memset(MimeType,'\0',MAXCMD);
323  if (MagicType)
324  {
325  LOG_VERBOSE0("Found mimetype by magic: '%s'",MagicType);
326  /* Magic contains additional data after a ';' */
327  for(i=0;
328  (i<MAXCMD) && (MagicType[i] != '\0') &&
329  !isspace(MagicType[i]) && !strchr(",;",MagicType[i]);
330  i++)
331  {
332  MimeType[i] = MagicType[i];
333  }
334  if (!strchr(MimeType,'/')) { memset(MimeType,'\0',MAXCMD); }
335  }
336 
337  /* If there is no mimetype, or there is one but it is a default value,
338  then determine based on extension */
339  if (!strcmp(MimeType,"text/plain") || !strcmp(MimeType,"application/octet-stream") || (MimeType[0]=='\0'))
340  {
341  /* unknown type... Guess based on file extention */
342  MimeTypeID = DBCheckFileExtention();
343  /* not known? */
344  if (MimeTypeID < 0) MimeTypeID = GetDefaultMime(MimeType,Filename);
345  }
346  else
347  {
348  /* We have a mime-type! Update the database */
349  MimeTypeID = DBFindMime(MimeType);
350  }
351 
352  /* Make sure there is a mime-type */
353  if (MimeTypeID < 0)
354  {
355  /* This should never happen; give it a default. */
356  MimeTypeID = DBFindMime("application/octet-stream");
357  }
358 
359  /* Update pfile record */
360  if (Akey >= 0)
361  {
362  result = PQexec(pgConn, "BEGIN;");
363  if (fo_checkPQcommand(pgConn, result, SQL, __FILE__, __LINE__))
364  {
365  PQfinish(pgConn);
366  exit(-1);
367  }
368 
369  memset(SQL,'\0',sizeof(SQL));
370  snprintf(SQL,sizeof(SQL)-1,"SELECT * FROM pfile WHERE pfile_pk = %d FOR UPDATE;",Akey);
371  PQclear(result);
372  result = PQexec(pgConn, SQL);
373  if (fo_checkPQresult(pgConn, result, SQL, __FILE__, __LINE__))
374  {
375  PQfinish(pgConn);
376  exit(-1);
377  }
378 
379  memset(SQL,'\0',sizeof(SQL));
380  snprintf(SQL,sizeof(SQL)-1,"UPDATE pfile SET pfile_mimetypefk = %d WHERE pfile_pk = %d;",MimeTypeID,Akey);
381  PQclear(result);
382  result = PQexec(pgConn, SQL);
383  if (fo_checkPQcommand(pgConn, result, SQL, __FILE__, __LINE__))
384  {
385  PQfinish(pgConn);
386  exit(-1);
387  }
388 
389  PQclear(result);
390  result = PQexec(pgConn, "COMMIT;");
391  if (fo_checkPQcommand(pgConn, result, SQL, __FILE__, __LINE__))
392  {
393  PQfinish(pgConn);
394  exit(-1);
395  }
396  PQclear(result);
397  }
398  else
399  {
400  /* IF no Akey, then display to stdout */
401  int i;
402  for(i=0; i < MaxDBMime; i++)
403  {
404  if (MimeTypeID == atoi(PQgetvalue(DBMime,i,0)))
405  {
406  printf("%s : mimetype_pk=%d : ",PQgetvalue(DBMime,i,1),MimeTypeID);
407  }
408  }
409  printf("%s\n",Filename);
410  }
411 } /* DBCheckMime() */
412 
425 char * GetFieldValue (char *Sin, char *Field, int FieldMax,
426  char *Value, int ValueMax)
427 {
428  int s,f,v;
429  int GotQuote;
430 
431  memset(Field,0,FieldMax);
432  memset(Value,0,ValueMax);
433 
434  while(isspace(Sin[0])) Sin++; /* skip initial spaces */
435  if (Sin[0]=='\0') return(NULL);
436  f=0; v=0;
437 
438  for(s=0; (Sin[s] != '\0') && !isspace(Sin[s]) && (Sin[s] != '='); s++)
439  {
440  Field[f++] = Sin[s];
441  }
442  while(isspace(Sin[s])) s++; /* skip spaces after field name */
443  if (Sin[s] != '=') /* if it is not a field, then just return it. */
444  {
445  return(Sin+s);
446  }
447  if (Sin[s]=='\0') return(NULL);
448  s++; /* skip '=' */
449  while(isspace(Sin[s])) s++; /* skip spaces after '=' */
450  if (Sin[s]=='\0') return(NULL);
451 
452  GotQuote='\0';
453  if ((Sin[s]=='\'') || (Sin[s]=='"'))
454  {
455  GotQuote = Sin[s];
456  s++; /* skip quote */
457  if (Sin[s]=='\0') return(NULL);
458  }
459  if (GotQuote)
460  {
461  for( ; (Sin[s] != '\0') && (Sin[s] != GotQuote); s++)
462  {
463  if (Sin[s]=='\\') Value[v++]=Sin[++s];
464  else Value[v++]=Sin[s];
465  }
466  }
467  else
468  {
469  /* if it gets here, then there is no quote */
470  for( ; (Sin[s] != '\0') && !isspace(Sin[s]); s++)
471  {
472  if (Sin[s]=='\\') Value[v++]=Sin[++s];
473  else Value[v++]=Sin[s];
474  }
475  }
476  while(isspace(Sin[s])) s++; /* skip spaces */
477  return(Sin+s);
478 } /* GetFieldValue() */
479 
489 int ReadLine(FILE *Fin, char *Line, int MaxLine)
490 {
491  int C;
492  int i;
493 
494  memset(Line,'\0',MaxLine);
495  if (feof(Fin)) return(-1);
496  i=0;
497  C=fgetc(Fin);
498  if (C<0) return(-1);
499  while(!feof(Fin) && (C>=0) && (i<MaxLine))
500  {
501  if (C=='\n')
502  {
503  if (i > 0) return(i);
504  /* if it is a blank line, then ignore it. */
505  }
506  else
507  {
508  Line[i]=C;
509  i++;
510  }
511  C=fgetc(Fin);
512  }
513  return(i);
514 } /* ReadLine() */
515 
521 void Usage(char *Name)
522 {
523  printf("Usage: %s [options] [file [file [...]]\n",Name);
524  printf(" -h :: help (print this message), then exit.\n");
525  printf(" -i :: initialize the database, then exit.\n");
526  printf(" -v :: verbose (-vv = more verbose)\n");
527  printf(" -c :: Specify the directory for the system configuration.\n");
528  printf(" -C :: run from command line.\n");
529  printf(" -V :: print the version info, then exit.\n");
530  printf(" file :: if files are listed, display their mimetype.\n");
531  printf(" no file :: process data from the scheduler.\n");
532 } /* Usage() */
int fo_checkPQresult(PGconn *pgConn, PGresult *result, char *sql, char *FileID, int LineNumb)
Check the result status of a postgres SELECT.
Definition: libfossdb.c:181
PGresult * DBMime
contents of mimetype table
Definition: finder.c:27
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:196
void DBLoadMime()
Populate the DBMime table.
Definition: finder.c:69
int s
The socket that the CLI will use to communicate.
Definition: fo_cli.c:48
int DBFindMime(char *Mimetype)
Find a mime type in the DBMime table.
Definition: finder.c:92
int GetDefaultMime(char *MimeType, char *Filename)
Get the ID for the default mimetype.
Definition: finder.c:258
char * GetFieldValue(char *Sin, char *Field, int FieldMax, char *Value, int ValueMax)
Given a string that contains field=&#39;value&#39; pairs, save the items.
Definition: finder.c:425
char A[MAXCMD]
input for this system
Definition: finder.c:37
char SQL[MAXCMD]
For DB.
Definition: finder.c:25
int fo_checkPQcommand(PGconn *pgConn, PGresult *result, char *sql, char *FileID, int LineNumb)
Check the result status of a postgres commands (not select) If an error occured, write the error to s...
Definition: libfossdb.c:215
void DBCheckMime(char *Filename)
Given a file, check if it has a mime type in the DB.
Definition: finder.c:292
int Agent_pk
agent identifier
Definition: finder.c:30
int MaxDBMime
how many rows in DBMime
Definition: finder.c:28
FILE * FMimetype
for /etc/mime.types
Definition: finder.c:32
magic_t MagicCookie
for Magic
Definition: finder.c:34
char * TaintString(char *S)
Create a string with taint quoting.
Definition: finder.c:46
int ReadLine(FILE *Fin, char *Line, int MaxLine)
Read a line each time from one file.
Definition: finder.c:489
PGconn * pgConn
Database connection.
Definition: finder.c:29
char * Filename
Filename.
Definition: run_tests.c:28
int CheckMimeTypes(char *Ext)
Given an extension, see if extension exists in the /etc/mime.types.
Definition: finder.c:138
void Usage(char *Name)
Here are some suggested options.
Definition: finder.c:521