xref: /haiku/src/add-ons/kernel/file_systems/ntfs/libntfs/device.c (revision be3db2942c0e8dda63cdd226ec3c99309d3eab0c)
1 /**
2  * device.c - Low level device io functions. Originated from the Linux-NTFS project.
3  *
4  * Copyright (c) 2004-2006 Anton Altaparmakov
5  * Copyright (c) 2004-2006 Szabolcs Szakacsits
6  *
7  * This program/include file is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as published
9  * by the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program/include file is distributed in the hope that it will be
13  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program (in the main directory of the NTFS-3G
19  * distribution in the file COPYING); if not, write to the Free Software
20  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30 #ifdef HAVE_STDLIB_H
31 #include <stdlib.h>
32 #endif
33 #ifdef HAVE_STRING_H
34 #include <string.h>
35 #endif
36 #ifdef HAVE_ERRNO_H
37 #include <errno.h>
38 #endif
39 #ifdef HAVE_STDIO_H
40 #include <stdio.h>
41 #endif
42 #ifdef HAVE_SYS_TYPES_H
43 #include <sys/types.h>
44 #endif
45 #ifdef HAVE_SYS_STAT_H
46 #include <sys/stat.h>
47 #endif
48 #ifdef HAVE_FCNTL_H
49 #include <fcntl.h>
50 #endif
51 #ifdef HAVE_SYS_IOCTL_H
52 #include <sys/ioctl.h>
53 #endif
54 #ifdef HAVE_SYS_PARAM_H
55 #include <sys/param.h>
56 #endif
57 #ifdef HAVE_SYS_MOUNT_H
58 #include <sys/mount.h>
59 #endif
60 #ifdef HAVE_LINUX_FD_H
61 #include <linux/fd.h>
62 #endif
63 #ifdef HAVE_LINUX_HDREG_H
64 #include <linux/hdreg.h>
65 #endif
66 
67 #include "types.h"
68 #include "mst.h"
69 #include "debug.h"
70 #include "device.h"
71 #include "logging.h"
72 #include "misc.h"
73 
74 #if defined(linux) && defined(_IO) && !defined(BLKGETSIZE)
75 #define BLKGETSIZE	_IO(0x12,96)  /* Get device size in 512-byte blocks. */
76 #endif
77 #if defined(linux) && defined(_IOR) && !defined(BLKGETSIZE64)
78 #define BLKGETSIZE64	_IOR(0x12,114,size_t)	/* Get device size in bytes. */
79 #endif
80 #if defined(linux) && !defined(HDIO_GETGEO)
81 #define HDIO_GETGEO	0x0301	/* Get device geometry. */
82 #endif
83 #if defined(linux) && defined(_IO) && !defined(BLKSSZGET)
84 #	define BLKSSZGET _IO(0x12,104) /* Get device sector size in bytes. */
85 #endif
86 #if defined(linux) && defined(_IO) && !defined(BLKBSZSET)
87 #	define BLKBSZSET _IOW(0x12,113,size_t) /* Set device block size in bytes. */
88 #endif
89 
90 /**
91  * ntfs_device_alloc - allocate an ntfs device structure and pre-initialize it
92  * @name:	name of the device (must be present)
93  * @state:	initial device state (usually zero)
94  * @dops:	ntfs device operations to use with the device (must be present)
95  * @priv_data:	pointer to private data (optional)
96  *
97  * Allocate an ntfs device structure and pre-initialize it with the user-
98  * specified device operations @dops, device state @state, device name @name,
99  * and optional private data @priv_data.
100  *
101  * Note, @name is copied and can hence be freed after this functions returns.
102  *
103  * On success return a pointer to the allocated ntfs device structure and on
104  * error return NULL with errno set to the error code returned by ntfs_malloc().
105  */
106 struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
107 		struct ntfs_device_operations *dops, void *priv_data)
108 {
109 	struct ntfs_device *dev;
110 
111 	if (!name) {
112 		errno = EINVAL;
113 		return NULL;
114 	}
115 
116 	dev = ntfs_malloc(sizeof(struct ntfs_device));
117 	if (dev) {
118 		if (!(dev->d_name = strdup(name))) {
119 			int eo = errno;
120 			free(dev);
121 			errno = eo;
122 			return NULL;
123 		}
124 		dev->d_ops = dops;
125 		dev->d_state = state;
126 		dev->d_private = priv_data;
127 	}
128 	return dev;
129 }
130 
131 /**
132  * ntfs_device_free - free an ntfs device structure
133  * @dev:	ntfs device structure to free
134  *
135  * Free the ntfs device structure @dev.
136  *
137  * Return 0 on success or -1 on error with errno set to the error code. The
138  * following error codes are defined:
139  *	EINVAL		Invalid pointer @dev.
140  *	EBUSY		Device is still open. Close it before freeing it!
141  */
142 int ntfs_device_free(struct ntfs_device *dev)
143 {
144 	if (!dev) {
145 		errno = EINVAL;
146 		return -1;
147 	}
148 	if (NDevOpen(dev)) {
149 		errno = EBUSY;
150 		return -1;
151 	}
152 	free(dev->d_name);
153 	free(dev);
154 	return 0;
155 }
156 
157 /**
158  * ntfs_pread - positioned read from disk
159  * @dev:	device to read from
160  * @pos:	position in device to read from
161  * @count:	number of bytes to read
162  * @b:		output data buffer
163  *
164  * This function will read @count bytes from device @dev at position @pos into
165  * the data buffer @b.
166  *
167  * On success, return the number of successfully read bytes. If this number is
168  * lower than @count this means that we have either reached end of file or
169  * encountered an error during the read so that the read is partial. 0 means
170  * end of file or nothing to read (@count is 0).
171  *
172  * On error and nothing has been read, return -1 with errno set appropriately
173  * to the return code of either seek, read, or set to EINVAL in case of
174  * invalid arguments.
175  */
176 s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b)
177 {
178 	s64 br, total;
179 	struct ntfs_device_operations *dops;
180 
181 	ntfs_log_trace("Entering for pos 0x%llx, count 0x%llx.\n", pos, count);
182 
183 	if (!b || count < 0 || pos < 0) {
184 		errno = EINVAL;
185 		return -1;
186 	}
187 	if (!count)
188 		return 0;
189 
190 	dops = dev->d_ops;
191 
192 	for (total = 0; count; count -= br, total += br) {
193 		br = dops->pread(dev, (char*)b + total, count, pos + total);
194 		/* If everything ok, continue. */
195 		if (br > 0)
196 			continue;
197 		/* If EOF or error return number of bytes read. */
198 		if (!br || total)
199 			return total;
200 		/* Nothing read and error, return error status. */
201 		return br;
202 	}
203 	/* Finally, return the number of bytes read. */
204 	return total;
205 }
206 
207 /**
208  * ntfs_pwrite - positioned write to disk
209  * @dev:	device to write to
210  * @pos:	position in file descriptor to write to
211  * @count:	number of bytes to write
212  * @b:		data buffer to write to disk
213  *
214  * This function will write @count bytes from data buffer @b to the device @dev
215  * at position @pos.
216  *
217  * On success, return the number of successfully written bytes. If this number
218  * is lower than @count this means that the write has been interrupted in
219  * flight or that an error was encountered during the write so that the write
220  * is partial. 0 means nothing was written (also return 0 when @count is 0).
221  *
222  * On error and nothing has been written, return -1 with errno set
223  * appropriately to the return code of either seek, write, or set
224  * to EINVAL in case of invalid arguments.
225  */
226 s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
227 		const void *b)
228 {
229 	s64 written, total, ret = -1;
230 	struct ntfs_device_operations *dops;
231 
232 	ntfs_log_trace("Entering for pos 0x%llx, count 0x%llx.\n", pos, count);
233 	if (!b || count < 0 || pos < 0) {
234 		errno = EINVAL;
235 		goto out;
236 	}
237 	if (!count)
238 		return 0;
239 	if (NDevReadOnly(dev)) {
240 		errno = EROFS;
241 		goto out;
242 	}
243 
244 	dops = dev->d_ops;
245 
246 	NDevSetDirty(dev);
247 	for (total = 0; count; count -= written, total += written) {
248 		written = dops->pwrite(dev, (const char*)b + total, count,
249 				       pos + total);
250 		/* If everything ok, continue. */
251 		if (written > 0)
252 			continue;
253 		/*
254 		 * If nothing written or error return number of bytes written.
255 		 */
256 		if (!written || total)
257 			break;
258 		/* Nothing written and error, return error status. */
259 		total = written;
260 		break;
261 	}
262 	ret = total;
263 out:
264 	return ret;
265 }
266 
267 /**
268  * ntfs_mst_pread - multi sector transfer (mst) positioned read
269  * @dev:	device to read from
270  * @pos:	position in file descriptor to read from
271  * @count:	number of blocks to read
272  * @bksize:	size of each block that needs mst deprotecting
273  * @b:		output data buffer
274  *
275  * Multi sector transfer (mst) positioned read. This function will read @count
276  * blocks of size @bksize bytes each from device @dev at position @pos into the
277  * the data buffer @b.
278  *
279  * On success, return the number of successfully read blocks. If this number is
280  * lower than @count this means that we have reached end of file, that the read
281  * was interrupted, or that an error was encountered during the read so that
282  * the read is partial. 0 means end of file or nothing was read (also return 0
283  * when @count or @bksize are 0).
284  *
285  * On error and nothing was read, return -1 with errno set appropriately to the
286  * return code of either seek, read, or set to EINVAL in case of invalid
287  * arguments.
288  *
289  * NOTE: If an incomplete multi sector transfer has been detected the magic
290  * will have been changed to magic_BAAD but no error will be returned. Thus it
291  * is possible that we return count blocks as being read but that any number
292  * (between zero and count!) of these blocks is actually subject to a multi
293  * sector transfer error. This should be detected by the caller by checking for
294  * the magic being "BAAD".
295  */
296 s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
297 		const u32 bksize, void *b)
298 {
299 	s64 br, i;
300 
301 	if (bksize & (bksize - 1) || bksize % NTFS_BLOCK_SIZE) {
302 		errno = EINVAL;
303 		return -1;
304 	}
305 	/* Do the read. */
306 	br = ntfs_pread(dev, pos, count * bksize, b);
307 	if (br < 0)
308 		return br;
309 	/*
310 	 * Apply fixups to successfully read data, disregarding any errors
311 	 * returned from the MST fixup function. This is because we want to
312 	 * fixup everything possible and we rely on the fact that the "BAAD"
313 	 * magic will be detected later on.
314 	 */
315 	count = br / bksize;
316 	for (i = 0; i < count; ++i)
317 		ntfs_mst_post_read_fixup((NTFS_RECORD*)
318 				((u8*)b + i * bksize), bksize);
319 	/* Finally, return the number of complete blocks read. */
320 	return count;
321 }
322 
323 /**
324  * ntfs_mst_pwrite - multi sector transfer (mst) positioned write
325  * @dev:	device to write to
326  * @pos:	position in file descriptor to write to
327  * @count:	number of blocks to write
328  * @bksize:	size of each block that needs mst protecting
329  * @b:		data buffer to write to disk
330  *
331  * Multi sector transfer (mst) positioned write. This function will write
332  * @count blocks of size @bksize bytes each from data buffer @b to the device
333  * @dev at position @pos.
334  *
335  * On success, return the number of successfully written blocks. If this number
336  * is lower than @count this means that the write has been interrupted or that
337  * an error was encountered during the write so that the write is partial. 0
338  * means nothing was written (also return 0 when @count or @bksize are 0).
339  *
340  * On error and nothing has been written, return -1 with errno set
341  * appropriately to the return code of either seek, write, or set
342  * to EINVAL in case of invalid arguments.
343  *
344  * NOTE: We mst protect the data, write it, then mst deprotect it using a quick
345  * deprotect algorithm (no checking). This saves us from making a copy before
346  * the write and at the same time causes the usn to be incremented in the
347  * buffer. This conceptually fits in better with the idea that cached data is
348  * always deprotected and protection is performed when the data is actually
349  * going to hit the disk and the cache is immediately deprotected again
350  * simulating an mst read on the written data. This way cache coherency is
351  * achieved.
352  */
353 s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
354 		const u32 bksize, void *b)
355 {
356 	s64 written, i;
357 
358 	if (count < 0 || bksize % NTFS_BLOCK_SIZE) {
359 		errno = EINVAL;
360 		return -1;
361 	}
362 	if (!count)
363 		return 0;
364 	/* Prepare data for writing. */
365 	for (i = 0; i < count; ++i) {
366 		int err;
367 
368 		err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)
369 				((u8*)b + i * bksize), bksize);
370 		if (err < 0) {
371 			/* Abort write at this position. */
372 			if (!i)
373 				return err;
374 			count = i;
375 			break;
376 		}
377 	}
378 	/* Write the prepared data. */
379 	written = ntfs_pwrite(dev, pos, count * bksize, b);
380 	/* Quickly deprotect the data again. */
381 	for (i = 0; i < count; ++i)
382 		ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)b + i * bksize));
383 	if (written <= 0)
384 		return written;
385 	/* Finally, return the number of complete blocks written. */
386 	return written / bksize;
387 }
388 
389 /**
390  * ntfs_cluster_read - read ntfs clusters
391  * @vol:	volume to read from
392  * @lcn:	starting logical cluster number
393  * @count:	number of clusters to read
394  * @b:		output data buffer
395  *
396  * Read @count ntfs clusters starting at logical cluster number @lcn from
397  * volume @vol into buffer @b. Return number of clusters read or -1 on error,
398  * with errno set to the error code.
399  */
400 s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count,
401 		void *b)
402 {
403 	s64 br;
404 
405 	if (!vol || lcn < 0 || count < 0) {
406 		errno = EINVAL;
407 		return -1;
408 	}
409 	if (vol->nr_clusters < lcn + count) {
410 		errno = ESPIPE;
411 		ntfs_log_perror("Trying to read outside of volume "
412 				"(%lld < %lld)", vol->nr_clusters, lcn + count);
413 		return -1;
414 	}
415 	br = ntfs_pread(vol->dev, lcn << vol->cluster_size_bits,
416 			count << vol->cluster_size_bits, b);
417 	if (br < 0) {
418 		ntfs_log_perror("Error reading cluster(s)");
419 		return br;
420 	}
421 	return br >> vol->cluster_size_bits;
422 }
423 
424 /**
425  * ntfs_cluster_write - write ntfs clusters
426  * @vol:	volume to write to
427  * @lcn:	starting logical cluster number
428  * @count:	number of clusters to write
429  * @b:		data buffer to write to disk
430  *
431  * Write @count ntfs clusters starting at logical cluster number @lcn from
432  * buffer @b to volume @vol. Return the number of clusters written or -1 on
433  * error, with errno set to the error code.
434  */
435 s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
436 		const s64 count, const void *b)
437 {
438 	s64 bw;
439 
440 	if (!vol || lcn < 0 || count < 0) {
441 		errno = EINVAL;
442 		return -1;
443 	}
444 	if (vol->nr_clusters < lcn + count) {
445 		errno = ESPIPE;
446 		ntfs_log_perror("Trying to write outside of volume "
447 				"(%lld < %lld)", vol->nr_clusters, lcn + count);
448 		return -1;
449 	}
450 	if (!NVolReadOnly(vol))
451 		bw = ntfs_pwrite(vol->dev, lcn << vol->cluster_size_bits,
452 				count << vol->cluster_size_bits, b);
453 	else
454 		bw = count << vol->cluster_size_bits;
455 	if (bw < 0) {
456 		ntfs_log_perror("Error writing cluster(s)");
457 		return bw;
458 	}
459 	return bw >> vol->cluster_size_bits;
460 }
461 
462 /**
463  * ntfs_device_offset_valid - test if a device offset is valid
464  * @dev:	open device
465  * @ofs:	offset to test for validity
466  *
467  * Test if the offset @ofs is an existing location on the device described
468  * by the open device structure @dev.
469  *
470  * Return 0 if it is valid and -1 if it is not valid.
471  */
472 static int ntfs_device_offset_valid(struct ntfs_device *dev, s64 ofs)
473 {
474 	char ch;
475 
476 	if (dev->d_ops->seek(dev, ofs, SEEK_SET) >= 0 &&
477 			dev->d_ops->read(dev, &ch, 1) == 1)
478 		return 0;
479 	return -1;
480 }
481 
482 /**
483  * ntfs_device_size_get - return the size of a device in blocks
484  * @dev:	open device
485  * @block_size:	block size in bytes in which to return the result
486  *
487  * Return the number of @block_size sized blocks in the device described by the
488  * open device @dev.
489  *
490  * Adapted from e2fsutils-1.19, Copyright (C) 1995 Theodore Ts'o.
491  *
492  * On error return -1 with errno set to the error code.
493  */
494 s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
495 {
496 	s64 high, low;
497 
498 	if (!dev || block_size <= 0 || (block_size - 1) & block_size) {
499 		errno = EINVAL;
500 		return -1;
501 	}
502 #ifdef BLKGETSIZE64
503 	{	u64 size;
504 
505 		if (dev->d_ops->ioctl(dev, BLKGETSIZE64, &size) >= 0) {
506 			ntfs_log_debug("BLKGETSIZE64 nr bytes = %llu (0x%llx)\n",
507 					(unsigned long long)size,
508 					(unsigned long long)size);
509 			return (s64)size / block_size;
510 		}
511 	}
512 #endif
513 #ifdef BLKGETSIZE
514 	{	unsigned long size;
515 
516 		if (dev->d_ops->ioctl(dev, BLKGETSIZE, &size) >= 0) {
517 			ntfs_log_debug("BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n",
518 					size, size);
519 			return (s64)size * 512 / block_size;
520 		}
521 	}
522 #endif
523 #ifdef FDGETPRM
524 	{       struct floppy_struct this_floppy;
525 
526 		if (dev->d_ops->ioctl(dev, FDGETPRM, &this_floppy) >= 0) {
527 			ntfs_log_debug("FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n",
528 					(unsigned long)this_floppy.size,
529 					(unsigned long)this_floppy.size);
530 			return (s64)this_floppy.size * 512 / block_size;
531 		}
532 	}
533 #endif
534 	/*
535 	 * We couldn't figure it out by using a specialized ioctl,
536 	 * so do binary search to find the size of the device.
537 	 */
538 	low = 0LL;
539 	for (high = 1024LL; !ntfs_device_offset_valid(dev, high); high <<= 1)
540 		low = high;
541 	while (low < high - 1LL) {
542 		const s64 mid = (low + high) / 2;
543 
544 		if (!ntfs_device_offset_valid(dev, mid))
545 			low = mid;
546 		else
547 			high = mid;
548 	}
549 	dev->d_ops->seek(dev, 0LL, SEEK_SET);
550 	return (low + 1LL) / block_size;
551 }
552 
553 /**
554  * ntfs_device_partition_start_sector_get - get starting sector of a partition
555  * @dev:	open device
556  *
557  * On success, return the starting sector of the partition @dev in the parent
558  * block device of @dev.  On error return -1 with errno set to the error code.
559  *
560  * The following error codes are defined:
561  *	EINVAL		Input parameter error
562  *	EOPNOTSUPP	System does not support HDIO_GETGEO ioctl
563  *	ENOTTY		@dev is a file or a device not supporting HDIO_GETGEO
564  */
565 s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev)
566 {
567 	if (!dev) {
568 		errno = EINVAL;
569 		return -1;
570 	}
571 #ifdef HDIO_GETGEO
572 	{	struct hd_geometry geo;
573 
574 		if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
575 			ntfs_log_debug("HDIO_GETGEO start_sect = %lu (0x%lx)\n",
576 					geo.start, geo.start);
577 			return geo.start;
578 		}
579 	}
580 #else
581 	errno = EOPNOTSUPP;
582 #endif
583 	return -1;
584 }
585 
586 /**
587  * ntfs_device_heads_get - get number of heads of device
588  * @dev:		open device
589  *
590  * On success, return the number of heads on the device @dev.  On error return
591  * -1 with errno set to the error code.
592  *
593  * The following error codes are defined:
594  *	EINVAL		Input parameter error
595  *	EOPNOTSUPP	System does not support HDIO_GETGEO ioctl
596  *	ENOTTY		@dev is a file or a device not supporting HDIO_GETGEO
597  */
598 int ntfs_device_heads_get(struct ntfs_device *dev)
599 {
600 	if (!dev) {
601 		errno = EINVAL;
602 		return -1;
603 	}
604 #ifdef HDIO_GETGEO
605 	{	struct hd_geometry geo;
606 
607 		if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
608 			ntfs_log_debug("HDIO_GETGEO heads = %u (0x%x)\n",
609 					(unsigned)geo.heads,
610 					(unsigned)geo.heads);
611 			return geo.heads;
612 		}
613 	}
614 #else
615 	errno = EOPNOTSUPP;
616 #endif
617 	return -1;
618 }
619 
620 /**
621  * ntfs_device_sectors_per_track_get - get number of sectors per track of device
622  * @dev:		open device
623  *
624  * On success, return the number of sectors per track on the device @dev.  On
625  * error return -1 with errno set to the error code.
626  *
627  * The following error codes are defined:
628  *	EINVAL		Input parameter error
629  *	EOPNOTSUPP	System does not support HDIO_GETGEO ioctl
630  *	ENOTTY		@dev is a file or a device not supporting HDIO_GETGEO
631  */
632 int ntfs_device_sectors_per_track_get(struct ntfs_device *dev)
633 {
634 	if (!dev) {
635 		errno = EINVAL;
636 		return -1;
637 	}
638 #ifdef HDIO_GETGEO
639 	{	struct hd_geometry geo;
640 
641 		if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
642 			ntfs_log_debug("HDIO_GETGEO sectors_per_track = %u (0x%x)\n",
643 					(unsigned)geo.sectors,
644 					(unsigned)geo.sectors);
645 			return geo.sectors;
646 		}
647 	}
648 #else
649 	errno = EOPNOTSUPP;
650 #endif
651 	return -1;
652 }
653 
654 /**
655  * ntfs_device_sector_size_get - get sector size of a device
656  * @dev:	open device
657  *
658  * On success, return the sector size in bytes of the device @dev.
659  * On error return -1 with errno set to the error code.
660  *
661  * The following error codes are defined:
662  *	EINVAL		Input parameter error
663  *	EOPNOTSUPP	System does not support BLKSSZGET ioctl
664  *	ENOTTY		@dev is a file or a device not supporting BLKSSZGET
665  */
666 int ntfs_device_sector_size_get(struct ntfs_device *dev)
667 {
668 	if (!dev) {
669 		errno = EINVAL;
670 		return -1;
671 	}
672 #ifdef BLKSSZGET
673 	{
674 		int sect_size = 0;
675 
676 		if (!dev->d_ops->ioctl(dev, BLKSSZGET, &sect_size)) {
677 			ntfs_log_debug("BLKSSZGET sector size = %d bytes\n",
678 					sect_size);
679 			return sect_size;
680 		}
681 	}
682 #else
683 	errno = EOPNOTSUPP;
684 #endif
685 	return -1;
686 }
687 
688 /**
689  * ntfs_device_block_size_set - set block size of a device
690  * @dev:	open device
691  * @block_size: block size to set @dev to
692  *
693  * On success, return 0.
694  * On error return -1 with errno set to the error code.
695  *
696  * The following error codes are defined:
697  *	EINVAL		Input parameter error
698  *	EOPNOTSUPP	System does not support BLKBSZSET ioctl
699  *	ENOTTY		@dev is a file or a device not supporting BLKBSZSET
700  */
701 int ntfs_device_block_size_set(struct ntfs_device *dev,
702 		int block_size __attribute__((unused)))
703 {
704 	if (!dev) {
705 		errno = EINVAL;
706 		return -1;
707 	}
708 #ifdef BLKBSZSET
709 	{
710 		size_t s_block_size = block_size;
711 		if (!dev->d_ops->ioctl(dev, BLKBSZSET, &s_block_size)) {
712 			ntfs_log_debug("Used BLKBSZSET to set block size to "
713 					"%d bytes.\n", block_size);
714 			return 0;
715 		}
716 		/* If not a block device, pretend it was successful. */
717 		if (!NDevBlock(dev))
718 			return 0;
719 	}
720 #else
721 	/* If not a block device, pretend it was successful. */
722 	if (!NDevBlock(dev))
723 		return 0;
724 	errno = EOPNOTSUPP;
725 #endif
726 	return -1;
727 }
728