1 /**
2 * device.c - Low level device io functions. Originated from the Linux-NTFS project.
3 *
4 * Copyright (c) 2004-2013 Anton Altaparmakov
5 * Copyright (c) 2004-2006 Szabolcs Szakacsits
6 * Copyright (c) 2010 Jean-Pierre Andre
7 * Copyright (c) 2008-2013 Tuxera Inc.
8 *
9 * This program/include file is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as published
11 * by the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program/include file is distributed in the hope that it will be
15 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program (in the main directory of the NTFS-3G
21 * distribution in the file COPYING); if not, write to the Free Software
22 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 #ifdef HAVE_STDLIB_H
33 #include <stdlib.h>
34 #endif
35 #ifdef HAVE_STRING_H
36 #include <string.h>
37 #endif
38 #ifdef HAVE_ERRNO_H
39 #include <errno.h>
40 #endif
41 #ifdef HAVE_STDIO_H
42 #include <stdio.h>
43 #endif
44 #ifdef HAVE_SYS_TYPES_H
45 #include <sys/types.h>
46 #endif
47 #ifdef HAVE_SYS_STAT_H
48 #include <sys/stat.h>
49 #endif
50 #ifdef HAVE_FCNTL_H
51 #include <fcntl.h>
52 #endif
53 #ifdef HAVE_SYS_IOCTL_H
54 #include <sys/ioctl.h>
55 #endif
56 #ifdef HAVE_SYS_PARAM_H
57 #include <sys/param.h>
58 #endif
59 #ifdef HAVE_SYS_MOUNT_H
60 #include <sys/mount.h>
61 #endif
62 #ifdef HAVE_SYS_DISK_H
63 #include <sys/disk.h>
64 #endif
65 #ifdef HAVE_LINUX_FD_H
66 #include <linux/fd.h>
67 #endif
68 #ifdef HAVE_LINUX_HDREG_H
69 #include <linux/hdreg.h>
70 #endif
71 #ifdef ENABLE_HD
72 #include <hd.h>
73 #endif
74 #ifdef __HAIKU__
75 #include <Drivers.h>
76 #endif
77
78 #include "types.h"
79 #include "mst.h"
80 #include "debug.h"
81 #include "device.h"
82 #include "logging.h"
83 #include "misc.h"
84
85 #if defined(linux) && defined(_IO) && !defined(BLKGETSIZE)
86 #define BLKGETSIZE _IO(0x12,96) /* Get device size in 512-byte blocks. */
87 #endif
88 #if defined(linux) && defined(_IOR) && !defined(BLKGETSIZE64)
89 #define BLKGETSIZE64 _IOR(0x12,114,size_t) /* Get device size in bytes. */
90 #endif
91 #if defined(linux) && !defined(HDIO_GETGEO)
92 #define HDIO_GETGEO 0x0301 /* Get device geometry. */
93 #endif
94 #if defined(linux) && defined(_IO) && !defined(BLKSSZGET)
95 # define BLKSSZGET _IO(0x12,104) /* Get device sector size in bytes. */
96 #endif
97 #if defined(linux) && defined(_IO) && !defined(BLKBSZSET)
98 # define BLKBSZSET _IOW(0x12,113,size_t) /* Set device block size in bytes. */
99 #endif
100
101 /**
102 * ntfs_device_alloc - allocate an ntfs device structure and pre-initialize it
103 * @name: name of the device (must be present)
104 * @state: initial device state (usually zero)
105 * @dops: ntfs device operations to use with the device (must be present)
106 * @priv_data: pointer to private data (optional)
107 *
108 * Allocate an ntfs device structure and pre-initialize it with the user-
109 * specified device operations @dops, device state @state, device name @name,
110 * and optional private data @priv_data.
111 *
112 * Note, @name is copied and can hence be freed after this functions returns.
113 *
114 * On success return a pointer to the allocated ntfs device structure and on
115 * error return NULL with errno set to the error code returned by ntfs_malloc().
116 */
ntfs_device_alloc(const char * name,const long state,struct ntfs_device_operations * dops,void * priv_data)117 struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
118 struct ntfs_device_operations *dops, void *priv_data)
119 {
120 struct ntfs_device *dev;
121
122 if (!name) {
123 errno = EINVAL;
124 return NULL;
125 }
126
127 dev = ntfs_malloc(sizeof(struct ntfs_device));
128 if (dev) {
129 if (!(dev->d_name = strdup(name))) {
130 int eo = errno;
131 free(dev);
132 errno = eo;
133 return NULL;
134 }
135 dev->d_ops = dops;
136 dev->d_state = state;
137 dev->d_private = priv_data;
138 dev->d_heads = -1;
139 dev->d_sectors_per_track = -1;
140 }
141 return dev;
142 }
143
144 /**
145 * ntfs_device_free - free an ntfs device structure
146 * @dev: ntfs device structure to free
147 *
148 * Free the ntfs device structure @dev.
149 *
150 * Return 0 on success or -1 on error with errno set to the error code. The
151 * following error codes are defined:
152 * EINVAL Invalid pointer @dev.
153 * EBUSY Device is still open. Close it before freeing it!
154 */
ntfs_device_free(struct ntfs_device * dev)155 int ntfs_device_free(struct ntfs_device *dev)
156 {
157 if (!dev) {
158 errno = EINVAL;
159 return -1;
160 }
161 if (NDevOpen(dev)) {
162 errno = EBUSY;
163 return -1;
164 }
165 free(dev->d_name);
166 free(dev);
167 return 0;
168 }
169
170 /*
171 * Sync the device
172 *
173 * returns zero if successful.
174 */
175
ntfs_device_sync(struct ntfs_device * dev)176 int ntfs_device_sync(struct ntfs_device *dev)
177 {
178 int ret;
179 struct ntfs_device_operations *dops;
180
181 if (NDevDirty(dev)) {
182 dops = dev->d_ops;
183 ret = dops->sync(dev);
184 } else
185 ret = 0;
186 return ret;
187 }
188
189 /**
190 * ntfs_pread - positioned read from disk
191 * @dev: device to read from
192 * @pos: position in device to read from
193 * @count: number of bytes to read
194 * @b: output data buffer
195 *
196 * This function will read @count bytes from device @dev at position @pos into
197 * the data buffer @b.
198 *
199 * On success, return the number of successfully read bytes. If this number is
200 * lower than @count this means that we have either reached end of file or
201 * encountered an error during the read so that the read is partial. 0 means
202 * end of file or nothing to read (@count is 0).
203 *
204 * On error and nothing has been read, return -1 with errno set appropriately
205 * to the return code of either seek, read, or set to EINVAL in case of
206 * invalid arguments.
207 */
ntfs_pread(struct ntfs_device * dev,const s64 pos,s64 count,void * b)208 s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b)
209 {
210 s64 br, total;
211 struct ntfs_device_operations *dops;
212
213 ntfs_log_trace("pos %lld, count %lld\n",(long long)pos,(long long)count);
214
215 if (!b || count < 0 || pos < 0) {
216 errno = EINVAL;
217 return -1;
218 }
219 if (!count)
220 return 0;
221
222 dops = dev->d_ops;
223
224 for (total = 0; count; count -= br, total += br) {
225 br = dops->pread(dev, (char*)b + total, count, pos + total);
226 /* If everything ok, continue. */
227 if (br > 0)
228 continue;
229 /* If EOF or error return number of bytes read. */
230 if (!br || total)
231 return total;
232 /* Nothing read and error, return error status. */
233 return br;
234 }
235 /* Finally, return the number of bytes read. */
236 return total;
237 }
238
239 /**
240 * ntfs_pwrite - positioned write to disk
241 * @dev: device to write to
242 * @pos: position in file descriptor to write to
243 * @count: number of bytes to write
244 * @b: data buffer to write to disk
245 *
246 * This function will write @count bytes from data buffer @b to the device @dev
247 * at position @pos.
248 *
249 * On success, return the number of successfully written bytes. If this number
250 * is lower than @count this means that the write has been interrupted in
251 * flight or that an error was encountered during the write so that the write
252 * is partial. 0 means nothing was written (also return 0 when @count is 0).
253 *
254 * On error and nothing has been written, return -1 with errno set
255 * appropriately to the return code of either seek, write, or set
256 * to EINVAL in case of invalid arguments.
257 */
ntfs_pwrite(struct ntfs_device * dev,const s64 pos,s64 count,const void * b)258 s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
259 const void *b)
260 {
261 s64 written, total, ret = -1;
262 struct ntfs_device_operations *dops;
263
264 ntfs_log_trace("pos %lld, count %lld\n",(long long)pos,(long long)count);
265
266 if (!b || count < 0 || pos < 0) {
267 errno = EINVAL;
268 goto out;
269 }
270 if (!count)
271 return 0;
272 if (NDevReadOnly(dev)) {
273 errno = EROFS;
274 goto out;
275 }
276
277 dops = dev->d_ops;
278
279 NDevSetDirty(dev);
280 for (total = 0; count; count -= written, total += written) {
281 written = dops->pwrite(dev, (const char*)b + total, count,
282 pos + total);
283 /* If everything ok, continue. */
284 if (written > 0)
285 continue;
286 /*
287 * If nothing written or error return number of bytes written.
288 */
289 if (!written || total)
290 break;
291 /* Nothing written and error, return error status. */
292 total = written;
293 break;
294 }
295 if (NDevSync(dev) && total && dops->sync(dev)) {
296 total--; /* on sync error, return partially written */
297 }
298 ret = total;
299 out:
300 return ret;
301 }
302
303 /**
304 * ntfs_mst_pread - multi sector transfer (mst) positioned read
305 * @dev: device to read from
306 * @pos: position in file descriptor to read from
307 * @count: number of blocks to read
308 * @bksize: size of each block that needs mst deprotecting
309 * @b: output data buffer
310 *
311 * Multi sector transfer (mst) positioned read. This function will read @count
312 * blocks of size @bksize bytes each from device @dev at position @pos into the
313 * the data buffer @b.
314 *
315 * On success, return the number of successfully read blocks. If this number is
316 * lower than @count this means that we have reached end of file, that the read
317 * was interrupted, or that an error was encountered during the read so that
318 * the read is partial. 0 means end of file or nothing was read (also return 0
319 * when @count or @bksize are 0).
320 *
321 * On error and nothing was read, return -1 with errno set appropriately to the
322 * return code of either seek, read, or set to EINVAL in case of invalid
323 * arguments.
324 *
325 * NOTE: If an incomplete multi sector transfer has been detected the magic
326 * will have been changed to magic_BAAD but no error will be returned. Thus it
327 * is possible that we return count blocks as being read but that any number
328 * (between zero and count!) of these blocks is actually subject to a multi
329 * sector transfer error. This should be detected by the caller by checking for
330 * the magic being "BAAD".
331 */
ntfs_mst_pread(struct ntfs_device * dev,const s64 pos,s64 count,const u32 bksize,void * b)332 s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
333 const u32 bksize, void *b)
334 {
335 s64 br, i;
336
337 if (bksize & (bksize - 1) || bksize % NTFS_BLOCK_SIZE) {
338 errno = EINVAL;
339 return -1;
340 }
341 /* Do the read. */
342 br = ntfs_pread(dev, pos, count * bksize, b);
343 if (br < 0)
344 return br;
345 /*
346 * Apply fixups to successfully read data, disregarding any errors
347 * returned from the MST fixup function. This is because we want to
348 * fixup everything possible and we rely on the fact that the "BAAD"
349 * magic will be detected later on.
350 */
351 count = br / bksize;
352 for (i = 0; i < count; ++i)
353 ntfs_mst_post_read_fixup((NTFS_RECORD*)
354 ((u8*)b + i * bksize), bksize);
355 /* Finally, return the number of complete blocks read. */
356 return count;
357 }
358
359 /**
360 * ntfs_mst_pwrite - multi sector transfer (mst) positioned write
361 * @dev: device to write to
362 * @pos: position in file descriptor to write to
363 * @count: number of blocks to write
364 * @bksize: size of each block that needs mst protecting
365 * @b: data buffer to write to disk
366 *
367 * Multi sector transfer (mst) positioned write. This function will write
368 * @count blocks of size @bksize bytes each from data buffer @b to the device
369 * @dev at position @pos.
370 *
371 * On success, return the number of successfully written blocks. If this number
372 * is lower than @count this means that the write has been interrupted or that
373 * an error was encountered during the write so that the write is partial. 0
374 * means nothing was written (also return 0 when @count or @bksize are 0).
375 *
376 * On error and nothing has been written, return -1 with errno set
377 * appropriately to the return code of either seek, write, or set
378 * to EINVAL in case of invalid arguments.
379 *
380 * NOTE: We mst protect the data, write it, then mst deprotect it using a quick
381 * deprotect algorithm (no checking). This saves us from making a copy before
382 * the write and at the same time causes the usn to be incremented in the
383 * buffer. This conceptually fits in better with the idea that cached data is
384 * always deprotected and protection is performed when the data is actually
385 * going to hit the disk and the cache is immediately deprotected again
386 * simulating an mst read on the written data. This way cache coherency is
387 * achieved.
388 */
ntfs_mst_pwrite(struct ntfs_device * dev,const s64 pos,s64 count,const u32 bksize,void * b)389 s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
390 const u32 bksize, void *b)
391 {
392 s64 written, i;
393
394 if (count < 0 || bksize % NTFS_BLOCK_SIZE) {
395 errno = EINVAL;
396 return -1;
397 }
398 if (!count)
399 return 0;
400 /* Prepare data for writing. */
401 for (i = 0; i < count; ++i) {
402 int err;
403
404 err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)
405 ((u8*)b + i * bksize), bksize);
406 if (err < 0) {
407 /* Abort write at this position. */
408 if (!i)
409 return err;
410 count = i;
411 break;
412 }
413 }
414 /* Write the prepared data. */
415 written = ntfs_pwrite(dev, pos, count * bksize, b);
416 /* Quickly deprotect the data again. */
417 for (i = 0; i < count; ++i)
418 ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)b + i * bksize));
419 if (written <= 0)
420 return written;
421 /* Finally, return the number of complete blocks written. */
422 return written / bksize;
423 }
424
425 /**
426 * ntfs_cluster_read - read ntfs clusters
427 * @vol: volume to read from
428 * @lcn: starting logical cluster number
429 * @count: number of clusters to read
430 * @b: output data buffer
431 *
432 * Read @count ntfs clusters starting at logical cluster number @lcn from
433 * volume @vol into buffer @b. Return number of clusters read or -1 on error,
434 * with errno set to the error code.
435 */
ntfs_cluster_read(const ntfs_volume * vol,const s64 lcn,const s64 count,void * b)436 s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count,
437 void *b)
438 {
439 s64 br;
440
441 if (!vol || lcn < 0 || count < 0) {
442 errno = EINVAL;
443 return -1;
444 }
445 if (vol->nr_clusters < lcn + count) {
446 errno = ESPIPE;
447 ntfs_log_perror("Trying to read outside of volume "
448 "(%lld < %lld)", (long long)vol->nr_clusters,
449 (long long)lcn + count);
450 return -1;
451 }
452 br = ntfs_pread(vol->dev, lcn << vol->cluster_size_bits,
453 count << vol->cluster_size_bits, b);
454 if (br < 0) {
455 ntfs_log_perror("Error reading cluster(s)");
456 return br;
457 }
458 return br >> vol->cluster_size_bits;
459 }
460
461 /**
462 * ntfs_cluster_write - write ntfs clusters
463 * @vol: volume to write to
464 * @lcn: starting logical cluster number
465 * @count: number of clusters to write
466 * @b: data buffer to write to disk
467 *
468 * Write @count ntfs clusters starting at logical cluster number @lcn from
469 * buffer @b to volume @vol. Return the number of clusters written or -1 on
470 * error, with errno set to the error code.
471 */
ntfs_cluster_write(const ntfs_volume * vol,const s64 lcn,const s64 count,const void * b)472 s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
473 const s64 count, const void *b)
474 {
475 s64 bw;
476
477 if (!vol || lcn < 0 || count < 0) {
478 errno = EINVAL;
479 return -1;
480 }
481 if (vol->nr_clusters < lcn + count) {
482 errno = ESPIPE;
483 ntfs_log_perror("Trying to write outside of volume "
484 "(%lld < %lld)", (long long)vol->nr_clusters,
485 (long long)lcn + count);
486 return -1;
487 }
488 if (!NVolReadOnly(vol))
489 bw = ntfs_pwrite(vol->dev, lcn << vol->cluster_size_bits,
490 count << vol->cluster_size_bits, b);
491 else
492 bw = count << vol->cluster_size_bits;
493 if (bw < 0) {
494 ntfs_log_perror("Error writing cluster(s)");
495 return bw;
496 }
497 return bw >> vol->cluster_size_bits;
498 }
499
500 /**
501 * ntfs_device_offset_valid - test if a device offset is valid
502 * @dev: open device
503 * @ofs: offset to test for validity
504 *
505 * Test if the offset @ofs is an existing location on the device described
506 * by the open device structure @dev.
507 *
508 * Return 0 if it is valid and -1 if it is not valid.
509 */
ntfs_device_offset_valid(struct ntfs_device * dev,s64 ofs)510 static int ntfs_device_offset_valid(struct ntfs_device *dev, s64 ofs)
511 {
512 char ch;
513
514 if (dev->d_ops->seek(dev, ofs, SEEK_SET) >= 0 &&
515 dev->d_ops->read(dev, &ch, 1) == 1)
516 return 0;
517 return -1;
518 }
519
520 /**
521 * ntfs_device_size_get - return the size of a device in blocks
522 * @dev: open device
523 * @block_size: block size in bytes in which to return the result
524 *
525 * Return the number of @block_size sized blocks in the device described by the
526 * open device @dev.
527 *
528 * Adapted from e2fsutils-1.19, Copyright (C) 1995 Theodore Ts'o.
529 *
530 * On error return -1 with errno set to the error code.
531 */
ntfs_device_size_get(struct ntfs_device * dev,int block_size)532 s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
533 {
534 s64 high, low;
535
536 if (!dev || block_size <= 0 || (block_size - 1) & block_size) {
537 errno = EINVAL;
538 return -1;
539 }
540 #ifdef BLKGETSIZE64
541 { u64 size;
542
543 if (dev->d_ops->ioctl(dev, BLKGETSIZE64, &size) >= 0) {
544 ntfs_log_debug("BLKGETSIZE64 nr bytes = %llu (0x%llx)\n",
545 (unsigned long long)size,
546 (unsigned long long)size);
547 return (s64)size / block_size;
548 }
549 }
550 #endif
551 #ifdef BLKGETSIZE
552 { unsigned long size;
553
554 if (dev->d_ops->ioctl(dev, BLKGETSIZE, &size) >= 0) {
555 ntfs_log_debug("BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n",
556 size, size);
557 return (s64)size * 512 / block_size;
558 }
559 }
560 #endif
561 #ifdef FDGETPRM
562 { struct floppy_struct this_floppy;
563
564 if (dev->d_ops->ioctl(dev, FDGETPRM, &this_floppy) >= 0) {
565 ntfs_log_debug("FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n",
566 (unsigned long)this_floppy.size,
567 (unsigned long)this_floppy.size);
568 return (s64)this_floppy.size * 512 / block_size;
569 }
570 }
571 #endif
572 #ifdef DIOCGMEDIASIZE
573 {
574 /* FreeBSD */
575 off_t size;
576
577 if (dev->d_ops->ioctl(dev, DIOCGMEDIASIZE, &size) >= 0) {
578 ntfs_log_debug("DIOCGMEDIASIZE nr bytes = %llu (0x%llx)\n",
579 (unsigned long long)size,
580 (unsigned long long)size);
581 return (s64)size / block_size;
582 }
583 }
584 #endif
585 #ifdef DKIOCGETBLOCKCOUNT
586 {
587 /* Mac OS X */
588 uint64_t blocks;
589 int sector_size;
590
591 sector_size = ntfs_device_sector_size_get(dev);
592 if (sector_size >= 0 && dev->d_ops->ioctl(dev,
593 DKIOCGETBLOCKCOUNT, &blocks) >= 0)
594 {
595 ntfs_log_debug("DKIOCGETBLOCKCOUNT nr blocks = %llu (0x%llx)\n",
596 (unsigned long long) blocks,
597 (unsigned long long) blocks);
598 return blocks * sector_size / block_size;
599 }
600 }
601 #endif
602 #ifdef __HAIKU__
603 {
604 off_t size = 0;
605
606 partition_info partitionInfo;
607 device_geometry geometry;
608
609 if (dev->d_ops->control(dev, B_GET_PARTITION_INFO, &partitionInfo) == 0)
610 size = partitionInfo.size;
611 else if (dev->d_ops->control(dev, B_GET_GEOMETRY, &geometry) == 0) {
612 size = (off_t)geometry.cylinder_count * geometry.sectors_per_track
613 * geometry.head_count * geometry.bytes_per_sector;
614 }
615
616 if (size > 0)
617 return (s64)size / block_size;
618 }
619 #endif
620
621 /*
622 * We couldn't figure it out by using a specialized ioctl,
623 * so do binary search to find the size of the device.
624 */
625 low = 0LL;
626 for (high = 1024LL; !ntfs_device_offset_valid(dev, high); high <<= 1)
627 low = high;
628 while (low < high - 1LL) {
629 const s64 mid = (low + high) / 2;
630
631 if (!ntfs_device_offset_valid(dev, mid))
632 low = mid;
633 else
634 high = mid;
635 }
636 dev->d_ops->seek(dev, 0LL, SEEK_SET);
637 return (low + 1LL) / block_size;
638 }
639
640 /**
641 * ntfs_device_partition_start_sector_get - get starting sector of a partition
642 * @dev: open device
643 *
644 * On success, return the starting sector of the partition @dev in the parent
645 * block device of @dev. On error return -1 with errno set to the error code.
646 *
647 * The following error codes are defined:
648 * EINVAL Input parameter error
649 * EOPNOTSUPP System does not support HDIO_GETGEO ioctl
650 * ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
651 */
ntfs_device_partition_start_sector_get(struct ntfs_device * dev)652 s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev)
653 {
654 if (!dev) {
655 errno = EINVAL;
656 return -1;
657 }
658 #ifdef HDIO_GETGEO
659 { struct hd_geometry geo;
660
661 if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
662 ntfs_log_debug("HDIO_GETGEO start_sect = %lu (0x%lx)\n",
663 geo.start, geo.start);
664 return geo.start;
665 }
666 }
667 #else
668 errno = EOPNOTSUPP;
669 #endif
670 return -1;
671 }
672
ntfs_device_get_geo(struct ntfs_device * dev)673 static int ntfs_device_get_geo(struct ntfs_device *dev)
674 {
675 int err;
676
677 if (!dev) {
678 errno = EINVAL;
679 return -1;
680 }
681 err = EOPNOTSUPP;
682 #ifdef ENABLE_HD
683 {
684 hd_data_t *hddata;
685 hd_t *hd, *devlist, *partlist = NULL;
686 str_list_t *names;
687 hd_res_t *res;
688 const int d_name_len = strlen(dev->d_name) + 1;
689 int done = 0;
690
691 hddata = calloc(1, sizeof(*hddata));
692 if (!hddata) {
693 err = ENOMEM;
694 goto skip_hd;
695 }
696 /* List all "disk" class devices on the system. */
697 devlist = hd_list(hddata, hw_disk, 1, NULL);
698 if (!devlist) {
699 free(hddata);
700 err = ENOMEM;
701 goto skip_hd;
702 }
703 /*
704 * Loop over each disk device looking for the device with the
705 * same unix name as @dev.
706 */
707 for (hd = devlist; hd; hd = hd->next) {
708 if (hd->unix_dev_name && !strncmp(dev->d_name,
709 hd->unix_dev_name, d_name_len))
710 goto got_hd;
711 if (hd->unix_dev_name2 && !strncmp(dev->d_name,
712 hd->unix_dev_name2, d_name_len))
713 goto got_hd;
714 for (names = hd->unix_dev_names; names;
715 names = names->next) {
716 if (names->str && !strncmp(dev->d_name,
717 names->str, d_name_len))
718 goto got_hd;
719 }
720 }
721 /*
722 * Device was not a whole disk device. Unless it is a file it
723 * is likely to be a partition device. List all "partition"
724 * class devices on the system.
725 */
726 partlist = hd_list(hddata, hw_partition, 1, NULL);
727 for (hd = partlist; hd; hd = hd->next) {
728 if (hd->unix_dev_name && !strncmp(dev->d_name,
729 hd->unix_dev_name, d_name_len))
730 goto got_part_hd;
731 if (hd->unix_dev_name2 && !strncmp(dev->d_name,
732 hd->unix_dev_name2, d_name_len))
733 goto got_part_hd;
734 for (names = hd->unix_dev_names; names;
735 names = names->next) {
736 if (names->str && !strncmp(dev->d_name,
737 names->str, d_name_len))
738 goto got_part_hd;
739 }
740 }
741 /* Failed to find the device. Stop trying and clean up. */
742 goto end_hd;
743 got_part_hd:
744 /* Get the whole block device the partition device is on. */
745 hd = hd_get_device_by_idx(hddata, hd->attached_to);
746 if (!hd)
747 goto end_hd;
748 got_hd:
749 /*
750 * @hd is now the whole block device either being formatted or
751 * that the partition being formatted is on.
752 *
753 * Loop over each resource of the disk device looking for the
754 * BIOS legacy geometry obtained from EDD which is what Windows
755 * needs to boot.
756 */
757 for (res = hd->res; res; res = res->next) {
758 /* geotype 3 is BIOS legacy. */
759 if (res->any.type != res_disk_geo ||
760 res->disk_geo.geotype != 3)
761 continue;
762 dev->d_heads = res->disk_geo.heads;
763 dev->d_sectors_per_track = res->disk_geo.sectors;
764 done = 1;
765 }
766 end_hd:
767 if (partlist)
768 hd_free_hd_list(partlist);
769 hd_free_hd_list(devlist);
770 hd_free_hd_data(hddata);
771 free(hddata);
772 if (done) {
773 ntfs_log_debug("EDD/BIOD legacy heads = %u, sectors "
774 "per track = %u\n", dev->d_heads,
775 dev->d_sectors_per_track);
776 return 0;
777 }
778 }
779 skip_hd:
780 #endif
781 #ifdef HDIO_GETGEO
782 { struct hd_geometry geo;
783
784 if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
785 dev->d_heads = geo.heads;
786 dev->d_sectors_per_track = geo.sectors;
787 ntfs_log_debug("HDIO_GETGEO heads = %u, sectors per "
788 "track = %u\n", dev->d_heads,
789 dev->d_sectors_per_track);
790 return 0;
791 }
792 err = errno;
793 }
794 #endif
795 errno = err;
796 return -1;
797 }
798
799 /**
800 * ntfs_device_heads_get - get number of heads of device
801 * @dev: open device
802 *
803 * On success, return the number of heads on the device @dev. On error return
804 * -1 with errno set to the error code.
805 *
806 * The following error codes are defined:
807 * EINVAL Input parameter error
808 * EOPNOTSUPP System does not support HDIO_GETGEO ioctl
809 * ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
810 * ENOMEM Not enough memory to complete the request
811 */
ntfs_device_heads_get(struct ntfs_device * dev)812 int ntfs_device_heads_get(struct ntfs_device *dev)
813 {
814 if (!dev) {
815 errno = EINVAL;
816 return -1;
817 }
818 if (dev->d_heads == -1) {
819 if (ntfs_device_get_geo(dev) == -1)
820 return -1;
821 if (dev->d_heads == -1) {
822 errno = EINVAL;
823 return -1;
824 }
825 }
826 return dev->d_heads;
827 }
828
829 /**
830 * ntfs_device_sectors_per_track_get - get number of sectors per track of device
831 * @dev: open device
832 *
833 * On success, return the number of sectors per track on the device @dev. On
834 * error return -1 with errno set to the error code.
835 *
836 * The following error codes are defined:
837 * EINVAL Input parameter error
838 * EOPNOTSUPP System does not support HDIO_GETGEO ioctl
839 * ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
840 * ENOMEM Not enough memory to complete the request
841 */
ntfs_device_sectors_per_track_get(struct ntfs_device * dev)842 int ntfs_device_sectors_per_track_get(struct ntfs_device *dev)
843 {
844 if (!dev) {
845 errno = EINVAL;
846 return -1;
847 }
848 if (dev->d_sectors_per_track == -1) {
849 if (ntfs_device_get_geo(dev) == -1)
850 return -1;
851 if (dev->d_sectors_per_track == -1) {
852 errno = EINVAL;
853 return -1;
854 }
855 }
856 return dev->d_sectors_per_track;
857 }
858
859 /**
860 * ntfs_device_sector_size_get - get sector size of a device
861 * @dev: open device
862 *
863 * On success, return the sector size in bytes of the device @dev.
864 * On error return -1 with errno set to the error code.
865 *
866 * The following error codes are defined:
867 * EINVAL Input parameter error
868 * EOPNOTSUPP System does not support BLKSSZGET ioctl
869 * ENOTTY @dev is a file or a device not supporting BLKSSZGET
870 */
ntfs_device_sector_size_get(struct ntfs_device * dev)871 int ntfs_device_sector_size_get(struct ntfs_device *dev)
872 {
873 if (!dev) {
874 errno = EINVAL;
875 return -1;
876 }
877 #ifdef BLKSSZGET
878 {
879 int sect_size = 0;
880
881 if (!dev->d_ops->ioctl(dev, BLKSSZGET, §_size)) {
882 ntfs_log_debug("BLKSSZGET sector size = %d bytes\n",
883 sect_size);
884 return sect_size;
885 }
886 }
887 #elif defined(DIOCGSECTORSIZE)
888 {
889 /* FreeBSD */
890 size_t sect_size = 0;
891
892 if (!dev->d_ops->ioctl(dev, DIOCGSECTORSIZE, §_size)) {
893 ntfs_log_debug("DIOCGSECTORSIZE sector size = %d bytes\n",
894 (int) sect_size);
895 return sect_size;
896 }
897 }
898 #elif defined(DKIOCGETBLOCKSIZE)
899 {
900 /* Mac OS X */
901 uint32_t sect_size = 0;
902
903 if (!dev->d_ops->ioctl(dev, DKIOCGETBLOCKSIZE, §_size)) {
904 ntfs_log_debug("DKIOCGETBLOCKSIZE sector size = %d bytes\n",
905 (int) sect_size);
906 return sect_size;
907 }
908 }
909 #else
910 errno = EOPNOTSUPP;
911 #endif
912 return -1;
913 }
914
915 /**
916 * ntfs_device_block_size_set - set block size of a device
917 * @dev: open device
918 * @block_size: block size to set @dev to
919 *
920 * On success, return 0.
921 * On error return -1 with errno set to the error code.
922 *
923 * The following error codes are defined:
924 * EINVAL Input parameter error
925 * EOPNOTSUPP System does not support BLKBSZSET ioctl
926 * ENOTTY @dev is a file or a device not supporting BLKBSZSET
927 */
ntfs_device_block_size_set(struct ntfs_device * dev,int block_size)928 int ntfs_device_block_size_set(struct ntfs_device *dev,
929 int block_size __attribute__((unused)))
930 {
931 if (!dev) {
932 errno = EINVAL;
933 return -1;
934 }
935 #ifdef BLKBSZSET
936 {
937 size_t s_block_size = block_size;
938 if (!dev->d_ops->ioctl(dev, BLKBSZSET, &s_block_size)) {
939 ntfs_log_debug("Used BLKBSZSET to set block size to "
940 "%d bytes.\n", block_size);
941 return 0;
942 }
943 /* If not a block device, pretend it was successful. */
944 if (!NDevBlock(dev))
945 return 0;
946 }
947 #else
948 /* If not a block device, pretend it was successful. */
949 if (!NDevBlock(dev))
950 return 0;
951 errno = EOPNOTSUPP;
952 #endif
953 return -1;
954 }
955