1*9663SMark.Logan@Sun.COM /**
2*9663SMark.Logan@Sun.COM  * unix_io.c - Unix style disk io functions. Part of the Linux-NTFS project.
3*9663SMark.Logan@Sun.COM  *
4*9663SMark.Logan@Sun.COM  * Copyright (c) 2000-2006 Anton Altaparmakov
5*9663SMark.Logan@Sun.COM  *
6*9663SMark.Logan@Sun.COM  * This program/include file is free software; you can redistribute it and/or
7*9663SMark.Logan@Sun.COM  * modify it under the terms of the GNU General Public License as published
8*9663SMark.Logan@Sun.COM  * by the Free Software Foundation; either version 2 of the License, or
9*9663SMark.Logan@Sun.COM  * (at your option) any later version.
10*9663SMark.Logan@Sun.COM  *
11*9663SMark.Logan@Sun.COM  * This program/include file is distributed in the hope that it will be
12*9663SMark.Logan@Sun.COM  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13*9663SMark.Logan@Sun.COM  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*9663SMark.Logan@Sun.COM  * GNU General Public License for more details.
15*9663SMark.Logan@Sun.COM  *
16*9663SMark.Logan@Sun.COM  * You should have received a copy of the GNU General Public License
17*9663SMark.Logan@Sun.COM  * along with this program (in the main directory of the Linux-NTFS
18*9663SMark.Logan@Sun.COM  * distribution in the file COPYING); if not, write to the Free Software
19*9663SMark.Logan@Sun.COM  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20*9663SMark.Logan@Sun.COM  */
21*9663SMark.Logan@Sun.COM 
22*9663SMark.Logan@Sun.COM #ifdef HAVE_CONFIG_H
23*9663SMark.Logan@Sun.COM #include "config.h"
24*9663SMark.Logan@Sun.COM #endif
25*9663SMark.Logan@Sun.COM 
26*9663SMark.Logan@Sun.COM #ifdef HAVE_UNISTD_H
27*9663SMark.Logan@Sun.COM #include <unistd.h>
28*9663SMark.Logan@Sun.COM #endif
29*9663SMark.Logan@Sun.COM #ifdef HAVE_STDLIB_H
30*9663SMark.Logan@Sun.COM #include <stdlib.h>
31*9663SMark.Logan@Sun.COM #endif
32*9663SMark.Logan@Sun.COM #ifdef HAVE_STRING_H
33*9663SMark.Logan@Sun.COM #include <string.h>
34*9663SMark.Logan@Sun.COM #endif
35*9663SMark.Logan@Sun.COM #ifdef HAVE_ERRNO_H
36*9663SMark.Logan@Sun.COM #include <errno.h>
37*9663SMark.Logan@Sun.COM #endif
38*9663SMark.Logan@Sun.COM #ifdef HAVE_STDIO_H
39*9663SMark.Logan@Sun.COM #include <stdio.h>
40*9663SMark.Logan@Sun.COM #endif
41*9663SMark.Logan@Sun.COM #ifdef HAVE_SYS_TYPES_H
42*9663SMark.Logan@Sun.COM #include <sys/types.h>
43*9663SMark.Logan@Sun.COM #endif
44*9663SMark.Logan@Sun.COM #ifdef HAVE_SYS_STAT_H
45*9663SMark.Logan@Sun.COM #include <sys/stat.h>
46*9663SMark.Logan@Sun.COM #endif
47*9663SMark.Logan@Sun.COM #ifdef HAVE_FCNTL_H
48*9663SMark.Logan@Sun.COM #include <fcntl.h>
49*9663SMark.Logan@Sun.COM #endif
50*9663SMark.Logan@Sun.COM #ifdef HAVE_SYS_IOCTL_H
51*9663SMark.Logan@Sun.COM #include <sys/ioctl.h>
52*9663SMark.Logan@Sun.COM #endif
53*9663SMark.Logan@Sun.COM #ifdef HAVE_LINUX_FD_H
54*9663SMark.Logan@Sun.COM #include <linux/fd.h>
55*9663SMark.Logan@Sun.COM #endif
56*9663SMark.Logan@Sun.COM 
57*9663SMark.Logan@Sun.COM #include "types.h"
58*9663SMark.Logan@Sun.COM #include "mst.h"
59*9663SMark.Logan@Sun.COM #include "debug.h"
60*9663SMark.Logan@Sun.COM #include "device.h"
61*9663SMark.Logan@Sun.COM #include "logging.h"
62*9663SMark.Logan@Sun.COM 
63*9663SMark.Logan@Sun.COM #define DEV_FD(dev)	(*(int *)dev->d_private)
64*9663SMark.Logan@Sun.COM 
65*9663SMark.Logan@Sun.COM /* Define to nothing if not present on this system. */
66*9663SMark.Logan@Sun.COM #ifndef O_EXCL
67*9663SMark.Logan@Sun.COM #	define O_EXCL 0
68*9663SMark.Logan@Sun.COM #endif
69*9663SMark.Logan@Sun.COM 
70*9663SMark.Logan@Sun.COM /**
71*9663SMark.Logan@Sun.COM  * ntfs_device_unix_io_open - Open a device and lock it exclusively
72*9663SMark.Logan@Sun.COM  * @dev:
73*9663SMark.Logan@Sun.COM  * @flags:
74*9663SMark.Logan@Sun.COM  *
75*9663SMark.Logan@Sun.COM  * Description...
76*9663SMark.Logan@Sun.COM  *
77*9663SMark.Logan@Sun.COM  * Returns:
78*9663SMark.Logan@Sun.COM  */
79*9663SMark.Logan@Sun.COM static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags)
80*9663SMark.Logan@Sun.COM {
81*9663SMark.Logan@Sun.COM 	struct flock flk;
82*9663SMark.Logan@Sun.COM 	struct stat sbuf;
83*9663SMark.Logan@Sun.COM 	int err;
84*9663SMark.Logan@Sun.COM 
85*9663SMark.Logan@Sun.COM 	if (NDevOpen(dev)) {
86*9663SMark.Logan@Sun.COM 		errno = EBUSY;
87*9663SMark.Logan@Sun.COM 		return -1;
88*9663SMark.Logan@Sun.COM 	}
89*9663SMark.Logan@Sun.COM 	if (!(dev->d_private = ntfs_malloc(sizeof(int))))
90*9663SMark.Logan@Sun.COM 		return -1;
91*9663SMark.Logan@Sun.COM 	*(int*)dev->d_private = open(dev->d_name, flags);
92*9663SMark.Logan@Sun.COM 	if (*(int*)dev->d_private == -1) {
93*9663SMark.Logan@Sun.COM 		err = errno;
94*9663SMark.Logan@Sun.COM 		goto err_out;
95*9663SMark.Logan@Sun.COM 	}
96*9663SMark.Logan@Sun.COM 	/* Setup our read-only flag. */
97*9663SMark.Logan@Sun.COM 	if ((flags & O_RDWR) != O_RDWR)
98*9663SMark.Logan@Sun.COM 		NDevSetReadOnly(dev);
99*9663SMark.Logan@Sun.COM 	/* Acquire exclusive (mandatory) lock on the whole device. */
100*9663SMark.Logan@Sun.COM 	memset(&flk, 0, sizeof(flk));
101*9663SMark.Logan@Sun.COM 	if (NDevReadOnly(dev))
102*9663SMark.Logan@Sun.COM 		flk.l_type = F_RDLCK;
103*9663SMark.Logan@Sun.COM 	else
104*9663SMark.Logan@Sun.COM 		flk.l_type = F_WRLCK;
105*9663SMark.Logan@Sun.COM 	flk.l_whence = SEEK_SET;
106*9663SMark.Logan@Sun.COM 	flk.l_start = flk.l_len = 0LL;
107*9663SMark.Logan@Sun.COM 	if (fcntl(DEV_FD(dev), F_SETLK, &flk)) {
108*9663SMark.Logan@Sun.COM 		err = errno;
109*9663SMark.Logan@Sun.COM 		ntfs_log_debug("ntfs_device_unix_io_open: Could not lock %s "
110*9663SMark.Logan@Sun.COM 				"for %s\n", dev->d_name, NDevReadOnly(dev) ?
111*9663SMark.Logan@Sun.COM 				"reading" : "writing");
112*9663SMark.Logan@Sun.COM 		if (close(DEV_FD(dev)))
113*9663SMark.Logan@Sun.COM 			ntfs_log_perror("ntfs_device_unix_io_open: Warning: "
114*9663SMark.Logan@Sun.COM 					"Could not close %s", dev->d_name);
115*9663SMark.Logan@Sun.COM 		goto err_out;
116*9663SMark.Logan@Sun.COM 	}
117*9663SMark.Logan@Sun.COM 	/* Determine if device is a block device or not, ignoring errors. */
118*9663SMark.Logan@Sun.COM 	if (!fstat(DEV_FD(dev), &sbuf) && S_ISBLK(sbuf.st_mode))
119*9663SMark.Logan@Sun.COM 		NDevSetBlock(dev);
120*9663SMark.Logan@Sun.COM 	/* Set our open flag. */
121*9663SMark.Logan@Sun.COM 	NDevSetOpen(dev);
122*9663SMark.Logan@Sun.COM 	return 0;
123*9663SMark.Logan@Sun.COM err_out:
124*9663SMark.Logan@Sun.COM 	free(dev->d_private);
125*9663SMark.Logan@Sun.COM 	dev->d_private = NULL;
126*9663SMark.Logan@Sun.COM 	errno = err;
127*9663SMark.Logan@Sun.COM 	return -1;
128*9663SMark.Logan@Sun.COM }
129*9663SMark.Logan@Sun.COM 
130*9663SMark.Logan@Sun.COM /**
131*9663SMark.Logan@Sun.COM  * ntfs_device_unix_io_close - Close the device, releasing the lock
132*9663SMark.Logan@Sun.COM  * @dev:
133*9663SMark.Logan@Sun.COM  *
134*9663SMark.Logan@Sun.COM  * Description...
135*9663SMark.Logan@Sun.COM  *
136*9663SMark.Logan@Sun.COM  * Returns:
137*9663SMark.Logan@Sun.COM  */
138*9663SMark.Logan@Sun.COM static int ntfs_device_unix_io_close(struct ntfs_device *dev)
139*9663SMark.Logan@Sun.COM {
140*9663SMark.Logan@Sun.COM 	struct flock flk;
141*9663SMark.Logan@Sun.COM 
142*9663SMark.Logan@Sun.COM 	if (!NDevOpen(dev)) {
143*9663SMark.Logan@Sun.COM 		errno = EBADF;
144*9663SMark.Logan@Sun.COM 		return -1;
145*9663SMark.Logan@Sun.COM 	}
146*9663SMark.Logan@Sun.COM 	if (NDevDirty(dev))
147*9663SMark.Logan@Sun.COM 		fsync(DEV_FD(dev));
148*9663SMark.Logan@Sun.COM 	/* Release exclusive (mandatory) lock on the whole device. */
149*9663SMark.Logan@Sun.COM 	memset(&flk, 0, sizeof(flk));
150*9663SMark.Logan@Sun.COM 	flk.l_type = F_UNLCK;
151*9663SMark.Logan@Sun.COM 	flk.l_whence = SEEK_SET;
152*9663SMark.Logan@Sun.COM 	flk.l_start = flk.l_len = 0LL;
153*9663SMark.Logan@Sun.COM 	if (fcntl(DEV_FD(dev), F_SETLK, &flk))
154*9663SMark.Logan@Sun.COM 		ntfs_log_perror("ntfs_device_unix_io_close: Warning: Could not "
155*9663SMark.Logan@Sun.COM 				"unlock %s", dev->d_name);
156*9663SMark.Logan@Sun.COM 	/* Close the file descriptor and clear our open flag. */
157*9663SMark.Logan@Sun.COM 	if (close(DEV_FD(dev)))
158*9663SMark.Logan@Sun.COM 		return -1;
159*9663SMark.Logan@Sun.COM 	NDevClearOpen(dev);
160*9663SMark.Logan@Sun.COM 	free(dev->d_private);
161*9663SMark.Logan@Sun.COM 	dev->d_private = NULL;
162*9663SMark.Logan@Sun.COM 	return 0;
163*9663SMark.Logan@Sun.COM }
164*9663SMark.Logan@Sun.COM 
165*9663SMark.Logan@Sun.COM /**
166*9663SMark.Logan@Sun.COM  * ntfs_device_unix_io_seek - Seek to a place on the device
167*9663SMark.Logan@Sun.COM  * @dev:
168*9663SMark.Logan@Sun.COM  * @offset:
169*9663SMark.Logan@Sun.COM  * @whence:
170*9663SMark.Logan@Sun.COM  *
171*9663SMark.Logan@Sun.COM  * Description...
172*9663SMark.Logan@Sun.COM  *
173*9663SMark.Logan@Sun.COM  * Returns:
174*9663SMark.Logan@Sun.COM  */
175*9663SMark.Logan@Sun.COM static s64 ntfs_device_unix_io_seek(struct ntfs_device *dev, s64 offset,
176*9663SMark.Logan@Sun.COM 		int whence)
177*9663SMark.Logan@Sun.COM {
178*9663SMark.Logan@Sun.COM 	return lseek(DEV_FD(dev), offset, whence);
179*9663SMark.Logan@Sun.COM }
180*9663SMark.Logan@Sun.COM 
181*9663SMark.Logan@Sun.COM /**
182*9663SMark.Logan@Sun.COM  * ntfs_device_unix_io_read - Read from the device, from the current location
183*9663SMark.Logan@Sun.COM  * @dev:
184*9663SMark.Logan@Sun.COM  * @buf:
185*9663SMark.Logan@Sun.COM  * @count:
186*9663SMark.Logan@Sun.COM  *
187*9663SMark.Logan@Sun.COM  * Description...
188*9663SMark.Logan@Sun.COM  *
189*9663SMark.Logan@Sun.COM  * Returns:
190*9663SMark.Logan@Sun.COM  */
191*9663SMark.Logan@Sun.COM static s64 ntfs_device_unix_io_read(struct ntfs_device *dev, void *buf,
192*9663SMark.Logan@Sun.COM 		s64 count)
193*9663SMark.Logan@Sun.COM {
194*9663SMark.Logan@Sun.COM 	return read(DEV_FD(dev), buf, count);
195*9663SMark.Logan@Sun.COM }
196*9663SMark.Logan@Sun.COM 
197*9663SMark.Logan@Sun.COM /**
198*9663SMark.Logan@Sun.COM  * ntfs_device_unix_io_write - Write to the device, at the current location
199*9663SMark.Logan@Sun.COM  * @dev:
200*9663SMark.Logan@Sun.COM  * @buf:
201*9663SMark.Logan@Sun.COM  * @count:
202*9663SMark.Logan@Sun.COM  *
203*9663SMark.Logan@Sun.COM  * Description...
204*9663SMark.Logan@Sun.COM  *
205*9663SMark.Logan@Sun.COM  * Returns:
206*9663SMark.Logan@Sun.COM  */
207*9663SMark.Logan@Sun.COM static s64 ntfs_device_unix_io_write(struct ntfs_device *dev, const void *buf,
208*9663SMark.Logan@Sun.COM 		s64 count)
209*9663SMark.Logan@Sun.COM {
210*9663SMark.Logan@Sun.COM 	if (NDevReadOnly(dev)) {
211*9663SMark.Logan@Sun.COM 		errno = EROFS;
212*9663SMark.Logan@Sun.COM 		return -1;
213*9663SMark.Logan@Sun.COM 	}
214*9663SMark.Logan@Sun.COM 	NDevSetDirty(dev);
215*9663SMark.Logan@Sun.COM 	return write(DEV_FD(dev), buf, count);
216*9663SMark.Logan@Sun.COM }
217*9663SMark.Logan@Sun.COM 
218*9663SMark.Logan@Sun.COM /**
219*9663SMark.Logan@Sun.COM  * ntfs_device_unix_io_pread - Perform a positioned read from the device
220*9663SMark.Logan@Sun.COM  * @dev:
221*9663SMark.Logan@Sun.COM  * @buf:
222*9663SMark.Logan@Sun.COM  * @count:
223*9663SMark.Logan@Sun.COM  * @offset:
224*9663SMark.Logan@Sun.COM  *
225*9663SMark.Logan@Sun.COM  * Description...
226*9663SMark.Logan@Sun.COM  *
227*9663SMark.Logan@Sun.COM  * Returns:
228*9663SMark.Logan@Sun.COM  */
229*9663SMark.Logan@Sun.COM static s64 ntfs_device_unix_io_pread(struct ntfs_device *dev, void *buf,
230*9663SMark.Logan@Sun.COM 		s64 count, s64 offset)
231*9663SMark.Logan@Sun.COM {
232*9663SMark.Logan@Sun.COM 	return pread(DEV_FD(dev), buf, count, offset);
233*9663SMark.Logan@Sun.COM }
234*9663SMark.Logan@Sun.COM 
235*9663SMark.Logan@Sun.COM /**
236*9663SMark.Logan@Sun.COM  * ntfs_device_unix_io_pwrite - Perform a positioned write to the device
237*9663SMark.Logan@Sun.COM  * @dev:
238*9663SMark.Logan@Sun.COM  * @buf:
239*9663SMark.Logan@Sun.COM  * @count:
240*9663SMark.Logan@Sun.COM  * @offset:
241*9663SMark.Logan@Sun.COM  *
242*9663SMark.Logan@Sun.COM  * Description...
243*9663SMark.Logan@Sun.COM  *
244*9663SMark.Logan@Sun.COM  * Returns:
245*9663SMark.Logan@Sun.COM  */
246*9663SMark.Logan@Sun.COM static s64 ntfs_device_unix_io_pwrite(struct ntfs_device *dev, const void *buf,
247*9663SMark.Logan@Sun.COM 		s64 count, s64 offset)
248*9663SMark.Logan@Sun.COM {
249*9663SMark.Logan@Sun.COM 	if (NDevReadOnly(dev)) {
250*9663SMark.Logan@Sun.COM 		errno = EROFS;
251*9663SMark.Logan@Sun.COM 		return -1;
252*9663SMark.Logan@Sun.COM 	}
253*9663SMark.Logan@Sun.COM 	NDevSetDirty(dev);
254*9663SMark.Logan@Sun.COM 	return pwrite(DEV_FD(dev), buf, count, offset);
255*9663SMark.Logan@Sun.COM }
256*9663SMark.Logan@Sun.COM 
257*9663SMark.Logan@Sun.COM /**
258*9663SMark.Logan@Sun.COM  * ntfs_device_unix_io_sync - Flush any buffered changes to the device
259*9663SMark.Logan@Sun.COM  * @dev:
260*9663SMark.Logan@Sun.COM  *
261*9663SMark.Logan@Sun.COM  * Description...
262*9663SMark.Logan@Sun.COM  *
263*9663SMark.Logan@Sun.COM  * Returns:
264*9663SMark.Logan@Sun.COM  */
265*9663SMark.Logan@Sun.COM static int ntfs_device_unix_io_sync(struct ntfs_device *dev)
266*9663SMark.Logan@Sun.COM {
267*9663SMark.Logan@Sun.COM 	if (!NDevReadOnly(dev) && NDevDirty(dev)) {
268*9663SMark.Logan@Sun.COM 		int res = fsync(DEV_FD(dev));
269*9663SMark.Logan@Sun.COM 		if (!res)
270*9663SMark.Logan@Sun.COM 			NDevClearDirty(dev);
271*9663SMark.Logan@Sun.COM 		return res;
272*9663SMark.Logan@Sun.COM 	}
273*9663SMark.Logan@Sun.COM 	return 0;
274*9663SMark.Logan@Sun.COM }
275*9663SMark.Logan@Sun.COM 
276*9663SMark.Logan@Sun.COM /**
277*9663SMark.Logan@Sun.COM  * ntfs_device_unix_io_stat - Get information about the device
278*9663SMark.Logan@Sun.COM  * @dev:
279*9663SMark.Logan@Sun.COM  * @buf:
280*9663SMark.Logan@Sun.COM  *
281*9663SMark.Logan@Sun.COM  * Description...
282*9663SMark.Logan@Sun.COM  *
283*9663SMark.Logan@Sun.COM  * Returns:
284*9663SMark.Logan@Sun.COM  */
285*9663SMark.Logan@Sun.COM static int ntfs_device_unix_io_stat(struct ntfs_device *dev, struct stat *buf)
286*9663SMark.Logan@Sun.COM {
287*9663SMark.Logan@Sun.COM 	return fstat(DEV_FD(dev), buf);
288*9663SMark.Logan@Sun.COM }
289*9663SMark.Logan@Sun.COM 
290*9663SMark.Logan@Sun.COM /**
291*9663SMark.Logan@Sun.COM  * ntfs_device_unix_io_ioctl - Perform an ioctl on the device
292*9663SMark.Logan@Sun.COM  * @dev:
293*9663SMark.Logan@Sun.COM  * @request:
294*9663SMark.Logan@Sun.COM  * @argp:
295*9663SMark.Logan@Sun.COM  *
296*9663SMark.Logan@Sun.COM  * Description...
297*9663SMark.Logan@Sun.COM  *
298*9663SMark.Logan@Sun.COM  * Returns:
299*9663SMark.Logan@Sun.COM  */
300*9663SMark.Logan@Sun.COM static int ntfs_device_unix_io_ioctl(struct ntfs_device *dev, int request,
301*9663SMark.Logan@Sun.COM 		void *argp)
302*9663SMark.Logan@Sun.COM {
303*9663SMark.Logan@Sun.COM 	return ioctl(DEV_FD(dev), request, argp);
304*9663SMark.Logan@Sun.COM }
305*9663SMark.Logan@Sun.COM 
306*9663SMark.Logan@Sun.COM /**
307*9663SMark.Logan@Sun.COM  * Device operations for working with unix style devices and files.
308*9663SMark.Logan@Sun.COM  */
309*9663SMark.Logan@Sun.COM struct ntfs_device_operations ntfs_device_unix_io_ops = {
310*9663SMark.Logan@Sun.COM 	.open		= ntfs_device_unix_io_open,
311*9663SMark.Logan@Sun.COM 	.close		= ntfs_device_unix_io_close,
312*9663SMark.Logan@Sun.COM 	.seek		= ntfs_device_unix_io_seek,
313*9663SMark.Logan@Sun.COM 	.read		= ntfs_device_unix_io_read,
314*9663SMark.Logan@Sun.COM 	.write		= ntfs_device_unix_io_write,
315*9663SMark.Logan@Sun.COM 	.pread		= ntfs_device_unix_io_pread,
316*9663SMark.Logan@Sun.COM 	.pwrite		= ntfs_device_unix_io_pwrite,
317*9663SMark.Logan@Sun.COM 	.sync		= ntfs_device_unix_io_sync,
318*9663SMark.Logan@Sun.COM 	.stat		= ntfs_device_unix_io_stat,
319*9663SMark.Logan@Sun.COM 	.ioctl		= ntfs_device_unix_io_ioctl,
320*9663SMark.Logan@Sun.COM };
321