mirror of
https://github.com/nginx/nginx.git
synced 2025-01-10 03:58:28 +08:00
b63da701e5
This will result in alphabetical sorting of included files if the "include" directive with wildcards is used. Note that the behaviour is now different from that on Windows, where alphabetical sorting is not guaranteed for FindFirsFile()/FindNextFile() (used to be alphabetical on NTFS, but not on FAT). Approved by Igor Sysoev, prodded by many.
565 lines
11 KiB
C
565 lines
11 KiB
C
|
|
/*
|
|
* Copyright (C) Igor Sysoev
|
|
* Copyright (C) Nginx, Inc.
|
|
*/
|
|
|
|
|
|
#include <ngx_config.h>
|
|
#include <ngx_core.h>
|
|
|
|
|
|
#if (NGX_HAVE_FILE_AIO)
|
|
|
|
ngx_uint_t ngx_file_aio = 1;
|
|
|
|
#endif
|
|
|
|
|
|
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() \"%s\" failed", 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() \"%s\" failed", file->name.data);
|
|
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() \"%s\" failed", file->name.data);
|
|
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, written;
|
|
|
|
ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0,
|
|
"write: %d, %p, %uz, %O", file->fd, buf, size, offset);
|
|
|
|
written = 0;
|
|
|
|
#if (NGX_HAVE_PWRITE)
|
|
|
|
for ( ;; ) {
|
|
n = pwrite(file->fd, buf + written, size, offset);
|
|
|
|
if (n == -1) {
|
|
ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
|
|
"pwrite() \"%s\" failed", file->name.data);
|
|
return NGX_ERROR;
|
|
}
|
|
|
|
file->offset += n;
|
|
written += n;
|
|
|
|
if ((size_t) n == size) {
|
|
return written;
|
|
}
|
|
|
|
offset += n;
|
|
size -= n;
|
|
}
|
|
|
|
#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() \"%s\" failed", file->name.data);
|
|
return NGX_ERROR;
|
|
}
|
|
|
|
file->sys_offset = offset;
|
|
}
|
|
|
|
for ( ;; ) {
|
|
n = write(file->fd, buf + written, size);
|
|
|
|
if (n == -1) {
|
|
ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
|
|
"write() \"%s\" failed", file->name.data);
|
|
return NGX_ERROR;
|
|
}
|
|
|
|
file->offset += n;
|
|
written += n;
|
|
|
|
if ((size_t) n == size) {
|
|
return written;
|
|
}
|
|
|
|
size -= n;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
ngx_fd_t
|
|
ngx_open_tempfile(u_char *name, ngx_uint_t persistent, ngx_uint_t access)
|
|
{
|
|
ngx_fd_t fd;
|
|
|
|
fd = open((const char *) name, O_CREAT|O_EXCL|O_RDWR,
|
|
access ? access : 0600);
|
|
|
|
if (fd != -1 && !persistent) {
|
|
(void) 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 total, 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);
|
|
}
|
|
|
|
total = 0;
|
|
|
|
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;
|
|
|
|
n = ngx_write_file(file, (u_char *) iov[0].iov_base,
|
|
iov[0].iov_len, offset);
|
|
|
|
if (n == NGX_ERROR) {
|
|
return n;
|
|
}
|
|
|
|
return total + n;
|
|
}
|
|
|
|
if (file->sys_offset != offset) {
|
|
if (lseek(file->fd, offset, SEEK_SET) == -1) {
|
|
ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno,
|
|
"lseek() \"%s\" failed", file->name.data);
|
|
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() \"%s\" failed", file->name.data);
|
|
return NGX_ERROR;
|
|
}
|
|
|
|
if ((size_t) n != size) {
|
|
ngx_log_error(NGX_LOG_CRIT, file->log, 0,
|
|
"writev() \"%s\" has written only %z of %uz",
|
|
file->name.data, n, size);
|
|
return NGX_ERROR;
|
|
}
|
|
|
|
ngx_log_debug2(NGX_LOG_DEBUG_CORE, file->log, 0,
|
|
"writev: %d, %z", file->fd, n);
|
|
|
|
file->sys_offset += n;
|
|
file->offset += n;
|
|
offset += n;
|
|
total += n;
|
|
|
|
} while (cl);
|
|
|
|
return total;
|
|
}
|
|
|
|
|
|
ngx_int_t
|
|
ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s)
|
|
{
|
|
struct timeval tv[2];
|
|
|
|
tv[0].tv_sec = ngx_time();
|
|
tv[0].tv_usec = 0;
|
|
tv[1].tv_sec = s;
|
|
tv[1].tv_usec = 0;
|
|
|
|
if (utimes((char *) name, tv) != -1) {
|
|
return NGX_OK;
|
|
}
|
|
|
|
return NGX_ERROR;
|
|
}
|
|
|
|
|
|
ngx_int_t
|
|
ngx_create_file_mapping(ngx_file_mapping_t *fm)
|
|
{
|
|
fm->fd = ngx_open_file(fm->name, NGX_FILE_RDWR, NGX_FILE_TRUNCATE,
|
|
NGX_FILE_DEFAULT_ACCESS);
|
|
if (fm->fd == NGX_INVALID_FILE) {
|
|
ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
|
|
ngx_open_file_n " \"%s\" failed", fm->name);
|
|
return NGX_ERROR;
|
|
}
|
|
|
|
if (ftruncate(fm->fd, fm->size) == -1) {
|
|
ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
|
|
"ftruncate() \"%s\" failed", fm->name);
|
|
goto failed;
|
|
}
|
|
|
|
fm->addr = mmap(NULL, fm->size, PROT_READ|PROT_WRITE, MAP_SHARED,
|
|
fm->fd, 0);
|
|
if (fm->addr != MAP_FAILED) {
|
|
return NGX_OK;
|
|
}
|
|
|
|
ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
|
|
"mmap(%uz) \"%s\" failed", fm->size, fm->name);
|
|
|
|
failed:
|
|
|
|
if (ngx_close_file(fm->fd) == NGX_FILE_ERROR) {
|
|
ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno,
|
|
ngx_close_file_n " \"%s\" failed", fm->name);
|
|
}
|
|
|
|
return NGX_ERROR;
|
|
}
|
|
|
|
|
|
void
|
|
ngx_close_file_mapping(ngx_file_mapping_t *fm)
|
|
{
|
|
if (munmap(fm->addr, fm->size) == -1) {
|
|
ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno,
|
|
"munmap(%uz) \"%s\" failed", fm->size, fm->name);
|
|
}
|
|
|
|
if (ngx_close_file(fm->fd) == NGX_FILE_ERROR) {
|
|
ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno,
|
|
ngx_close_file_n " \"%s\" failed", fm->name);
|
|
}
|
|
}
|
|
|
|
|
|
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_read_dir(ngx_dir_t *dir)
|
|
{
|
|
dir->de = readdir(dir->dir);
|
|
|
|
if (dir->de) {
|
|
#if (NGX_HAVE_D_TYPE)
|
|
dir->type = dir->de->d_type;
|
|
#else
|
|
dir->type = 0;
|
|
#endif
|
|
return NGX_OK;
|
|
}
|
|
|
|
return NGX_ERROR;
|
|
}
|
|
|
|
|
|
ngx_int_t
|
|
ngx_open_glob(ngx_glob_t *gl)
|
|
{
|
|
int n;
|
|
|
|
n = glob((char *) gl->pattern, 0, NULL, &gl->pglob);
|
|
|
|
if (n == 0) {
|
|
return NGX_OK;
|
|
}
|
|
|
|
#ifdef GLOB_NOMATCH
|
|
|
|
if (n == GLOB_NOMATCH && gl->test) {
|
|
return NGX_OK;
|
|
}
|
|
|
|
#endif
|
|
|
|
return NGX_ERROR;
|
|
}
|
|
|
|
|
|
ngx_int_t
|
|
ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name)
|
|
{
|
|
size_t count;
|
|
|
|
#ifdef GLOB_NOMATCH
|
|
count = (size_t) gl->pglob.gl_pathc;
|
|
#else
|
|
count = (size_t) gl->pglob.gl_matchc;
|
|
#endif
|
|
|
|
if (gl->n < count) {
|
|
|
|
name->len = (size_t) ngx_strlen(gl->pglob.gl_pathv[gl->n]);
|
|
name->data = (u_char *) gl->pglob.gl_pathv[gl->n];
|
|
gl->n++;
|
|
|
|
return NGX_OK;
|
|
}
|
|
|
|
return NGX_DONE;
|
|
}
|
|
|
|
|
|
void
|
|
ngx_close_glob(ngx_glob_t *gl)
|
|
{
|
|
globfree(&gl->pglob);
|
|
}
|
|
|
|
|
|
ngx_err_t
|
|
ngx_trylock_fd(ngx_fd_t fd)
|
|
{
|
|
struct flock fl;
|
|
|
|
ngx_memzero(&fl, sizeof(struct flock));
|
|
fl.l_type = F_WRLCK;
|
|
fl.l_whence = SEEK_SET;
|
|
|
|
if (fcntl(fd, F_SETLK, &fl) == -1) {
|
|
return ngx_errno;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
ngx_err_t
|
|
ngx_lock_fd(ngx_fd_t fd)
|
|
{
|
|
struct flock fl;
|
|
|
|
ngx_memzero(&fl, sizeof(struct flock));
|
|
fl.l_type = F_WRLCK;
|
|
fl.l_whence = SEEK_SET;
|
|
|
|
if (fcntl(fd, F_SETLKW, &fl) == -1) {
|
|
return ngx_errno;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
ngx_err_t
|
|
ngx_unlock_fd(ngx_fd_t fd)
|
|
{
|
|
struct flock fl;
|
|
|
|
ngx_memzero(&fl, sizeof(struct flock));
|
|
fl.l_type = F_UNLCK;
|
|
fl.l_whence = SEEK_SET;
|
|
|
|
if (fcntl(fd, F_SETLK, &fl) == -1) {
|
|
return ngx_errno;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#if (NGX_HAVE_POSIX_FADVISE) && !(NGX_HAVE_F_READAHEAD)
|
|
|
|
ngx_int_t
|
|
ngx_read_ahead(ngx_fd_t fd, size_t n)
|
|
{
|
|
int err;
|
|
|
|
err = posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
|
|
|
|
if (err == 0) {
|
|
return 0;
|
|
}
|
|
|
|
ngx_set_errno(err);
|
|
return NGX_FILE_ERROR;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#if (NGX_HAVE_O_DIRECT)
|
|
|
|
ngx_int_t
|
|
ngx_directio_on(ngx_fd_t fd)
|
|
{
|
|
int flags;
|
|
|
|
flags = fcntl(fd, F_GETFL);
|
|
|
|
if (flags == -1) {
|
|
return NGX_FILE_ERROR;
|
|
}
|
|
|
|
return fcntl(fd, F_SETFL, flags | O_DIRECT);
|
|
}
|
|
|
|
|
|
ngx_int_t
|
|
ngx_directio_off(ngx_fd_t fd)
|
|
{
|
|
int flags;
|
|
|
|
flags = fcntl(fd, F_GETFL);
|
|
|
|
if (flags == -1) {
|
|
return NGX_FILE_ERROR;
|
|
}
|
|
|
|
return fcntl(fd, F_SETFL, flags & ~O_DIRECT);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#if (NGX_HAVE_STATFS)
|
|
|
|
size_t
|
|
ngx_fs_bsize(u_char *name)
|
|
{
|
|
struct statfs fs;
|
|
|
|
if (statfs((char *) name, &fs) == -1) {
|
|
return 512;
|
|
}
|
|
|
|
if ((fs.f_bsize % 512) != 0) {
|
|
return 512;
|
|
}
|
|
|
|
return (size_t) fs.f_bsize;
|
|
}
|
|
|
|
#elif (NGX_HAVE_STATVFS)
|
|
|
|
size_t
|
|
ngx_fs_bsize(u_char *name)
|
|
{
|
|
struct statvfs fs;
|
|
|
|
if (statvfs((char *) name, &fs) == -1) {
|
|
return 512;
|
|
}
|
|
|
|
if ((fs.f_frsize % 512) != 0) {
|
|
return 512;
|
|
}
|
|
|
|
return (size_t) fs.f_frsize;
|
|
}
|
|
|
|
#else
|
|
|
|
size_t
|
|
ngx_fs_bsize(u_char *name)
|
|
{
|
|
return 512;
|
|
}
|
|
|
|
#endif
|