home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 February / PCO_0299.ISO / filesbbs / linux / mikmod-3.000 / mikmod-3 / mikmod-3.1.2 / mikmod / marchive.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-12-07  |  10.4 KB  |  422 lines

  1. /*  MikMod example player
  2.     (c) 1998 Miodrag Vallat and others - see file AUTHORS for complete list
  3.  
  4.     This program is free software; you can redistribute it and/or modify
  5.     it under the terms of the GNU General Public License as published by
  6.     the Free Software Foundation; either version 2 of the License, or
  7.     (at your option) any later version.
  8.  
  9.     This program is distributed in the hope that it will be useful,
  10.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.     GNU General Public License for more details.
  13.  
  14.     You should have received a copy of the GNU General Public License
  15.     along with this program; if not, write to the Free Software
  16.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18.  
  19. /*==============================================================================
  20.  
  21.   $Id: marchive.c,v 1.22 1998/12/07 06:01:24 miod Exp $
  22.  
  23.   Archive support
  24.  
  25.   These routines are used to detect different archive/compression formats
  26.   and decompress/de-archive the mods from them if necessary.
  27.  
  28. ==============================================================================*/
  29.  
  30. #ifdef HAVE_CONFIG_H
  31. #include "config.h"
  32. #endif
  33.  
  34. #ifdef HAVE_UNISTD_H
  35. #include <unistd.h>
  36. #endif
  37. #ifndef HAVE_FNMATCH_H
  38. #include "../extra/fnmatch.h"
  39. #else
  40. #include <fnmatch.h>
  41. #endif
  42. #ifdef HAVE_LIMITS_H
  43. #include <limits.h>
  44. #endif
  45. #ifdef __EMX__
  46. #define PATH_MAX _POSIX_PATH_MAX
  47. #endif
  48. #include <signal.h>
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include <string.h>
  52. #include <sys/types.h>
  53. #include <sys/stat.h>
  54. #if !defined(__OS2__)&&!defined(__EMX__)
  55. #ifdef HAVE_FCNTL_H
  56. #include <fcntl.h>
  57. #endif
  58. #include <pwd.h>
  59. #include <sys/wait.h>
  60. #endif
  61.  
  62. #include <mikmod.h>
  63. #include "player.h"
  64.  
  65. /*========== Archives */
  66.  
  67. typedef struct {
  68.     unsigned int location;
  69.     char *marker;
  70.     char *command;
  71. #if !defined(__OS2__)&&!defined(__EMX__)
  72.     char *extrargs,*extrargs2;
  73.     char *listargs,*listargs2;
  74. #else
  75.     char *extrargs;
  76.     char *listargs;
  77. #endif
  78.     unsigned int nameoffset;
  79. } ARCHIVE;
  80.  
  81. /* use similar signature idea to "file" to see what format we have... */
  82. static    char gzsignature[]={0x1f,0x8b,0};
  83. static    char pksignature[]={'P','K',0x03,0x04,0};
  84. static    char zoosignature[]={0xdc,0xa7,0xc4,0xfd,0};
  85. static    char rarsignature[]={'R','a','r','!',0};
  86. #if !defined(__OS2__)&&!defined(__EMX__)
  87. static    char arjsignature[]={0x60,0xea,0};
  88. static    char lhsignature[]={'-','l','h',0};
  89. static    char lzsignature[]={'-','l','z',0};
  90. #endif
  91.  
  92. ARCHIVE MA_archiver[]={
  93.     /* location, marker, command, extract and view args, filenames column */
  94. #if !defined(__OS2__)&&!defined(__EMX__)
  95. /* PKzip archive */
  96.     {    0,    pksignature,    "unzip",    "-pqq", "",        "-vqq", "",    58},
  97. /* gzip */
  98.     {    0,    gzsignature,    "gzip",        "-dqc", "",        "-lq", "",    27},
  99. /* zoo */
  100.     {    20,    zoosignature,    "zoo",        "xpq", "",        "lq", "",    47},
  101. /* rar */
  102.     {    0,    rarsignature,    "unrar",    "p", "-inul",    "v", "-c-",    1},
  103. /* lharc */
  104.     {    2,    lhsignature,    "lha",        "pq", "",        "vvq", "",    0},
  105.     {    2,    lzsignature,    "lha",        "pq", "",        "vvq", "",    0},
  106. /* arj with the "extract to stdout" patch */
  107.     {    0,    arjsignature,    "unarj",    "c", "",        "l", "",    0},
  108. /* needed to end the array... */
  109.     {    0,    NULL,            NULL,        NULL, NULL,        NULL, NULL,    0}
  110. #else
  111. /* PKzip archive */
  112.     {    0,    pksignature,    "unzip",    "-pqq",        "-lqq",    41},
  113. /* gzip */
  114.     {    0,    gzsignature,    "gzip",        "-dqc",        "-lq",    27},
  115. /* zoo */
  116.     {    20,    zoosignature,    "zoo",        "xpq",        "lq",    47},
  117.     {    0,    rarsignature,    "unrar",    "p -inul",    "v -c-",    1},
  118. /* needed to end the array... */
  119.     {    0,    NULL,            NULL,        NULL,        NULL,    0}
  120. #endif
  121. };
  122.  
  123. /* rightmost column position */
  124. #if defined(__OS2__)||defined(__EMX__)
  125. #define MAXCOLUMN 47
  126. #else
  127. #define MAXCOLUMN 58
  128. #endif
  129.  
  130. /* largest signature length */
  131. #define MAXSIGNATURE 16
  132.  
  133. /* module filenames patterns */
  134. #define PATTERNCOUNT 13
  135. CHAR* modulepatterns[PATTERNCOUNT]={
  136.     "*.669",
  137.     "*.[Aa][Mm][Ff]",
  138.     "*.[Dd][Ss][Mm]",
  139.     "*.[Ff][Aa][Rr]",
  140.     "*.[Ii][Tt]",
  141.     "*.[Mm][Ee][Dd]",
  142.     "*.[Mm][Oo][Dd]",
  143.     "[Mm][Oo][Dd].*",
  144.     "*.[Mm][Tt][Mm]",
  145.     "*.[Ss]3[Mm]",
  146.     "*.[Ss][Tt][Mm]",
  147.     "*.[Uu][Ll][Tt]",
  148.     "*.[Xx][Mm]"
  149. };
  150.  
  151. #if !defined(__OS2__)&&!defined(__EMX__)
  152. BOOL DropPrivileges(void)
  153. {
  154.     if(!geteuid()) {
  155.         if(getuid()) {
  156.             /* setuid root -> drop setuid, become the real user */
  157.             if(setuid(getuid()))
  158.                 return 1;
  159.         } else {
  160.             /* run as root -> drop all, become user 'nobody' */
  161.             struct passwd *nobody;
  162.             int uid;
  163.  
  164.             if(!(nobody=getpwnam("nobody")))
  165.                 return 1; /* no such user ? */
  166.             uid=nobody->pw_uid;
  167.             free(nobody);
  168.             if(!uid) /* user 'nobody' has root privileges ? weird... */
  169.                 return 1;
  170.             if(setuid(uid))
  171.                 return 1;
  172.         }
  173.     }
  174.     return 0;
  175. }
  176. #endif
  177.  
  178. BOOL MA_ismodulefilename(CHAR* filename)
  179. {
  180.     int t;
  181.  
  182.     for(t=0;t<PATTERNCOUNT;t++)
  183.         if(!fnmatch(modulepatterns[t],filename,0))
  184.             return 1;
  185.     return 0;
  186. }
  187.  
  188. int* MA_identify(CHAR* filename,int header_location,CHAR* header_string)
  189. {
  190.     FILE *fp;
  191.     CHAR id[MAXSIGNATURE+1];
  192.  
  193. #ifdef MIKMOD_DEBUG
  194.     if(strlen(header_string)>MAXSIGNATURE)
  195.         fputs("Error: wrong constant MAXSIGNATURE in MikMod source\n",stderr);
  196. #endif
  197.     if(!(fp=fopen(filename,"rb")))
  198.         return NULL;
  199.  
  200.     fseek(fp,header_location,SEEK_SET);
  201.  
  202.     if(!fread(id,strlen(header_string),1,fp)) {
  203.         fclose(fp);
  204.         return 0;
  205.     }
  206.     if(!memcmp(id,(CHAR*)header_string,strlen(header_string))) {
  207.         fclose(fp);
  208.         return (int*)1;
  209.     }
  210.     fclose(fp);
  211.  
  212.     return 0;
  213. }
  214.  
  215. CHAR* MA_dearchive(CHAR* arc,CHAR* file)
  216. {
  217.     int t;
  218.     CHAR *tmp_file;
  219.  
  220.     /* not an archive file... */
  221.     if((!arc)||(!arc[0]))
  222.         return strdup(file);
  223.  
  224. #if defined(__OS2__) && defined(__WATCOMC__)
  225.     if(!(tmp_file=malloc(strlen(getenv("TEMP"))+strlen("\\!MikMod.tmp")+1)))
  226.         return NULL;
  227.     strcpy(tmp_file,getenv("TEMP"));
  228.     strcat(tmp_file,"\\!MikMod.tmp");
  229. #else
  230.     if(!(tmp_file=tempnam(NULL,".mod")))
  231.         if(!(tmp_file=tempnam(getenv("HOME"),".mod")))
  232.             return NULL;
  233. #endif
  234.  
  235.     for(t=0;MA_archiver[t].command;t++) 
  236.         if(MA_identify(arc,MA_archiver[t].location,MA_archiver[t].marker)) {
  237.             /* display "extracting" message, as this may take some time... */
  238.             display_extractbanner();
  239. #if defined(__OS2__)||defined(__EMX__)
  240.             /* extracting, the non-Unix way */
  241.         {
  242.             CHAR command_buff[PATH_MAX<<1];
  243.  
  244.             sprintf(command_buff,"%s %s %s \"%s\" >\"%s\"",
  245.                     MA_archiver[t].command,MA_archiver[t].extrargs,arc,file,tmp_file);
  246.             system(command_buff);
  247.         }
  248. #else
  249.             /* extracting, the Unix way */
  250.         {
  251.             pid_t pid;
  252.             int status,fd;
  253.  
  254.             switch(pid=fork()) {
  255.                 case -1: /* fork failed */
  256.                     return NULL;
  257.                     break;
  258.                 case 0: /* fork succeeded, child process code */
  259.                     /* if we have root privileges, drop them */
  260.                     if(DropPrivileges()) exit(0);
  261.                     fd=open(tmp_file,O_WRONLY|O_CREAT|O_TRUNC,S_IREAD|S_IWRITE);
  262.                     if(fd!=-1) {
  263.                         close(0);close(1);close(2);
  264.                         dup2(fd,1);
  265.                         signal(SIGINT,SIG_DFL);signal(SIGQUIT,SIG_DFL);
  266.                         execlp(MA_archiver[t].command,
  267.                                MA_archiver[t].command,
  268.                                MA_archiver[t].extrargs,
  269.                                MA_archiver[t].extrargs2,
  270.                                arc,
  271.                                file,
  272.                                NULL);
  273.                         close(fd);
  274.                         unlink(tmp_file);
  275.                     }
  276.                     exit(0);
  277.                     break;
  278.                 default: /* fork succeeded, main process code */
  279.                     waitpid(pid,&status,0);
  280.                     if(!WIFEXITED(status)) {
  281.                         unlink(tmp_file);
  282.                         return NULL;
  283.                     }
  284.                     break;
  285.             }
  286.         }
  287. #endif
  288.             break;
  289.         }
  290.  
  291.     return tmp_file;
  292. }
  293.  
  294. void MA_FindFiles(PLAYLIST* pl,CHAR* filename)
  295. {
  296.     int t;
  297.     int archive=0;
  298.     CHAR string[PATH_MAX+(MAXCOLUMN+1)+1];
  299.     struct stat statbuf;
  300.  
  301. #ifdef MIKMOD_DEBUG
  302.     for(t=0;MA_archiver[t].command;t++)
  303.         if(MA_archiver[t].nameoffset>MAXCOLUMN) {
  304.             fputs("Error: wrong constant MAXCOLUMN in MikMod source\n",stderr);
  305.             return;
  306.         }
  307. #endif
  308.  
  309.     if (stat(filename,&statbuf))
  310.         return; /* File does not exist or not enough access rights */
  311.     if ((S_ISDIR(statbuf.st_mode))||(S_ISCHR(statbuf.st_mode))
  312. #ifndef __EMX__
  313.         ||(S_ISBLK(statbuf.st_mode))
  314. #endif
  315.        )
  316.         return; /* Directories and devices can't be modules... */
  317.  
  318.     /* if filename looks like a module, don't try to unzip the file...*/
  319.     if(MA_ismodulefilename(filename)) {
  320.         PL_Add(pl,filename,NULL);
  321.         return;
  322.     }
  323.  
  324.     for(t=0;MA_archiver[t].command;t++) 
  325.         if(MA_identify(filename,MA_archiver[t].location,MA_archiver[t].marker)) {
  326.             archive=t+1;
  327.             break;
  328.         }
  329.  
  330.     if(archive--) {
  331. #if defined(__OS2__)||defined(__EMX__)
  332. /* Archive display, the non-Unix way */
  333.         FILE *file;
  334.  
  335.         sprintf(string,"%s %s \"%s\"",MA_archiver[archive].command,
  336.                 MA_archiver[archive].listargs,filename);
  337. #ifdef __WATCOMC__
  338.         file=_popen(string,"r");
  339. #else
  340.         file=popen(string,"r");
  341. #endif
  342.         fgets(string,PATH_MAX+MAXCOLUMN+1,file);
  343.         while(!feof(file)) {
  344.             string[strlen(string)-1]=0;
  345.             if(!MA_archiver[archive].nameoffset) {
  346.                 /* this won't work with .arj and files embedding whitespaces,
  347.                    but arj shouldn't exist anyway... */
  348.                 for(t=0;string[t]!=' ';t++);
  349.                 string[t]=0;
  350.             }
  351.             if(MA_ismodulefilename(string+MA_archiver[archive].nameoffset))
  352.                 PL_Add(pl,(string+MA_archiver[archive].nameoffset),filename);
  353.             fgets(string,PATH_MAX,file);
  354.         }
  355. #ifdef __WATCOMC__
  356.         _pclose(file);
  357. #else
  358.         pclose(file);
  359. #endif
  360. #else
  361. /* Archive display, the Unix way */
  362.         int fd[2];
  363.  
  364.         if(!pipe(fd)) {
  365.             pid_t pid;
  366.             int status,cur;
  367.             char ch;
  368.  
  369.             switch(pid=fork()) {
  370.                 case -1: /* fork failed */
  371.                     break;
  372.                 case 0: /* fork succeeded, child process code */
  373.                     /* if we have root privileges, drop them */
  374.                     if(DropPrivileges()) exit(0);
  375.                     close(0);close(1);close(2);
  376.                     dup2(fd[1],1);dup2(fd[1],2);
  377.                     signal(SIGINT,SIG_DFL);signal(SIGQUIT,SIG_DFL);
  378.                     execlp(MA_archiver[archive].command,
  379.                            MA_archiver[archive].command,
  380.                            MA_archiver[archive].listargs,
  381.                            MA_archiver[archive].listargs2,
  382.                            filename,
  383.                            NULL);
  384.                     close(fd[1]);
  385.                     exit(0);
  386.                     break;
  387.                 default: /* fork succeeded, main process code */
  388.                     /* have to wait for the child to ensure the command was
  389.                        successful and the pipe contains useful information */
  390.                     waitpid(pid,&status,0);
  391.                     close(fd[1]);
  392.                     if(!WIFEXITED(status)) {
  393.                         close(fd[0]);
  394.                         break;
  395.                     }
  396.                     /* read from the pipe */
  397.                     cur=0;
  398.                     while(read(fd[0],&ch,1)) {
  399.                         if(ch=='\n') ch=0;
  400.                         string[cur++]=ch;
  401.                         if(!ch) {
  402.                             cur=0;
  403.                             if(!MA_archiver[archive].nameoffset) {
  404.                                 /* this won't work with .arj and files embedding
  405.                                    whitespaces, but arj shouldn't exist anyway
  406.                                    and I doubt it can store those files...*/
  407.                                 for(t=0;string[t]!=' ';t++);
  408.                                 string[t]=0;
  409.                             }
  410.                             if(MA_ismodulefilename(string+MA_archiver[archive].nameoffset))
  411.                                 PL_Add(pl,(string+MA_archiver[archive].nameoffset),filename);
  412.                         }
  413.                     }
  414.                     close(fd[0]);
  415.                     break;
  416.             }
  417.         }
  418. #endif
  419.     } else
  420.         PL_Add(pl,filename,NULL);
  421. }
  422.