blob: c77d8f9576fd8201dd5ffbb538e7c18548fce8c9
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, §_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 |