summaryrefslogtreecommitdiff
path: root/usr/src/lib/libc
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2020-03-27 11:29:00 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2020-03-27 11:29:00 +0000
commit6dcfbbc68f881fbf5c20d25817a0221dfb135170 (patch)
tree40307666f6d7711499061d8c4be75029a6d851e9 /usr/src/lib/libc
parentb0624b90ec9a0c04cca626925beee3ae403457ce (diff)
parentcd62a92d4a964bfe61d35ba2301b69e65e22a509 (diff)
downloadillumos-joyent-6dcfbbc68f881fbf5c20d25817a0221dfb135170.tar.gz
[illumos-gate merge]
commit cd62a92d4a964bfe61d35ba2301b69e65e22a509 7092 Want support for stdio memory streams 12360 fwrite can loop forever on zero byte write 12392 ftello64 doesn't handle ungetc() correctly when unbuffered commit 1470234269f4edea4cbf270cb2475e4988b788d5 12359 Want a means to set the umem mtbf at runtine commit 0ac311bae7f6f50d9ba506b52bd8860f2d68d4ce 12358 Need mbrtowc variant that indicates consumed zero bytes commit d726994754c938f91b6fd7e96b5cab3829615c58 12357 getc/putc_unlocked need to set orientation
Diffstat (limited to 'usr/src/lib/libc')
-rw-r--r--usr/src/lib/libc/amd64/Makefile4
-rw-r--r--usr/src/lib/libc/i386/Makefile.com4
-rw-r--r--usr/src/lib/libc/inc/file64.h27
-rw-r--r--usr/src/lib/libc/inc/libc.h8
-rw-r--r--usr/src/lib/libc/inc/mtlib.h6
-rw-r--r--usr/src/lib/libc/inc/stdiom.h62
-rw-r--r--usr/src/lib/libc/port/locale/big5.c10
-rw-r--r--usr/src/lib/libc/port/locale/euc.c42
-rw-r--r--usr/src/lib/libc/port/locale/fgetwc.c2
-rw-r--r--usr/src/lib/libc/port/locale/gb18030.c10
-rw-r--r--usr/src/lib/libc/port/locale/gb2312.c10
-rw-r--r--usr/src/lib/libc/port/locale/gbk.c10
-rw-r--r--usr/src/lib/libc/port/locale/lctype.h6
-rw-r--r--usr/src/lib/libc/port/locale/mblocal.h2
-rw-r--r--usr/src/lib/libc/port/locale/mbrtowc.c20
-rw-r--r--usr/src/lib/libc/port/locale/mbsnrtowcs.c8
-rw-r--r--usr/src/lib/libc/port/locale/mskanji.c10
-rw-r--r--usr/src/lib/libc/port/locale/none.c8
-rw-r--r--usr/src/lib/libc/port/locale/utf8.c27
-rw-r--r--usr/src/lib/libc/port/mapfile-vers7
-rw-r--r--usr/src/lib/libc/port/stdio/README.design327
-rw-r--r--usr/src/lib/libc/port/stdio/_endopen.c58
-rw-r--r--usr/src/lib/libc/port/stdio/_filbuf.c26
-rw-r--r--usr/src/lib/libc/port/stdio/_findbuf.c55
-rw-r--r--usr/src/lib/libc/port/stdio/_flsbuf.c19
-rw-r--r--usr/src/lib/libc/port/stdio/_stdio_flags.c109
-rw-r--r--usr/src/lib/libc/port/stdio/doscan.c12
-rw-r--r--usr/src/lib/libc/port/stdio/fileno.c6
-rw-r--r--usr/src/lib/libc/port/stdio/flush.c199
-rw-r--r--usr/src/lib/libc/port/stdio/fmemopen.c270
-rw-r--r--usr/src/lib/libc/port/stdio/fopen.c19
-rw-r--r--usr/src/lib/libc/port/stdio/fputs.c13
-rw-r--r--usr/src/lib/libc/port/stdio/fseek.c6
-rw-r--r--usr/src/lib/libc/port/stdio/fseeko.c6
-rw-r--r--usr/src/lib/libc/port/stdio/ftell.c44
-rw-r--r--usr/src/lib/libc/port/stdio/ftello.c29
-rw-r--r--usr/src/lib/libc/port/stdio/fwrite.c14
-rw-r--r--usr/src/lib/libc/port/stdio/getc.c16
-rw-r--r--usr/src/lib/libc/port/stdio/getw.c6
-rw-r--r--usr/src/lib/libc/port/stdio/open_memstream.c263
-rw-r--r--usr/src/lib/libc/port/stdio/open_wmemstream.c225
-rw-r--r--usr/src/lib/libc/port/stdio/putc.c24
-rw-r--r--usr/src/lib/libc/port/stdio/putw.c6
-rw-r--r--usr/src/lib/libc/port/stdio/rewind.c6
-rw-r--r--usr/src/lib/libc/port/stdio/setbuf.c28
-rw-r--r--usr/src/lib/libc/port/stdio/setvbuf.c16
-rw-r--r--usr/src/lib/libc/sparc/Makefile.com6
-rw-r--r--usr/src/lib/libc/sparcv9/Makefile.com6
48 files changed, 1778 insertions, 319 deletions
diff --git a/usr/src/lib/libc/amd64/Makefile b/usr/src/lib/libc/amd64/Makefile
index c0a065c9df..c21ef76ee2 100644
--- a/usr/src/lib/libc/amd64/Makefile
+++ b/usr/src/lib/libc/amd64/Makefile
@@ -639,6 +639,7 @@ PORTSTDIO= \
_filbuf.o \
_findbuf.o \
_flsbuf.o \
+ _stdio_flags.o \
_wrtchk.o \
clearerr.o \
ctermid.o \
@@ -654,6 +655,7 @@ PORTSTDIO= \
fileno.o \
flockf.o \
flush.o \
+ fmemopen.o \
fopen.o \
fpos.o \
fputc.o \
@@ -671,6 +673,8 @@ PORTSTDIO= \
gets.o \
getw.o \
mse.o \
+ open_memstream.o \
+ open_wmemstream.o \
popen.o \
putc.o \
putchar.o \
diff --git a/usr/src/lib/libc/i386/Makefile.com b/usr/src/lib/libc/i386/Makefile.com
index 9987e2ee87..d9e56ee8ec 100644
--- a/usr/src/lib/libc/i386/Makefile.com
+++ b/usr/src/lib/libc/i386/Makefile.com
@@ -686,6 +686,7 @@ PORTSTDIO= \
_filbuf.o \
_findbuf.o \
_flsbuf.o \
+ _stdio_flags.o \
_wrtchk.o \
clearerr.o \
ctermid.o \
@@ -701,6 +702,7 @@ PORTSTDIO= \
fileno.o \
flockf.o \
flush.o \
+ fmemopen.o \
fopen.o \
fpos.o \
fputc.o \
@@ -718,6 +720,8 @@ PORTSTDIO= \
gets.o \
getw.o \
mse.o \
+ open_memstream.o \
+ open_wmemstream.o \
popen.o \
putc.o \
putchar.o \
diff --git a/usr/src/lib/libc/inc/file64.h b/usr/src/lib/libc/inc/file64.h
index 40504d35ec..1bbc98e2bc 100644
--- a/usr/src/lib/libc/inc/file64.h
+++ b/usr/src/lib/libc/inc/file64.h
@@ -25,6 +25,10 @@
*/
/*
+ * Copyright 2020 Robert Mustacchi
+ */
+
+/*
* This is the header where the internal to libc definition of the FILE
* structure is defined. The exrernal defintion defines the FILE structure
* as an array of longs. This prevents customers from writing code that
@@ -41,8 +45,6 @@
#ifndef _FILE64_H
#define _FILE64_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <synch.h>
#include <stdio_tag.h>
#include <wchar_impl.h>
@@ -58,8 +60,25 @@ typedef __mbstate_t mbstate_t;
#define rmutex_t mutex_t
+typedef ssize_t (*fread_t)(__FILE *, char *, size_t);
+typedef ssize_t (*fwrite_t)(__FILE *, const char *, size_t);
+typedef off_t (*fseek_t)(__FILE *, off_t, int);
+typedef int (*fclose_t)(__FILE *);
+
+typedef struct {
+ fread_t std_read;
+ fwrite_t std_write;
+ fseek_t std_seek;
+ fclose_t std_close;
+ void *std_data;
+} stdio_ops_t;
+
#ifdef _LP64
+/*
+ * This structure cannot grow beyond its current size of 128 bytes. See the file
+ * lib/libc/port/stdio/README.design for more information.
+ */
struct __FILE_TAG {
unsigned char *_ptr; /* next character from/to here in buffer */
unsigned char *_base; /* the buffer */
@@ -69,7 +88,8 @@ struct __FILE_TAG {
unsigned int _flag; /* the state of the stream */
rmutex_t _lock; /* lock for this structure */
mbstate_t _state; /* mbstate_t */
- char __fill[32]; /* filler to bring size to 128 bytes */
+ stdio_ops_t *_ops; /* Alternate impl ops */
+ char __fill[24]; /* filler to bring size to 128 bytes */
};
#else
@@ -83,6 +103,7 @@ struct xFILEdata {
rmutex_t _lock; /* lock for this structure */
mbstate_t _state; /* mbstate_t */
int _altfd; /* alternate fd if > 255 */
+ stdio_ops_t *_ops; /* Alternate impl ops */
};
#define XFILEINITIALIZER { 0, NULL, RECURSIVEMUTEX, DEFAULTMBSTATE }
diff --git a/usr/src/lib/libc/inc/libc.h b/usr/src/lib/libc/inc/libc.h
index 448523df01..90a2859b33 100644
--- a/usr/src/lib/libc/inc/libc.h
+++ b/usr/src/lib/libc/inc/libc.h
@@ -333,6 +333,14 @@ extern void __throw_constraint_handler_s(const char *_RESTRICT_KYWD, int);
*/
extern void common_panic(const char *, const char *);
+/*
+ * defined in mbrtowc.c.
+ */
+extern size_t mbrtowc_nz_l(wchar_t *_RESTRICT_KYWD, const char *_RESTRICT_KYWD,
+ size_t, mbstate_t *_RESTRICT_KYWD, locale_t);
+extern size_t mbrtowc_nz(wchar_t *_RESTRICT_KYWD, const char *_RESTRICT_KYWD,
+ size_t, mbstate_t *_RESTRICT_KYWD);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/libc/inc/mtlib.h b/usr/src/lib/libc/inc/mtlib.h
index aa5e9e0992..cad6c7ab8d 100644
--- a/usr/src/lib/libc/inc/mtlib.h
+++ b/usr/src/lib/libc/inc/mtlib.h
@@ -27,8 +27,6 @@
#ifndef _MTLIB_H
#define _MTLIB_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <thread.h>
#ifdef __cplusplus
@@ -66,9 +64,9 @@ extern void assert_no_libc_locks_held(void);
#define _FWRITE _fwrite_unlocked
#define FILENO(s) _fileno(s)
#define FERROR(s) ferror(s)
-#define GETC(s) _getc_unlocked(s)
+#define GETC(s) _getc_internal(s)
#define UNGETC(c, s) _ungetc_unlocked(c, s)
-#define PUTC(c, s) _putc_unlocked(c, s)
+#define PUTC(c, s) _putc_internal(c, s)
#define GETWC(s) getwc(s)
#define PUTWC(c, s) putwc(c, s)
diff --git a/usr/src/lib/libc/inc/stdiom.h b/usr/src/lib/libc/inc/stdiom.h
index 9befb8a3c6..4769231968 100644
--- a/usr/src/lib/libc/inc/stdiom.h
+++ b/usr/src/lib/libc/inc/stdiom.h
@@ -25,7 +25,11 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
+/* All Rights Reserved */
+
+/*
+ * Copyright 2020 Robert Mustacchi
+ */
/*
* stdiom.h - shared guts of stdio
@@ -34,8 +38,6 @@
#ifndef _STDIOM_H
#define _STDIOM_H
-#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.9 */
-
#include <thread.h>
#include <synch.h>
#include <mtlib.h>
@@ -48,11 +50,18 @@
/*
* The following flags, and the macros that manipulate them, operate upon
* the FILE structure used by stdio. If new flags are required, they should
- * be created in this file. The values of the flags must be differnt from
+ * be created in this file. The values of the flags must be different from
* the currently used values. New macros should be created to use the flags
* so that the compilation mode dependencies can be isolated here.
*/
+/*
+ * The 32-bit version of the stdio FILE has 8 bits for its flags (see
+ * lib/libc/port/stdio/README.design). These 8 bits are used to determine if the
+ * FILE structure is allocated. We define '_DEF_FLAG_MASK' as a means to
+ * indicate this.
+ */
+#define _DEF_FLAG_MASK 0377
#ifdef _LP64
#define _BYTE_MODE_FLAG 0400
#define _WC_MODE_FLAG 01000
@@ -152,7 +161,7 @@ extern int __flsbuf(int, FILE *);
*/
#define _realbufend(iop) ((iop)->_end)
#else
-extern Uchar *_realbufend(FILE *iop);
+extern Uchar *_realbufend(FILE *iop);
extern rmutex_t *_reallock(FILE *iop);
#endif /* _LP64 */
@@ -171,7 +180,7 @@ extern void close_pid(void);
/*
* Internal routines from flush.c
*/
-extern int _file_get(FILE *);
+extern int _get_fd(FILE *);
extern int _file_set(FILE *, int, const char *);
/*
@@ -180,11 +189,8 @@ extern int _file_set(FILE *, int, const char *);
* since 64-bit Solaris is not affected by this.
*/
#ifdef _LP64
-#define GET_FD(iop) ((iop)->_file)
#define SET_FILE(iop, fd) ((iop)->_file = (fd))
#else
-#define GET_FD(iop) \
- (((iop)->__extendedfd) ? _file_get(iop) : (iop)->_magic)
#define SET_FILE(iop, fd) (iop)->_magic = (fd); (iop)->__extendedfd = 0
#endif
@@ -206,7 +212,7 @@ extern int _fileno(FILE *iop);
/*
* Internal routines from _findbuf.c
*/
-extern Uchar *_findbuf(FILE *iop);
+extern Uchar *_findbuf(FILE *iop);
/*
* Internal routine used by fopen.c
@@ -221,12 +227,12 @@ extern size_t _fwrite_unlocked(const void *, size_t, size_t, FILE *);
/*
* Internal routine from getc.c
*/
-int _getc_unlocked(FILE *);
+int _getc_internal(FILE *);
/*
* Internal routine from put.c
*/
-int _putc_unlocked(int, FILE *);
+int _putc_internal(int, FILE *);
/*
* Internal routine from ungetc.c
@@ -260,4 +266,36 @@ extern struct xFILEdata _xftab[];
#endif /* _LP64 */
+/*
+ * A set of stdio routines to allow us to have alternate read, write, lseek, and
+ * close implementations.
+ */
+extern ssize_t _xread(FILE *iop, void *buf, size_t nbytes);
+extern ssize_t _xwrite(FILE *iop, const void *buf, size_t nbytes);
+extern off_t _xseek(FILE *iop, off_t off, int whence);
+extern off64_t _xseek64(FILE *iop, off64_t off, int whence);
+extern int _xclose(FILE *iop);
+extern void *_xdata(FILE *iop);
+extern int _xassoc(FILE *iop, fread_t readf, fwrite_t writef,
+ fseek_t seekf, fclose_t closef, void *data);
+extern void _xunassoc(FILE *iop);
+
+/*
+ * Internal functions from _stdio_flags.c.
+ */
+extern int _stdio_flags(const char *type, int *oflags, int *fflags);
+
+/*
+ * Internal functions from open_memstream.c.
+ */
+extern boolean_t memstream_seek(size_t base, off_t off, size_t max,
+ size_t *nposp);
+extern int memstream_newsize(size_t pos, size_t alloc, size_t nbytes,
+ size_t *nallocp);
+
+/*
+ * Internal function from ftell.o.
+ */
+extern off64_t ftell_common(FILE *iop);
+
#endif /* _STDIOM_H */
diff --git a/usr/src/lib/libc/port/locale/big5.c b/usr/src/lib/libc/port/locale/big5.c
index 2729ab0289..889b182de5 100644
--- a/usr/src/lib/libc/port/locale/big5.c
+++ b/usr/src/lib/libc/port/locale/big5.c
@@ -44,7 +44,7 @@
static size_t _BIG5_mbrtowc(wchar_t *_RESTRICT_KYWD,
const char *_RESTRICT_KYWD,
- size_t, mbstate_t *RESTRICT_KYWD);
+ size_t, mbstate_t *RESTRICT_KYWD, boolean_t);
static int _BIG5_mbsinit(const mbstate_t *);
static size_t _BIG5_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
mbstate_t *_RESTRICT_KYWD);
@@ -88,7 +88,7 @@ _big5_check(uint_t c)
static size_t
_BIG5_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
- size_t n, mbstate_t *_RESTRICT_KYWD ps)
+ size_t n, mbstate_t *_RESTRICT_KYWD ps, boolean_t zero)
{
_BIG5State *bs;
wchar_t wc;
@@ -143,7 +143,11 @@ _BIG5_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
} else {
if (pwc != NULL)
*pwc = wc;
- return (wc == L'\0' ? 0 : 1);
+ if (zero || wc != L'\0') {
+ return (1);
+ } else {
+ return (0);
+ }
}
}
diff --git a/usr/src/lib/libc/port/locale/euc.c b/usr/src/lib/libc/port/locale/euc.c
index a99cdf8689..1d1d25b17b 100644
--- a/usr/src/lib/libc/port/locale/euc.c
+++ b/usr/src/lib/libc/port/locale/euc.c
@@ -46,22 +46,23 @@
static size_t _EUC_mbrtowc_impl(wchar_t *_RESTRICT_KYWD,
const char *_RESTRICT_KYWD,
- size_t, mbstate_t *_RESTRICT_KYWD, uint8_t, uint8_t, uint8_t, uint8_t);
+ size_t, mbstate_t *_RESTRICT_KYWD, uint8_t, uint8_t, uint8_t, uint8_t,
+ boolean_t);
static size_t _EUC_wcrtomb_impl(char *_RESTRICT_KYWD, wchar_t,
mbstate_t *_RESTRICT_KYWD, uint8_t, uint8_t, uint8_t, uint8_t);
static size_t _EUC_CN_mbrtowc(wchar_t *_RESTRICT_KYWD,
const char *_RESTRICT_KYWD,
- size_t, mbstate_t *_RESTRICT_KYWD);
+ size_t, mbstate_t *_RESTRICT_KYWD, boolean_t);
static size_t _EUC_JP_mbrtowc(wchar_t *_RESTRICT_KYWD,
const char *_RESTRICT_KYWD,
- size_t, mbstate_t *_RESTRICT_KYWD);
+ size_t, mbstate_t *_RESTRICT_KYWD, boolean_t);
static size_t _EUC_KR_mbrtowc(wchar_t *_RESTRICT_KYWD,
const char *_RESTRICT_KYWD,
- size_t, mbstate_t *_RESTRICT_KYWD);
+ size_t, mbstate_t *_RESTRICT_KYWD, boolean_t);
static size_t _EUC_TW_mbrtowc(wchar_t *_RESTRICT_KYWD,
const char *_RESTRICT_KYWD,
- size_t, mbstate_t *_RESTRICT_KYWD);
+ size_t, mbstate_t *_RESTRICT_KYWD, boolean_t);
static size_t _EUC_CN_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
mbstate_t *_RESTRICT_KYWD);
@@ -131,9 +132,9 @@ _EUC_CN_init(struct lc_ctype *lct)
static size_t
_EUC_CN_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
- size_t n, mbstate_t *_RESTRICT_KYWD ps)
+ size_t n, mbstate_t *_RESTRICT_KYWD ps, boolean_t zero)
{
- return (_EUC_mbrtowc_impl(pwc, s, n, ps, SS2, 4, 0, 0));
+ return (_EUC_mbrtowc_impl(pwc, s, n, ps, SS2, 4, 0, 0, zero));
}
static size_t
@@ -176,9 +177,9 @@ _EUC_KR_init(struct lc_ctype *lct)
static size_t
_EUC_KR_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
- size_t n, mbstate_t *_RESTRICT_KYWD ps)
+ size_t n, mbstate_t *_RESTRICT_KYWD ps, boolean_t zero)
{
- return (_EUC_mbrtowc_impl(pwc, s, n, ps, 0, 0, 0, 0));
+ return (_EUC_mbrtowc_impl(pwc, s, n, ps, 0, 0, 0, 0, zero));
}
static size_t
@@ -221,9 +222,9 @@ _EUC_JP_init(struct lc_ctype *lct)
static size_t
_EUC_JP_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
- size_t n, mbstate_t *_RESTRICT_KYWD ps)
+ size_t n, mbstate_t *_RESTRICT_KYWD ps, boolean_t zero)
{
- return (_EUC_mbrtowc_impl(pwc, s, n, ps, SS2, 2, SS3, 3));
+ return (_EUC_mbrtowc_impl(pwc, s, n, ps, SS2, 2, SS3, 3, zero));
}
static size_t
@@ -266,9 +267,9 @@ _EUC_TW_init(struct lc_ctype *lct)
static size_t
_EUC_TW_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
- size_t n, mbstate_t *_RESTRICT_KYWD ps)
+ size_t n, mbstate_t *_RESTRICT_KYWD ps, boolean_t zero)
{
- return (_EUC_mbrtowc_impl(pwc, s, n, ps, SS2, 4, 0, 0));
+ return (_EUC_mbrtowc_impl(pwc, s, n, ps, SS2, 4, 0, 0, zero));
}
static size_t
@@ -300,7 +301,8 @@ _EUC_TW_wcsnrtombs(char *_RESTRICT_KYWD dst, const wchar_t **_RESTRICT_KYWD src,
static size_t
_EUC_mbrtowc_impl(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
size_t n, mbstate_t *_RESTRICT_KYWD ps,
- uint8_t cs2, uint8_t cs2width, uint8_t cs3, uint8_t cs3width)
+ uint8_t cs2, uint8_t cs2width, uint8_t cs3, uint8_t cs3width,
+ boolean_t zero)
{
_EucState *es;
int i, want;
@@ -329,7 +331,11 @@ _EUC_mbrtowc_impl(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
if (((ch = (unsigned char)*s) & 0x80) == 0) {
if (pwc != NULL)
*pwc = ch;
- return (ch != '\0' ? 1 : 0);
+ if (zero || ch != '\0') {
+ return (1);
+ } else {
+ return (0);
+ }
}
if (ch >= 0xa1) {
@@ -367,7 +373,11 @@ _EUC_mbrtowc_impl(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
if (pwc != NULL)
*pwc = wc;
es->want = 0;
- return (wc == L'\0' ? 0 : want);
+ if (zero || wc != L'\0') {
+ return (want);
+ } else {
+ return (0);
+ }
}
static size_t
diff --git a/usr/src/lib/libc/port/locale/fgetwc.c b/usr/src/lib/libc/port/locale/fgetwc.c
index 282b65cebc..254a785891 100644
--- a/usr/src/lib/libc/port/locale/fgetwc.c
+++ b/usr/src/lib/libc/port/locale/fgetwc.c
@@ -66,7 +66,7 @@ _fgetwc_unlocked_l(FILE *fp, locale_t loc)
}
do {
char x = (char)c;
- nconv = lct->lc_mbrtowc(&wc, &x, 1, statep);
+ nconv = lct->lc_mbrtowc(&wc, &x, 1, statep, B_FALSE);
if (nconv == (size_t)-1) {
break;
} else if (nconv == (size_t)-2) {
diff --git a/usr/src/lib/libc/port/locale/gb18030.c b/usr/src/lib/libc/port/locale/gb18030.c
index 232daade50..36c48c5cc5 100644
--- a/usr/src/lib/libc/port/locale/gb18030.c
+++ b/usr/src/lib/libc/port/locale/gb18030.c
@@ -44,7 +44,7 @@
static size_t _GB18030_mbrtowc(wchar_t *_RESTRICT_KYWD,
const char *_RESTRICT_KYWD,
- size_t, mbstate_t *_RESTRICT_KYWD);
+ size_t, mbstate_t *_RESTRICT_KYWD, boolean_t);
static int _GB18030_mbsinit(const mbstate_t *);
static size_t _GB18030_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
mbstate_t *_RESTRICT_KYWD);
@@ -83,7 +83,7 @@ _GB18030_mbsinit(const mbstate_t *ps)
static size_t
_GB18030_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
- size_t n, mbstate_t *_RESTRICT_KYWD ps)
+ size_t n, mbstate_t *_RESTRICT_KYWD ps, boolean_t zero)
{
_GB18030State *gs;
wchar_t wch;
@@ -159,7 +159,11 @@ _GB18030_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
if (pwc != NULL)
*pwc = wch;
gs->count = 0;
- return (wch == L'\0' ? 0 : len - ocount);
+ if (zero || wch != L'\0') {
+ return (len - ocount);
+ } else {
+ return (0);
+ }
ilseq:
errno = EILSEQ;
return ((size_t)-1);
diff --git a/usr/src/lib/libc/port/locale/gb2312.c b/usr/src/lib/libc/port/locale/gb2312.c
index a25af781b4..bfb6c0177b 100644
--- a/usr/src/lib/libc/port/locale/gb2312.c
+++ b/usr/src/lib/libc/port/locale/gb2312.c
@@ -39,7 +39,7 @@
static size_t _GB2312_mbrtowc(wchar_t *_RESTRICT_KYWD,
const char *_RESTRICT_KYWD,
- size_t, mbstate_t *_RESTRICT_KYWD);
+ size_t, mbstate_t *_RESTRICT_KYWD, boolean_t);
static int _GB2312_mbsinit(const mbstate_t *);
static size_t _GB2312_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
mbstate_t *_RESTRICT_KYWD);
@@ -101,7 +101,7 @@ _GB2312_check(const char *str, size_t n)
static size_t
_GB2312_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
- size_t n, mbstate_t *_RESTRICT_KYWD ps)
+ size_t n, mbstate_t *_RESTRICT_KYWD ps, boolean_t zero)
{
_GB2312State *gs;
wchar_t wc;
@@ -137,7 +137,11 @@ _GB2312_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
if (pwc != NULL)
*pwc = wc;
gs->count = 0;
- return (wc == L'\0' ? 0 : len - ocount);
+ if (zero || wc != L'\0') {
+ return (len - ocount);
+ } else {
+ return (0);
+ }
}
static size_t
diff --git a/usr/src/lib/libc/port/locale/gbk.c b/usr/src/lib/libc/port/locale/gbk.c
index 5c94b9954b..f422ce8fb5 100644
--- a/usr/src/lib/libc/port/locale/gbk.c
+++ b/usr/src/lib/libc/port/locale/gbk.c
@@ -44,7 +44,7 @@
static size_t _GBK_mbrtowc(wchar_t *_RESTRICT_KYWD,
const char *_RESTRICT_KYWD,
- size_t, mbstate_t *_RESTRICT_KYWD);
+ size_t, mbstate_t *_RESTRICT_KYWD, boolean_t);
static int _GBK_mbsinit(const mbstate_t *);
static size_t _GBK_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
mbstate_t *_RESTRICT_KYWD);
@@ -88,7 +88,7 @@ _gbk_check(uint_t c)
static size_t
_GBK_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
- size_t n, mbstate_t *_RESTRICT_KYWD ps)
+ size_t n, mbstate_t *_RESTRICT_KYWD ps, boolean_t zero)
{
_GBKState *gs;
wchar_t wc;
@@ -143,7 +143,11 @@ _GBK_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
} else {
if (pwc != NULL)
*pwc = wc;
- return (wc == L'\0' ? 0 : 1);
+ if (zero || wc != L'\0') {
+ return (1);
+ } else {
+ return (0);
+ }
}
}
diff --git a/usr/src/lib/libc/port/locale/lctype.h b/usr/src/lib/libc/port/locale/lctype.h
index 25652da1d4..0a9e1335bf 100644
--- a/usr/src/lib/libc/port/locale/lctype.h
+++ b/usr/src/lib/libc/port/locale/lctype.h
@@ -17,6 +17,7 @@
#define _LCTYPE_H_
#include <wchar.h>
+#include <sys/types.h>
/* private LC_CTYPE related structures */
@@ -24,7 +25,8 @@
struct lc_ctype {
size_t (*lc_mbrtowc)(wchar_t *_RESTRICT_KYWD,
- const char *_RESTRICT_KYWD, size_t, mbstate_t *_RESTRICT_KYWD);
+ const char *_RESTRICT_KYWD, size_t, mbstate_t *_RESTRICT_KYWD,
+ boolean_t);
int (*lc_mbsinit)(const mbstate_t *);
@@ -51,7 +53,7 @@ struct lc_ctype {
* Default implementation (C locale, i.e. ASCII).
*/
size_t __mbrtowc_ascii(wchar_t *_RESTRICT_KYWD,
- const char *_RESTRICT_KYWD, size_t, mbstate_t *_RESTRICT_KYWD);
+ const char *_RESTRICT_KYWD, size_t, mbstate_t *_RESTRICT_KYWD, boolean_t);
int __mbsinit_ascii(const mbstate_t *);
size_t __mbsnrtowcs_ascii(wchar_t *_RESTRICT_KYWD dst,
const char **_RESTRICT_KYWD src, size_t nms, size_t len,
diff --git a/usr/src/lib/libc/port/locale/mblocal.h b/usr/src/lib/libc/port/locale/mblocal.h
index 4412bec7cb..3d958e364e 100644
--- a/usr/src/lib/libc/port/locale/mblocal.h
+++ b/usr/src/lib/libc/port/locale/mblocal.h
@@ -48,7 +48,7 @@ void _BIG5_init(struct lc_ctype *);
void _MSKanji_init(struct lc_ctype *);
typedef size_t (*mbrtowc_pfn_t)(wchar_t *_RESTRICT_KYWD,
- const char *_RESTRICT_KYWD, size_t, mbstate_t *_RESTRICT_KYWD);
+ const char *_RESTRICT_KYWD, size_t, mbstate_t *_RESTRICT_KYWD, boolean_t);
typedef size_t (*wcrtomb_pfn_t)(char *_RESTRICT_KYWD, wchar_t,
mbstate_t *_RESTRICT_KYWD);
size_t __mbsnrtowcs_std(wchar_t *_RESTRICT_KYWD, const char **_RESTRICT_KYWD,
diff --git a/usr/src/lib/libc/port/locale/mbrtowc.c b/usr/src/lib/libc/port/locale/mbrtowc.c
index cd1e7b064f..c0934c88d1 100644
--- a/usr/src/lib/libc/port/locale/mbrtowc.c
+++ b/usr/src/lib/libc/port/locale/mbrtowc.c
@@ -40,7 +40,7 @@ mbrtowc_l(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
if (ps == NULL)
ps = &mbs;
- return (loc->ctype->lc_mbrtowc(pwc, s, n, ps));
+ return (loc->ctype->lc_mbrtowc(pwc, s, n, ps, B_FALSE));
}
size_t
@@ -49,3 +49,21 @@ mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
{
return (mbrtowc_l(pwc, s, n, ps, uselocale(NULL)));
}
+
+size_t
+mbrtowc_nz_l(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
+ size_t n, mbstate_t *_RESTRICT_KYWD ps, locale_t loc)
+{
+ static mbstate_t mbs;
+
+ if (ps == NULL)
+ ps = &mbs;
+ return (loc->ctype->lc_mbrtowc(pwc, s, n, ps, B_TRUE));
+}
+
+size_t
+mbrtowc_nz(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
+ size_t n, mbstate_t *_RESTRICT_KYWD ps)
+{
+ return (mbrtowc_nz_l(pwc, s, n, ps, uselocale(NULL)));
+}
diff --git a/usr/src/lib/libc/port/locale/mbsnrtowcs.c b/usr/src/lib/libc/port/locale/mbsnrtowcs.c
index 533b7776e0..6411cfcb74 100644
--- a/usr/src/lib/libc/port/locale/mbsnrtowcs.c
+++ b/usr/src/lib/libc/port/locale/mbsnrtowcs.c
@@ -68,11 +68,13 @@ __mbsnrtowcs_std(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
if (dst == NULL) {
for (;;) {
- if ((nb = pmbrtowc(&wc, s, nms, ps)) == (size_t)-1)
+ if ((nb = pmbrtowc(&wc, s, nms, ps, B_FALSE)) ==
+ (size_t)-1) {
/* Invalid sequence - mbrtowc() sets errno. */
return ((size_t)-1);
- else if (nb == 0 || nb == (size_t)-2)
+ } else if (nb == 0 || nb == (size_t)-2) {
return (nchr);
+ }
s += nb;
nms -= nb;
nchr++;
@@ -81,7 +83,7 @@ __mbsnrtowcs_std(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
}
while (len-- > 0) {
- if ((nb = pmbrtowc(dst, s, nms, ps)) == (size_t)-1) {
+ if ((nb = pmbrtowc(dst, s, nms, ps, B_FALSE)) == (size_t)-1) {
*src = s;
return ((size_t)-1);
} else if (nb == (size_t)-2) {
diff --git a/usr/src/lib/libc/port/locale/mskanji.c b/usr/src/lib/libc/port/locale/mskanji.c
index 5d9b899aae..69955e5afa 100644
--- a/usr/src/lib/libc/port/locale/mskanji.c
+++ b/usr/src/lib/libc/port/locale/mskanji.c
@@ -46,7 +46,7 @@
static size_t _MSKanji_mbrtowc(wchar_t *_RESTRICT_KYWD,
const char *_RESTRICT_KYWD,
- size_t, mbstate_t *_RESTRICT_KYWD);
+ size_t, mbstate_t *_RESTRICT_KYWD, boolean_t);
static int _MSKanji_mbsinit(const mbstate_t *);
static size_t _MSKanji_wcrtomb(char *_RESTRICT_KYWD, wchar_t,
mbstate_t *_RESTRICT_KYWD);
@@ -83,7 +83,7 @@ _MSKanji_mbsinit(const mbstate_t *ps)
static size_t
_MSKanji_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
- size_t n, mbstate_t *_RESTRICT_KYWD ps)
+ size_t n, mbstate_t *_RESTRICT_KYWD ps, boolean_t zero)
{
_MSKanjiState *ms;
wchar_t wc;
@@ -135,7 +135,11 @@ _MSKanji_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
} else {
if (pwc != NULL)
*pwc = wc;
- return (wc == L'\0' ? 0 : 1);
+ if (zero || wc != L'\0') {
+ return (1);
+ } else {
+ return (0);
+ }
}
}
diff --git a/usr/src/lib/libc/port/locale/none.c b/usr/src/lib/libc/port/locale/none.c
index 0511563cb1..5eefc746aa 100644
--- a/usr/src/lib/libc/port/locale/none.c
+++ b/usr/src/lib/libc/port/locale/none.c
@@ -73,7 +73,7 @@ __mbsinit_ascii(const mbstate_t *unused)
size_t
__mbrtowc_ascii(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
- size_t n, mbstate_t *_RESTRICT_KYWD unused)
+ size_t n, mbstate_t *_RESTRICT_KYWD unused, boolean_t zero)
{
_NOTE(ARGUNUSED(unused));
@@ -85,7 +85,11 @@ __mbrtowc_ascii(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
return ((size_t)-2);
if (pwc != NULL)
*pwc = (unsigned char)*s;
- return (*s == '\0' ? 0 : 1);
+ if (zero || *s != '\0') {
+ return (1);
+ } else {
+ return (0);
+ }
}
size_t
diff --git a/usr/src/lib/libc/port/locale/utf8.c b/usr/src/lib/libc/port/locale/utf8.c
index e919b9dd4a..a6e037d94e 100644
--- a/usr/src/lib/libc/port/locale/utf8.c
+++ b/usr/src/lib/libc/port/locale/utf8.c
@@ -37,7 +37,7 @@
static size_t _UTF8_mbrtowc(wchar_t *_RESTRICT_KYWD,
const char *_RESTRICT_KYWD,
- size_t, mbstate_t *_RESTRICT_KYWD);
+ size_t, mbstate_t *_RESTRICT_KYWD, boolean_t);
static int _UTF8_mbsinit(const mbstate_t *);
static size_t _UTF8_mbsnrtowcs(wchar_t *_RESTRICT_KYWD,
const char **_RESTRICT_KYWD, size_t, size_t,
@@ -75,7 +75,7 @@ _UTF8_mbsinit(const mbstate_t *ps)
static size_t
_UTF8_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
- size_t n, mbstate_t *_RESTRICT_KYWD ps)
+ size_t n, mbstate_t *_RESTRICT_KYWD ps, boolean_t zero)
{
_UTF8State *us;
int ch, i, mask, want;
@@ -116,7 +116,11 @@ _UTF8_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
/* Fast path for plain ASCII characters. */
if (pwc != NULL)
*pwc = ch;
- return (ch != '\0' ? 1 : 0);
+ if (zero || ch != '\0') {
+ return (1);
+ } else {
+ return (0);
+ }
}
if ((ch & 0xe0) == 0xc0) {
mask = 0x1f;
@@ -192,7 +196,11 @@ _UTF8_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s,
if (pwc != NULL)
*pwc = wch;
us->want = 0;
- return (wch == L'\0' ? 0 : want);
+ if (zero || wch != L'\0') {
+ return (want);
+ } else {
+ return (0);
+ }
}
static size_t
@@ -221,18 +229,19 @@ _UTF8_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
return ((size_t)-1);
}
for (;;) {
- if (nms > 0 && (signed char)*s > 0)
+ if (nms > 0 && (signed char)*s > 0) {
/*
* Fast path for plain ASCII characters
* excluding NUL.
*/
nb = 1;
- else if ((nb = _UTF8_mbrtowc(&wc, s, nms, ps)) ==
- (size_t)-1)
+ } else if ((nb = _UTF8_mbrtowc(&wc, s, nms, ps,
+ B_FALSE)) == (size_t)-1) {
/* Invalid sequence - mbrtowc() sets errno. */
return ((size_t)-1);
- else if (nb == 0 || nb == (size_t)-2)
+ } else if (nb == 0 || nb == (size_t)-2) {
return (nchr);
+ }
s += nb;
nms -= nb;
nchr++;
@@ -257,7 +266,7 @@ _UTF8_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst, const char **_RESTRICT_KYWD src,
*/
*dst = (wchar_t)*s;
nb = 1;
- } else if ((nb = _UTF8_mbrtowc(dst, s, nms, ps)) ==
+ } else if ((nb = _UTF8_mbrtowc(dst, s, nms, ps, B_FALSE)) ==
(size_t)-1) {
*src = s;
return ((size_t)-1);
diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers
index dbe33eb9d1..da8de86f25 100644
--- a/usr/src/lib/libc/port/mapfile-vers
+++ b/usr/src/lib/libc/port/mapfile-vers
@@ -78,6 +78,13 @@ $if _x86 && _ELF64
$add amd64
$endif
+SYMBOL_VERSION ILLUMOS_0.32 {
+ protected:
+ fmemopen;
+ open_memstream;
+ open_wmemstream;
+} ILLUMOS_0.31;
+
SYMBOL_VERSION ILLUMOS_0.31 {
protected:
__unlockpt_xpg4;
diff --git a/usr/src/lib/libc/port/stdio/README.design b/usr/src/lib/libc/port/stdio/README.design
new file mode 100644
index 0000000000..748f7f9913
--- /dev/null
+++ b/usr/src/lib/libc/port/stdio/README.design
@@ -0,0 +1,327 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2020 Robert Mustacchi
+#
+ _ _ _
+ ___| |_ __| (_) ___
+/ __| __/ _` | |/ _ \
+\__ \ || (_| | | (_) |
+|___/\__\__,_|_|\___/
+
+Notes on the design of stdio.
+
+------------
+File Streams
+------------
+
+At the heart of the stdio is the 'FILE *'. The 'FILE *' represents a
+stream that can be read, written, and seeked. The streams traditionally
+refer to a file descriptor, when created by fopen(3C), or may refer to
+memory, when created by open_memstream(3C) or fmopen(3C). This document
+focuses on the implementation of streams. Other misc. functions in stdio
+are not discussed.
+
+------------
+Organization
+------------
+
+Most functions exist in a file with the same name. When adding new
+files to stdio the file name should match the primary function name.
+There are a few exceptions. Almost all of the logic related to both
+flushing and knowledge of how to handle the 32-bit ABI issues (described
+in the next section) can be found in flush.c.
+
+-----------------------------
+struct __FILE_TAG and the ABI
+-----------------------------
+
+The definition of the 'FILE *' is a pointer to a 'struct __FILE_TAG'.
+The 'struct __FILE_TAG' structure has a long history that dates back to
+historical UNIX. For better or for worse, we have inherited some of the
+design decisions of the past, it's important to understand what those
+are as they have profound impact on the stdio design and serve as a good
+cautionary tale for future ABI decisions.
+
+In the original UNIX designs, the 'struct __FILE_TAG' was exposed as a
+non-opaque structure. This was also true on other platforms. This had a
+couple of challenges:
+
+* It meant the size of the 'struct __FILE_TAG' was part of the ABI
+* Consumers would access the members directly. You can find examples of
+ this in our public headers where things like getc() are inlined in
+ terms of the implementation. Various 3rd-party software that has
+ existed for quite some time knows the offset of members and directly
+ manipulates them. This is still true as of 2020.
+* The 'struct __FILE_TAG' only used an unsigned char (uint8_t) for the
+ file descriptor in the 32-bit version. Other systems used a short, so
+ they were in better shape. This was changed in the 64-bit version to
+ use an int.
+* The main C stdio symbols 'stdin', 'stdout', and 'stderr', were (and
+ still are) exposed as an array. This means that while the 64-bit
+ structure is opaque, its size is actually part of the ABI.
+
+All of these issues have been dealt with in different ways in the
+system. The first thing that is a little confusing is where to find the
+definitions of the actual implementation. The 32-bit 'struct __FILE_BUF'
+is split into two different pieces, the part that is public and a
+secondary, private part.
+
+The public definition of the 'struct __FILE_TAG' for 32-bit code and the
+opaque definition for 64-bit code may be found in
+'usr/src/head/stdio_impl.h.'. The actual definition of the 64-bit
+structure and the 32-bit additions are all found in
+'usr/src/lib/libc/inc/file64.h.'
+
+In file64.h, one will find the 'struct xFILEdata' (extended FILE * data).
+This represents all of the data that has been added to stdio that is
+missing from the public structure. Whenever a 'FILE *' is allocated,
+32-bit code always ensures that there is a corresponding 'struct
+xFILEdata' that exists. Currently, we still have plenty of padding left
+in the 64-bit version of the structure for at least 3 pointers.
+
+To add a member to the structure, one has to add data to the structures
+in 'lib/libc/inc/file64.h'. If for some reason, all the padding would be
+used up, then you must stop. The size of the 64-bit structure _cannot_
+be extended, as noted earlier it is part of the ABI. If we hit this
+case, then one must introduce the struct xFILEdata for the lp64
+environment.
+
+--------------------------
+Allocating FILE Structures
+--------------------------
+
+libc defines a number of 'FILE *' structures by default. These can all
+be found in 'data.c'. The first _NFILE (20 or 60 depending on the
+platform) are defined statically. In the 32-bit case, the corresponding
+'struct _xFILEdata' is allocated along with it.
+
+To determine if a structure is free or not in the array, the `_flag`
+member is consulted. If the flag has been set to zero, then the STREAM
+is considered free and can be allocated. All of the allocated (whether
+used or not) 'FILE *' structures are present on a linked list which is
+found in 'flush.c' rooted at the symbol '__first_link'. This list is
+always scanned to try and reuse an existing 'FILE *' structure before
+allocating a new one. If all of the existing ones are in use, then one
+will be allocated.
+
+An important thing to understand is that once allocated, a 'FILE *' will
+never be freed by libc. It will always exist on the global list of
+structures to be reused.
+
+---------
+Buffering
+---------
+
+Every stream in stdio starts out as buffered. Buffering can be changed
+by calling either setbuf(3C) or setvbuf(3C). This buffer is stored in
+the `_base` member of the 'struct __FILE_TAG'. The amount of valid data
+in the buffer is maintained in the '_cnt' member of the structure. By
+default, there is no associated buffer with a stream. When the stream is
+first used, the buffer will be assigned by a call to _findbuf() in
+_findbuf.c.
+
+There are pre-allocated buffers that exist. There are two specifically
+for stdin and stdout (stderr is unbuffered). These include space for
+both the buffer and the pushback buffer. The pushback buffer is used so
+someone can call fungetc(3C) regardless of whether a buffering mode is
+enabled or not. Characters that we 'unget' are placed on the pushback
+buffer.
+
+For other buffering modes, we'll try and allocate an appropriate sized
+buffer. The buffer size defaults to BUFSIZ, but if the stream is backed
+by a file descriptor, we'll use fstat() to determine the appropriate
+size to use and match the file system block size. If we cannot allocate
+that, we'll fall back to trying to allocate a pushback buffer.
+
+libc defines static data for _NFILE worth of pushback buffers which are
+indexed based on the underlying file descriptor. This and the stdin and
+stdout buffers are all found in 'data.c' in _smbuf, _sibuf, and _sobuf
+respectively.
+
+------------------------------
+Reading, Writing, and Flushing
+------------------------------
+
+By default, reads and writes on a stream, whether backed by a
+file-descriptor or not, go through the buffer described in the previous
+section. If a read or write can be satisfied by the buffer, then no
+underlying I/O will occur, unless buffering has been disabled.
+
+The various function entry points that read such as fread(3C) or
+fgetc(3C) will not call read() directly but will instead try to fill the
+buffer, which will cause a read if required. This is centralized in
+_filbuf(). When a read is required from the underlying file, it will
+call _xread() in flush.c. For more on _xread() see the operations vector
+section further along.
+
+Unlike reads, writes are much less centralized and each of the main
+writing entry points has reimplemented the path of writing to the buffer
+and flushing it. It would be good in the future to consolidate them. In
+general, data will be written directly to the stdio buffer. When that
+buffer needs to be flushed either the _flsbuf() or _xflsbuf() functions
+will be called to actually flush out the buffer.
+
+When data needs to be flushed from a buffer to its underlying file
+descriptor (or other backing store), all of the write family functions
+ultimately call _xwrite().
+
+Flushes can occur in a few different ways:
+
+1. A write has filled up the buffer.
+2. A new line ('\n') is written and new-line buffering is used.
+3. fflush(3C) or a similar function has been called.
+4. A read occurs on a buffer that has unflushed writes.
+5. The stream is being closed.
+
+Most of these methods are fairly similar; however, the fflush(3C) case
+is a little different. fflush() may be asked to flush all of the streams
+when it is passed a NULL stream. Even when that happens it will still
+utilize the same underlying mechanism via _xflsbuf() or _flsbuf().
+
+-----------
+Orientation
+-----------
+
+Streams handle both wide characters and narrow characters. There is an
+internal multi-byte conversion state buffer that is included with every
+stream. A stream may exist in one of three modes:
+
+1. It may have an explicit narrow orientation
+2. It may have an explicit wide orientation
+3. It may have no orientation
+
+When most streams are created, they have no orientation. The orientation
+can then be explicitly set by calling fwide(3C). Some streams are also
+created with an explicit orientation, for example, open_wmemstream(3C)
+always sets the stream to be wide.
+
+The C standard dictates that certain operations will actually cause a
+stream with no orientation to have an explicit orientation set. Calling
+a narrow or wide related character function, such as 'fgetc(3C)' or
+'fgetwc(3C)' respectively will then cause the orientation to be set if
+it has not been. Once an orientation for a stream has been set, it
+cannot be changed until the stream has been closed or it is reset by
+calling freopen(3C).
+
+There are a few functions that don't change this today. One example is
+ungetc(3C). Often this isn't indicative of whether it should or
+shouldn't change the orientation, but is a side effect of the history of
+the stdio implementation.
+
+-------------------------------------
+Operations Vectors and Memory Streams
+-------------------------------------
+
+Traditionally, stdio streams were always backed by a file descriptor of
+some kind and therefore always called out into functions like read(2),
+write(2), lseek(2), and close(2) directly. A series of new functions
+were introduced in POSIX 2008 that add support for streams backed by
+memory in the form of fmemopen(3C), open_memstream(3C), and
+open_wmemstream(3C).
+
+To deal with this and other possible designs, an operations vector was
+added to the stream represented by the 'stdio_ops_t' structure. This is
+stored in the '_ops' member of the 'struct __FILE_BUF'. For a normal
+stream backed by a file descriptor, this member will be NULL.
+
+In places where a normal system call would have been made there is now a
+call to a corresponding function such as _xread(), _xwrite(), xseek(),
+_xseek64(), and _xclose(). If an operations vector is defined, it will
+call into the corresponding operation vector. If not, it will perform
+the traditional system call. This design choice consolidates all of the
+work required to implement non-file descriptor backed streams.
+
+When creating a non-file backed stream there are several expectations in
+the system:
+
+* The stream code should obtain a stream normally through a call to
+ _findiop().
+* If one needs to translate the normal fopen(3C) arguments, they should
+ use the _stdio_flags() function. This will also construct the
+ appropriate internal stdio flags for the stream.
+* The stream code must call _xassoc() to set the file operations vector
+ before return a 'FILE *' out of libc.
+* All of the operations vectors must be implemented.
+* If the stream is seekable, it must explicitly use the SET_SEEKABLE()
+ macro before return the stream.
+* If the stream is supposed to have a default orientation, it must set
+ it by calling _setorientation(). Not all streams have a default
+ orientation.
+* In the stream's close entry point it should call _xunassoc().
+
+--------------------------
+Extended File and fileno()
+--------------------------
+
+The 32-bit libc has historically been limited to 255 open streams
+because of the use of an unsigned char. This problem does not impact the
+64-bit libc. To deal with this, libc uses a series of techniques which
+are summarized for users in extendedFILE(5). The usage of extendedFILE
+can also be enabled by passing the special 'F' character to fopen(3C).
+
+The '_magic' member in the 32-bit 'struct __FILE_TAG' contains what used
+to be the file descriptor. When extended file is not in use, the
+_magic member still does contain the file descriptor. However, when
+extendedFILE is enabled, then the _magic member contains a sentinel
+value and the actual value is stored in the 'struct xFILEdata' _magic
+member.
+
+The act of getting the correct file descriptor has been centralized in a
+function called _get_fd(). This function knows how to handle the special
+32-bit case and the normal case. It also centralizes the logic of
+checking for a non-file backed stream. There are many cases in libc
+where we want to know the file descriptor to perform some operation;
+however, non-file backed streams do not have a corresponding file
+descriptor. When such a stream is detected, we will explicitly return
+-1. This ensures that a bad file descriptor will be used if someone
+mistakenly calls a system call. Functions like _fileno() call this
+directly.
+
+-------
+Testing
+-------
+
+There is a burgeoning test suite for stdio in
+usr/src/test/libc-tests/tests/stdio. If working in stdio (or libc more
+generally) it is recommended that you run this test suite and add new
+tests to it where appropriate. For most new functionality it is
+encouraged that you both import test suites that may already exist and
+that you also write your own test suites to properly cover a number of
+error and corner cases.
+
+Tests should also be written against libumem(3LIB), and umem debugging
+should be explicitly enabled in the program. Enabling umem debugging can
+catch a number of common memory usage errors. It also makes it easier to
+test for memory leaks by taking a core file and used the mdb
+'::findleaks' dcmd. A good starting point is to place the following in
+the program:
+
+const char *
+_umem_debug_init(void)
+{
+ return ("default,verbose");
+}
+
+const char *
+_umem_logging_init(void)
+{
+ return ("fail,contents");
+}
+
+For the definition of these flags, see umem_debug(3MALLOC).
+
+In addition, by leveraging umem debugging it becomes very easy to
+simulate malloc failure when required. This can be enabled by calling
+umem_setmtbf(1), which ensures that any subsequent memory requests
+through malloc(), including those made indirectly by libc, will fail. To
+restore the behavior after a test, one can simply call umem_setmtbf(0).
diff --git a/usr/src/lib/libc/port/stdio/_endopen.c b/usr/src/lib/libc/port/stdio/_endopen.c
index a7c4508cbb..fa548f6385 100644
--- a/usr/src/lib/libc/port/stdio/_endopen.c
+++ b/usr/src/lib/libc/port/stdio/_endopen.c
@@ -25,7 +25,7 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
+/* All Rights Reserved */
/* Copyright (c) 2013 OmniTI Computer Consulting, Inc. All rights reserved. */
@@ -60,53 +60,9 @@ _endopen(const char *name, const char *type, FILE *iop, int largefile)
if (iop == NULL)
return (NULL);
- switch (type[0]) {
- default:
- errno = EINVAL;
- return (NULL);
- case 'r':
- oflag = O_RDONLY;
- fflag = _IOREAD;
- break;
- case 'w':
- oflag = O_WRONLY | O_TRUNC | O_CREAT;
- fflag = _IOWRT;
- break;
- case 'a':
- oflag = O_WRONLY | O_APPEND | O_CREAT;
- fflag = _IOWRT;
- break;
- }
- plusflag = 0;
- eflag = 0;
- xflag = 0;
- for (echr = type + 1; *echr != '\0'; echr++) {
- switch (*echr) {
- /* UNIX ignores 'b' and treats text and binary the same */
- default:
- break;
- case '+':
- plusflag = 1;
- break;
- case 'e':
- eflag = 1;
- break;
- case 'x':
- xflag = 1;
- break;
- }
- }
- if (eflag) {
- /* Subsequent to a mode flag, 'e' indicates O_CLOEXEC */
- oflag = oflag | O_CLOEXEC;
- }
- if (plusflag) {
- oflag = (oflag & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
- fflag = _IORW;
- }
- if (xflag) {
- oflag |= O_EXCL;
+ if (_stdio_flags(type, &oflag, &fflag) != 0) {
+ return (NULL);
}
/* select small or large file open based on flag */
@@ -121,21 +77,23 @@ _endopen(const char *name, const char *type, FILE *iop, int largefile)
/* As long as we make sure _flag stays != 0, we don't need to lock */
#ifdef _LP64
iop->_file = fd;
- iop->_flag = (iop->_flag & ~0377) | fflag;
+ iop->_flag = (iop->_flag & ~_DEF_FLAG_MASK) | fflag;
#else
if (fd <= _FILE_FD_MAX) {
SET_FILE(iop, fd);
} else if (_file_set(iop, fd, type) != 0) {
/* errno set in _file_set() */
+ int err = errno;
(void) close(fd);
+ errno = err;
return (NULL);
}
iop->_flag = fflag;
#endif /* _LP64 */
if (oflag == (O_WRONLY | O_APPEND | O_CREAT)) { /* type == "a" */
- if (lseek64(fd, (off64_t)0, SEEK_END) < (off64_t)0) {
- (void) close(fd);
+ if (_xseek64(iop, (off64_t)0, SEEK_END) < (off64_t)0) {
+ (void) _xclose(iop);
return (NULL);
}
}
diff --git a/usr/src/lib/libc/port/stdio/_filbuf.c b/usr/src/lib/libc/port/stdio/_filbuf.c
index 73150feb3a..2accbe1158 100644
--- a/usr/src/lib/libc/port/stdio/_filbuf.c
+++ b/usr/src/lib/libc/port/stdio/_filbuf.c
@@ -25,10 +25,7 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
+/* All Rights Reserved */
#pragma weak __filbuf = _filbuf
@@ -62,24 +59,24 @@ _filbuf(FILE *iop)
unsigned char flag;
#endif
- if (!(iop->_flag & _IOREAD)) /* check, correct permissions */
- {
- if (iop->_flag & _IORW)
- iop->_flag |= _IOREAD; /* change direction */
+ if (!(iop->_flag & _IOREAD)) { /* check, correct permissions */
+ if (iop->_flag & _IORW) {
+ iop->_flag |= _IOREAD; /* change direction */
/* to read - fseek */
- else {
+ } else {
errno = EBADF;
return (EOF);
}
}
if (iop->_base == 0) {
- if ((endbuf = _findbuf(iop)) == 0) /* get buffer and */
- /* end_of_buffer */
+ /* Get the buffer and end of buffer */
+ if ((endbuf = _findbuf(iop)) == 0) {
return (EOF);
- }
- else
+ }
+ } else {
endbuf = _bufend(iop);
+ }
/*
* Flush all line-buffered streams before we
@@ -109,6 +106,7 @@ _filbuf(FILE *iop)
return (EOF);
}
}
+
/*
* Fill buffer or read 1 byte for unbuffered, handling any errors.
*/
@@ -117,7 +115,7 @@ _filbuf(FILE *iop)
nbyte = 1;
else
nbyte = endbuf - iop->_base;
- if ((res = read(GET_FD(iop), (char *)iop->_base, nbyte)) > 0) {
+ if ((res = _xread(iop, (char *)iop->_base, nbyte)) > 0) {
iop->_cnt = res - 1;
return (*iop->_ptr++);
}
diff --git a/usr/src/lib/libc/port/stdio/_findbuf.c b/usr/src/lib/libc/port/stdio/_findbuf.c
index d0c1949e98..e0633c80c6 100644
--- a/usr/src/lib/libc/port/stdio/_findbuf.c
+++ b/usr/src/lib/libc/port/stdio/_findbuf.c
@@ -25,9 +25,11 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
+/* All Rights Reserved */
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2020 Robert Mustacchi
+ */
#define _LARGEFILE64_SOURCE 1
@@ -51,48 +53,47 @@
Uchar *
_findbuf(FILE *iop)
{
- int fd = GET_FD(iop);
+ int fd = _get_fd(iop);
Uchar *buf;
int size = BUFSIZ;
Uchar *endbuf;
int tty = -1;
- struct stat64 stbuf; /* used to get file system block size */
-
- if (iop->_flag & _IONBF) /* need a small buffer, at least */
- {
- trysmall:;
+ if (iop->_flag & _IONBF) { /* need a small buffer, at least */
+ trysmall:
size = _SMBFSZ - PUSHBACK;
- if (fd < _NFILE)
+ if (fd >= 0 && fd < _NFILE) {
buf = _smbuf[fd];
- else if ((buf = (Uchar *)malloc(_SMBFSZ * sizeof (Uchar))) !=
- NULL)
+ } else if ((buf = (Uchar *)malloc(_SMBFSZ * sizeof (Uchar))) !=
+ NULL) {
iop->_flag |= _IOMYBUF;
- }
-#ifndef _STDIO_ALLOCATE
- else if (fd < 2 && (tty = isatty(fd))) {
- buf = (fd == 0) ? _sibuf : _sobuf; /* special buffer */
- /* for std{in,out} */
- }
-#endif
- else {
+ }
+ } else if (fd >= 0 && fd < 2 && (tty = isatty(fd))) {
+ /* Use special buffers for standard in and standard out */
+ buf = (fd == 0) ? _sibuf : _sobuf;
+ } else {
+
/*
- * The operating system can tell us the
- * right size for a buffer;
- * avoid 0-size buffers as returned for some
- * special files (doors)
+ * The operating system can tell us the right size for a buffer;
+ * avoid 0-size buffers as returned for some special files
+ * (doors). Use the default buffer size for memory streams.
*/
- if (fstat64(fd, &stbuf) == 0 && stbuf.st_blksize > 0)
+ struct stat64 stbuf;
+
+ if (fd != -1 && fstat64(fd, &stbuf) == 0 && stbuf.st_blksize >
+ 0) {
size = stbuf.st_blksize;
+ }
if ((buf = (Uchar *)malloc(sizeof (Uchar)*(size+_SMBFSZ))) !=
- NULL)
+ NULL) {
iop->_flag |= _IOMYBUF;
- else
+ } else {
goto trysmall;
+ }
}
if (buf == NULL)
- return (NULL); /* malloc() failed */
+ return (NULL); /* malloc() failed */
iop->_base = buf + PUSHBACK; /* bytes for pushback */
iop->_ptr = buf + PUSHBACK;
endbuf = iop->_base + size;
diff --git a/usr/src/lib/libc/port/stdio/_flsbuf.c b/usr/src/lib/libc/port/stdio/_flsbuf.c
index 234d9fd2c4..81d3b0dc3a 100644
--- a/usr/src/lib/libc/port/stdio/_flsbuf.c
+++ b/usr/src/lib/libc/port/stdio/_flsbuf.c
@@ -25,9 +25,7 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/* All Rights Reserved */
#pragma weak __flsbuf = _flsbuf
@@ -41,17 +39,18 @@
#include <sys/types.h>
#include "stdiom.h"
+/*
+ * flush (write) buffer, save ch,
+ * return EOF on failure
+ */
int
-_flsbuf(int ch, FILE *iop) /* flush (write) buffer, save ch, */
- /* return EOF on failure */
+_flsbuf(int ch, FILE *iop)
{
Uchar uch;
- do /* only loop if need to use _wrtchk() on non-_IOFBF */
- {
+ do { /* only loop if need to use _wrtchk() on non-_IOFBF */
switch (iop->_flag & (_IOFBF | _IOLBF | _IONBF |
- _IOWRT | _IOEOF))
- {
+ _IOWRT | _IOEOF)) {
case _IOFBF | _IOWRT: /* okay to do full-buffered case */
if (iop->_base != 0 && iop->_ptr > iop->_base)
goto flush_putc; /* skip _wrtchk() */
@@ -71,7 +70,7 @@ _flsbuf(int ch, FILE *iop) /* flush (write) buffer, save ch, */
case _IONBF | _IOWRT: /* okay to do no-buffered case */
iop->_cnt = 0;
uch = (unsigned char)ch;
- if (write(GET_FD(iop), (char *)&uch, 1) != 1) {
+ if (_xwrite(iop, (char *)&uch, 1) != 1) {
if (!cancel_active())
iop->_flag |= _IOERR;
return (EOF);
diff --git a/usr/src/lib/libc/port/stdio/_stdio_flags.c b/usr/src/lib/libc/port/stdio/_stdio_flags.c
new file mode 100644
index 0000000000..b54f9051e6
--- /dev/null
+++ b/usr/src/lib/libc/port/stdio/_stdio_flags.c
@@ -0,0 +1,109 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1988 AT&T */
+/* All Rights Reserved */
+
+/* Copyright (c) 2013 OmniTI Computer Consulting, Inc. All rights reserved. */
+/*
+ * Copyright 2020 Robert Mustacchi
+ */
+
+/*
+ * Commonized processing of the 'mode' string for stdio.
+ */
+
+#include "mtlib.h"
+#include "file64.h"
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+int
+_stdio_flags(const char *type, int *oflagsp, int *fflagsp)
+{
+ int oflag, fflag, plusflag, eflag, xflag;
+ const char *echr;
+
+ oflag = fflag = 0;
+ switch (type[0]) {
+ default:
+ errno = EINVAL;
+ return (-1);
+ case 'r':
+ oflag = O_RDONLY;
+ fflag = _IOREAD;
+ break;
+ case 'w':
+ oflag = O_WRONLY | O_TRUNC | O_CREAT;
+ fflag = _IOWRT;
+ break;
+ case 'a':
+ oflag = O_WRONLY | O_APPEND | O_CREAT;
+ fflag = _IOWRT;
+ break;
+ }
+
+ plusflag = 0;
+ eflag = 0;
+ xflag = 0;
+ for (echr = type + 1; *echr != '\0'; echr++) {
+ switch (*echr) {
+ /* UNIX ignores 'b' and treats text and binary the same */
+ default:
+ break;
+ case '+':
+ plusflag = 1;
+ break;
+ case 'e':
+ eflag = 1;
+ break;
+ case 'x':
+ xflag = 1;
+ break;
+ }
+ }
+
+ if (eflag) {
+ /* Subsequent to a mode flag, 'e' indicates O_CLOEXEC */
+ oflag = oflag | O_CLOEXEC;
+ }
+
+ if (plusflag) {
+ oflag = (oflag & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
+ fflag = _IORW;
+ }
+
+ if (xflag) {
+ oflag |= O_EXCL;
+ }
+
+ *oflagsp = oflag;
+ *fflagsp = fflag;
+
+ return (0);
+}
diff --git a/usr/src/lib/libc/port/stdio/doscan.c b/usr/src/lib/libc/port/stdio/doscan.c
index e375d9824f..fda4d5c2ea 100644
--- a/usr/src/lib/libc/port/stdio/doscan.c
+++ b/usr/src/lib/libc/port/stdio/doscan.c
@@ -25,9 +25,7 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/* All Rights Reserved */
#include "lint.h"
#include <sys/types.h>
@@ -402,7 +400,7 @@ charswitch: /* target of a goto 8-( */
if (size == 'l') {
int c, len, i;
int negflg = 0;
- unsigned char *p;
+ unsigned char *p;
p = (unsigned char *)(fmt - 1);
len = 0;
@@ -830,10 +828,10 @@ readchar(FILE *iop, int *chcount)
int inchar;
char buf[1];
- if ((iop->_flag & _IOWRT) || (iop->_cnt != 0))
+ if ((iop->_flag & _IOWRT) || (iop->_cnt != 0)) {
inchar = locgetc((*chcount));
- else {
- if (read(FILENO(iop), buf, 1) != 1)
+ } else {
+ if (_xread(iop, buf, 1) != 1)
return (EOF);
inchar = (int)buf[0];
(*chcount) += 1;
diff --git a/usr/src/lib/libc/port/stdio/fileno.c b/usr/src/lib/libc/port/stdio/fileno.c
index 70f64faa89..4e99438dc9 100644
--- a/usr/src/lib/libc/port/stdio/fileno.c
+++ b/usr/src/lib/libc/port/stdio/fileno.c
@@ -25,9 +25,7 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/* All Rights Reserved */
#pragma weak _fileno = fileno
@@ -43,5 +41,5 @@
int
fileno(FILE *iop)
{
- return (GET_FD(iop));
+ return (_get_fd(iop));
}
diff --git a/usr/src/lib/libc/port/stdio/flush.c b/usr/src/lib/libc/port/stdio/flush.c
index 7d3549ca0d..be710ccb2a 100644
--- a/usr/src/lib/libc/port/stdio/flush.c
+++ b/usr/src/lib/libc/port/stdio/flush.c
@@ -21,10 +21,11 @@
/*
* Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2020 Robert Mustacchi
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
+/* All Rights Reserved */
#include "lint.h"
#include "mtlib.h"
@@ -42,6 +43,8 @@
#include <stddef.h>
#include <errno.h>
#include <fcntl.h>
+#include <sys/debug.h>
+#include <limits.h>
#define _iob __iob
@@ -376,7 +379,8 @@ rescan:
lastlink = *prev = hdr;
fp->_ptr = 0;
fp->_base = 0;
- fp->_flag = 0377; /* claim the fp by setting low 8 bits */
+ /* claim the fp by setting low 8 bits */
+ fp->_flag = _DEF_FLAG_MASK;
if (threaded)
cancel_safe_mutex_unlock(&_first_link_lock);
@@ -387,11 +391,19 @@ static void
isseekable(FILE *iop)
{
struct stat64 fstatbuf;
- int save_errno;
+ int fd, save_errno;
save_errno = errno;
- if (fstat64(GET_FD(iop), &fstatbuf) != 0) {
+ /*
+ * non-FILE based STREAMS are required to declare their own seekability
+ * and therefore we should not try and test them below.
+ */
+ fd = _get_fd(iop);
+ if (fd == -1) {
+ return;
+ }
+ if (fstat64(fd, &fstatbuf) != 0) {
/*
* when we don't know what it is we'll
* do the old behaviour and flush
@@ -545,8 +557,7 @@ _xflsbuf(FILE *iop)
_bufsync(iop, bufend);
if (n > 0) {
- int fd = GET_FD(iop);
- while ((num_wrote = write(fd, base, (size_t)n)) != n) {
+ while ((num_wrote = _xwrite(iop, base, (size_t)n)) != n) {
if (num_wrote <= 0) {
if (!cancel_active())
iop->_flag |= _IOERR;
@@ -600,8 +611,8 @@ _fflush_l_iops(void) /* flush all buffers */
* knowing that when it is 0, it isn't allocated and
* cannot be allocated while we're holding the
* _first_link_lock. And when _IONBF is set (also the
- * case when _flag is 0377, or alloc in progress), we
- * also ignore it.
+ * case when _flag is 0377 -- _DEF_FLAG_MASK, or alloc in
+ * progress), we also ignore it.
*
* Ignore locked streams; it will appear as if
* concurrent updates happened after fflush(NULL). Note
@@ -662,7 +673,7 @@ _fflush_u(FILE *iop)
/* this portion is always assumed locked */
if (!(iop->_flag & _IOWRT)) {
- (void) lseek64(GET_FD(iop), -iop->_cnt, SEEK_CUR);
+ (void) _xseek64(iop, -iop->_cnt, SEEK_CUR);
iop->_cnt = 0;
/* needed for ungetc & multibyte pushbacks */
iop->_ptr = iop->_base;
@@ -700,7 +711,7 @@ fclose(FILE *iop)
/* Is not unbuffered and opened for read and/or write ? */
if (!(iop->_flag & _IONBF) && (iop->_flag & (_IOWRT | _IOREAD | _IORW)))
res = _fflush_u(iop);
- if (close(GET_FD(iop)) < 0)
+ if (_xclose(iop) < 0)
res = EOF;
if (iop->_flag & _IOMYBUF) {
(void) free((char *)iop->_base - PUSHBACK);
@@ -751,7 +762,7 @@ fcloseall(void)
if (!(iop->_flag & _IONBF) &&
(iop->_flag & (_IOWRT | _IOREAD | _IORW)))
(void) _fflush_u(iop);
- (void) close(GET_FD(iop));
+ (void) _xclose(iop);
if (iop->_flag & _IOMYBUF)
free((char *)iop->_base - PUSHBACK);
iop->_base = NULL;
@@ -781,7 +792,7 @@ close_fd(FILE *iop)
/* Is not unbuffered and opened for read and/or write ? */
if (!(iop->_flag & _IONBF) && (iop->_flag & (_IOWRT | _IOREAD | _IORW)))
res = _fflush_u(iop);
- if (close(GET_FD(iop)) < 0)
+ if (_xclose(iop) < 0)
res = EOF;
if (iop->_flag & _IOMYBUF) {
(void) free((char *)iop->_base - PUSHBACK);
@@ -809,7 +820,8 @@ getiop(FILE *fp, rmutex_t *lk, mbstate_t *mb)
fp->_cnt = 0;
fp->_ptr = NULL;
fp->_base = NULL;
- fp->_flag = 0377; /* claim the fp by setting low 8 bits */
+ /* claim the fp by setting low 8 bits */
+ fp->_flag = _DEF_FLAG_MASK;
(void) memset(mb, 0, sizeof (mbstate_t));
FUNLOCKFILE(lk);
return (fp);
@@ -943,3 +955,164 @@ enable_extended_FILE_stdio(int fd, int action)
return (0);
}
#endif
+
+/*
+ * Wrappers around the various system calls that stdio needs to make on a file
+ * descriptor.
+ */
+static stdio_ops_t *
+get_stdops(FILE *iop)
+{
+#ifdef _LP64
+ return (iop->_ops);
+#else
+ struct xFILEdata *dat = getxfdat(iop);
+ return (dat->_ops);
+#endif
+}
+
+static void
+set_stdops(FILE *iop, stdio_ops_t *ops)
+{
+#ifdef _LP64
+ ASSERT3P(iop->_ops, ==, NULL);
+ iop->_ops = ops;
+#else
+ struct xFILEdata *dat = getxfdat(iop);
+ ASSERT3P(dat->_ops, ==, NULL);
+ dat->_ops = ops;
+#endif
+
+}
+
+ssize_t
+_xread(FILE *iop, void *buf, size_t nbytes)
+{
+ stdio_ops_t *ops = get_stdops(iop);
+ if (ops != NULL) {
+ return (ops->std_read(iop, buf, nbytes));
+ }
+
+ return (read(_get_fd(iop), buf, nbytes));
+}
+
+ssize_t
+_xwrite(FILE *iop, const void *buf, size_t nbytes)
+{
+ stdio_ops_t *ops = get_stdops(iop);
+ if (ops != NULL) {
+ return (ops->std_write(iop, buf, nbytes));
+ }
+ return (write(_get_fd(iop), buf, nbytes));
+}
+
+off_t
+_xseek(FILE *iop, off_t off, int whence)
+{
+ stdio_ops_t *ops = get_stdops(iop);
+ if (ops != NULL) {
+ return (ops->std_seek(iop, off, whence));
+ }
+
+ return (lseek(_get_fd(iop), off, whence));
+}
+
+off64_t
+_xseek64(FILE *iop, off64_t off, int whence)
+{
+ stdio_ops_t *ops = get_stdops(iop);
+ if (ops != NULL) {
+ /*
+ * The internal APIs only operate with an off_t. An off64_t in
+ * an ILP32 environment may represent a value larger than they
+ * can accept. As such, we try and catch such cases and error
+ * about it before we get there.
+ */
+ if (off > LONG_MAX || off < LONG_MIN) {
+ errno = EOVERFLOW;
+ return (-1);
+ }
+ return (ops->std_seek(iop, off, whence));
+ }
+
+ return (lseek64(_get_fd(iop), off, whence));
+}
+
+int
+_xclose(FILE *iop)
+{
+ stdio_ops_t *ops = get_stdops(iop);
+ if (ops != NULL) {
+ return (ops->std_close(iop));
+ }
+
+ return (close(_get_fd(iop)));
+}
+
+void *
+_xdata(FILE *iop)
+{
+ stdio_ops_t *ops = get_stdops(iop);
+ if (ops != NULL) {
+ return (ops->std_data);
+ }
+
+ return (NULL);
+}
+
+int
+_xassoc(FILE *iop, fread_t readf, fwrite_t writef, fseek_t seekf,
+ fclose_t closef, void *data)
+{
+ stdio_ops_t *ops = get_stdops(iop);
+
+ if (ops == NULL) {
+ ops = malloc(sizeof (*ops));
+ if (ops == NULL) {
+ return (-1);
+ }
+ set_stdops(iop, ops);
+ }
+
+ ops->std_read = readf;
+ ops->std_write = writef;
+ ops->std_seek = seekf;
+ ops->std_close = closef;
+ ops->std_data = data;
+
+ return (0);
+}
+
+void
+_xunassoc(FILE *iop)
+{
+ stdio_ops_t *ops = get_stdops(iop);
+ if (ops == NULL) {
+ return;
+ }
+ set_stdops(iop, NULL);
+ free(ops);
+}
+
+int
+_get_fd(FILE *iop)
+{
+ /*
+ * Streams with an ops vector (currently the memory stream family) do
+ * not have an underlying file descriptor that we can give back to the
+ * user. In such cases, return -1 to explicitly make sure that they'll
+ * get an ebadf from things.
+ */
+ if (get_stdops(iop) != NULL) {
+ return (-1);
+ }
+#ifdef _LP64
+ return (iop->_file);
+#else
+ if (iop->__extendedfd) {
+ return (_file_get(iop));
+ } else {
+ return (iop->_magic);
+ }
+#endif
+}
diff --git a/usr/src/lib/libc/port/stdio/fmemopen.c b/usr/src/lib/libc/port/stdio/fmemopen.c
new file mode 100644
index 0000000000..e2321c9632
--- /dev/null
+++ b/usr/src/lib/libc/port/stdio/fmemopen.c
@@ -0,0 +1,270 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2020 Robert Mustacchi
+ */
+
+/*
+ * Implements fmemopen(3C).
+ */
+
+#include "mtlib.h"
+#include "file64.h"
+#include <stdio.h>
+#include "stdiom.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/sysmacros.h>
+#include <limits.h>
+
+typedef enum fmemopen_flags {
+ /*
+ * Indicates that the user gave us the buffer and so we shouldn't free
+ * it.
+ */
+ FMO_F_USER_BUFFER = 1 << 0,
+ /*
+ * When the stream is open for update (a, a+) then we have to have
+ * slightly different behavior on write and zeroing the buffer.
+ */
+ FMO_F_APPEND = 1 << 1
+} fmemopen_flags_t;
+
+typedef struct fmemopen {
+ /*
+ * Pointer to the underlying memory stream.
+ */
+ char *fmo_buf;
+ /*
+ * Allocated length of the buffer.
+ */
+ size_t fmo_alloc;
+ /*
+ * Current position of the buffer.
+ */
+ size_t fmo_pos;
+ /*
+ * Current 'size' of the buffer. POSIX describes a size that the buffer
+ * has which is separate from the allocated size, but cannot exceed it.
+ */
+ size_t fmo_lsize;
+ fmemopen_flags_t fmo_flags;
+} fmemopen_t;
+
+static ssize_t
+fmemopen_read(FILE *iop, char *buf, size_t nbytes)
+{
+ fmemopen_t *fmp = _xdata(iop);
+
+ nbytes = MIN(nbytes, fmp->fmo_lsize - fmp->fmo_pos);
+ if (nbytes == 0) {
+ return (0);
+ }
+
+ (void) memcpy(buf, fmp->fmo_buf, nbytes);
+ fmp->fmo_pos += nbytes;
+
+ return (nbytes);
+}
+
+static ssize_t
+fmemopen_write(FILE *iop, const char *buf, size_t nbytes)
+{
+ size_t npos;
+ fmemopen_t *fmp = _xdata(iop);
+
+ if ((fmp->fmo_flags & FMO_F_APPEND) != 0) {
+ /*
+ * POSIX says that if append mode is in effect, we must always
+ * seek to the logical size. This effectively is mimicking the
+ * O_APPEND behavior.
+ */
+ fmp->fmo_pos = fmp->fmo_lsize;
+ }
+
+ if (nbytes == 0) {
+ return (0);
+ } else if (nbytes >= SSIZE_MAX) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ npos = fmp->fmo_pos + nbytes;
+ if (npos < nbytes) {
+ errno = EOVERFLOW;
+ return (-1);
+ } else if (npos > fmp->fmo_alloc) {
+ nbytes = fmp->fmo_alloc - fmp->fmo_pos;
+ }
+
+ (void) memcpy(&fmp->fmo_buf[fmp->fmo_pos], buf, nbytes);
+ fmp->fmo_pos += nbytes;
+
+ if (fmp->fmo_pos > fmp->fmo_lsize) {
+ fmp->fmo_lsize = fmp->fmo_pos;
+
+ /*
+ * POSIX distinguishes behavior for writing a NUL in these
+ * streams. Basically if we are open for update and we are at
+ * the end of the buffer, we don't place a NUL. Otherwise, we
+ * always place one at the current position (or the end if we
+ * were over the edge).
+ */
+ if (fmp->fmo_lsize < fmp->fmo_alloc) {
+ fmp->fmo_buf[fmp->fmo_lsize] = '\0';
+ } else if ((fmp->fmo_flags & FMO_F_APPEND) == 0) {
+ fmp->fmo_buf[fmp->fmo_alloc - 1] = '\0';
+ }
+ }
+
+ return (nbytes);
+}
+
+static off_t
+fmemopen_seek(FILE *iop, off_t off, int whence)
+{
+ fmemopen_t *fmp = _xdata(iop);
+ size_t base, npos;
+
+ switch (whence) {
+ case SEEK_SET:
+ base = 0;
+ break;
+ case SEEK_CUR:
+ base = fmp->fmo_pos;
+ break;
+ case SEEK_END:
+ base = fmp->fmo_lsize;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (!memstream_seek(base, off, fmp->fmo_alloc, &npos)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ fmp->fmo_pos = npos;
+
+ return ((off_t)fmp->fmo_pos);
+}
+
+static void
+fmemopen_free(fmemopen_t *fmp)
+{
+ if (fmp->fmo_buf != NULL &&
+ (fmp->fmo_flags & FMO_F_USER_BUFFER) == 0) {
+ free(fmp->fmo_buf);
+ }
+
+ free(fmp);
+}
+
+static int
+fmemopen_close(FILE *iop)
+{
+ fmemopen_t *fmp = _xdata(iop);
+ fmemopen_free(fmp);
+ _xunassoc(iop);
+ return (0);
+}
+
+FILE *
+fmemopen(void *_RESTRICT_KYWD buf, size_t size,
+ const char *_RESTRICT_KYWD mode)
+{
+ int oflags, fflags, err;
+ fmemopen_t *fmp;
+ FILE *iop;
+
+ if (size == 0 || mode == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if (_stdio_flags(mode, &oflags, &fflags) != 0) {
+ /* errno set for us */
+ return (NULL);
+ }
+
+ /*
+ * buf is only allowed to be NULL if the '+' is specified. If the '+'
+ * mode was specified, then we'll have fflags set to _IORW.
+ */
+ if (buf == NULL && fflags != _IORW) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if ((fmp = calloc(1, sizeof (fmemopen_t))) == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+
+ if (buf == NULL) {
+ fmp->fmo_buf = calloc(size, sizeof (uint8_t));
+ if (fmp->fmo_buf == NULL) {
+ errno = ENOMEM;
+ goto cleanup;
+ }
+ } else {
+ fmp->fmo_buf = buf;
+ fmp->fmo_flags |= FMO_F_USER_BUFFER;
+ }
+
+ fmp->fmo_alloc = size;
+
+ /*
+ * Set the initial logical size and position depending on whether we're
+ * using r(+), w(+), and a(+). The latter two are identified by O_TRUNC
+ * and O_APPEND in oflags.
+ */
+ if ((oflags & O_APPEND) != 0) {
+ fmp->fmo_pos = strnlen(fmp->fmo_buf, fmp->fmo_alloc);
+ fmp->fmo_lsize = fmp->fmo_pos;
+ fmp->fmo_flags |= FMO_F_APPEND;
+ } else if ((oflags & O_TRUNC) != 0) {
+ fmp->fmo_buf[0] = '\0';
+ fmp->fmo_pos = 0;
+ fmp->fmo_lsize = 0;
+ } else {
+ fmp->fmo_pos = 0;
+ fmp->fmo_lsize = size;
+ }
+
+ iop = _findiop();
+ if (iop == NULL) {
+ goto cleanup;
+ }
+
+#ifdef _LP64
+ iop->_flag = (iop->_flag & ~_DEF_FLAG_MASK) | fflags;
+#else
+ iop->_flag = fflags;
+#endif
+ if (_xassoc(iop, fmemopen_read, fmemopen_write, fmemopen_seek,
+ fmemopen_close, fmp) != 0) {
+ goto cleanup;
+ }
+
+ SET_SEEKABLE(iop);
+
+ return (iop);
+
+cleanup:
+ err = errno;
+ fmemopen_free(fmp);
+ errno = err;
+ return (NULL);
+}
diff --git a/usr/src/lib/libc/port/stdio/fopen.c b/usr/src/lib/libc/port/stdio/fopen.c
index eea8093aca..728a0f4978 100644
--- a/usr/src/lib/libc/port/stdio/fopen.c
+++ b/usr/src/lib/libc/port/stdio/fopen.c
@@ -25,7 +25,7 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
+/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
@@ -37,7 +37,9 @@
* contributors.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2020 Robert Mustacchi
+ */
#include "lint.h"
#include "file64.h"
@@ -88,6 +90,17 @@ _freopen_null(const char *type, FILE *iop)
return (NULL);
}
+ /*
+ * If this is not a file-based stream (as in we have no file
+ * descriptor), then we need to close this, but still actually return an
+ * error.
+ */
+ if (_get_fd(iop) == -1) {
+ (void) close_fd(iop);
+ errno = EBADF;
+ return (NULL);
+ }
+
if (!(iop->_flag & _IONBF) && (iop->_flag & (_IOWRT | _IOREAD | _IORW)))
(void) _fflush_u(iop);
@@ -140,7 +153,7 @@ _freopen_null(const char *type, FILE *iop)
}
#ifdef _LP64
- iop->_flag &= ~0377; /* clear lower 8-bits */
+ iop->_flag &= ~_DEF_FLAG_MASK; /* clear lower 8-bits */
if (mode == 'r') {
iop->_flag |= _IOREAD;
nflag = oflag & ~O_APPEND;
diff --git a/usr/src/lib/libc/port/stdio/fputs.c b/usr/src/lib/libc/port/stdio/fputs.c
index be0f5b4f8f..46b0d87107 100644
--- a/usr/src/lib/libc/port/stdio/fputs.c
+++ b/usr/src/lib/libc/port/stdio/fputs.c
@@ -25,10 +25,7 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
+/* All Rights Reserved */
/*
* Ptr args aren't checked for NULL because the program would be a
@@ -112,15 +109,13 @@ fputs(const char *ptr, FILE *iop)
return (EOF);
}
}
- }
- else
- {
+ } else {
/* write out to an unbuffered file */
ssize_t num_wrote;
ssize_t count = (ssize_t)ptrlen;
- int fd = GET_FD(iop);
- while ((num_wrote = write(fd, ptr, (size_t)count)) != count) {
+ while ((num_wrote = _xwrite(iop, ptr, (size_t)count)) !=
+ count) {
if (num_wrote <= 0) {
if (!cancel_active())
iop->_flag |= _IOERR;
diff --git a/usr/src/lib/libc/port/stdio/fseek.c b/usr/src/lib/libc/port/stdio/fseek.c
index 55017a6584..01ef4c4c00 100644
--- a/usr/src/lib/libc/port/stdio/fseek.c
+++ b/usr/src/lib/libc/port/stdio/fseek.c
@@ -25,9 +25,7 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/* All Rights Reserved */
/*
* Seek for standard library. Coordinates with buffering.
@@ -76,7 +74,7 @@ fseek(FILE *iop, long offset, int ptrname)
if (iop->_flag & _IORW) {
iop->_flag &= ~(_IOREAD | _IOWRT);
}
- p = lseek(FILENO(iop), (off_t)offset, ptrname);
+ p = _xseek(iop, (off_t)offset, ptrname);
FUNLOCKFILE(lk);
return ((p == (off_t)-1) ? -1: 0);
}
diff --git a/usr/src/lib/libc/port/stdio/fseeko.c b/usr/src/lib/libc/port/stdio/fseeko.c
index b47c7a5313..2af3fdf532 100644
--- a/usr/src/lib/libc/port/stdio/fseeko.c
+++ b/usr/src/lib/libc/port/stdio/fseeko.c
@@ -25,9 +25,7 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/* All Rights Reserved */
/*
* Seek for standard library. Coordinates with buffering.
@@ -83,7 +81,7 @@ fseeko64(FILE *iop, off64_t offset, int ptrname)
if (iop->_flag & _IORW) {
iop->_flag &= ~(_IOREAD | _IOWRT);
}
- p = lseek64(FILENO(iop), offset, ptrname);
+ p = _xseek64(iop, offset, ptrname);
FUNLOCKFILE(lk);
return ((p == -1)? -1: 0);
}
diff --git a/usr/src/lib/libc/port/stdio/ftell.c b/usr/src/lib/libc/port/stdio/ftell.c
index 45c0b841d6..dae2abea03 100644
--- a/usr/src/lib/libc/port/stdio/ftell.c
+++ b/usr/src/lib/libc/port/stdio/ftell.c
@@ -25,9 +25,7 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/* All Rights Reserved */
/*
* Return file offset.
@@ -49,41 +47,63 @@
#include <sys/types.h>
#include "stdiom.h"
-long
-ftell(FILE *iop)
+off64_t
+ftell_common(FILE *iop)
{
ptrdiff_t adjust;
off64_t tres;
rmutex_t *lk;
FLOCKFILE(lk, iop);
+
+ /*
+ * If we're dealing with a memory stream, we need to flush the internal
+ * state before we try and determine the location. This is especially
+ * important for open_wmemstream() as it will have buffered bytes, but
+ * we need to convert that to wide characters before we proceed. If we
+ * have no file descriptor, then the units that the backing store are in
+ * can be arbitrary.
+ */
+ if (_get_fd(iop) == -1) {
+ (void) _fflush_u(iop);
+ }
+
if (iop->_cnt < 0)
iop->_cnt = 0;
- if (iop->_flag & _IOREAD)
+ if (iop->_flag & _IOREAD) {
adjust = (ptrdiff_t)-iop->_cnt;
- else if (iop->_flag & (_IOWRT | _IORW)) {
+ } else if (iop->_flag & (_IOWRT | _IORW)) {
adjust = 0;
if (((iop->_flag & (_IOWRT | _IONBF)) == _IOWRT) &&
- (iop->_base != 0))
+ (iop->_base != 0)) {
adjust = iop->_ptr - iop->_base;
- else if ((iop->_flag & _IORW) && (iop->_base != 0))
+ } else if ((iop->_flag & _IORW) && (iop->_base != 0)) {
adjust = (ptrdiff_t)-iop->_cnt;
+ }
} else {
errno = EBADF; /* file descriptor refers to no open file */
FUNLOCKFILE(lk);
return (EOF);
}
- tres = lseek64(FILENO(iop), 0, SEEK_CUR);
+ tres = _xseek64(iop, 0, SEEK_CUR);
if (tres >= 0)
tres += adjust;
+ FUNLOCKFILE(lk);
+ return ((long)tres);
+}
+
+long
+ftell(FILE *iop)
+{
+ off64_t tres;
+
+ tres = ftell_common(iop);
if (tres > LONG_MAX) {
errno = EOVERFLOW;
- FUNLOCKFILE(lk);
return (EOF);
}
- FUNLOCKFILE(lk);
return ((long)tres);
}
diff --git a/usr/src/lib/libc/port/stdio/ftello.c b/usr/src/lib/libc/port/stdio/ftello.c
index 2eafdf1fef..cd43037ab1 100644
--- a/usr/src/lib/libc/port/stdio/ftello.c
+++ b/usr/src/lib/libc/port/stdio/ftello.c
@@ -25,9 +25,7 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/* All Rights Reserved */
/*
* Return file offset.
@@ -60,30 +58,7 @@
off64_t
ftello64(FILE *iop)
{
- ptrdiff_t adjust;
- off64_t tres;
- rmutex_t *lk;
-
- FLOCKFILE(lk, iop);
- if (iop->_cnt < 0)
- iop->_cnt = 0;
- if (iop->_flag & _IOREAD)
- adjust = (ptrdiff_t)-iop->_cnt;
- else if (iop->_flag & (_IOWRT | _IORW)) {
- adjust = 0;
- if (((iop->_flag & (_IOWRT | _IONBF)) == _IOWRT) &&
- (iop->_base != 0))
- adjust = iop->_ptr - iop->_base;
- } else {
- errno = EBADF; /* file descriptor refers to no open file */
- FUNLOCKFILE(lk);
- return ((off64_t)EOF);
- }
- tres = lseek64(FILENO(iop), 0, SEEK_CUR);
- if (tres >= 0)
- tres += (off64_t)adjust;
- FUNLOCKFILE(lk);
- return (tres);
+ return (ftell_common(iop));
}
#endif /* _LP64 */
diff --git a/usr/src/lib/libc/port/stdio/fwrite.c b/usr/src/lib/libc/port/stdio/fwrite.c
index db5928f9f4..070354f24b 100644
--- a/usr/src/lib/libc/port/stdio/fwrite.c
+++ b/usr/src/lib/libc/port/stdio/fwrite.c
@@ -25,9 +25,7 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/* All Rights Reserved */
#include "lint.h"
#include "file64.h"
@@ -108,9 +106,9 @@ _fwrite_unlocked(const void *ptr, size_t size, size_t count, FILE *iop)
bytes = iop->_ptr - iop->_base;
data = (char *)iop->_base;
- while ((n = write(fileno(iop), data, (size_t)bytes))
- != bytes) {
- if (n == -1) {
+ while ((n = _xwrite(iop, data, (size_t)bytes)) !=
+ bytes) {
+ if (n <= 0) {
if (!cancel_active())
iop->_flag |= _IOERR;
return (0);
@@ -126,8 +124,8 @@ _fwrite_unlocked(const void *ptr, size_t size, size_t count, FILE *iop)
* written is in bytes until the return.
* Then it is divided by size to produce items.
*/
- while ((n = write(fileno(iop), dptr, s)) != s) {
- if (n == -1) {
+ while ((n = _xwrite(iop, dptr, s)) != s) {
+ if (n <= 0) {
if (!cancel_active())
iop->_flag |= _IOERR;
return (written / size);
diff --git a/usr/src/lib/libc/port/stdio/getc.c b/usr/src/lib/libc/port/stdio/getc.c
index cfcf53f347..b7a48b7f3a 100644
--- a/usr/src/lib/libc/port/stdio/getc.c
+++ b/usr/src/lib/libc/port/stdio/getc.c
@@ -25,9 +25,7 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/* All Rights Reserved */
#pragma weak _getc_unlocked = getc_unlocked
@@ -51,10 +49,7 @@ getc(FILE *iop)
int c;
FLOCKFILE(lk, iop);
-
- _SET_ORIENTATION_BYTE(iop);
-
- c = (--iop->_cnt < 0) ? __filbuf(iop) : *iop->_ptr++;
+ c = getc_unlocked(iop);
FUNLOCKFILE(lk);
return (c);
}
@@ -63,5 +58,12 @@ getc(FILE *iop)
int
getc_unlocked(FILE *iop)
{
+ _SET_ORIENTATION_BYTE(iop);
+ return ((--iop->_cnt < 0) ? __filbuf(iop) : *iop->_ptr++);
+}
+
+int
+_getc_internal(FILE *iop)
+{
return ((--iop->_cnt < 0) ? __filbuf(iop) : *iop->_ptr++);
}
diff --git a/usr/src/lib/libc/port/stdio/getw.c b/usr/src/lib/libc/port/stdio/getw.c
index cca7732a00..9c81e8cea9 100644
--- a/usr/src/lib/libc/port/stdio/getw.c
+++ b/usr/src/lib/libc/port/stdio/getw.c
@@ -25,9 +25,7 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/* All Rights Reserved */
/*
* The intent here is to provide a means to make the order of
@@ -57,7 +55,7 @@ getw(FILE *stream)
FLOCKFILE(lk, stream);
while (--i >= 0 && !(stream->_flag & (_IOERR | _IOEOF)))
- *s++ = GETC(stream);
+ *s++ = getc_unlocked(stream);
ret = ((stream->_flag & (_IOERR | _IOEOF)) ? EOF : w);
FUNLOCKFILE(lk);
return (ret);
diff --git a/usr/src/lib/libc/port/stdio/open_memstream.c b/usr/src/lib/libc/port/stdio/open_memstream.c
new file mode 100644
index 0000000000..a841f44fb5
--- /dev/null
+++ b/usr/src/lib/libc/port/stdio/open_memstream.c
@@ -0,0 +1,263 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2020 Robert Mustacchi
+ */
+
+/*
+ * Implements open_memstream(3C).
+ */
+
+#include "mtlib.h"
+#include "file64.h"
+#include <stdio.h>
+#include "stdiom.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/sysmacros.h>
+#include <limits.h>
+
+typedef struct memstream {
+ char *mstr_buf;
+ size_t mstr_alloc;
+ size_t mstr_pos;
+ size_t mstr_lsize;
+ char **mstr_ubufp;
+ size_t *mstr_usizep;
+} memstream_t;
+
+/*
+ * Common seek and overflow detection logic for the memory stream family of
+ * functions (open_memstream, open_wmemstream, etc.). We need to validate
+ * several things:
+ *
+ * - That the offset when applied to base doesn't cause an over or underflow.
+ * - That the resulting offset is positive (done implicitly with the above)
+ * - That the resulting offset does not exceed an off_t's maximum size.
+ * Unfortunately the kernel doesn't export an OFF_MAX value to userland, so
+ * we have to know that it will always be equivalent to the environment's
+ * long. This is designed with the assumption that in an ILP32 environment we
+ * care about an off_t and not an off64_t. In cases where an off64_t is
+ * valid, we still have to fit inside of the size_t constraints.
+ *
+ * We check for each of the cases and only perform unsigned arithmetic to verify
+ * that we have defined behavior.
+ */
+boolean_t
+memstream_seek(size_t base, off_t off, size_t max, size_t *nposp)
+{
+ size_t npos;
+
+ npos = base + (size_t)off;
+ if (off >= 0 && npos < base) {
+ return (B_FALSE);
+ }
+
+ if (off >= 0 && npos > LONG_MAX) {
+ return (B_FALSE);
+ }
+
+ if (off < 0 && npos >= base) {
+ return (B_FALSE);
+ }
+
+ if (npos > max) {
+ return (B_FALSE);
+ }
+
+ *nposp = npos;
+ return (B_TRUE);
+}
+
+int
+memstream_newsize(size_t pos, size_t alloc, size_t nbytes, size_t *nallocp)
+{
+ size_t npos = pos + nbytes + 1;
+ if (npos < pos) {
+ /*
+ * We've been asked to write a number of bytes that would result
+ * in an overflow in the position. This means the stream would
+ * need to allocate all of memory, that's impractical.
+ */
+ errno = EOVERFLOW;
+ return (-1);
+ }
+
+ /*
+ * If the new position is beyond the allocated amount, grow the array to
+ * a practical amount.
+ */
+ if (npos > alloc) {
+ size_t newalloc = P2ROUNDUP(npos, BUFSIZ);
+ if (newalloc < npos) {
+ errno = EOVERFLOW;
+ return (-1);
+ }
+ *nallocp = newalloc;
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * The SUSv4 spec says that this should not support reads.
+ */
+static ssize_t
+open_memstream_read(FILE *iop, char *buf, size_t nbytes)
+{
+ errno = EBADF;
+ return (-1);
+}
+
+static ssize_t
+open_memstream_write(FILE *iop, const char *buf, size_t nbytes)
+{
+ memstream_t *memp = _xdata(iop);
+ size_t newsize;
+ int ret;
+
+ /*
+ * We need to fit inside of an ssize_t, so we need to first constrain
+ * nbytes to a reasonable value.
+ */
+ nbytes = MIN(nbytes, SSIZE_MAX);
+ ret = memstream_newsize(memp->mstr_pos, memp->mstr_alloc, nbytes,
+ &newsize);
+ if (ret < 0) {
+ return (-1);
+ } else if (ret > 0) {
+ void *temp;
+ temp = recallocarray(memp->mstr_buf, memp->mstr_alloc,
+ newsize, sizeof (char));
+ if (temp == NULL) {
+ return (-1);
+ }
+ memp->mstr_buf = temp;
+ memp->mstr_alloc = newsize;
+ *memp->mstr_ubufp = temp;
+ }
+
+ (void) memcpy(&memp->mstr_buf[memp->mstr_pos], buf, nbytes);
+ memp->mstr_pos += nbytes;
+
+ if (memp->mstr_pos > memp->mstr_lsize) {
+ memp->mstr_lsize = memp->mstr_pos;
+ memp->mstr_buf[memp->mstr_pos] = '\0';
+ }
+ *memp->mstr_usizep = MIN(memp->mstr_pos, memp->mstr_lsize);
+
+ return (nbytes);
+}
+
+static off_t
+open_memstream_seek(FILE *iop, off_t off, int whence)
+{
+ memstream_t *memp = _xdata(iop);
+ size_t base, npos;
+
+ switch (whence) {
+ case SEEK_SET:
+ base = 0;
+ break;
+ case SEEK_CUR:
+ base = memp->mstr_pos;
+ break;
+ case SEEK_END:
+ base = memp->mstr_lsize;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (!memstream_seek(base, off, SSIZE_MAX, &npos)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ memp->mstr_pos = npos;
+ *memp->mstr_usizep = MIN(memp->mstr_pos, memp->mstr_lsize);
+
+ return ((off_t)memp->mstr_pos);
+}
+
+static int
+open_memstream_close(FILE *iop)
+{
+ memstream_t *memp = _xdata(iop);
+ free(memp);
+ _xunassoc(iop);
+ return (0);
+}
+
+FILE *
+open_memstream(char **bufp, size_t *sizep)
+{
+ int err;
+ FILE *iop;
+ memstream_t *memp;
+
+ if (bufp == NULL || sizep == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ memp = calloc(1, sizeof (memstream_t));
+ if (memp == NULL) {
+ return (NULL);
+ }
+
+ memp->mstr_alloc = BUFSIZ;
+ memp->mstr_buf = calloc(memp->mstr_alloc, sizeof (char));
+ if (memp->mstr_buf == NULL) {
+ goto cleanup;
+ }
+ memp->mstr_buf[0] = '\0';
+ memp->mstr_pos = 0;
+ memp->mstr_lsize = 0;
+ memp->mstr_ubufp = bufp;
+ memp->mstr_usizep = sizep;
+
+ iop = _findiop();
+ if (iop == NULL) {
+ goto cleanup;
+ }
+
+#ifdef _LP64
+ iop->_flag = (iop->_flag & ~_DEF_FLAG_MASK) | _IOWRT;
+#else
+ iop->_flag = _IOWRT;
+#endif
+
+ /*
+ * Update the user pointers now, in case a call to fflush() happens
+ * immediately.
+ */
+
+ if (_xassoc(iop, open_memstream_read, open_memstream_write,
+ open_memstream_seek, open_memstream_close, memp) != 0) {
+ goto cleanup;
+ }
+ _setorientation(iop, _BYTE_MODE);
+ SET_SEEKABLE(iop);
+
+ *memp->mstr_ubufp = memp->mstr_buf;
+ *memp->mstr_usizep = MIN(memp->mstr_pos, memp->mstr_lsize);
+
+ return (iop);
+
+cleanup:
+ free(memp->mstr_buf);
+ free(memp);
+ return (NULL);
+}
diff --git a/usr/src/lib/libc/port/stdio/open_wmemstream.c b/usr/src/lib/libc/port/stdio/open_wmemstream.c
new file mode 100644
index 0000000000..d46c5e34ce
--- /dev/null
+++ b/usr/src/lib/libc/port/stdio/open_wmemstream.c
@@ -0,0 +1,225 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2020 Robert Mustacchi
+ */
+
+/*
+ * Implements open_wmemstream(3C).
+ */
+
+#include "mtlib.h"
+#include "file64.h"
+#include <stdio.h>
+#include "stdiom.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/sysmacros.h>
+#include <limits.h>
+#include "libc.h"
+
+typedef struct wmemstream {
+ wchar_t *wmstr_buf;
+ size_t wmstr_alloc;
+ size_t wmstr_pos;
+ size_t wmstr_lsize;
+ mbstate_t wmstr_mbs;
+ wchar_t **wmstr_ubufp;
+ size_t *wmstr_usizep;
+} wmemstream_t;
+
+#define WMEMSTREAM_MAX (SSIZE_MAX / sizeof (wchar_t))
+
+/*
+ * The SUSv4 spec says that this should not support reads.
+ */
+static ssize_t
+open_wmemstream_read(FILE *iop, char *buf, size_t nbytes)
+{
+ errno = EBADF;
+ return (-1);
+}
+
+static ssize_t
+open_wmemstream_write(FILE *iop, const char *buf, size_t nbytes)
+{
+ wmemstream_t *wmemp = _xdata(iop);
+ size_t newsize, mbscount;
+ ssize_t nwritten = 0;
+ int ret;
+
+ /*
+ * nbytes is in bytes not wide characters. However, the most
+ * pathological case from a writing perspective is using ASCII
+ * characters. Thus if we size things assuming that nbytes will all
+ * possibly be valid wchar_t values on their own, then we'll always have
+ * enough buffer space.
+ */
+ nbytes = MIN(nbytes, WMEMSTREAM_MAX);
+ ret = memstream_newsize(wmemp->wmstr_pos, wmemp->wmstr_alloc, nbytes,
+ &newsize);
+ if (ret < 0) {
+ return (-1);
+ } else if (ret > 0) {
+ void *temp;
+ temp = recallocarray(wmemp->wmstr_buf, wmemp->wmstr_alloc,
+ newsize, sizeof (wchar_t));
+ if (temp == NULL) {
+ return (-1);
+ }
+ wmemp->wmstr_buf = temp;
+ wmemp->wmstr_alloc = newsize;
+ *wmemp->wmstr_ubufp = temp;
+
+ }
+
+ while (nbytes > 0) {
+ size_t nchars;
+
+ nchars = mbrtowc_nz(&wmemp->wmstr_buf[wmemp->wmstr_pos],
+ &buf[nwritten], nbytes, &wmemp->wmstr_mbs);
+ if (nchars == (size_t)-1) {
+ if (nwritten > 0) {
+ errno = 0;
+ break;
+ } else {
+ /*
+ * Overwrite errno in this case to be EIO. Most
+ * callers of stdio routines don't expect
+ * EILSEQ and it's not documented in POSIX, so
+ * we use this instead.
+ */
+ errno = EIO;
+ return (-1);
+ }
+ } else if (nchars == (size_t)-2) {
+ nwritten += nbytes;
+ nbytes = 0;
+ } else {
+ nwritten += nchars;
+ nbytes -= nchars;
+ wmemp->wmstr_pos++;
+ }
+ }
+
+ if (wmemp->wmstr_pos > wmemp->wmstr_lsize) {
+ wmemp->wmstr_lsize = wmemp->wmstr_pos;
+ wmemp->wmstr_buf[wmemp->wmstr_pos] = L'\0';
+ }
+ *wmemp->wmstr_usizep = MIN(wmemp->wmstr_pos, wmemp->wmstr_lsize);
+ return (nwritten);
+}
+
+static off_t
+open_wmemstream_seek(FILE *iop, off_t off, int whence)
+{
+ wmemstream_t *wmemp = _xdata(iop);
+ size_t base, npos;
+
+ switch (whence) {
+ case SEEK_SET:
+ base = 0;
+ break;
+ case SEEK_CUR:
+ base = wmemp->wmstr_pos;
+ break;
+ case SEEK_END:
+ base = wmemp->wmstr_lsize;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (!memstream_seek(base, off, WMEMSTREAM_MAX, &npos)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ wmemp->wmstr_pos = npos;
+ *wmemp->wmstr_usizep = MIN(wmemp->wmstr_pos, wmemp->wmstr_lsize);
+
+ return ((off_t)wmemp->wmstr_pos);
+}
+
+static int
+open_wmemstream_close(FILE *iop)
+{
+ wmemstream_t *wmemp = _xdata(iop);
+ free(wmemp);
+ _xunassoc(iop);
+ return (0);
+}
+
+
+FILE *
+open_wmemstream(wchar_t **bufp, size_t *sizep)
+{
+ int err;
+ FILE *iop;
+ wmemstream_t *wmemp;
+
+ if (bufp == NULL || sizep == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ wmemp = calloc(1, sizeof (wmemstream_t));
+ if (wmemp == NULL) {
+ return (NULL);
+ }
+
+ wmemp->wmstr_alloc = BUFSIZ;
+ wmemp->wmstr_buf = calloc(wmemp->wmstr_alloc, sizeof (wchar_t));
+ if (wmemp->wmstr_buf == NULL) {
+ goto cleanup;
+ }
+ wmemp->wmstr_buf[0] = L'\0';
+ wmemp->wmstr_pos = 0;
+ wmemp->wmstr_lsize = 0;
+ wmemp->wmstr_ubufp = bufp;
+ wmemp->wmstr_usizep = sizep;
+
+ iop = _findiop();
+ if (iop == NULL) {
+ goto cleanup;
+ }
+
+#ifdef _LP64
+ iop->_flag = (iop->_flag & ~_DEF_FLAG_MASK) | _IOWRT;
+#else
+ iop->_flag = _IOWRT;
+#endif
+
+ /*
+ * Update the user pointers now, in case a call to fflush() happens
+ * immediately.
+ */
+
+ if (_xassoc(iop, open_wmemstream_read, open_wmemstream_write,
+ open_wmemstream_seek, open_wmemstream_close, wmemp) != 0) {
+ goto cleanup;
+ }
+ _setorientation(iop, _WC_MODE);
+ SET_SEEKABLE(iop);
+
+ *wmemp->wmstr_ubufp = wmemp->wmstr_buf;
+ *wmemp->wmstr_usizep = MIN(wmemp->wmstr_pos, wmemp->wmstr_lsize);
+
+ return (iop);
+
+cleanup:
+ free(wmemp->wmstr_buf);
+ free(wmemp);
+ return (NULL);
+}
diff --git a/usr/src/lib/libc/port/stdio/putc.c b/usr/src/lib/libc/port/stdio/putc.c
index 05383201a3..df74a0cf89 100644
--- a/usr/src/lib/libc/port/stdio/putc.c
+++ b/usr/src/lib/libc/port/stdio/putc.c
@@ -25,9 +25,7 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/* All Rights Reserved */
#pragma weak _putc_unlocked = putc_unlocked
@@ -51,22 +49,24 @@ putc(int ch, FILE *iop)
int ret;
FLOCKFILE(lk, iop);
+ ret = putc_unlocked(ch, iop);
+ FUNLOCKFILE(lk);
+ return (ret);
+}
+int
+putc_unlocked(int ch, FILE *iop)
+{
_SET_ORIENTATION_BYTE(iop);
if (--iop->_cnt < 0)
- ret = __flsbuf((unsigned char) ch, iop);
- else {
- (*iop->_ptr++) = (unsigned char)ch;
- ret = (unsigned char)ch;
- }
- FUNLOCKFILE(lk);
- return (ret);
+ return (__flsbuf((unsigned char) ch, iop));
+ else
+ return (*iop->_ptr++ = (unsigned char)ch);
}
-
int
-putc_unlocked(int ch, FILE *iop)
+_putc_internal(int ch, FILE *iop)
{
if (--iop->_cnt < 0)
return (__flsbuf((unsigned char) ch, iop));
diff --git a/usr/src/lib/libc/port/stdio/putw.c b/usr/src/lib/libc/port/stdio/putw.c
index 043125e113..70848e6a06 100644
--- a/usr/src/lib/libc/port/stdio/putw.c
+++ b/usr/src/lib/libc/port/stdio/putw.c
@@ -25,9 +25,7 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/* All Rights Reserved */
/*
* The intent here is to provide a means to make the order of
@@ -54,7 +52,7 @@ putw(int w, FILE *stream)
rmutex_t *lk;
FLOCKFILE(lk, stream);
- while (--i >= 0 && PUTC(*s++, stream) != EOF)
+ while (--i >= 0 && putc_unlocked(*s++, stream) != EOF)
;
ret = stream->_flag & _IOERR;
FUNLOCKFILE(lk);
diff --git a/usr/src/lib/libc/port/stdio/rewind.c b/usr/src/lib/libc/port/stdio/rewind.c
index 57e4cc2540..c7da173ec3 100644
--- a/usr/src/lib/libc/port/stdio/rewind.c
+++ b/usr/src/lib/libc/port/stdio/rewind.c
@@ -25,9 +25,7 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/* All Rights Reserved */
#include "lint.h"
#include "file64.h"
@@ -55,7 +53,7 @@ void
_rewind_unlocked(FILE *iop)
{
(void) _fflush_u(iop);
- (void) lseek64(FILENO(iop), 0, SEEK_SET);
+ (void) _xseek64(iop, 0, SEEK_SET);
iop->_cnt = 0;
iop->_ptr = iop->_base;
iop->_flag &= ~(_IOERR | _IOEOF);
diff --git a/usr/src/lib/libc/port/stdio/setbuf.c b/usr/src/lib/libc/port/stdio/setbuf.c
index 78c4c8cc76..10eb21d5b5 100644
--- a/usr/src/lib/libc/port/stdio/setbuf.c
+++ b/usr/src/lib/libc/port/stdio/setbuf.c
@@ -25,9 +25,11 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
+/* All Rights Reserved */
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2020 Robert Mustacchi
+ */
#include "lint.h"
#include "file64.h"
@@ -39,41 +41,37 @@
#include <synch.h>
#include "stdiom.h"
-
void
setbuf(FILE *iop, char *abuf)
{
Uchar *buf = (Uchar *)abuf;
- int fno = GET_FD(iop); /* file number */
+ int fno = _get_fd(iop); /* file number */
int size = BUFSIZ - _SMBFSZ;
Uchar *temp;
rmutex_t *lk;
FLOCKFILE(lk, iop);
- if ((iop->_base != 0) && (iop->_flag & _IOMYBUF))
+ if ((iop->_base != NULL) && (iop->_flag & _IOMYBUF))
free((char *)iop->_base - PUSHBACK);
iop->_flag &= ~(_IOMYBUF | _IONBF | _IOLBF);
- if (buf == 0) {
+ if (buf == NULL) {
iop->_flag |= _IONBF;
-#ifndef _STDIO_ALLOCATE
- if (fno < 2) {
+ if (fno == 0 || fno == 1) {
/* use special buffer for std{in,out} */
buf = (fno == 0) ? _sibuf : _sobuf;
- } else /* needed for ifndef */
-#endif
- if (fno < _NFILE) {
+ } else if (fno >= 2 && fno < _NFILE) {
buf = _smbuf[fno];
size = _SMBFSZ - PUSHBACK;
- } else
- if ((buf = (Uchar *)malloc(_SMBFSZ * sizeof (Uchar))) != 0) {
+ } else if ((buf = (Uchar *)malloc(_SMBFSZ *
+ sizeof (Uchar))) != NULL) {
iop->_flag |= _IOMYBUF;
size = _SMBFSZ - PUSHBACK;
}
} else { /* regular buffered I/O, standard buffer size */
- if (isatty(fno))
+ if (fno != -1 && isatty(fno))
iop->_flag |= _IOLBF;
}
- if (buf == 0) {
+ if (buf == NULL) {
FUNLOCKFILE(lk);
return; /* malloc() failed */
}
diff --git a/usr/src/lib/libc/port/stdio/setvbuf.c b/usr/src/lib/libc/port/stdio/setvbuf.c
index a6e63e09f7..936466f893 100644
--- a/usr/src/lib/libc/port/stdio/setvbuf.c
+++ b/usr/src/lib/libc/port/stdio/setvbuf.c
@@ -25,9 +25,7 @@
*/
/* Copyright (c) 1988 AT&T */
-/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/* All Rights Reserved */
#include "lint.h"
#include "file64.h"
@@ -47,7 +45,7 @@ setvbuf(FILE *iop, char *abuf, int type, size_t size)
Uchar *temp;
int sflag = iop->_flag & _IOMYBUF;
rmutex_t *lk;
- int fd = GET_FD(iop);
+ int fd = _get_fd(iop);
FLOCKFILE(lk, iop);
iop->_flag &= ~(_IOMYBUF | _IONBF | _IOLBF);
@@ -55,17 +53,14 @@ setvbuf(FILE *iop, char *abuf, int type, size_t size)
/* note that the flags are the same as the possible values for type */
case _IONBF:
iop->_flag |= _IONBF; /* file is unbuffered */
-#ifndef _STDIO_ALLOCATE
- if (fd < 2) {
+ if (fd == 0 || fd == 1) {
/* use special buffer for std{in,out} */
buf = (fd == 0) ? _sibuf : _sobuf;
size = BUFSIZ;
- } else /* needed for ifdef */
-#endif
- if (fd < _NFILE) {
+ } else if (fd >= 2 && fd < _NFILE) {
buf = _smbuf[fd];
size = _SMBFSZ - PUSHBACK;
- } else
+ } else {
if ((buf = malloc(_SMBFSZ * sizeof (Uchar))) != NULL) {
iop->_flag |= _IOMYBUF;
size = _SMBFSZ - PUSHBACK;
@@ -73,6 +68,7 @@ setvbuf(FILE *iop, char *abuf, int type, size_t size)
FUNLOCKFILE(lk);
return (EOF);
}
+ }
break;
case _IOLBF:
case _IOFBF:
diff --git a/usr/src/lib/libc/sparc/Makefile.com b/usr/src/lib/libc/sparc/Makefile.com
index e48562f400..ee580e8513 100644
--- a/usr/src/lib/libc/sparc/Makefile.com
+++ b/usr/src/lib/libc/sparc/Makefile.com
@@ -715,6 +715,7 @@ PORTSTDIO= \
_filbuf.o \
_findbuf.o \
_flsbuf.o \
+ _stdio_flags.o \
_wrtchk.o \
clearerr.o \
ctermid.o \
@@ -730,6 +731,7 @@ PORTSTDIO= \
fileno.o \
flockf.o \
flush.o \
+ fmemopen.o \
fopen.o \
fpos.o \
fputc.o \
@@ -746,6 +748,9 @@ PORTSTDIO= \
getpass.o \
gets.o \
getw.o \
+ mse.o \
+ open_memstream.o \
+ open_wmemstream.o \
popen.o \
putc.o \
putchar.o \
@@ -761,7 +766,6 @@ PORTSTDIO= \
tmpfile.o \
tmpnam_r.o \
ungetc.o \
- mse.o \
vscanf.o \
vwscanf.o \
wscanf.o
diff --git a/usr/src/lib/libc/sparcv9/Makefile.com b/usr/src/lib/libc/sparcv9/Makefile.com
index d9bfef117f..3aacce8f61 100644
--- a/usr/src/lib/libc/sparcv9/Makefile.com
+++ b/usr/src/lib/libc/sparcv9/Makefile.com
@@ -658,6 +658,7 @@ PORTSTDIO= \
_filbuf.o \
_findbuf.o \
_flsbuf.o \
+ _stdio_flags.o \
_wrtchk.o \
clearerr.o \
ctermid.o \
@@ -673,6 +674,7 @@ PORTSTDIO= \
fileno.o \
flockf.o \
flush.o \
+ fmemopen.o \
fopen.o \
fpos.o \
fputc.o \
@@ -689,6 +691,9 @@ PORTSTDIO= \
getpass.o \
gets.o \
getw.o \
+ mse.o \
+ open_memstream.o \
+ open_wmemstream.o \
popen.o \
putc.o \
putchar.o \
@@ -704,7 +709,6 @@ PORTSTDIO= \
tmpfile.o \
tmpnam_r.o \
ungetc.o \
- mse.o \
vscanf.o \
vwscanf.o \
wscanf.o