summaryrefslogtreecommitdiff
path: root/libntfs-3g/unix_io.c (plain)
blob: 2f3ddf0501e5fb9963ef9c8badb426a5131d9c24
1/**
2 * unix_io.c - Unix style disk io functions. Originated from the Linux-NTFS project.
3 *
4 * Copyright (c) 2000-2006 Anton Altaparmakov
5 *
6 * This program/include file is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program/include file is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program (in the main directory of the NTFS-3G
18 * distribution in the file COPYING); if not, write to the Free Software
19 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#ifdef HAVE_UNISTD_H
27#include <unistd.h>
28#endif
29#ifdef HAVE_STDLIB_H
30#include <stdlib.h>
31#endif
32#ifdef HAVE_STRING_H
33#include <string.h>
34#endif
35#ifdef HAVE_ERRNO_H
36#include <errno.h>
37#endif
38#ifdef HAVE_STDIO_H
39#include <stdio.h>
40#endif
41#ifdef HAVE_SYS_TYPES_H
42#include <sys/types.h>
43#endif
44#ifdef HAVE_SYS_STAT_H
45#include <sys/stat.h>
46#endif
47#ifdef HAVE_FCNTL_H
48#include <fcntl.h>
49#endif
50#ifdef HAVE_SYS_IOCTL_H
51#include <sys/ioctl.h>
52#endif
53#ifdef HAVE_LINUX_FD_H
54#include <linux/fd.h>
55#endif
56
57#include "types.h"
58#include "mst.h"
59#include "debug.h"
60#include "device.h"
61#include "logging.h"
62#include "misc.h"
63
64#ifdef __USE_FILE_OFFSET64
65#include <unistd.h>
66#endif
67
68#define DEV_FD(dev) (*(int *)dev->d_private)
69
70#ifdef __USE_FILE_OFFSET64
71//#define fcntl __fcntl64
72#endif
73
74/* Define to nothing if not present on this system. */
75#ifndef O_EXCL
76# define O_EXCL 0
77#endif
78
79/**
80 * fsync replacement which makes every effort to try to get the data down to
81 * disk, using different means for different operating systems. Specifically,
82 * it issues the proper fcntl for Mac OS X or does fsync where it is available
83 * or as a last resort calls the fsync function. Information on this problem
84 * was retrieved from:
85 * http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf
86 */
87static int ntfs_fsync(int fildes)
88{
89 int ret = -1;
90#if defined(__APPLE__) || defined(__DARWIN__)
91# ifndef F_FULLFSYNC
92# error "Mac OS X: F_FULLFSYNC is not defined. Either you didn't include fcntl.h or you're using an older, unsupported version of Mac OS X (pre-10.3)."
93# endif
94 /*
95 * Apple has disabled fsync() for internal disk drives in OS X.
96 * To force a synchronization of disk contents, we use a Mac OS X
97 * specific fcntl, F_FULLFSYNC.
98 */
99 ret = fcntl(fildes, F_FULLFSYNC, NULL);
100 if (ret) {
101 /*
102 * If we are not on a file system that supports this,
103 * then fall back to a plain fsync.
104 */
105 ret = fsync(fildes);
106 }
107#else
108 ret = fsync(fildes);
109#endif
110 return ret;
111}
112
113/**
114 * ntfs_device_unix_io_open - Open a device and lock it exclusively
115 * @dev:
116 * @flags:
117 *
118 * Description...
119 *
120 * Returns:
121 */
122static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags)
123{
124 struct flock flk;
125 struct stat sbuf;
126 int err;
127
128 if (NDevOpen(dev)) {
129 errno = EBUSY;
130 return -1;
131 }
132 if (stat(dev->d_name, &sbuf)) {
133 ntfs_log_perror("Failed to access '%s'", dev->d_name);
134 return -1;
135 }
136 if (S_ISBLK(sbuf.st_mode))
137 NDevSetBlock(dev);
138
139 dev->d_private = ntfs_malloc(sizeof(int));
140 if (!dev->d_private)
141 return -1;
142 /*
143 * Open file for exclusive access if mounting r/w.
144 * Fuseblk takes care about block devices.
145 */
146 if (!NDevBlock(dev) && (flags & O_RDWR) == O_RDWR)
147 flags |= O_EXCL;
148 *(int*)dev->d_private = open(dev->d_name, flags);
149 if (*(int*)dev->d_private == -1) {
150 err = errno;
151 goto err_out;
152 }
153
154 if ((flags & O_RDWR) != O_RDWR)
155 NDevSetReadOnly(dev);
156
157 memset(&flk, 0, sizeof(flk));
158 if (NDevReadOnly(dev))
159 flk.l_type = F_RDLCK;
160 else
161 flk.l_type = F_WRLCK;
162 flk.l_whence = SEEK_SET;
163 flk.l_start = flk.l_len = 0LL;
164 if (fcntl(DEV_FD(dev), F_SETLK, &flk)) {
165 err = errno;
166 ntfs_log_perror("Failed to %s lock '%s'", NDevReadOnly(dev) ?
167 "read" : "write", dev->d_name);
168 if (close(DEV_FD(dev)))
169 ntfs_log_perror("Failed to close '%s'", dev->d_name);
170 goto err_out;
171 }
172
173 NDevSetOpen(dev);
174 return 0;
175err_out:
176 free(dev->d_private);
177 dev->d_private = NULL;
178 errno = err;
179 return -1;
180}
181
182/**
183 * ntfs_device_unix_io_close - Close the device, releasing the lock
184 * @dev:
185 *
186 * Description...
187 *
188 * Returns:
189 */
190static int ntfs_device_unix_io_close(struct ntfs_device *dev)
191{
192 struct flock flk;
193
194 if (!NDevOpen(dev)) {
195 errno = EBADF;
196 ntfs_log_perror("Device %s is not open", dev->d_name);
197 return -1;
198 }
199 if (NDevDirty(dev))
200 if (ntfs_fsync(DEV_FD(dev))) {
201 ntfs_log_perror("Failed to fsync device %s", dev->d_name);
202 return -1;
203 }
204
205 memset(&flk, 0, sizeof(flk));
206 flk.l_type = F_UNLCK;
207 flk.l_whence = SEEK_SET;
208 flk.l_start = flk.l_len = 0LL;
209 if (fcntl(DEV_FD(dev), F_SETLK, &flk))
210 ntfs_log_perror("Could not unlock %s", dev->d_name);
211 if (close(DEV_FD(dev))) {
212 ntfs_log_perror("Failed to close device %s", dev->d_name);
213 return -1;
214 }
215 NDevClearOpen(dev);
216 free(dev->d_private);
217 dev->d_private = NULL;
218 return 0;
219}
220
221/**
222 * ntfs_device_unix_io_seek - Seek to a place on the device
223 * @dev:
224 * @offset:
225 * @whence:
226 *
227 * Description...
228 *
229 * Returns:
230 */
231static s64 ntfs_device_unix_io_seek(struct ntfs_device *dev, s64 offset,
232 int whence)
233{
234#ifdef __USE_FILE_OFFSET64
235 return lseek64(DEV_FD(dev), offset, whence);
236#else
237 return lseek(DEV_FD(dev), offset, whence);
238#endif
239}
240
241/**
242 * ntfs_device_unix_io_read - Read from the device, from the current location
243 * @dev:
244 * @buf:
245 * @count:
246 *
247 * Description...
248 *
249 * Returns:
250 */
251static s64 ntfs_device_unix_io_read(struct ntfs_device *dev, void *buf,
252 s64 count)
253{
254 return read(DEV_FD(dev), buf, count);
255}
256
257/**
258 * ntfs_device_unix_io_write - Write to the device, at the current location
259 * @dev:
260 * @buf:
261 * @count:
262 *
263 * Description...
264 *
265 * Returns:
266 */
267static s64 ntfs_device_unix_io_write(struct ntfs_device *dev, const void *buf,
268 s64 count)
269{
270 if (NDevReadOnly(dev)) {
271 errno = EROFS;
272 return -1;
273 }
274 NDevSetDirty(dev);
275 return write(DEV_FD(dev), buf, count);
276}
277
278/**
279 * ntfs_device_unix_io_pread - Perform a positioned read from the device
280 * @dev:
281 * @buf:
282 * @count:
283 * @offset:
284 *
285 * Description...
286 *
287 * Returns:
288 */
289static s64 ntfs_device_unix_io_pread(struct ntfs_device *dev, void *buf,
290 s64 count, s64 offset)
291{
292#ifdef __USE_FILE_OFFSET64
293 return pread64(DEV_FD(dev), buf, count, offset);
294#else
295 return pread(DEV_FD(dev), buf, count, offset);
296#endif
297}
298
299/**
300 * ntfs_device_unix_io_pwrite - Perform a positioned write to the device
301 * @dev:
302 * @buf:
303 * @count:
304 * @offset:
305 *
306 * Description...
307 *
308 * Returns:
309 */
310static s64 ntfs_device_unix_io_pwrite(struct ntfs_device *dev, const void *buf,
311 s64 count, s64 offset)
312{
313 if (NDevReadOnly(dev)) {
314 errno = EROFS;
315 return -1;
316 }
317 NDevSetDirty(dev);
318#ifdef __USE_FILE_OFFSET64
319 return pwrite64(DEV_FD(dev), buf, count, offset);
320#else
321 return pwrite(DEV_FD(dev), buf, count, offset);
322#endif
323}
324
325/**
326 * ntfs_device_unix_io_sync - Flush any buffered changes to the device
327 * @dev:
328 *
329 * Description...
330 *
331 * Returns:
332 */
333static int ntfs_device_unix_io_sync(struct ntfs_device *dev)
334{
335 int res = 0;
336
337 if (!NDevReadOnly(dev)) {
338 res = ntfs_fsync(DEV_FD(dev));
339 if (res)
340 ntfs_log_perror("Failed to sync device %s", dev->d_name);
341 else
342 NDevClearDirty(dev);
343 }
344 return res;
345}
346
347/**
348 * ntfs_device_unix_io_stat - Get information about the device
349 * @dev:
350 * @buf:
351 *
352 * Description...
353 *
354 * Returns:
355 */
356static int ntfs_device_unix_io_stat(struct ntfs_device *dev, struct stat *buf)
357{
358 return fstat(DEV_FD(dev), buf);
359}
360
361/**
362 * ntfs_device_unix_io_ioctl - Perform an ioctl on the device
363 * @dev:
364 * @request:
365 * @argp:
366 *
367 * Description...
368 *
369 * Returns:
370 */
371static int ntfs_device_unix_io_ioctl(struct ntfs_device *dev, int request,
372 void *argp)
373{
374 return ioctl(DEV_FD(dev), request, argp);
375}
376
377/**
378 * Device operations for working with unix style devices and files.
379 */
380struct ntfs_device_operations ntfs_device_unix_io_ops = {
381 .open = ntfs_device_unix_io_open,
382 .close = ntfs_device_unix_io_close,
383 .seek = ntfs_device_unix_io_seek,
384 .read = ntfs_device_unix_io_read,
385 .write = ntfs_device_unix_io_write,
386 .pread = ntfs_device_unix_io_pread,
387 .pwrite = ntfs_device_unix_io_pwrite,
388 .sync = ntfs_device_unix_io_sync,
389 .stat = ntfs_device_unix_io_stat,
390 .ioctl = ntfs_device_unix_io_ioctl,
391};
392