Point Cloud Library (PCL)  1.14.0-dev
low_level_io.h
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2012-, Open Perception, Inc.
6  * Copyright (c) 2018 Fizyr BV. - https://fizyr.com
7  *
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * * Redistributions of source code must retain the above copyright
15  * notice, this list of conditions and the following disclaimer.
16  * * Redistributions in binary form must reproduce the above
17  * copyright notice, this list of conditions and the following
18  * disclaimer in the documentation and/or other materials provided
19  * with the distribution.
20  * * Neither the name of the copyright holder(s) nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 /**
39  * This file defines compatibility wrappers for low level I/O functions.
40  * Implemented as inlinable functions to prevent any performance overhead.
41  */
42 
43 #pragma once
44 
45 #ifdef _WIN32
46 # ifndef WIN32_LEAN_AND_MEAN
47 # define WIN32_LEAN_AND_MEAN
48 # endif
49 # ifndef NOMINMAX
50 # define NOMINMAX
51 # endif
52 # include <io.h>
53 # include <windows.h>
54 # ifdef _MSC_VER
55 // ssize_t is already defined in MinGW and its definition conflicts with that of
56 // SSIZE_T on a 32-bit target, so do this only for MSVC.
57 # include <basetsd.h>
58 using ssize_t = SSIZE_T;
59 # endif /* _MSC_VER */
60 #else
61 # include <unistd.h>
62 # include <sys/mman.h>
63 # include <sys/types.h>
64 # include <sys/stat.h>
65 # include <fcntl.h>
66 # include <cerrno>
67 #endif
68 #include <cstddef>
69 
70 namespace pcl
71 {
72  namespace io
73  {
74 #ifdef _WIN32
75  inline int raw_open(const char * pathname, int flags, int mode)
76  {
77  return ::_open(pathname, flags, mode);
78  }
79 
80  inline int raw_open(const char * pathname, int flags)
81  {
82  return ::_open(pathname, flags);
83  }
84 
85  inline int raw_close(int fd)
86  {
87  return ::_close(fd);
88  }
89 
90  inline int raw_lseek(int fd, long offset, int whence)
91  {
92  return ::_lseek(fd, offset, whence);
93  }
94 
95  inline int raw_read(int fd, void * buffer, std::size_t count)
96  {
97  return ::_read(fd, buffer, count);
98  }
99 
100  inline int raw_write(int fd, const void * buffer, std::size_t count)
101  {
102  return ::_write(fd, buffer, count);
103  }
104 
105  inline int raw_ftruncate(int fd, long length)
106  {
107  return ::_chsize(fd, length);
108  }
109 
110  inline int raw_fallocate(int fd, long length)
111  {
112  // Doesn't actually allocate, but best we can do?
113  return raw_ftruncate(fd, length);
114  }
115 #else
116  inline int raw_open(const char * pathname, int flags, int mode)
117  {
118  return ::open(pathname, flags, mode);
119  }
120 
121  inline int raw_open(const char * pathname, int flags)
122  {
123  return ::open(pathname, flags);
124  }
125 
126  inline int raw_close(int fd)
127  {
128  return ::close(fd);
129  }
130 
131  inline off_t raw_lseek(int fd, off_t offset, int whence)
132  {
133  return ::lseek(fd, offset, whence);
134  }
135 
136  inline ssize_t raw_read(int fd, void * buffer, std::size_t count)
137  {
138  return ::read(fd, buffer, count);
139  }
140 
141  inline ssize_t raw_write(int fd, const void * buffer, std::size_t count)
142  {
143  return ::write(fd, buffer, count);
144  }
145 
146  inline int raw_ftruncate(int fd, off_t length)
147  {
148  return ::ftruncate(fd, length);
149  }
150 
151 # ifdef __APPLE__
152  inline int raw_fallocate(int fd, off_t length)
153  {
154  // OS X doesn't have posix_fallocate, but it has a fcntl that does the job.
155  // It may make the file too big though, so we truncate before returning.
156 
157  // Try to allocate contiguous space first.
158  ::fstore_t store = {F_ALLOCATEALL | F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, length, 0};
159  if (::fcntl(fd, F_PREALLOCATE, &store) != -1)
160  return raw_ftruncate(fd, length);
161 
162  // Try fragmented if it failed.
163  store.fst_flags = F_ALLOCATEALL;
164  if (::fcntl(fd, F_PREALLOCATE, &store) != -1)
165  return raw_ftruncate(fd, length);
166 
167  // Fragmented also failed.
168  return -1;
169  }
170 
171 # else // __APPLE__
172  inline int raw_fallocate(int fd, off_t length)
173  {
174 # ifdef ANDROID
175  // Android's libc doesn't have posix_fallocate.
176  if (::fallocate(fd, 0, 0, length) == 0)
177  return 0;
178 
179  // fallocate returns -1 on error and sets errno
180  // EINVAL should indicate an unsupported filesystem.
181  // All other errors are passed up.
182  if (errno != EINVAL)
183  return -1;
184 # elif defined(__OpenBSD__)
185  // OpenBSD has neither posix_fallocate nor fallocate
186  if (::ftruncate(fd, length) == 0)
187  return 0;
188  if (errno != EINVAL)
189  return -1;
190 # else
191  // Conforming POSIX systems have posix_fallocate.
192  const int res = ::posix_fallocate(fd, 0, length);
193  if (res == 0)
194  return 0;
195 
196  // posix_fallocate does not set errno
197  // EINVAL should indicate an unsupported filesystem.
198  // All other errors are passed up.
199  if (res != EINVAL)
200  return res;
201 # endif
202 
203  // Try to deal with unsupported filesystems by simply seeking + writing.
204  // This may not really allocate space, but the file size will be set.
205  // Writes to the mmapped file may still trigger SIGBUS errors later.
206 
207  // Remember the old position and seek to the desired length.
208  off_t old_pos = raw_lseek(fd, 0, SEEK_CUR);
209  if (old_pos == -1)
210  return -1;
211  if (raw_lseek(fd, length - 1, SEEK_SET) == -1)
212  return -1;
213 
214  // Write a single byte to resize the file.
215  char buffer = 0;
216  ssize_t written = raw_write(fd, &buffer, 1);
217 
218  // Seek back to the old position.
219  if (raw_lseek(fd, old_pos, SEEK_SET) == -1)
220  return -1;
221 
222  // Fail if we didn't write exactly one byte,
223  if (written != 1)
224  return -1;
225 
226  return 0;
227  }
228 # endif // __APPLE
229 #endif // _WIN32
230 
231  }
232 }
int raw_ftruncate(int fd, long length)
Definition: low_level_io.h:105
int raw_close(int fd)
Definition: low_level_io.h:85
int raw_lseek(int fd, long offset, int whence)
Definition: low_level_io.h:90
int raw_write(int fd, const void *buffer, std::size_t count)
Definition: low_level_io.h:100
int raw_fallocate(int fd, long length)
Definition: low_level_io.h:110
int raw_open(const char *pathname, int flags, int mode)
Definition: low_level_io.h:75
int raw_read(int fd, void *buffer, std::size_t count)
Definition: low_level_io.h:95