1 /*@ S-nail - a mail user agent derived from Berkeley Mail. 2 *@ File- and pipe streams, as well as temporary file creation. 3 * 4 * Copyright (c) 2012 - 2020 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>. 5 * SPDX-License-Identifier: ISC 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 #ifndef mx_FILE_STREAMS_H 20 #define mx_FILE_STREAMS_H 21 22 #include <mx/nail.h> 23 24 #define mx_HEADER 25 #include <su/code-in.h> 26 27 struct mx_fs_tmp_ctx; 28 29 enum mx_fs_oflags{ 30 mx_FS_O_RDONLY = 1u<<0, 31 mx_FS_O_WRONLY = 1u<<1, 32 mx_FS_O_RDWR = 1u<<2, 33 mx_FS_O_APPEND = 1u<<3, 34 mx_FS_O_CREATE = 1u<<4, 35 mx_FS_O_TRUNC = 1u<<5, 36 mx_FS_O_EXCL = 1u<<6, 37 mx_FS_O_UNLINK = 1u<<7, /* Only for tmp_open(): unlink(2) after creation */ 38 /* Register file in our file table, causing its close when we jump away 39 * and/or the mainloop ticks otherwise, shall it still exist */ 40 mx_FS_O_REGISTER = 1u<<8, 41 /* tmp_open(): unlink at unregistration: O_REGISTER!, !O_UNLINK */ 42 mx_FS_O_REGISTER_UNLINK = 1u<<9, 43 /* tmp_open(): do not release signals/unlink: !O_UNLINK! */ 44 mx_FS_O_HOLDSIGS = 1u<<10, 45 /* The name hint given to tmp_open() must be a mandatory member of the 46 * result string as a whole. Also, the random characters are to be placed 47 * before the name hint, not after it */ 48 mx_FS_O_SUFFIX = 1u<<11 49 }; 50 51 enum mx_fs_open_state{ /* TODO add mx_fs_open_mode, too */ 52 /* Lower bits are in fact enum protocol! */ 53 mx_FS_OPEN_STATE_NONE = 0, 54 mx_FS_OPEN_STATE_EXISTS = 1u<<5 55 }; 56 MCTA(n_PROTO_MASK < mx_FS_OPEN_STATE_EXISTS, "Bit carrier ranges overlap") 57 58 /* Note: actually publicly visible part of larger internal struct */ 59 struct mx_fs_tmp_ctx{ 60 char const *fstc_filename; 61 }; 62 63 /* */ 64 #ifdef O_CLOEXEC 65 # define mx_FS_FD_CLOEXEC_SET(FD) (1) 66 #else 67 # define mx_FS_FD_CLOEXEC_SET(FD) mx_fs_fd_cloexec_set(FD) 68 #endif 69 70 /* oflags implied: cloexec,O_REGISTER. 71 * {"r", O_RDONLY}, 72 * {"w", O_WRONLY | O_CREAT | n_O_NOXY_BITS | O_TRUNC}, 73 * {"wx", O_WRONLY | O_CREAT | O_EXCL}, 74 * {"a", O_WRONLY | O_APPEND | O_CREAT | mx_O_NOXY_BITS}, 75 * {"a+", O_RDWR | O_APPEND | O_CREAT | mx_O_NOXY_BITS}, 76 * {"r+", O_RDWR}, 77 * {"w+", O_RDWR | O_CREAT | mx_O_NOXY_BITS | O_TRUNC}, 78 * {"W+", O_RDWR | O_CREAT | O_EXCL} 79 * Prepend (!) an ampersand & ("background") to _not_ include O_REGISTER, 80 * in which case the returned file must be closed with normal fclose(3). 81 * mx_O_NOXY_BITS come from mx-config.h */ 82 EXPORT FILE *mx_fs_open(char const *file, char const *oflags); 83 84 /* TODO: Should be Mailbox::create_from_url(URL::from_string(DATA))! 85 * Open file according to oflags (& prefix disallowed)m and register it 86 * (leading ampersand & to suppress this is disallowed). 87 * Handles compressed files, maildir etc. 88 * If fs_or_nil is given it will be filled accordingly */ 89 EXPORT FILE *mx_fs_open_any(char const *file, char const *oflags, 90 enum mx_fs_open_state *fs_or_nil); 91 92 /* Create a temporary file in $TMPDIR, use namehint for its name (prefix 93 * unless O_SUFFIX is set in the fs_oflags oflags and *namehint!=NUL), 94 * and return a stdio FILE pointer with access oflags. 95 * *fstcp_or_nil may only be non-NIL under certain asserted conditions: 96 * - if O_REGISTER: it is fully filled in; whether the filename is actually 97 * useful depends on the chosen UNLINK mode. 98 * - Else if O_HOLDSIGS: filename filled in, tmp_release() is callable, 99 * - else O_UNLINK must not and O_REGISTER_UNLINK could be set (filename is 100 * filled in, tmp_release() is not callable. 101 * In the latter two cases autorec memory storage will be created (on success). 102 * One of O_WRONLY and O_RDWR must be set. Implied: 0600,cloexec */ 103 EXPORT FILE *mx_fs_tmp_open(char const *namehint, u32 oflags, 104 struct mx_fs_tmp_ctx **fstcp_or_nil); 105 106 /* If (O_REGISTER|)O_HOLDSIGS and a context pointer was set when calling 107 * tmp_open(), then sigs_all_*() had not been released yet. 108 * Call this to first unlink(2) the temporary file and then release signals */ 109 EXPORT void mx_fs_tmp_release(struct mx_fs_tmp_ctx *fstcp); 110 111 /* oflags implied: cloexec (unless nocloexec), O_REGISTER */ 112 EXPORT FILE *mx_fs_fd_open(sz fd, char const *oflags, boole nocloexec); 113 114 /* */ 115 EXPORT boole mx_fs_fd_cloexec_set(sz fd); 116 117 /* Close and unregister a FILE* opened with any of fs_open(), fs_open_any(), 118 * fs_tmp_open() (with O_REGISTER) or fd_open() */ 119 EXPORT boole mx_fs_close(FILE *fp); 120 121 /* Create a pair of file descriptors piped together, and ensure the CLOEXEC 122 * bit is set in both; no registration is performed */ 123 EXPORT boole mx_fs_pipe_cloexec(sz fd[2]); 124 125 /* Create a process to be communicated with via a pipe. 126 * mode can be r, W (newfd1 must be set, maybe to CHILD_FD_PASS or 127 * CHILD_FD_NULL) or w (newfd1 is implicitly CHILD_FD_PASS). 128 * In CHILD_FD_PASS cases pipe_close() must be called with waiting enabled, 129 * which is asserted! Note that child.h is NOT included. 130 * env_addon may be NIL, otherwise it is expected to be a NIL terminated 131 * array of "K=V" strings to be placed into the children's environment 132 * TODO v15 hack: If cmd==(char*)-1 then shell is indeed expected to be a PTF 133 * TODO v15 hack: :P that will be called from within the child process */ 134 EXPORT FILE *mx_fs_pipe_open(char const *cmd, char const *mode, 135 char const *shell, char const **env_addon, int newfd1); 136 137 /* Takes a FILE* returned by pipe_open, and returns <0 if no process can be 138 * found, 0 on success, and an errno on kill(2) failure */ 139 EXPORT s32 mx_fs_pipe_signal(FILE *fp, s32 sig); 140 141 /* Close fp, which has been opened by fs_pipe_open(). 142 * With dowait returns true only upon successful program exit. 143 * In conjunction with CHILD_FD_PASS dowait is mandatory. */ 144 EXPORT boole mx_fs_pipe_close(FILE *fp, boole dowait); 145 146 /* Flush the given or (if NIL) all streams */ 147 EXPORT boole mx_fs_flush(FILE *fp); 148 149 /* Close all files and pipes created without O_NOREGISTER */ 150 EXPORT void mx_fs_close_all(void); 151 152 /* XXX Temporary (pre v15 I/O) line buffer "pool". 153 * (Possibly) Get a line buffer, and release one to the pool, respectively. 154 * _book() returns false for integer overflow, or if reallocation survives 155 * su_STATE_ERR_NONMEM. 156 * The last is driven by the mainloop to perform cleanups */ 157 EXPORT void mx_fs_linepool_aquire(char **dp, uz *dsp); 158 EXPORT void mx_fs_linepool_release(char *dp, uz ds); 159 EXPORT boole mx_fs_linepool_book(char **dp, uz *dsp, uz len, uz toadd 160 su_DBG_LOC_ARGS_DECL); 161 EXPORT void mx_fs_linepool_cleanup(boole completely); 162 163 #ifdef su_HAVE_DBG_LOC_ARGS 164 # define mx_fs_linepool_book(A,B,C,D) \ 165 mx_fs_linepool_book(A, B, C, D su_DBG_LOC_ARGS_INJ) 166 #endif 167 168 /* TODO The rest below is old-style (will vanish with I/O layer rewrite) */ 169 170 /* fgets() replacement to handle lines of arbitrary size and with embedded \0 171 * characters. 172 * line - line buffer. *line may be NIL. 173 * linesize - allocated size of line buffer. 174 * count - maximum characters to read. May be NIL. 175 * llen_or_nil - length_of_line(*line); set to 0 on entry if set. 176 * fp - input FILE. 177 * appendnl - always terminate line with \n, append if necessary. 178 * Manages the n_PS_READLINE_NL hack */ 179 EXPORT char *fgetline(char **line, uz *linesize, uz *count, uz *llen_or_nil, 180 FILE *fp, int appendnl su_DBG_LOC_ARGS_DECL); 181 #ifdef su_HAVE_DBG_LOC_ARGS 182 # define fgetline(A,B,C,D,E,F) \ 183 fgetline(A, B, C, D, E, F su_DBG_LOC_ARGS_INJ) 184 #endif 185 186 /* Read up a line from the specified input into the linebuffer. 187 * Return the number of characters read. Do not include the newline at EOL. 188 * n is the number of characters already read and present in *linebuf; it'll be 189 * treated as _the_ line if no more (successful) reads are possible. 190 * Manages the n_PS_READLINE_NL hack */ 191 EXPORT int readline_restart(FILE *ibuf, char **linebuf, uz *linesize, uz n 192 su_DBG_LOC_ARGS_DECL); 193 #ifdef su_HAVE_DBG_LOC_ARGS 194 # define readline_restart(A,B,C,D) \ 195 readline_restart(A, B, C, D su_DBG_LOC_ARGS_INJ) 196 #endif 197 198 /* Determine the size of the file possessed by the passed buffer */ 199 EXPORT off_t fsize(FILE *iob); 200 201 #include <su/code-ou.h> 202 #endif /* mx_FILE_STREAMS_H */ 203 /* s-it-mode */ 204