简体   繁体   English

如何创建一个可以安全地执行并发执行的临时文件名?

[英]How to I make a temporary filename that's safe for concurrent execution?

In the following code, I need a unique filename, do some stuff with it, and let it be. 在下面的代码中,我需要一个唯一的文件名,使用它做一些事情,然后顺其自然。 It is about converting a .class file to binary, let us call it compilation. 它是关于将.class文件转换为二进制文件,我们称之为编译。

It works perfectly when run in isolation or done 3 times at a time; 孤立运行或一次运行3次时,它可以完美工作。 however, I run into issues when I start up many multiple processes (eg, 7) where one or more of my compilations fail. 但是,当我启动许多多个过程(例如7)时,我的一个或多个编译失败,我遇到了问题。

This is the code: 这是代码:

#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;
}

After looking around, people recommend using mkstemp() ; 环顾四周后,人们建议使用mkstemp() however, as you can see, I actually do need the filename in several places. 但是,正如您所看到的,我实际上确实需要在多个位置使用文件名。

I tried adjusting this but keep running into errors. 我尝试调整此设置,但始终遇到错误。 How can I safely adjust this work method? 如何安全地调整此工作方法?

From the manpage for mkstemp mkstemp的联机帮助页

int mkstemp(char *template);

The mkstemp() function generates a unique temporary filename from template, creates and opens the file, and returns an open file descriptor for the file. mkstemp()函数从模板生成唯一的临时文件名,创建并打开文件,并返回该文件的打开文件描述符。 The last six characters of template must be "XXXXXX" and these are replaced with a string that makes the filename unique. 模板的最后六个字符必须为“ XXXXXX”,并用使文件名唯一的字符串替换。 Since it will be modified, template must not be a string constant, but should be declared as a character array. 由于将对其进行修改,因此模板不能为字符串常量,而应声明为字符数组。 The file is created with permissions 0600, that is, read plus write for owner only. 创建的文件具有权限0600,即,仅所有者拥有读写权限。 The returned file descriptor provides both read and write access to the file. 返回的文件描述符提供对文件的读写访问。 The file is opened with the open(2) O_EXCL flag, guaranteeing that the caller is the process that creates the file. 使用open(2)O_EXCL标志打开文件,以确保调用者是创建文件的进程。

so if you need the filename, you can find it in the template argument passed to mkstemp. 因此,如果您需要文件名,则可以在传递给mkstemp的template参数中找到它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM