Способы POSIX для создания временного файла с красивым именем файла

Я хочу создать временный файл с «хорошим» именем, например

my-app-Mar27-120357-Qf3K0a.html

следуя рекомендациям по безопасности.

POSIX предлагает мне mkstemp(3), который принимает шаблон имени файла (обычно что-то вроде /tmp/my-app-XXXXXX), но у него есть две проблемы:

  1. Мне нужно выбрать выходной каталог самостоятельно. Когда я вижу glibc tempnam(3) (который устарел для из соображений безопасности) учитывает множество факторов, я хочу, чтобы библиотечная функция выбрала его.
  2. В имени файла нет расширения

Ко второму элементу можно обратиться с помощью mkstemps(3), что требует некоторого количества символов для сохранения в качестве определяемого пользователем расширения. В моем случае я могу пройти my-app-Mar27-120357-XXXXXX.html и 5, но есть свои проблемы:

  1. Мне все еще нужно выбрать выходной каталог
  2. Это не совсем портативно. NetBSD, кажется, отсутствует.

Поэтому я рассматриваю возможность использования устаревшего tempnam(3) для создания имени файла с выходным путем к каталогу, перезаписать часть имени файла с помощью X и передать его в mkstemp(3), а затем переименовать файл в моем предпочтительном формате. Таким образом, проблема заключается в последнем шаге, переименовании без перезаписи; возможно ли это в POSIX?

Или может быть есть лучшие альтернативы?


person nodakai    schedule 27.03.2016    source источник
comment
Я бы тоже рекомендовал ответ Алекса, но есть стандартная функция C tmpnam< /a> вы можете использовать, если вам действительно нужно имя.   -  person Some programmer dude    schedule 27.03.2016
comment
@JoachimPileborg tmpnam(3) менее гибкий, чем tempnam(3), о котором я уже упоминал в своем посте.   -  person nodakai    schedule 27.03.2016
comment
NetBSD 7.0 и новее имеют mkstemps. Однако в настоящее время его нет в Minix3 libc.   -  person kdhp    schedule 27.03.2016
comment
@kdhp Я, видимо, проверяю ПО УМОЛЧАНИЮ (NetBSD-6.1.5). Возможно, он по умолчанию сделал консервативный выбор.   -  person nodakai    schedule 27.03.2016


Ответы (2)


Позвольте mkstemp создать файл, который он хочет создать, POSIX-совместимым способом, которым он хочет. Используйте symlink, чтобы создать символическую ссылку из исходного файла и пути по вашему выбору к месту назначения, которое соответствует тому, что получается при использовании mkstemp. Удалите символическую ссылку, когда закончите.

person Alex Reynolds    schedule 27.03.2016
comment
Хм, не могу сказать, что мне нравится это решение... Удалите символическую ссылку, когда закончите. Представьте, что я работаю над аварийным дампом, который моя программа предлагает пользователю отправить на наш сервер по электронной почте или через Интернет. Но да, это может быть самым близким к моему намерению. - person nodakai; 27.03.2016
comment
Если вы создаете исключение, которое вызывает фатальную ошибку, вы можете (должны) справиться с очисткой в ​​обработчике этого исключения. - person Alex Reynolds; 27.03.2016
comment
Я имею в виду, что временные файлы могут законно пережить свою программу-производителя в некоторых довольно распространенных случаях использования. - person nodakai; 27.03.2016
comment
@nodakai, если вы беспокоитесь о случайных символических ссылках или временных файлах, оставшихся после сбоя, обычно trap позаботится об этом за вас. - person David C. Rankin; 27.03.2016

Другой подход — просто изменить шаблон и добавить свой путь. Здесь мы описываем такую ​​функцию в наборе инструментов BEDOPS, используемую приложением sort-bed, чтобы позволить конечному пользователю указать, где хранятся временные промежуточные файлы: /applications/bed/sort-bed/src/SortDetails.cpp#L115" rel="nofollow">https://github.com/bedops/bedops/blob/6da835468565dfc30a3fcb65807e91fcf133ea2b/applications/bed/sort-bed/src/SortDetails .cpp#L115

FILE *
createTmpFile(char const* path, char** fileName)
{
    FILE* fp;
    int fd;
    char* tmpl;

    if (path == NULL)
        {
            fileName = NULL;
            return tmpfile();
        }

    tmpl = static_cast<char*>( malloc(1 + strlen(path) + L_tmpnam) );
    strcpy(tmpl, path);
    strcpy(tmpl+strlen(path), "/sb.XXXXXX");
    fd = mkstemp(tmpl);
    if(fd == -1)
        {
            fprintf(stderr, "unable to create temp file!\n");
            return NULL;
        }
    fp = fdopen(fd, "wb+");
    *fileName = static_cast<char*>( malloc(strlen(tmpl) + 1) );
    strcpy(*fileName, tmpl);
    free(tmpl);
    return fp;
} 

При этом используется макрос L_tmpnam, часть библиотеки stdio, для установки количества символов, которые может хранить переменная tmpl (в конечном счете, имя файла).

Это компилируется и работает под хостами Linux и OS X (BSD), а также использует подпрограммы POSIX.

Это сложнее, чем другое мое решение, но оно может работать лучше для вашего варианта использования.

person Alex Reynolds    schedule 27.03.2016
comment
Спасибо, что поделились реальным примером. Вы работаете над интересным проектом, кстати - person nodakai; 27.03.2016