Files
nginx-unit/src/nxt_file.h
Andrew Clayton 34b3a812b1 Add nxt_file_chown()
This wraps chown(2) but takes the user/owner and group as strings.

It's a little long winded as it uses the thread safe versions of
getpwnam()/getgrname() which require a little more work.

This function will be used by the following commit that allows to set
the permissions of the Unix domain control socket.

We need to cast uid & gid to long in the call to nxt_thread_log_alert()
to appease clang-ast as it's adamant that uid/gid are unsigned ints, but
chown(2) takes -1 for these values to indicate don't change this item,
and it'd be nice to show them in the error message.

Note that getpwnam()/getgrname() don't define "not found" as an error as
per their man page

  The  formulation given above under "RETURN VALUE" is from POSIX.1-2001.
  It does not call "not found" an error, and hence does not specify  what
  value errno might have in this situation.  But that makes it impossible
  to  recognize  errors.   One  might argue that according to POSIX errno
  should be left unchanged if an entry is not found.  Experiments on var‐
  ious UNIX-like systems show that lots of different values occur in this
  situation: 0, ENOENT, EBADF, ESRCH, EWOULDBLOCK,  EPERM,  and  probably
  others.

Thus if we log an error from these functions we can end up with the
slightly humorous error message

  2024/02/12 15:15:12 [alert] 99404#99404 getpwnam_r("noddy", ...) failed (0: Success) (User not found) while creating listening socket on unix:/opt/unit/control.unit.sock

Reviewed-by: Zhidao Hong <z.hong@f5.com>
Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
2024-02-19 12:59:29 +00:00

220 lines
6.3 KiB
C

