fix(member-files): reject local FIFO without blocking disk worker
This commit is contained in:
1 parent
1c1b2b2026
commit
41f0aa2439
2 files changed
+42
-10
No files matched your search
+10
-3
@@ -58,7 +58,10 @@ static int disk_win_error(const char* operation) {
|
||||
static int disk_handle_info(HANDLE h, struct mf_disk_info* out) {
|
||||
BY_HANDLE_FILE_INFORMATION i;
|
||||
if (!GetFileInformationByHandle(h, &i)) return disk_win_error("GetFileInformationByHandle");
|
||||
if ((i.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) || i.nNumberOfLinks > 1) return MF_INVALID_PATH;
|
||||
if ((i.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) || i.nNumberOfLinks > 1) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "member_files: unsupported file attributes=%lu links=%lu", i.dwFileAttributes, i.nNumberOfLinks);
|
||||
return MF_INVALID_PATH;
|
||||
}
|
||||
memset(out, 0, sizeof(*out));
|
||||
out->type = i.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? MF_DIRECTORY : MF_FILE;
|
||||
out->size = out->type == MF_FILE ? ((uint64_t)i.nFileSizeHigh << 32) | i.nFileSizeLow : 0;
|
||||
@@ -254,7 +257,11 @@ static int disk_parent_open(struct mf_disk_root* root, const char* path, struct
|
||||
}
|
||||
|
||||
static int disk_posix_info(const struct stat* st, struct mf_disk_info* i) {
|
||||
if ((!S_ISREG(st->st_mode) && !S_ISDIR(st->st_mode)) || (S_ISREG(st->st_mode) && st->st_nlink != 1)) return MF_INVALID_PATH;
|
||||
if ((!S_ISREG(st->st_mode) && !S_ISDIR(st->st_mode)) || (S_ISREG(st->st_mode) && st->st_nlink != 1)) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "member_files: unsupported file mode=%lo links=%llu",
|
||||
(unsigned long)st->st_mode, (unsigned long long)st->st_nlink);
|
||||
return MF_INVALID_PATH;
|
||||
}
|
||||
memset(i, 0, sizeof(*i)); i->type = S_ISDIR(st->st_mode) ? MF_DIRECTORY : MF_FILE;
|
||||
i->size = i->type == MF_FILE ? (uint64_t)st->st_size : 0; i->mtime = (uint64_t)st->st_mtime;
|
||||
i->identity[0] = st->st_dev; i->identity[1] = st->st_ino;
|
||||
@@ -352,7 +359,7 @@ int mf_disk_resize(int fd, uint64_t size) { return ftruncate(fd, (off_t)size) ?
|
||||
int mf_disk_sync(int fd) { return fsync(fd) ? disk_error("sync", NULL) : MF_OK; }
|
||||
int mf_disk_close(int fd) { return close(fd) ? disk_error("close", NULL) : MF_OK; }
|
||||
int mf_disk_local_open(const char* path, int create, int* fd) {
|
||||
*fd = open(path, O_CLOEXEC | O_NOFOLLOW | (create ? O_RDWR | O_CREAT | O_EXCL : O_RDONLY), 0600);
|
||||
*fd = open(path, O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK | (create ? O_RDWR | O_CREAT | O_EXCL : O_RDONLY), 0600);
|
||||
return *fd < 0 ? disk_error("local open", path) : MF_OK;
|
||||
}
|
||||
int mf_disk_local_publish(const char* from, const char* to) { return rename(from, to) ? disk_error("local publish", to) : MF_OK; }
|
||||
|
||||
+32
-7
@@ -1,39 +1,64 @@
|
||||
/* Примитивы диска для storage и клиентского worker. На POSIX пути разрешаются
|
||||
/* Синхронные примитивы диска для storage и клиентского worker; не вызывать из uasync callbacks.
|
||||
* Возврат — MF_OK либо положительный mf_status, не errno/-1. Аргументы/выходы обязательны, кроме отмеченных NULL.
|
||||
* Серверные path/from/to — уже проверенные относительные пути; сам слой не запрещает '.'/'..'.
|
||||
* На POSIX пути разрешаются
|
||||
* относительно открытого каталога через *at/O_NOFOLLOW. Windows удерживает каталоги
|
||||
* без FILE_SHARE_DELETE и отвергает reparse points; имена преобразуются UTF-8→UTF-16.
|
||||
* fd принадлежит вызывающему; read/write работают по 64-битному смещению. */
|
||||
* fd принадлежит вызывающему; read/write работают по 64-битному смещению.
|
||||
* Локальные пути приложения не ограничены корнем storage; их родители/назначение остаются ответственностью caller. */
|
||||
#ifndef MEMBER_FILES_DISK_H
|
||||
#define MEMBER_FILES_DISK_H
|
||||
#include "protocol.h"
|
||||
#include "../../lib/platform_compat.h"
|
||||
|
||||
struct mf_disk_info { uint64_t size, mtime, identity[6]; uint8_t type; };
|
||||
struct mf_disk_info {
|
||||
uint64_t size; // Байты regular-файла; каталог — 0.
|
||||
uint64_t mtime; // Unix seconds; для version используются более точные identity.
|
||||
uint64_t identity[6]; // Непрозрачный снимок inode/file ID и времён; платформенно зависим, не wire.
|
||||
uint8_t type; // MF_FILE/MF_DIRECTORY; другие типы и regular hardlink отклоняются.
|
||||
};
|
||||
struct mf_disk_root {
|
||||
char path[2048];
|
||||
char path[2048]; // Заимствованный при open путь копируется; предел2047 байт + NUL.
|
||||
#ifdef _WIN32
|
||||
HANDLE handle;
|
||||
HANDLE handle; // Собственный handle корня, закрывается после всех операций.
|
||||
#else
|
||||
int fd;
|
||||
int fd; // Собственный directory fd; операции разрешают имена относительно него.
|
||||
#endif
|
||||
};
|
||||
/* Создать корень, если отсутствует (не создаёт родителей), и закрепить его. Close нужен только после успеха. */
|
||||
int mf_disk_root_open(struct mf_disk_root* root, const char* path);
|
||||
void mf_disk_root_close(struct mf_disk_root* root);
|
||||
/* Открыть regular-файл без усечения. create!=0 — эксклюзивное создание, writable!=0 — read/write.
|
||||
* fd использовать/закрывать только после MF_OK; отказ не гарантирует значение *fd. */
|
||||
int mf_disk_open(struct mf_disk_root* root, const char* path, int create, int writable, int* fd);
|
||||
/* Снимок без чтения содержимого: stat — по имени, info — уже открытого fd. Выход использовать только при успехе. */
|
||||
int mf_disk_stat(struct mf_disk_root* root, const char* path, struct mf_disk_info* info);
|
||||
int mf_disk_info(int fd, struct mf_disk_info* info);
|
||||
/* created, если не NULL, показывает факт создания даже при последующей ошибке sync. */
|
||||
/* Создать один каталог. created, если не NULL, показывает факт создания даже при последующей ошибке sync. */
|
||||
int mf_disk_mkdir(struct mf_disk_root* root, const char* path, int* created);
|
||||
/* Удалить файл либо пустой каталог. Ошибка sync на POSIX возможна уже после удаления. */
|
||||
int mf_disk_remove(struct mf_disk_root* root, const char* path, int directory);
|
||||
/* Заменяющий rename: запрет замены при обычном RENAME проверяет storage. На POSIX sync обоих родителей;
|
||||
* ошибка sync не означает откат уже выполненного rename. */
|
||||
int mf_disk_rename(struct mf_disk_root* root, const char* from, const char* to);
|
||||
/* name/info заимствованы на время callback; 0 — продолжить, >0 — успешная ранняя остановка, <0 — -mf_status. */
|
||||
typedef int (*mf_disk_entry_fn)(void* arg, const char* name, const struct mf_disk_info* info);
|
||||
/* Перечислить записи в порядке файловой системы, без '.'/'..'. Пустой path означает корень. */
|
||||
int mf_disk_list(struct mf_disk_root* root, const char* path, mf_disk_entry_fn cb, void* arg);
|
||||
/* Точный диапазон: 0 байт допустимо, короткий read — ошибка. Caller гарантирует offset+size <= INT64_MAX. */
|
||||
int mf_disk_read(int fd, uint64_t offset, void* data, size_t size);
|
||||
int mf_disk_write(int fd, uint64_t offset, const void* data, size_t size);
|
||||
/* Изменить длину (size<=INT64_MAX), синхронизировать содержимое либо закрыть fd; каждый вызов независим. */
|
||||
int mf_disk_resize(int fd, uint64_t size);
|
||||
int mf_disk_sync(int fd);
|
||||
int mf_disk_close(int fd);
|
||||
/* Локальный source (create=0) либо эксклюзивный read/write temp (create!=0), без усечения.
|
||||
* Тип проверяет caller через info; POSIX O_NONBLOCK позволяет отвергнуть FIFO до блокирующего чтения. */
|
||||
int mf_disk_local_open(const char* path, int create, int* fd);
|
||||
/* Заменить local назначение: POSIX rename без sync каталога; Windows MOVEFILE_WRITE_THROUGH. */
|
||||
int mf_disk_local_publish(const char* from, const char* to);
|
||||
/* Удалить собственный local temp; отсутствие самого файла допустимо. Владение проверяет caller. */
|
||||
int mf_disk_local_remove(const char* path);
|
||||
/* SHA256 ровно size байт от нуля, включая пустой файл; ошибка делает hash непригодным. fd остаётся у caller. */
|
||||
int mf_disk_hash(int fd, uint64_t size, uint8_t hash[32]);
|
||||
#endif
|
||||
Reference in new issue
Block a user