2017-04-04 1 views
1

次のコードでは、一意のファイル名が必要です。これは、.classファイルをバイナリに変換することです。コンパイルと呼ぶことにします。並行実行に安全な一時ファイル名を作成する方法は?

単独で実行したり、一度に3回実行すると完全に機能します。しかし、1つ以上のコンパイルが失敗する複数のプロセス(たとえば7)を起動すると問題が発生します。

これはコードです:

#include <stdio.h> 
#include <errno.h> 
#include <stdlib.h> 
#include <string.h> 

static unsigned int numFiles = 0; 
static unsigned long numBytes = 0; 

FILE* rawf; 
char* raw_file_name_end = ".raw_ujc"; 
char * rawfilename; 

static void byte(unsigned char v){ 
    if(numBytes) printf(", "); 

    printf((numBytes & 0x0F) ? "0x%02X" : "\n\t0x%02X", v); 

    fwrite(&v,sizeof(v),1,rawf); 

    numBytes++; 
} 

int main(int argc, char** argv){ 

    const char* self = argv[0]; 
    int c; 
    const char* classCvt = 0; 
    long len; 

    if(argc == 1){ 

     fprintf(stderr, "USAGE: %s [-c <path_to_classCvt>] <file 1> [<file 2> [ <file 3> [...]]] > result.c\n", self); 
     return -1; 
    } 

    argv++; 
    argc--; 

    if(argv[0][0] == '-' && argv[0][1] == 'c' && !argv[0][2]){ 

     classCvt = argv[1]; 
     argv += 2; 
     argc -= 2; 
    } 

    printf("\nService optimized bytecode = {\n\t"); 

    while(argc--){ 
     char* filename = *argv; 

     rawfilename = malloc(sizeof(char) * (strlen(filename)-strlen(".class")) + sizeof(char) * strlen(raw_file_name_end)+1); 

     strncpy(rawfilename,filename,(strlen(filename)-strlen(".class"))); 
     strcat(rawfilename,raw_file_name_end); 
     fprintf(stderr, "rawfilename after alloc: %s \n", rawfilename); 

     if(classCvt){ 

      char* t; 

      filename = tempnam(NULL, NULL); 
      if(!filename){ 
       fprintf(stderr, "%s: failed to create a tempfile: %d\n", self, errno); 
       return -10; 
      } 

      t = malloc(strlen(filename) + strlen(classCvt) + strlen(*argv) + 32); 
      if(!t){ 
       fprintf(stderr, "%s: failed to alloc a small string. This is unlikely\n", self); 
       free(t); 
       return -11; 
      } 
      sprintf(t, "%s < %s > %s", classCvt, *argv, filename); 

      if(system(t)){ 

       fprintf(stderr, "%s: system() fail: %d\n", self, errno); 
       free(t); 
       return -12; 
      } 
      free(t); 
     } 
     printf("filename is %s\n",filename); 
     FILE* f = fopen(filename, "r"); 
     rawf = fopen(rawfilename, "wb"); 


     if(filename != *argv){ 
      unlink(filename); 
      free(filename); 
     } 

     if(!f){ 
      fprintf(stderr, "%s: failed to open '%s': %d\n", self, *argv, errno); 
      fclose(f); 
      return -2; 
     } 
     if(!f){ 
      fprintf(stderr, "%s: failed to open '%s': %d\n", self, *argv, errno); 
      fclose(f); 
      return -2; 
     } 
     if(fseek(f, 0, SEEK_END)){ 
      fprintf(stderr, "%s: failed to seek(1) in '%s': %d\n", self, *argv, errno); 
      fclose(f); 
      return -3; 
     } 
     len = ftell(f); 
     if(len < 0){ 
      fprintf(stderr, "%s: failed to tell in '%s': %d\n", self, *argv, errno); 
      fclose(f); 
      return -4; 
     } 
     if(fseek(f, 0, SEEK_SET)){ 
      fprintf(stderr, "%s: failed to seek(2) in '%s': %d\n", self, *argv, errno); 
      fclose(f); 
      return -5; 
     } 
     if(len > 0x00FFFFFFUL){ 
      fprintf(stderr, "%s: file '%s' is %lu bytes, while maximum allowable size is %lu.\n", self, *argv, len, 0x00FFFFFFUL); 
      fclose(f); 
      return -6; 
     } 

     byte(len >> 16); 
     byte(len >> 8); 
     byte(len); 

     while((c = fgetc(f)) != EOF){ 
      byte(c); 
     } 

     numFiles++; 
     fclose(f); 
     fclose(rawf); 

     argv++; 
    } 

    byte(0); 
    byte(0); 
    byte(0); 

    printf("\n};\n"); 

    fprintf(stderr, "%s: processed %u files, producing %lu (0x%lX) bytes of output\n", self, numFiles, numBytes, numBytes); 
    fprintf(stderr, "rawfilename at end: %s \n", rawfilename); 
    free(rawfilename); 

    return 0; 
} 

周りを探した後、人々はmkstemp()を使用することをお勧めします。しかし、あなたが見ることができるように、私は実際にはいくつかの場所でファイル名が必要です。

これを調整しようとしましたが、エラーが発生し続けました。どうすればこの作業方法を安全​​に調整できますか?

+0

実際に実行されている問題の種類を具体的に指定してください。 – alk

+2

コードを編集して問題の[mcve]にしてください。あなたの現在のコードには、問題の周辺にあるものが多く含まれています。通常、最小単位のサンプルは良い単位テストと似ています。特に、他の人があなたの問題を調査するときに試してみたいかもしれないコードで 'system()'にそのような呼び出しを埋め込むことは無礼と考えられます。 –

答えて

4

manページからmkstemp

int mkstemp(char *template); 

ためにはmkstemp()関数は、テンプレートから一意の一時ファイル名を生成したファイルを作成して開き、ファイルのオープンファイル記述子を返します。 テンプレートの最後の6文字は "XXXXXX"で、 はファイル名を一意にする文字列に置き換えられています。 が変更されるため、テンプレートは文字列定数であってはなりませんが、文字配列として宣言された である必要があります。 ファイルはアクセス許可0600で作成されます。つまり、所有者専用には、リードプラスプラス となります。返されたファイル記述子は、ファイルへの読み取りアクセスと書き込みアクセスの両方を提供します( )。ファイルはopen(2)O_EXCL フラグで開かれ、呼び出し元が ファイルを作成するプロセスであることが保証されます。

ファイル名が必要な場合は、template引数がmkstempに渡されています。

関連する問題