/*
* Copyright (C) Igor Sysoev
* Copyright (C) NGINX, Inc.
*/
#ifndef _NXT_UNIX_FILE_H_INCLUDED_
#define _NXT_UNIX_FILE_H_INCLUDED_
typedef int nxt_fd_t;
#define NXT_FILE_INVALID -1
typedef nxt_uint_t nxt_file_access_t;
typedef struct stat nxt_file_info_t;
#define NXT_FILE_SYSTEM_NAME_UTF8 1
typedef u_char nxt_file_name_t;
typedef struct {
size_t len;
nxt_file_name_t *start;
} nxt_file_name_str_t;
#define nxt_file_name_str_set(file_name, mem_pool, name) \
((file_name) = (nxt_file_name_t *) (name), NXT_OK)
#define nxt_file_name_alloc(mem_pool, len) \
nxt_mp_nget(mem_pool, len)
#define nxt_file_name_copy(dst, src, len) \
nxt_cpymem(dst, src, len)
#define nxt_file_name_add(dst, src, len) \
nxt_cpymem(dst, src, len)
#if (NXT_HAVE_CASELESS_FILESYSTEM)
/* MacOSX, Cygwin. */
#define nxt_file_name_eq(fn1, fn2) \
(nxt_strcasecmp(fn1, fn2) == 0)
#else
#define nxt_file_name_eq(fn1, fn2) \
(nxt_strcmp(fn1, fn2) == 0)
#endif
#define nxt_file_name_is_absolute(name) \
(name[0] == '/')
#define NXT_MAX_PATH_LEN MAXPATHLEN
typedef enum {
NXT_FILE_UNKNOWN = 0,
NXT_FILE_REGULAR,
NXT_FILE_DIRECTORY,
} nxt_file_type_t;
typedef struct {
nxt_file_name_t *name;
/* Both are int's. */
nxt_fd_t fd;
nxt_err_t error;
#define NXT_FILE_ACCESSED_LONG_AGO 0xFFFF
/*
* Number of seconds ago the file content was last
* read. The maximum value is about 18 hours.
*/
uint16_t accessed;
uint8_t type; /* nxt_file_type_t */
/*
* Log open() file error with given log level if it is non zero.
* Note that zero log level is NXT_LOG_ALERT.
*/
uint8_t log_level;
nxt_time_t mtime;
nxt_off_t size;
} nxt_file_t;
NXT_EXPORT nxt_int_t nxt_file_open(nxt_task_t *task, nxt_file_t *file,
nxt_uint_t mode, nxt_uint_t create, nxt_file_access_t access);
#if (NXT_HAVE_OPENAT2)
NXT_EXPORT nxt_int_t nxt_file_openat2(nxt_task_t *task, nxt_file_t *file,
nxt_uint_t mode, nxt_uint_t create, nxt_file_access_t access, nxt_fd_t dfd,
nxt_uint_t resolve);
#endif
/* The file open access modes. */
#define NXT_FILE_RDONLY O_RDONLY
#define NXT_FILE_WRONLY O_WRONLY
#define NXT_FILE_RDWR O_RDWR
#define NXT_FILE_APPEND (O_WRONLY | O_APPEND)
#if (NXT_HAVE_OPENAT2)
#if defined(O_DIRECTORY)
#define NXT_FILE_DIRECTORY O_DIRECTORY
#else
#define NXT_FILE_DIRECTORY 0
#endif
#if defined(O_SEARCH)
#define NXT_FILE_SEARCH (O_SEARCH|NXT_FILE_DIRECTORY)
#elif defined(O_EXEC)
#define NXT_FILE_SEARCH (O_EXEC|NXT_FILE_DIRECTORY)
#else
/*
* O_PATH is used in combination with O_RDONLY. The last one is ignored
* if O_PATH is used, but it allows Unit to not fail when it was built on
* modern system (i.e. glibc 2.14+) and run with a kernel older than 2.6.39.
* Then O_PATH is unknown to the kernel and ignored, while O_RDONLY is used.
*/
#define NXT_FILE_SEARCH (O_PATH|O_RDONLY|NXT_FILE_DIRECTORY)
#endif
#endif /* NXT_HAVE_OPENAT2 */
/* The file creation modes. */
#define NXT_FILE_CREATE_OR_OPEN O_CREAT
#define NXT_FILE_OPEN 0
#define NXT_FILE_TRUNCATE (O_CREAT | O_TRUNC)
/* The file access rights. */
#define NXT_FILE_DEFAULT_ACCESS 0644
#define NXT_FILE_OWNER_ACCESS 0600
NXT_EXPORT void nxt_file_close(nxt_task_t *task, nxt_file_t *file);
NXT_EXPORT ssize_t nxt_file_write(nxt_file_t *file, const u_char *buf,
size_t size, nxt_off_t offset);
NXT_EXPORT ssize_t nxt_file_read(nxt_file_t *file, u_char *buf, size_t size,
nxt_off_t offset);
NXT_EXPORT void nxt_file_read_ahead(nxt_file_t *file, nxt_off_t offset,
size_t size);
NXT_EXPORT nxt_int_t nxt_file_info(nxt_file_t *file, nxt_file_info_t *fi);
#define nxt_is_dir(fi) \
(S_ISDIR((fi)->st_mode))
#define nxt_is_file(fi) \
(S_ISREG((fi)->st_mode))
#define nxt_file_size(fi) \
(fi)->st_size
#define nxt_file_mtime(fi) \
(fi)->st_mtime
NXT_EXPORT nxt_int_t nxt_file_delete(nxt_file_name_t *name);
NXT_EXPORT nxt_int_t nxt_file_set_access(nxt_file_name_t *name,
nxt_file_access_t access);
NXT_EXPORT nxt_int_t nxt_file_chown(nxt_file_name_t *name, const char *owner,
const char *group);
NXT_EXPORT nxt_int_t nxt_file_rename(nxt_file_name_t *old_name,
nxt_file_name_t *new_name);
NXT_EXPORT nxt_int_t nxt_fd_nonblocking(nxt_task_t *task, nxt_fd_t fd);
NXT_EXPORT nxt_int_t nxt_fd_blocking(nxt_task_t *task, nxt_fd_t fd);
NXT_EXPORT ssize_t nxt_fd_write(nxt_fd_t fd, u_char *buf, size_t size);
NXT_EXPORT ssize_t nxt_fd_read(nxt_fd_t fd, u_char *buf, size_t size);
NXT_EXPORT void nxt_fd_close(nxt_fd_t fd);
NXT_EXPORT FILE *nxt_file_fopen(nxt_task_t *task, const char *pathname,
const char *mode);
NXT_EXPORT void nxt_file_fclose(nxt_task_t *task, FILE *fp);
NXT_EXPORT nxt_int_t nxt_file_redirect(nxt_file_t *file, nxt_fd_t fd);
NXT_EXPORT nxt_int_t nxt_file_stdout(nxt_file_t *file);
NXT_EXPORT nxt_int_t nxt_file_stderr(nxt_file_t *file);
NXT_EXPORT nxt_int_t nxt_stderr_start(void);
#define nxt_stdout STDOUT_FILENO
#define nxt_stderr STDERR_FILENO
#define nxt_write_console(fd, buf, size) \
write(fd, buf, size)
#define nxt_write_syslog(priority, message) \
syslog(priority, "%s", message)
NXT_EXPORT nxt_int_t nxt_pipe_create(nxt_task_t *task, nxt_fd_t *pp,
nxt_bool_t nbread, nxt_bool_t nbwrite);
NXT_EXPORT void nxt_pipe_close(nxt_task_t *task, nxt_fd_t *pp);
NXT_EXPORT size_t nxt_dir_current(char *buf, size_t len);
#endif /* _NXT_UNIX_FILE_H_INCLUDED_ */