// file_comp.c
// $Id: libfile_comp.c,v 1.2 2007/10/17 11:03:08 sendan Exp $
// masashi shimakura
//


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pwd.h>
#include<grp.h>
#include<sys/types.h>
#include<sys/stat.h>

#include "file_comp.h"
#include "../almemsys/almemsys.h"


// int file_comp(char * chB);
int noget(char * swap_data);
int valin(private_data_comp * pd, char * chB);
int write_file(private_data_comp * pd, char * file_data, char * comp_path);
int head_default_set(private_data_comp * pd);
int print_head(private_data_comp * pd);




// フォーマットされたファイルから実際にファイルを配置する関数、正常なら0を返す。
// 異常の場合は異常のあった行番めの番号を返す。
int file_comp(char * chB, char * comp_path)
{
int new_len, count, stat_attr, ret;
private_data_comp *pd;

ret = 0;
stat_attr = 0;

char * file_data = (char *)calloc(IP_BUFF, sizeof(char));

if((pd = (private_data_comp *)malloc(sizeof(private_data_comp)))==NULL){exit(1);}

new_len = valin(pd, chB);

for(count = 0; count < new_len; count++){
   if(pd->val_attr[count] == 111){
      conf_seting(pd, pd->val_data[count]);
      if(stat_attr == 2){
         if(-1 == write_file(pd, file_data, comp_path)){
            fprintf(stderr,"file_comp(1): write_file()がエラーを返しています\n");
            ret = count;
            }
         file_data = safe_memcpy(file_data, "", MAX_BUFF);
         }
      stat_attr = 1;
      }   
   else if(pd->val_attr[count] == 222){
      file_data = safe_strncat(file_data, pd->val_data[count], MAX_BUFF);
      file_data = safe_strncat(file_data, "\n", MAX_BUFF);
      stat_attr = 2;
      }   
   else{
      if(stat_attr == 2){
         if(-1 == write_file(pd, file_data, comp_path)){
            fprintf(stderr,"file_comp(2): write_file()がエラーを返しています\n");
            ret = count;
            }
         file_data = safe_memcpy(file_data, "", MAX_BUFF);
         }
      stat_attr = 0;
      }
   }

comp_private_malloc_free(pd, new_len);
free(pd);
free(file_data);
return ret;
}




// デフォルトのヘッダーをセット 
int head_default_set(private_data_comp * pd)
{
int ret;
ret = 0;

pd->head_buff.comment = safe_memcpy(pd->head_buff.comment, VER_INFO, MAX_BUFF);
pd->head_buff.command_path = safe_memcpy(pd->head_buff.command_path, DEFAULT_PATH, MAX_BUFF);
pd->head_buff.command_name = safe_memcpy(pd->head_buff.command_name, DEFAULT_NAME, MAX_BUFF);
pd->head_buff.user = safe_memcpy(pd->head_buff.user, DEFAULT_USER, MAX_BUFF);
pd->head_buff.group = safe_memcpy(pd->head_buff.group, DEFAULT_GROUP, MAX_BUFF);
pd->head_buff.permission = safe_memcpy(pd->head_buff.permission, DEFAULT_PERM, MAX_BUFF);

return ret;
}


// ヘッダーの内容を表示
int print_head(private_data_comp * pd)
{
int ret;
ret = 0;

printf("現在のヘッダー情報\n");
printf("COMMENT        : %s\n", pd->head_buff.comment);
printf("COMMAND_PATH   : %s\n", pd->head_buff.command_path);
printf("COMMAND_NAME   : %s\n", pd->head_buff.command_name);
printf("USER           : %s\n", pd->head_buff.user);
printf("GROUP          : %s\n", pd->head_buff.group);
printf("PERMMISION     : %s\n", pd->head_buff.permission);
printf("\n");

return ret;
}



