Всем привет!
Есть такая задача.
Допустим, есть некая информация, например, дипломная работа.
Я пытаюсь ее сохранить в файл с названием diplomnaya
char *document_name = "diplomnaya";
int fd = openat(dirfd, document_name, O_RDWR | O_CREAT | O_EXCL, 0644); // -1, errno = EEXIST
Оказывается, что файл с таким именем уже есть.
Какой бы вы посоватовали наиболее удачный способ изменения названия файла для того чтобы наименее слабо модифицировать это название?
Первое что приходит в голову: добавлять число в конце названия, постепенно его увеличивая если и такие названия будут заняты. Такой алгоритм используется, например, в современных браузерах.
Однако хочу заметить, что помимо прочего, существует ограничение на длину названия файла в 255 байт (NAME_MAX), как и в длину общего пути (PATH_MAX). И вполне реально «упасть» при попытке создания файла с подобным именем в errno == ENAMETOOLONG.
Какие есть предложения? Модифицировать оригинальное имя вплоть до наихудшего случая (полная неузнаваемость по сравнению с оригинальным названием) разрешается.
Выбирать имя файла пользователю не предлагать - он его видить не будет в 99% случаев, а совпадения по названию при сохранении иногда будут.
Стоит ли велосипедить что-то свое или достаточно просто взять https://man7.org/linux/man-pages/man3/tempnam.3.html ?
UPD: Решил сделать так: Нужен алгоритм гарантированного создания названий файлов (комментарий)
UPD2: Код:
int randfd = -1; // randfd = open("/dev/urandon", O_RDONLY);
#define RANDBYTES_WIDTH 11
void randfilename(char *ptr, size_t len) {
const char pool[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char randbytes[RANDBYTES_WIDTH];
ssize_t got = read(randfd, randbytes, sizeof(randbytes));
if (randfd < 0 or got < sizeof(randbytes)) { //fallback
for (unsigned i = 0; i < sizeof(randbytes); i++) {
randbytes[i] = (char) rand();
}
}
for (unsigned i = 0; i < sizeof(randbytes); i++) {
randbytes[i] = pool[randbytes[i] % (sizeof(pool) - 1)];
}
if (len + sizeof(randbytes) > NAME_MAX) len -= len + sizeof(randbytes) - NAME_MAX;
memcpy(ptr + len, randbytes, sizeof(randbytes));
ptr[len + sizeof(randbytes)] = '\0';
}