xref: /third_party/musl/src/stdio/__fdopen.c (revision 570af302)
1570af302Sopenharmony_ci/* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
2570af302Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
3570af302Sopenharmony_ci * you may not use this file except in compliance with the License.
4570af302Sopenharmony_ci * You may obtain a copy of the License at
5570af302Sopenharmony_ci *
6570af302Sopenharmony_ci *	 http://www.apache.org/licenses/LICENSE-2.0
7570af302Sopenharmony_ci *
8570af302Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
9570af302Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
10570af302Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11570af302Sopenharmony_ci * See the License for the specific language governing permissions and
12570af302Sopenharmony_ci * limitations under the License.
13570af302Sopenharmony_ci */
14570af302Sopenharmony_ci
15570af302Sopenharmony_ci#include "stdio_impl.h"
16570af302Sopenharmony_ci#include <stdlib.h>
17570af302Sopenharmony_ci#include <sys/ioctl.h>
18570af302Sopenharmony_ci#include <sys/stat.h>
19570af302Sopenharmony_ci#include <fcntl.h>
20570af302Sopenharmony_ci#include <errno.h>
21570af302Sopenharmony_ci#include <string.h>
22570af302Sopenharmony_ci#include "libc.h"
23570af302Sopenharmony_ci
24570af302Sopenharmony_cistatic size_t __get_bufsize(int fd)
25570af302Sopenharmony_ci{
26570af302Sopenharmony_ci	struct stat st;
27570af302Sopenharmony_ci	size_t buf_size = 0;
28570af302Sopenharmony_ci
29570af302Sopenharmony_ci	if (fstat(fd, &st) < 0) {
30570af302Sopenharmony_ci		buf_size = BUFSIZ;
31570af302Sopenharmony_ci	} else if (st.st_blksize == 0) {
32570af302Sopenharmony_ci		buf_size = BUFSIZ;
33570af302Sopenharmony_ci	} else {
34570af302Sopenharmony_ci		buf_size = st.st_blksize;
35570af302Sopenharmony_ci	}
36570af302Sopenharmony_ci
37570af302Sopenharmony_ci	return buf_size;
38570af302Sopenharmony_ci}
39570af302Sopenharmony_ci
40570af302Sopenharmony_ciint __falloc_buf(FILE *f)
41570af302Sopenharmony_ci{
42570af302Sopenharmony_ci	/* return if already allocated, or F_NOBUF set */
43570af302Sopenharmony_ci	if (f->buf != NULL || f->buf_size != 0 || f->flags & F_NOBUF) {
44570af302Sopenharmony_ci		return 0;
45570af302Sopenharmony_ci	}
46570af302Sopenharmony_ci
47570af302Sopenharmony_ci	/* Default,  base and buf are NULL,and buf_size = 0 */
48570af302Sopenharmony_ci	size_t buf_size = 0;
49570af302Sopenharmony_ci
50570af302Sopenharmony_ci	/* get buffer size via file stat */
51570af302Sopenharmony_ci	buf_size = __get_bufsize(f->fd);
52570af302Sopenharmony_ci
53570af302Sopenharmony_ci	/* alloc R/W buffer */
54570af302Sopenharmony_ci	f->base = (unsigned char *)malloc(UNGET + buf_size * sizeof(unsigned char));
55570af302Sopenharmony_ci	if (!f->base) {
56570af302Sopenharmony_ci		errno = -ENOMEM;
57570af302Sopenharmony_ci		return errno;
58570af302Sopenharmony_ci	}
59570af302Sopenharmony_ci
60570af302Sopenharmony_ci	/* reserve UNGET buffer */
61570af302Sopenharmony_ci	f->buf = f->base + UNGET;
62570af302Sopenharmony_ci	f->buf_size = buf_size;
63570af302Sopenharmony_ci
64570af302Sopenharmony_ci	return 0;
65570af302Sopenharmony_ci}
66570af302Sopenharmony_ci
67570af302Sopenharmony_ciFILE *__fdopen(int fd, const char *mode)
68570af302Sopenharmony_ci{
69570af302Sopenharmony_ci	FILE *f = NULL;
70570af302Sopenharmony_ci	int file_flags = 0;
71570af302Sopenharmony_ci	int mode_flags = 0;
72570af302Sopenharmony_ci
73570af302Sopenharmony_ci	int flags = syscall(SYS_fcntl, fd, F_GETFL, 0);
74570af302Sopenharmony_ci	if (flags == -1) {
75570af302Sopenharmony_ci		return NULL;
76570af302Sopenharmony_ci	}
77570af302Sopenharmony_ci
78570af302Sopenharmony_ci	/* Compute the flags to pass to open() */
79570af302Sopenharmony_ci	mode_flags = __fmodeflags(mode, &file_flags);
80570af302Sopenharmony_ci	if (mode_flags < 0) {
81570af302Sopenharmony_ci		return NULL;
82570af302Sopenharmony_ci	}
83570af302Sopenharmony_ci
84570af302Sopenharmony_ci	if (mode_flags & O_CLOEXEC) {
85570af302Sopenharmony_ci		__syscall(SYS_fcntl, fd, F_SETFD, FD_CLOEXEC);
86570af302Sopenharmony_ci	}
87570af302Sopenharmony_ci
88570af302Sopenharmony_ci	if (mode_flags & O_APPEND) {
89570af302Sopenharmony_ci		flags = __syscall(SYS_fcntl, fd, F_GETFL);
90570af302Sopenharmony_ci		if (!(flags & O_APPEND))
91570af302Sopenharmony_ci			__syscall(SYS_fcntl, fd, F_SETFL, flags | O_APPEND);
92570af302Sopenharmony_ci	}
93570af302Sopenharmony_ci
94570af302Sopenharmony_ci	f = __fdopenx(fd, file_flags);
95570af302Sopenharmony_ci	if (f) {
96570af302Sopenharmony_ci		return f;
97570af302Sopenharmony_ci	}
98570af302Sopenharmony_ci
99570af302Sopenharmony_ci	return NULL;
100570af302Sopenharmony_ci}
101570af302Sopenharmony_ciweak_alias(__fdopen, fdopen);
102570af302Sopenharmony_ci
103570af302Sopenharmony_ciFILE *__fdopenx(int fd, int flags)
104570af302Sopenharmony_ci{
105570af302Sopenharmony_ci	FILE *f = 0;
106570af302Sopenharmony_ci	struct winsize wsz;
107570af302Sopenharmony_ci
108570af302Sopenharmony_ci	/* Allocate FILE or fail */
109570af302Sopenharmony_ci	if (!(f = __ofl_alloc())) {
110570af302Sopenharmony_ci		return NULL;
111570af302Sopenharmony_ci	}
112570af302Sopenharmony_ci
113570af302Sopenharmony_ci	/* Zero-fill only the struct, not the buffer */
114570af302Sopenharmony_ci	memset(f, 0, sizeof *f);
115570af302Sopenharmony_ci
116570af302Sopenharmony_ci	f->flags = flags;
117570af302Sopenharmony_ci	f->fd = fd;
118570af302Sopenharmony_ci
119570af302Sopenharmony_ci	/* Activate line buffered mode for terminals */
120570af302Sopenharmony_ci	f->lbf = EOF;
121570af302Sopenharmony_ci	if (!(f->flags & F_NOWR) && !__syscall(SYS_ioctl, fd, TIOCGWINSZ, &wsz)) {
122570af302Sopenharmony_ci		f->lbf = '\n';
123570af302Sopenharmony_ci	}
124570af302Sopenharmony_ci
125570af302Sopenharmony_ci#ifndef __LITEOS__
126570af302Sopenharmony_ci	/* set file tag in fdtable, FILE type */
127570af302Sopenharmony_ci	fdsan_exchange_owner_tag(fd, 0, __get_file_tag(f));
128570af302Sopenharmony_ci#endif
129570af302Sopenharmony_ci
130570af302Sopenharmony_ci	/* Initialize op ptrs. No problem if some are unneeded. */
131570af302Sopenharmony_ci	f->read = __stdio_read;
132570af302Sopenharmony_ci	f->write = __stdio_write;
133570af302Sopenharmony_ci	f->seek = __stdio_seek;
134570af302Sopenharmony_ci	f->close = __stdio_close;
135570af302Sopenharmony_ci	f->readx = __stdio_readx;
136570af302Sopenharmony_ci
137570af302Sopenharmony_ci	if (!libc.threaded) {
138570af302Sopenharmony_ci		f->lock = -1;
139570af302Sopenharmony_ci	}
140570af302Sopenharmony_ci
141570af302Sopenharmony_ci	/* Add new FILE to open file list */
142570af302Sopenharmony_ci	return __ofl_add(f);
143570af302Sopenharmony_ci}
144570af302Sopenharmony_ci
145