blob: b5a807bb6f8c885451e6d72eab14e4bbe1a9d48a [file] [log] [blame]
/*
* Copyright (C) Igor Sysoev
*/
#include <ngx_config.h>
#include <ngx_core.h>
ssize_t
ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
{
ssize_t n;
ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
"read: %d, %p, %uz, %O", file->fd, buf, size, offset);
#if (NGX_HAVE_PREAD)
n = pread(file->fd, buf, size, offset);
if (n == -1) {
ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
"pread() failed, file \"%s\"", file->name.data);
return NGX_ERROR;
}
#else
if (file->sys_offset != offset) {
if (lseek(file->fd, offset, SEEK_SET) == -1) {
ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "lseek() failed");
return NGX_ERROR;
}
file->sys_offset = offset;
}
n = read(file->fd, buf, size);
if (n == -1) {
ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "read() failed");
return NGX_ERROR;
}
file->sys_offset += n;
#endif
file->offset += n;
return n;
}
ssize_t
ngx_write_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
{
ssize_t n;
ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
"write: %d, %p, %uz, %O", file->fd, buf, size, offset);
#if (NGX_HAVE_PWRITE)
n = pwrite(file->fd, buf, size, offset);
if (n == -1) {
ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "pwrite() failed");
return NGX_ERROR;
}
if ((size_t) n != size) {
ngx_log_error(NGX_LOG_CRIT, file->log, 0,
"pwrite() has written only %z of %uz", n, size);
return NGX_ERROR;
}
#else
if (file->sys_offset != offset) {
if (lseek(file->fd, offset, SEEK_SET) == -1) {
ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "lseek() failed");
return NGX_ERROR;
}
file->sys_offset = offset;
}
n = write(file->fd, buf, size);
if (n == -1) {
ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, "write() failed");
return NGX_ERROR;
}
if ((size_t) n != size) {
ngx_log_error(NGX_LOG_CRIT, file->log, 0,
"write() has written only %z of %uz", n, size);
return NGX_ERROR;
}
file->sys_offset += n;
#endif
file->offset += n;
return n;
}
ngx_fd_t
ngx_open_tempfile(u_char *name, ngx_uint_t persistent)
{
ngx_fd_t fd;
fd = open((const char *) name, O_CREAT|O_EXCL|O_RDWR, 0600);
if (fd != -1 && !persistent) {
unlink((const char *) name);
}
return fd;
}
#define NGX_IOVS 8
ssize_t
ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, off_t offset,
ngx_pool_t *pool)
{
u_char *prev;
size_t size;
ssize_t n;
ngx_array_t vec;
struct iovec *iov, iovs[NGX_IOVS];
/* use pwrite() if there is the only buf in a chain */
if (cl->next == NULL) {
return ngx_write_file(file, cl->buf->pos,
(size_t) (cl->buf->last - cl->buf->pos),
offset);
}
vec.elts = iovs;
vec.size = sizeof(struct iovec);
vec.nalloc = NGX_IOVS;
vec.pool = pool;
do {
prev = NULL;
iov = NULL;
size = 0;
vec.nelts = 0;
/* create the iovec and coalesce the neighbouring bufs */
while (cl && vec.nelts < IOV_MAX) {
if (prev == cl->buf->pos) {
iov->iov_len += cl->buf->last - cl->buf->pos;
} else {
iov = ngx_array_push(&vec);
if (iov == NULL) {
return NGX_ERROR;
}
iov->iov_base = (void *) cl->buf->pos;
iov->iov_len = cl->buf->last - cl->buf->pos;
}
size += cl->buf->last - cl->buf->pos;
prev = cl->buf->last;
cl = cl->next;
}
/* use pwrite() if there is the only iovec buffer */
if (vec.nelts == 1) {
iov = vec.elts;
return ngx_write_file(file, (u_char *) iov[0].iov_base,
iov[0].iov_len, offset);
}
if (file->sys_offset != offset) {
if (lseek(file->fd, offset, SEEK_SET) == -1) {
ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
"lseek() failed");
return NGX_ERROR;
}
file->sys_offset = offset;
}
n = writev(file->fd, vec.elts, vec.nelts);
if (n == -1) {
ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
"writev() failed");
return NGX_ERROR;
}
if ((size_t) n != size) {
ngx_log_error(NGX_LOG_CRIT, file->log, 0,
"writev() has written only %z of %uz", n, size);
return NGX_ERROR;
}
file->sys_offset += n;
file->offset += n;
} while (cl);
return n;
}
ngx_int_t
ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir)
{
dir->dir = opendir((const char *) name->data);
if (dir->dir == NULL) {
return NGX_ERROR;
}
dir->valid_info = 0;
return NGX_OK;
}
ngx_int_t
ngx_lock_file(ngx_file_t *file)
{
ngx_err_t err;
struct flock fl;
fl.l_whence = SEEK_SET;
fl.l_len = 0;
fl.l_pid = 0;
fl.l_type = F_WRLCK;
fl.l_start = 0;
if (fcntl(file->fd, F_SETLK, &fl) == -1) {
err = ngx_errno;
if (err == NGX_EAGAIN) {
return NGX_BUSY;
}
ngx_log_error(NGX_LOG_ALERT, file->log, err,
"fcntl(%s, F_SETLK, F_WRLCK) failed", file->name.data);
return NGX_ERROR;
}
return NGX_OK;
}
ngx_int_t
ngx_unlock_file(ngx_file_t *file)
{
ngx_err_t err;
struct flock fl;
fl.l_whence = SEEK_SET;
fl.l_len = 0;
fl.l_pid = 0;
fl.l_type = F_UNLCK;
fl.l_start = 0;
if (fcntl(file->fd, F_SETLK, &fl) == -1) {
err = ngx_errno;
if (err == NGX_EAGAIN) {
return NGX_BUSY;
}
ngx_log_error(NGX_LOG_ALERT, file->log, err,
"fcntl(%s, F_SETLK, F_UNLCK) failed", file->name.data);
return NGX_ERROR;
}
return NGX_OK;
}