aboutsummaryrefslogtreecommitdiff
path: root/src/xz/file_io.h
blob: b16a8faa948482df063700076c2c0136730e092c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// SPDX-License-Identifier: 0BSD

///////////////////////////////////////////////////////////////////////////////
//
/// \file       file_io.h
/// \brief      I/O types and functions
//
//  Author:     Lasse Collin
//
///////////////////////////////////////////////////////////////////////////////

// Some systems have suboptimal BUFSIZ. Use a bit bigger value on them.
// We also need that IO_BUFFER_SIZE is a multiple of 8 (sizeof(uint64_t))
#if BUFSIZ <= 1024
#	define IO_BUFFER_SIZE 8192
#else
#	define IO_BUFFER_SIZE (BUFSIZ & ~7U)
#endif

#ifdef _MSC_VER
	// The first one renames both "struct stat" -> "struct _stat64"
	// and stat() -> _stat64(). The documentation mentions only
	// "struct __stat64", not "struct _stat64", but the latter
	// works too.
#	define stat _stat64
#	define fstat _fstat64
#	define off_t __int64
#endif


/// is_sparse() accesses the buffer as uint64_t for maximum speed.
/// The u32 and u64 members must only be access through this union
/// to avoid strict aliasing violations. Taking a pointer of u8
/// should be fine as long as uint8_t maps to unsigned char which
/// can alias anything.
typedef union {
	uint8_t u8[IO_BUFFER_SIZE];
	uint32_t u32[IO_BUFFER_SIZE / sizeof(uint32_t)];
	uint64_t u64[IO_BUFFER_SIZE / sizeof(uint64_t)];
} io_buf;


typedef struct {
	/// Name of the source filename (as given on the command line) or
	/// pointer to static "(stdin)" when reading from standard input.
	const char *src_name;

	/// Destination filename converted from src_name or pointer to static
	/// "(stdout)" when writing to standard output.
	char *dest_name;

	/// File descriptor of the source file
	int src_fd;

	/// File descriptor of the target file
	int dest_fd;

	/// True once end of the source file has been detected.
	bool src_eof;

	/// For --flush-timeout: True if at least one byte has been read
	/// since the previous flush or the start of the file.
	bool src_has_seen_input;

	/// For --flush-timeout: True when flushing is needed.
	bool flush_needed;

	/// If true, we look for long chunks of zeros and try to create
	/// a sparse file.
	bool dest_try_sparse;

	/// This is used only if dest_try_sparse is true. This holds the
	/// number of zero bytes we haven't written out, because we plan
	/// to make that byte range a sparse chunk.
	off_t dest_pending_sparse;

	/// Stat of the source file.
	struct stat src_st;

	/// Stat of the destination file.
	struct stat dest_st;

} file_pair;


/// \brief      Initialize the I/O module
extern void io_init(void);


#ifndef TUKLIB_DOSLIKE
/// \brief      Write a byte to user_abort_pipe[1]
///
/// This is called from a signal handler.
extern void io_write_to_user_abort_pipe(void);
#endif


/// \brief      Disable creation of sparse files when decompressing
extern void io_no_sparse(void);


#ifdef ENABLE_SANDBOX
/// \brief      main() calls this if conditions for sandboxing have been met.
extern void io_allow_sandbox(void);
#endif


/// \brief      Open the source file
extern file_pair *io_open_src(const char *src_name);


/// \brief      Open the destination file
extern bool io_open_dest(file_pair *pair);


/// \brief      Closes the file descriptors and frees possible allocated memory
///
/// The success argument determines if source or destination file gets
/// unlinked:
///  - false: The destination file is unlinked.
///  - true: The source file is unlinked unless writing to stdout or --keep
///    was used.
extern void io_close(file_pair *pair, bool success);


/// \brief      Reads from the source file to a buffer
///
/// \param      pair    File pair having the source file open for reading
/// \param      buf     Destination buffer to hold the read data
/// \param      size    Size of the buffer; must be at most IO_BUFFER_SIZE
///
/// \return     On success, number of bytes read is returned. On end of
///             file zero is returned and pair->src_eof set to true.
///             On error, SIZE_MAX is returned and error message printed.
extern size_t io_read(file_pair *pair, io_buf *buf, size_t size);


/// \brief      Fix the position in src_fd
///
/// This is used when --single-thream has been specified and decompression
/// is successful. If the input file descriptor supports seeking, this
/// function fixes the input position to point to the next byte after the
/// decompressed stream.
///
/// \param      pair        File pair having the source file open for reading
/// \param      rewind_size How many bytes of extra have been read i.e.
///                         how much to seek backwards.
extern void io_fix_src_pos(file_pair *pair, size_t rewind_size);


/// \brief      Seek to the given absolute position in the source file
///
/// This calls lseek() and also clears pair->src_eof.
///
/// \param      pair    Seekable source file
/// \param      pos     Offset relative to the beginning of the file,
///                     from which the data should be read.
///
/// \return     On success, false is returned. On error, error message
///             is printed and true is returned.
extern bool io_seek_src(file_pair *pair, uint64_t pos);


/// \brief      Read from source file from given offset to a buffer
///
/// This is remotely similar to standard pread(). This uses lseek() though,
/// so the read offset is changed on each call.
///
/// \param      pair    Seekable source file
/// \param      buf     Destination buffer
/// \param      size    Amount of data to read
/// \param      pos     Offset relative to the beginning of the file,
///                     from which the data should be read.
///
/// \return     On success, false is returned. On error, error message
///             is printed and true is returned.
extern bool io_pread(file_pair *pair, io_buf *buf, size_t size, uint64_t pos);


/// \brief      Writes a buffer to the destination file
///
/// \param      pair    File pair having the destination file open for writing
/// \param      buf     Buffer containing the data to be written
/// \param      size    Size of the buffer; must be at most IO_BUFFER_SIZE
///
/// \return     On success, zero is returned. On error, -1 is returned
///             and error message printed.
extern bool io_write(file_pair *pair, const io_buf *buf, size_t size);