/*****************************************************************************
* storage.c
*****************************************************************************
* Copyright (C) 2023 VLC authors and VideoLAN
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <assert.h>
#include <fcntl.h>
#include <unistd.h> /* close() */
#include <vlc_common.h>
#include <vlc_block.h>
#include <vlc_fs.h>
#include "hls.h"
#include "storage.h"
struct storage_priv
{
hls_storage_t storage;
void (*destroy)(struct storage_priv *storage);
size_t size;
union
{
struct
{
block_t *content;
} mem;
struct
{
char *path;
} fs;
};
};
static void mem_storage_Destroy(struct storage_priv *priv)
{
block_ChainRelease(priv->mem.content);
free(priv);
}
static ssize_t mem_storage_GetContent(const hls_storage_t *storage,
uint8_t **dest)
{
const struct storage_priv *priv =
container_of(storage, struct storage_priv, storage);
*dest = malloc(priv->size);
if (unlikely(*dest == NULL))
return -1;
uint8_t *cursor = *dest;
for (const block_t *it = priv->mem.content; it != NULL; it = it->p_next)
{
memcpy(cursor, it->p_buffer, it->i_buffer);
cursor += it->i_buffer;
}
return priv->size;
}
static int mem_storage_FromBlock(block_t *content, hls_storage_t **out)
{
struct storage_priv *priv = malloc(sizeof(*priv));
if (unlikely(priv == NULL))
return -ENOMEM;
priv->storage.get_content = mem_storage_GetContent;
priv->destroy = mem_storage_Destroy;
priv->mem.content = content;
block_ChainProperties(content, NULL, &priv->size, NULL);
*out = &priv->storage;
return 0;
}
static int mem_storage_FromBytes(void *bytes, size_t size, hls_storage_t **out)
{
struct storage_priv *priv = malloc(sizeof(*priv));
if (unlikely(priv == NULL))
return -ENOMEM;
block_t *content = block_heap_Alloc(bytes, size);
if (unlikely(content == NULL))
{
free(priv);
return -ENOMEM;
}
priv->storage.get_content = mem_storage_GetContent;
priv->destroy = mem_storage_Destroy;
priv->size = size;
priv->mem.content = content;
*out = &priv->storage;
return 0;
}
static ssize_t fs_storage_Read(int fd, uint8_t buf[], size_t len)
{
size_t total = 0;
while (total < len)
{
const ssize_t n = read(fd, buf + total, len - total);
if (n == -1)
{
if (errno == EINTR || errno == EAGAIN)
continue;
return -1;
}
else if (n == 0)
break;
total += n;
}
return total;
}
static ssize_t fs_storage_GetContent(const hls_storage_t *storage,
uint8_t **dest)
{
const struct storage_priv *priv =
container_of(storage, struct storage_priv, storage);
const int fd = vlc_open(priv->fs.path, O_RDONLY);
if (fd == -1)
return -1;
*dest = malloc(priv->size);
if (unlikely(*dest == NULL))
goto err;
const ssize_t read = fs_storage_Read(fd, *dest, priv->size);
if (read == -1)
goto err;
close(fd);
return read;
err:
free(*dest);
close(fd);
return -1;
}
static int fs_storage_Write(int fd, const uint8_t *data, size_t len)
{
size_t written = 0;
while (written < len)
{
const ssize_t n = vlc_write(fd, data + written, len - written);
if (n == -1)
{
if (errno == EINTR || errno == EAGAIN)
continue;
return -errno;
}
written += n;
}
return 0;
}
static void fs_storage_Destroy(struct storage_priv *priv)
{
free(priv->fs.path);
free(priv);
}
static inline char *fs_storage_CreatePath(const char *outdir,
const char *storage_name)
{
char *ret;
if (asprintf(&ret, "%s/%s", outdir, storage_name) == -1)
return NULL;
return ret;
}
static int
fs_storage_FromBlock(block_t *content,
const struct hls_storage_config *config,
const struct hls_config *hls_config,
hls_storage_t **out)
{
int ret;
struct storage_priv *priv = malloc(sizeof(*priv));
if (unlikely(priv == NULL))
{
block_ChainRelease(content);
return -ENOMEM;
}
priv->fs.path = fs_storage_CreatePath(hls_config->outdir, config->name);
if (unlikely(priv->fs.path == NULL))
{
ret = -ENOMEM;
goto err;
}
const int fd = vlc_open(priv->fs.path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd == -1)
{
ret = -errno;
goto err;
}
size_t size = 0;
for (const block_t *it = content; it != NULL; it = it->p_next)
{
ret = fs_storage_Write(fd, it->p_buffer, it->i_buffer);
if (ret != 0)
{
close(fd);
goto err;
}
size += it->i_buffer;
}
close(fd);
block_ChainRelease(content);
priv->storage.get_content = fs_storage_GetContent;
priv->size = size;
priv->destroy = fs_storage_Destroy;
*out = &priv->storage;
return 0;
err:
block_ChainRelease(content);
free(priv->fs.path);
free(priv);
return ret;
}
static int
fs_storage_FromBytes(void *bytes,
size_t size,
const struct hls_storage_config *config,
const struct hls_config *hls_config,
hls_storage_t **out)
{
int ret;
struct storage_priv *priv = malloc(sizeof(*priv));
if (unlikely(priv == NULL))
{
free(bytes);
return -ENOMEM;
}
priv->fs.path = fs_storage_CreatePath(hls_config->outdir, config->name);
if (unlikely(priv->fs.path == NULL))
{
ret = -ENOMEM;
goto err;
}
const int fd = vlc_open(priv->fs.path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd == -1)
{
ret = -errno;
goto err;
}
ret = fs_storage_Write(fd, bytes, size);
close(fd);
if (unlikely(ret != 0))
goto err;
priv->storage.get_content = fs_storage_GetContent;
priv->size = size;
priv->destroy = fs_storage_Destroy;
free(bytes);
*out = &priv->storage;
return 0;
err:
free(bytes);
free(priv->fs.path);
free(priv);
return ret;
}
int hls_storage_FromBlocks(block_t *content,
const struct hls_storage_config *config,
const struct hls_config *hls_config,
hls_storage_t **out)
{
int ret;
if (hls_config_IsMemStorageEnabled(hls_config))
ret = mem_storage_FromBlock(content, out);
else
ret = fs_storage_FromBlock(content, config, hls_config, out);
if (ret == 0)
(*out)->mime = config->mime;
return ret;
}
int hls_storage_FromBytes(void *data,
size_t size,
const struct hls_storage_config *config,
const struct hls_config *hls_config,
hls_storage_t **out)
{
int ret;
if (hls_config_IsMemStorageEnabled(hls_config))
ret = mem_storage_FromBytes(data, size, out);
else
ret = fs_storage_FromBytes(data, size, config, hls_config, out);
if (ret == 0)
(*out)->mime = config->mime;
return ret;
}
size_t hls_storage_GetSize(const hls_storage_t *storage)
{
const struct storage_priv *priv =
container_of(storage, struct storage_priv, storage);
return priv->size;
}
void hls_storage_Destroy(hls_storage_t *storage)
{
struct storage_priv *priv =
container_of(storage, struct storage_priv, storage);
priv->destroy(priv);
}
¤ Dauer der Verarbeitung: 0.2 Sekunden
(vorverarbeitet am 2026-11-04)
¤
*© Formatika GbR, Deutschland
|
|