xref: /haiku/src/add-ons/kernel/file_systems/ntfs/libntfs/device.c (revision 893988af824e65e49e55f517b157db8386e8002b)
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("pos %lld, count %lld\n",(long long)pos,(long long)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("pos %lld, count %lld\n",(long long)pos,(long long)count);
233 
234 	if (!b || count < 0 || pos < 0) {
235 		errno = EINVAL;
236 		goto out;
237 	}
238 	if (!count)
239 		return 0;
240 	if (NDevReadOnly(dev)) {
241 		errno = EROFS;
242 		goto out;
243 	}
244 
245 	dops = dev->d_ops;
246 
247 	NDevSetDirty(dev);
248 	for (total = 0; count; count -= written, total += written) {
249 		written = dops->pwrite(dev, (const char*)b + total, count,
250 				       pos + total);
251 		/* If everything ok, continue. */
252 		if (written > 0)
253 			continue;
254 		/*
255 		 * If nothing written or error return number of bytes written.
256 		 */
257 		if (!written || total)
258 			break;
259 		/* Nothing written and error, return error status. */
260 		total = written;
261 		break;
262 	}
263 	ret = total;
264 out:
265 	return ret;
266 }
267 
268 /**
269  * ntfs_mst_pread - multi sector transfer (mst) positioned read
270  * @dev:	device to read from
271  * @pos:	position in file descriptor to read from
272  * @count:	number of blocks to read
273  * @bksize:	size of each block that needs mst deprotecting
274  * @b:		output data buffer
275  *
276  * Multi sector transfer (mst) positioned read. This function will read @count
277  * blocks of size @bksize bytes each from device @dev at position @pos into the
278  * the data buffer @b.
279  *
280  * On success, return the number of successfully read blocks. If this number is
281  * lower than @count this means that we have reached end of file, that the read
282  * was interrupted, or that an error was encountered during the read so that
283  * the read is partial. 0 means end of file or nothing was read (also return 0
284  * when @count or @bksize are 0).
285  *
286  * On error and nothing was read, return -1 with errno set appropriately to the
287  * return code of either seek, read, or set to EINVAL in case of invalid
288  * arguments.
289  *
290  * NOTE: If an incomplete multi sector transfer has been detected the magic
291  * will have been changed to magic_BAAD but no error will be returned. Thus it
292  * is possible that we return count blocks as being read but that any number
293  * (between zero and count!) of these blocks is actually subject to a multi
294  * sector transfer error. This should be detected by the caller by checking for
295  * the magic being "BAAD".
296  */
297 s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
298 		const u32 bksize, void *b)
299 {
300 	s64 br, i;
301 
302 	if (bksize & (bksize - 1) || bksize % NTFS_BLOCK_SIZE) {
303 		errno = EINVAL;
304 		return -1;
305 	}
306 	/* Do the read. */
307 	br = ntfs_pread(dev, pos, count * bksize, b);
308 	if (br < 0)
309 		return br;
310 	/*
311 	 * Apply fixups to successfully read data, disregarding any errors
312 	 * returned from the MST fixup function. This is because we want to
313 	 * fixup everything possible and we rely on the fact that the "BAAD"
314 	 * magic will be detected later on.
315 	 */
316 	count = br / bksize;
317 	for (i = 0; i < count; ++i)
318 		ntfs_mst_post_read_fixup((NTFS_RECORD*)
319 				((u8*)b + i * bksize), bksize);
320 	/* Finally, return the number of complete blocks read. */
321 	return count;
322 }
323 
324 /**
325  * ntfs_mst_pwrite - multi sector transfer (mst) positioned write
326  * @dev:	device to write to
327  * @pos:	position in file descriptor to write to
328  * @count:	number of blocks to write
329  * @bksize:	size of each block that needs mst protecting
330  * @b:		data buffer to write to disk
331  *
332  * Multi sector transfer (mst) positioned write. This function will write
333  * @count blocks of size @bksize bytes each from data buffer @b to the device
334  * @dev at position @pos.
335  *
336  * On success, return the number of successfully written blocks. If this number
337  * is lower than @count this means that the write has been interrupted or that
338  * an error was encountered during the write so that the write is partial. 0
339  * means nothing was written (also return 0 when @count or @bksize are 0).
340  *
341  * On error and nothing has been written, return -1 with errno set
342  * appropriately to the return code of either seek, write, or set
343  * to EINVAL in case of invalid arguments.
344  *
345  * NOTE: We mst protect the data, write it, then mst deprotect it using a quick
346  * deprotect algorithm (no checking). This saves us from making a copy before
347  * the write and at the same time causes the usn to be incremented in the
348  * buffer. This conceptually fits in better with the idea that cached data is
349  * always deprotected and protection is performed when the data is actually
350  * going to hit the disk and the cache is immediately deprotected again
351  * simulating an mst read on the written data. This way cache coherency is
352  * achieved.
353  */
354 s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
355 		const u32 bksize, void *b)
356 {
357 	s64 written, i;
358 
359 	if (count < 0 || bksize % NTFS_BLOCK_SIZE) {
360 		errno = EINVAL;
361 		return -1;
362 	}
363 	if (!count)
364 		return 0;
365 	/* Prepare data for writing. */
366 	for (i = 0; i < count; ++i) {
367 		int err;
368 
369 		err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)
370 				((u8*)b + i * bksize), bksize);
371 		if (err < 0) {
372 			/* Abort write at this position. */
373 			if (!i)
374 				return err;
375 			count = i;
376 			break;
377 		}
378 	}
379 	/* Write the prepared data. */
380 	written = ntfs_pwrite(dev, pos, count * bksize, b);
381 	/* Quickly deprotect the data again. */
382 	for (i = 0; i < count; ++i)
383 		ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)b + i * bksize));
384 	if (written <= 0)
385 		return written;
386 	/* Finally, return the number of complete blocks written. */
387 	return written / bksize;
388 }
389 
390 /**
391  * ntfs_cluster_read - read ntfs clusters
392  * @vol:	volume to read from
393  * @lcn:	starting logical cluster number
394  * @count:	number of clusters to read
395  * @b:		output data buffer
396  *
397  * Read @count ntfs clusters starting at logical cluster number @lcn from
398  * volume @vol into buffer @b. Return number of clusters read or -1 on error,
399  * with errno set to the error code.
400  */
401 s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count,
402 		void *b)
403 {
404 	s64 br;
405 
406 	if (!vol || lcn < 0 || count < 0) {
407 		errno = EINVAL;
408 		return -1;
409 	}
410 	if (vol->nr_clusters < lcn + count) {
411 		errno = ESPIPE;
412 		ntfs_log_perror("Trying to read outside of volume "
413 				"(%lld < %lld)", (long long)vol->nr_clusters,
414 			        (long long)lcn + count);
415 		return -1;
416 	}
417 	br = ntfs_pread(vol->dev, lcn << vol->cluster_size_bits,
418 			count << vol->cluster_size_bits, b);
419 	if (br < 0) {
420 		ntfs_log_perror("Error reading cluster(s)");
421 		return br;
422 	}
423 	return br >> vol->cluster_size_bits;
424 }
425 
426 /**
427  * ntfs_cluster_write - write ntfs clusters
428  * @vol:	volume to write to
429  * @lcn:	starting logical cluster number
430  * @count:	number of clusters to write
431  * @b:		data buffer to write to disk
432  *
433  * Write @count ntfs clusters starting at logical cluster number @lcn from
434  * buffer @b to volume @vol. Return the number of clusters written or -1 on
435  * error, with errno set to the error code.
436  */
437 s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
438 		const s64 count, const void *b)
439 {
440 	s64 bw;
441 
442 	if (!vol || lcn < 0 || count < 0) {
443 		errno = EINVAL;
444 		return -1;
445 	}
446 	if (vol->nr_clusters < lcn + count) {
447 		errno = ESPIPE;
448 		ntfs_log_perror("Trying to write outside of volume "
449 				"(%lld < %lld)", (long long)vol->nr_clusters,
450 			        (long long)lcn + count);
451 		return -1;
452 	}
453 	if (!NVolReadOnly(vol))
454 		bw = ntfs_pwrite(vol->dev, lcn << vol->cluster_size_bits,
455 				count << vol->cluster_size_bits, b);
456 	else
457 		bw = count << vol->cluster_size_bits;
458 	if (bw < 0) {
459 		ntfs_log_perror("Error writing cluster(s)");
460 		return bw;
461 	}
462 	return bw >> vol->cluster_size_bits;
463 }
464 
465 /**
466  * ntfs_device_offset_valid - test if a device offset is valid
467  * @dev:	open device
468  * @ofs:	offset to test for validity
469  *
470  * Test if the offset @ofs is an existing location on the device described
471  * by the open device structure @dev.
472  *
473  * Return 0 if it is valid and -1 if it is not valid.
474  */
475 static int ntfs_device_offset_valid(struct ntfs_device *dev, s64 ofs)
476 {
477 	char ch;
478 
479 	if (dev->d_ops->seek(dev, ofs, SEEK_SET) >= 0 &&
480 			dev->d_ops->read(dev, &ch, 1) == 1)
481 		return 0;
482 	return -1;
483 }
484 
485 /**
486  * ntfs_device_size_get - return the size of a device in blocks
487  * @dev:	open device
488  * @block_size:	block size in bytes in which to return the result
489  *
490  * Return the number of @block_size sized blocks in the device described by the
491  * open device @dev.
492  *
493  * Adapted from e2fsutils-1.19, Copyright (C) 1995 Theodore Ts'o.
494  *
495  * On error return -1 with errno set to the error code.
496  */
497 s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
498 {
499 	s64 high, low;
500 
501 	if (!dev || block_size <= 0 || (block_size - 1) & block_size) {
502 		errno = EINVAL;
503 		return -1;
504 	}
505 #ifdef BLKGETSIZE64
506 	{	u64 size;
507 
508 		if (dev->d_ops->ioctl(dev, BLKGETSIZE64, &size) >= 0) {
509 			ntfs_log_debug("BLKGETSIZE64 nr bytes = %llu (0x%llx)\n",
510 					(unsigned long long)size,
511 					(unsigned long long)size);
512 			return (s64)size / block_size;
513 		}
514 	}
515 #endif
516 #ifdef BLKGETSIZE
517 	{	unsigned long size;
518 
519 		if (dev->d_ops->ioctl(dev, BLKGETSIZE, &size) >= 0) {
520 			ntfs_log_debug("BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n",
521 					size, size);
522 			return (s64)size * 512 / block_size;
523 		}
524 	}
525 #endif
526 #ifdef FDGETPRM
527 	{       struct floppy_struct this_floppy;
528 
529 		if (dev->d_ops->ioctl(dev, FDGETPRM, &this_floppy) >= 0) {
530 			ntfs_log_debug("FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n",
531 					(unsigned long)this_floppy.size,
532 					(unsigned long)this_floppy.size);
533 			return (s64)this_floppy.size * 512 / block_size;
534 		}
535 	}
536 #endif
537 	/*
538 	 * We couldn't figure it out by using a specialized ioctl,
539 	 * so do binary search to find the size of the device.
540 	 */
541 	low = 0LL;
542 	for (high = 1024LL; !ntfs_device_offset_valid(dev, high); high <<= 1)
543 		low = high;
544 	while (low < high - 1LL) {
545 		const s64 mid = (low + high) / 2;
546 
547 		if (!ntfs_device_offset_valid(dev, mid))
548 			low = mid;
549 		else
550 			high = mid;
551 	}
552 	dev->d_ops->seek(dev, 0LL, SEEK_SET);
553 	return (low + 1LL) / block_size;
554 }
555 
556 /**
557  * ntfs_device_partition_start_sector_get - get starting sector of a partition
558  * @dev:	open device
559  *
560  * On success, return the starting sector of the partition @dev in the parent
561  * block device of @dev.  On error return -1 with errno set to the error code.
562  *
563  * The following error codes are defined:
564  *	EINVAL		Input parameter error
565  *	EOPNOTSUPP	System does not support HDIO_GETGEO ioctl
566  *	ENOTTY		@dev is a file or a device not supporting HDIO_GETGEO
567  */
568 s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev)
569 {
570 	if (!dev) {
571 		errno = EINVAL;
572 		return -1;
573 	}
574 #ifdef HDIO_GETGEO
575 	{	struct hd_geometry geo;
576 
577 		if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
578 			ntfs_log_debug("HDIO_GETGEO start_sect = %lu (0x%lx)\n",
579 					geo.start, geo.start);
580 			return geo.start;
581 		}
582 	}
583 #else
584 	errno = EOPNOTSUPP;
585 #endif
586 	return -1;
587 }
588 
589 /**
590  * ntfs_device_heads_get - get number of heads of device
591  * @dev:		open device
592  *
593  * On success, return the number of heads on the device @dev.  On error return
594  * -1 with errno set to the error code.
595  *
596  * The following error codes are defined:
597  *	EINVAL		Input parameter error
598  *	EOPNOTSUPP	System does not support HDIO_GETGEO ioctl
599  *	ENOTTY		@dev is a file or a device not supporting HDIO_GETGEO
600  */
601 int ntfs_device_heads_get(struct ntfs_device *dev)
602 {
603 	if (!dev) {
604 		errno = EINVAL;
605 		return -1;
606 	}
607 #ifdef HDIO_GETGEO
608 	{	struct hd_geometry geo;
609 
610 		if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
611 			ntfs_log_debug("HDIO_GETGEO heads = %u (0x%x)\n",
612 					(unsigned)geo.heads,
613 					(unsigned)geo.heads);
614 			return geo.heads;
615 		}
616 	}
617 #else
618 	errno = EOPNOTSUPP;
619 #endif
620 	return -1;
621 }
622 
623 /**
624  * ntfs_device_sectors_per_track_get - get number of sectors per track of device
625  * @dev:		open device
626  *
627  * On success, return the number of sectors per track on the device @dev.  On
628  * error return -1 with errno set to the error code.
629  *
630  * The following error codes are defined:
631  *	EINVAL		Input parameter error
632  *	EOPNOTSUPP	System does not support HDIO_GETGEO ioctl
633  *	ENOTTY		@dev is a file or a device not supporting HDIO_GETGEO
634  */
635 int ntfs_device_sectors_per_track_get(struct ntfs_device *dev)
636 {
637 	if (!dev) {
638 		errno = EINVAL;
639 		return -1;
640 	}
641 #ifdef HDIO_GETGEO
642 	{	struct hd_geometry geo;
643 
644 		if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
645 			ntfs_log_debug("HDIO_GETGEO sectors_per_track = %u (0x%x)\n",
646 					(unsigned)geo.sectors,
647 					(unsigned)geo.sectors);
648 			return geo.sectors;
649 		}
650 	}
651 #else
652 	errno = EOPNOTSUPP;
653 #endif
654 	return -1;
655 }
656 
657 /**
658  * ntfs_device_sector_size_get - get sector size of a device
659  * @dev:	open device
660  *
661  * On success, return the sector size in bytes of the device @dev.
662  * On error return -1 with errno set to the error code.
663  *
664  * The following error codes are defined:
665  *	EINVAL		Input parameter error
666  *	EOPNOTSUPP	System does not support BLKSSZGET ioctl
667  *	ENOTTY		@dev is a file or a device not supporting BLKSSZGET
668  */
669 int ntfs_device_sector_size_get(struct ntfs_device *dev)
670 {
671 	if (!dev) {
672 		errno = EINVAL;
673 		return -1;
674 	}
675 #ifdef BLKSSZGET
676 	{
677 		int sect_size = 0;
678 
679 		if (!dev->d_ops->ioctl(dev, BLKSSZGET, &sect_size)) {
680 			ntfs_log_debug("BLKSSZGET sector size = %d bytes\n",
681 					sect_size);
682 			return sect_size;
683 		}
684 	}
685 #else
686 	errno = EOPNOTSUPP;
687 #endif
688 	return -1;
689 }
690 
691 /**
692  * ntfs_device_block_size_set - set block size of a device
693  * @dev:	open device
694  * @block_size: block size to set @dev to
695  *
696  * On success, return 0.
697  * On error return -1 with errno set to the error code.
698  *
699  * The following error codes are defined:
700  *	EINVAL		Input parameter error
701  *	EOPNOTSUPP	System does not support BLKBSZSET ioctl
702  *	ENOTTY		@dev is a file or a device not supporting BLKBSZSET
703  */
704 int ntfs_device_block_size_set(struct ntfs_device *dev,
705 		int block_size __attribute__((unused)))
706 {
707 	if (!dev) {
708 		errno = EINVAL;
709 		return -1;
710 	}
711 #ifdef BLKBSZSET
712 	{
713 		size_t s_block_size = block_size;
714 		if (!dev->d_ops->ioctl(dev, BLKBSZSET, &s_block_size)) {
715 			ntfs_log_debug("Used BLKBSZSET to set block size to "
716 					"%d bytes.\n", block_size);
717 			return 0;
718 		}
719 		/* If not a block device, pretend it was successful. */
720 		if (!NDevBlock(dev))
721 			return 0;
722 	}
723 #else
724 	/* If not a block device, pretend it was successful. */
725 	if (!NDevBlock(dev))
726 		return 0;
727 	errno = EOPNOTSUPP;
728 #endif
729 	return -1;
730 }
731