// 情報から実際にファイルに書き込み、パーミッションなどを設定する関数
int write_file(private_data_comp * pd, char * file_data, char * comp_path)
{
struct passwd *pw;
struct group *gw;
FILE * fp;
int ret, fd;
ret = 0;
char * file_name = (char *)calloc(IP_BUFF, sizeof(char));

#ifdef LIBFILE_COMP_BUG
print_head(pd);
printf("%s\n", file_data);
#endif


if(0 >= (int)strlen(comp_path)){
   #ifdef COMPUL_PATH
   file_name=safe_sprintf(file_name, MAX_BUFF,"%s/%s",COMPUL_PATH, pd->head_buff.command_name);
   #else
   file_name=safe_sprintf(file_name, MAX_BUFF,"%s/%s",pd->head_buff.command_path,pd->head_buff.command_name);
   #endif
   }
else{
   file_name=safe_sprintf(file_name, MAX_BUFF,"%s/%s",comp_path, pd->head_buff.command_name);
   }


pw = getpwnam(pd->head_buff.user);
if(pw == 0){
   fprintf(stderr,"write_file(): getpwnam(%s) のエラー\n", pd->head_buff.user);
   free(file_name);
   return -1;
   }

gw = getgrnam(pd->head_buff.group);
if(gw == 0){
   fprintf(stderr,"write_file(): getgrnam(%s) のエラー\n", pd->head_buff.group);
   free(file_name);
   return -1;
   }

#ifdef LIBFILE_COMP_BUG
fprintf(stdout,"write_file(): UID=%d  GID=%d\n",pw->pw_uid, gw->gr_gid);
#endif

if((fp=fopen(file_name, "w+"))==NULL){
   fprintf(stderr,"write_file(): %s ファイルがひらけません\n",file_name);
   free(file_name);
   ret = -1;
   }
else{
   fd = fileno(fp);
   fprintf(fp,"%s", file_data);
   if(-1 == fchmod(fd, (mode_t)strtol(pd->head_buff.permission, (char **)NULL, 8))){
      fprintf(stderr,"write_file(): fchmod() のエラー\n");
      free(file_name);
      fclose(fp);
      return -1;
      }
   if(-1 == fchown(fd, (uid_t)pw->pw_uid, (gid_t)gw->gr_gid)){
      fprintf(stderr,"write_file(): fchown() のエラー\n");
      free(file_name);
      fclose(fp);
      return -1;
      }
   fclose(fp);
   }

free(file_name);
return ret;
}









// head で囲んだデータ行に111、bodyで囲んだデータ行に222の番号をふる。
// それ以外は全て0にし、プライベートバッファに格納。
int valin(private_data_comp * pd, char * chB)
{
int new_len, count, count2, ret, rets, retd;

char * swap_data = (char *)calloc(IP_BUFF, sizeof(char));

new_len = char_count(chB, '\n');

comp_private_malloc_set(pd, new_len);

head_default_set(pd);
#ifdef LIBFILE_COMP_BUG
print_head(pd);
#endif

rets = 0;
retd = 0;
count = 0;
for(count2 = 0; count2 < new_len; count2++){
   swap_data = delim_get(chB, swap_data, '\n', &ret, count2);
   if(0==memcmp(swap_data, "NOT", 3) || 0 != ret){
      }
   else{
      rets = noget(swap_data);
      if(rets == 1){
         pd->val_attr[count] = 0;
         pd->val_data[count] = safe_memcpy(pd->val_data[count], swap_data, MAX_BUFF);
         retd = 111;
         }
      else if(rets == 11){
         pd->val_attr[count] = 0;
         pd->val_data[count] = safe_memcpy(pd->val_data[count], swap_data, MAX_BUFF);
         retd = 0;
         }
      else if(rets == 2){
         pd->val_attr[count] = 0;
         pd->val_data[count] = safe_memcpy(pd->val_data[count], swap_data, MAX_BUFF);
         retd = 222;
         }
      else if(rets == 22){
         pd->val_attr[count] = 0;
         pd->val_data[count] = safe_memcpy(pd->val_data[count], swap_data, MAX_BUFF);
         retd = 0;
         }
      else{
         pd->val_attr[count] = retd;
         pd->val_data[count] = safe_memcpy(pd->val_data[count], swap_data, MAX_BUFF);
         }
      count++;
      }
   }

free(swap_data);
return new_len;
}



// noget() は<_headや<_bodyに対応した数字を返す。
// noget() が返す番号
//   1 -  <_head   2 - <_body
//  11 -  >_head  22 - >_body
// other 0;
int noget(char * swap_data)
{
int size, ret;
ret = 0;

if((size = strlen(swap_data)) == 6 && '<' == swap_data[0] && '_' == swap_data[1]){
   if('h' == swap_data[2] && 'e' == swap_data[3] && 'a' == swap_data[4] && 'd' == swap_data[5]){
      ret = 1;
      }
   else if('b' == swap_data[2] && 'o' == swap_data[3] && 'd' == swap_data[4] && 'y' == swap_data[5]){
      ret = 2;
      }
   else{
      ret = 0;
      }
   }
else if((size = strlen(swap_data)) == 6 && '>' == swap_data[0] && '_' == swap_data[1]){
   if('h' == swap_data[2] && 'e' == swap_data[3] && 'a' == swap_data[4] && 'd' == swap_data[5]){
      ret = 11;
      }
   else if('b' == swap_data[2] && 'o' == swap_data[3] && 'd' == swap_data[4] && 'y' == swap_data[5]){
      ret = 22;
      }
   else{
      ret = 0;
      }
   }
else{
   ret = 0;
   }

return ret;
}











