2 * disk_io.c - Disk io functions. Part of the Linux-NTFS project.
4 * Copyright (c) 2000-2003 Anton Altaparmakov
6 * This program/include file is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program/include file is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program (in the main directory of the Linux-NTFS
18 * distribution in the file COPYING); if not, write to the Free Software
19 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include <sys/types.h>
32 #include <sys/ioctl.h>
33 #ifdef HAVE_LINUX_FD_H
34 # include <linux/fd.h>
43 #if defined(linux) && defined(_IO) && !defined(BLKGETSIZE)
44 # define BLKGETSIZE _IO(0x12,96) /* Get device size in 512byte blocks. */
48 * ntfs_pread - positioned read from disk
49 * @dev: device to read from
50 * @pos: position in device to read from
51 * @count: number of bytes to read
52 * @b: output data buffer
54 * This function will read @count bytes from device @dev at position @pos into
57 * On success, return the number of successfully read bytes. If this number is
58 * lower than @count this means that we have either reached end of file or
59 * encountered an error during the read so that the read is partial. 0 means
60 * end of file or nothing to read (@count is 0).
62 * On error and nothing has been read, return -1 with errno set appropriately
63 * to the return code of either seek, read, or set to EINVAL in case of
66 s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b)
69 struct ntfs_device_operations *dops;
71 Dprintf("%s(): Entering for pos 0x%Lx, count 0x%Lx.\n", __FUNCTION__,
73 if (!b || count < 0 || pos < 0) {
80 /* Locate to position. */
81 if (dops->seek(dev, pos, SEEK_SET) == (off_t)-1) {
82 Dprintf("ntfs_pread: device seek to 0x%Lx returned error: "
83 "%s\n", pos, strerror(errno));
87 for (total = 0; count; count -= br, total += br) {
88 br = dops->read(dev, (char*)b + total, count);
89 /* If everything ok, continue. */
92 /* If EOF or error return number of bytes read. */
95 /* Nothing read and error, return error status. */
98 /* Finally, return the number of bytes read. */
103 * ntfs_pwrite - positioned write to disk
104 * @dev: device to write to
105 * @pos: position in file descriptor to write to
106 * @count: number of bytes to write
107 * @b: data buffer to write to disk
109 * This function will write @count bytes from data buffer @b to the device @dev
112 * On success, return the number of successfully written bytes. If this number
113 * is lower than @count this means that the write has been interrupted in
114 * flight or that an error was encountered during the write so that the write
115 * is partial. 0 means nothing was written (also return 0 when @count is 0).
117 * On error and nothing has been written, return -1 with errno set
118 * appropriately to the return code of either seek, write, or set
119 * to EINVAL in case of invalid arguments.
121 s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
125 struct ntfs_device_operations *dops;
127 Dprintf("%s(): Entering for pos 0x%Lx, count 0x%Lx.\n", __FUNCTION__,
129 if (!b || count < 0 || pos < 0) {
135 if (NDevReadOnly(dev)) {
140 /* Locate to position. */
141 if (dops->seek(dev, pos, SEEK_SET) == (off_t)-1) {
142 Dprintf("ntfs_pwrite: seek to 0x%Lx returned error: %s\n",
143 pos, strerror(errno));
147 /* Write the data. */
148 for (total = 0; count; count -= written, total += written) {
149 written = dops->write(dev, (char*)b + total, count);
150 /* If everything ok, continue. */
154 * If nothing written or error return number of bytes written.
156 if (!written || total)
158 /* Nothing written and error, return error status. */
161 /* Finally, return the number of bytes written. */
165 static int ntfs_device_disk_io_open(struct ntfs_device *dev, int flags)
173 /* Open the device/file obtaining the file descriptor. */
174 if (((int)dev->d_private = open(dev->d_name, flags)) == -1)
176 /* Setup our read-only flag. */
177 if ((flags & O_RDWR) != O_RDWR)
178 NDevSetReadOnly(dev);
179 /* Acquire exlusive (mandatory) lock on the whole device. */
180 memset(&flk, 0, sizeof(flk));
181 if (NDevReadOnly(dev))
182 flk.l_type = F_RDLCK;
184 flk.l_type = F_WRLCK;
185 flk.l_whence = SEEK_SET;
186 flk.l_start = flk.l_len = 0LL;
187 if (fcntl((int)dev->d_private, F_SETLK, &flk)) {
189 Dprintf("ntfs_device_disk_io_open: Could not lock %s for %s: "
190 "%s\n", dev->d_name, NDevReadOnly(dev) ?
191 "reading" : "writing", strerror(errno));
192 if (close((int)dev->d_private))
193 Dprintf("ntfs_device_disk_io_open: Warning: Could not "
194 "close %s: %s\n", dev->d_name,
199 /* Set our open flag. */
204 static int ntfs_device_disk_io_close(struct ntfs_device *dev)
208 if (!NDevOpen(dev)) {
213 fsync((int)dev->d_private);
214 /* Release exlusive (mandatory) lock on the whole device. */
215 memset(&flk, 0, sizeof(flk));
216 flk.l_type = F_UNLCK;
217 flk.l_whence = SEEK_SET;
218 flk.l_start = flk.l_len = 0LL;
219 if (fcntl((int)dev->d_private, F_SETLK, &flk))
220 Dprintf("ntfs_device_disk_io_close: Warning: Could not unlock "
221 "%s: %s\n", dev->d_name, strerror(errno));
222 /* Close the file descriptor and clear our open flag. */
223 if (close((int)dev->d_private))
229 static s64 ntfs_device_disk_io_seek(struct ntfs_device *dev, s64 offset,
232 return lseek((int)dev->d_private, offset, whence);
235 static s64 ntfs_device_disk_io_read(struct ntfs_device *dev, void *buf,
238 return read((int)dev->d_private, buf, count);
241 static s64 ntfs_device_disk_io_write(struct ntfs_device *dev, const void *buf,
244 if (NDevReadOnly(dev)) {
249 return write((int)dev->d_private, buf, count);
252 static s64 ntfs_device_disk_io_pread(struct ntfs_device *dev, void *buf,
253 s64 count, s64 offset)
255 return ntfs_pread(dev, offset, count, buf);
258 static s64 ntfs_device_disk_io_pwrite(struct ntfs_device *dev, const void *buf,
259 s64 count, s64 offset)
261 if (NDevReadOnly(dev)) {
266 return ntfs_pwrite(dev, offset, count, buf);
269 static int ntfs_device_disk_io_sync(struct ntfs_device *dev)
271 if (!NDevReadOnly(dev) && NDevDirty(dev)) {
272 int res = fsync((int)dev->d_private);
280 static int ntfs_device_disk_io_stat(struct ntfs_device *dev, struct stat *buf)
282 return fstat((int)dev->d_private, buf);
285 static int ntfs_device_disk_io_ioctl(struct ntfs_device *dev, int request,
288 return ioctl((int)dev->d_private, request, argp);
292 * Default device operations for working with unix style devices and files.
294 struct ntfs_device_operations ntfs_device_disk_io_ops = {
295 .open = ntfs_device_disk_io_open,
296 .close = ntfs_device_disk_io_close,
297 .seek = ntfs_device_disk_io_seek,
298 .read = ntfs_device_disk_io_read,
299 .write = ntfs_device_disk_io_write,
300 .pread = ntfs_device_disk_io_pread,
301 .pwrite = ntfs_device_disk_io_pwrite,
302 .sync = ntfs_device_disk_io_sync,
303 .stat = ntfs_device_disk_io_stat,
304 .ioctl = ntfs_device_disk_io_ioctl,
308 * ntfs_mst_pread - multi sector transfer (mst) positioned read
309 * @dev: device to read from
310 * @pos: position in file descriptor to read from
311 * @count: number of blocks to read
312 * @bksize: size of each block that needs mst deprotecting
313 * @b: output data buffer
315 * Multi sector transfer (mst) positioned read. This function will read @count
316 * blocks of size @bksize bytes each from device @dev at position @pos into the
317 * the data buffer @b.
319 * On success, return the number of successfully read blocks. If this number is
320 * lower than @count this means that we have reached end of file, that the read
321 * was interrupted, or that an error was encountered during the read so that
322 * the read is partial. 0 means end of file or nothing was read (also return 0
323 * when @count or @bksize are 0).
325 * On error and nothing was read, return -1 with errno set appropriately to the
326 * return code of either seek, read, or set to EINVAL in case of invalid
329 * NOTE: If an incomplete multi sector transfer has been detected the magic
330 * will have been changed to magic_BAAD but no error will be returned. Thus it
331 * is possible that we return count blocks as being read but that any number
332 * (between zero and count!) of these blocks is actually subject to a multi
333 * sector transfer error. This should be detected by the caller by checking for
334 * the magic being "BAAD".
336 s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
337 const u32 bksize, void *b)
341 if (bksize & (bksize - 1) || bksize % NTFS_SECTOR_SIZE) {
346 br = ntfs_pread(dev, pos, count * bksize, b);
350 * Apply fixups to successfully read data, disregarding any errors
351 * returned from the MST fixup function. This is because we want to
352 * fixup everything possible and we rely on the fact that the "BAAD"
353 * magic will be detected later on.
356 for (i = 0; i < count; ++i)
357 ntfs_mst_post_read_fixup((NTFS_RECORD*)
358 ((u8*)b + i * bksize), bksize);
359 /* Finally, return the number of complete blocks read. */
364 * ntfs_mst_pwrite - multi sector transfer (mst) positioned write
365 * @dev: device to write to
366 * @pos: position in file descriptor to write to
367 * @count: number of blocks to write
368 * @bksize: size of each block that needs mst protecting
369 * @b: data buffer to write to disk
371 * Multi sector transfer (mst) positioned write. This function will write
372 * @count blocks of size @bksize bytes each from data buffer @b to the device
373 * @dev at position @pos.
375 * On success, return the number of successfully written blocks. If this number
376 * is lower than @count this means that the write has been interrutped or that
377 * an error was encountered during the write so that the write is partial. 0
378 * means nothing was written (also return 0 when @count or @bksize are 0).
380 * On error and nothing has been written, return -1 with errno set
381 * appropriately to the return code of either seek, write, or set
382 * to EINVAL in case of invalid arguments.
384 * NOTE: We mst protect the data, write it, then mst deprotect it using a quick
385 * deprotect algorithm (no checking). This saves us from making a copy before
386 * the write and at the same time causes the usn to be incremented in the
387 * buffer. This conceptually fits in better with the idea that cached data is
388 * always deprotected and protection is performed when the data is actually
389 * going to hit the disk and the cache is immediately deprotected again
390 * simulating an mst read on the written data. This way cache coherency is
393 s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
394 const u32 bksize, const void *b)
398 if (count < 0 || bksize % NTFS_SECTOR_SIZE) {
404 /* Prepare data for writing. */
405 for (i = 0; i < count; ++i) {
408 err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)
409 ((u8*)b + i * bksize), bksize);
411 /* Abort write at this position. */
418 /* Write the prepared data. */
419 written = ntfs_pwrite(dev, pos, count * bksize, b);
420 /* Quickly deprotect the data again. */
421 for (i = 0; i < count; ++i)
422 ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)b + i * bksize));
425 /* Finally, return the number of complete blocks written. */
426 return written / bksize;
430 * ntfs_cluster_read - read ntfs clusters
431 * @vol: volume to read from
432 * @lcn: starting logical cluster number
433 * @count: number of clusters to read
434 * @b: output data buffer
436 * Read @count ntfs clusters starting at logical cluster number @lcn from
437 * volume @vol into buffer @b. Return number of clusters read or -1 on error,
438 * with errno set to the error code.
440 s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count,
445 if (!vol || lcn < 0 || count < 0) {
449 if (vol->nr_clusters < lcn + count) {
453 br = ntfs_pread(vol->dev, lcn << vol->cluster_size_bits,
454 count << vol->cluster_size_bits, b);
456 Dperror("Error reading cluster(s)");
459 return br >> vol->cluster_size_bits;
463 * ntfs_cluster_write - write ntfs clusters
464 * @vol: volume to write to
465 * @lcn: starting logical cluster number
466 * @count: number of clusters to write
467 * @b: data buffer to write to disk
469 * Write @count ntfs clusters starting at logical cluster number @lcn from
470 * buffer @b to volume @vol. Return the number of clusters written or -1 on
471 * error, with errno set to the error code.
473 s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
474 const s64 count, const void *b)
478 if (!vol || lcn < 0 || count < 0) {
482 if (vol->nr_clusters < lcn + count) {
486 if (!NVolReadOnly(vol))
487 bw = ntfs_pwrite(vol->dev, lcn << vol->cluster_size_bits,
488 count << vol->cluster_size_bits, b);
490 bw = count << vol->cluster_size_bits;
492 Dperror("Error writing cluster(s)");
495 return bw >> vol->cluster_size_bits;
499 * ntfs_device_offset_valid - test if a device offset is valid
501 * @ofs: offset to test for validity
503 * Test if the offset @ofs is an existing location on the device described
504 * by the open device structure @dev.
506 * Return 0 if it is valid and -1 if it is not valid.
508 static inline int ntfs_device_offset_valid(struct ntfs_device *dev, s64 ofs)
512 if (dev->d_ops->seek(dev, ofs, SEEK_SET) >= 0 &&
513 dev->d_ops->read(dev, &ch, 1) == 1)
519 * ntfs_device_size_get - return the size of a device in blocks
521 * @block_size: block size in bytes in which to return the result
523 * Return the number of @block_size sized blocks in the device described by the
526 * Adapted from e2fsutils-1.19, Copyright (C) 1995 Theodore Ts'o.
528 s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
534 if (dev->d_ops->ioctl(dev, BLKGETSIZE, &size) >= 0) {
535 Dprintf("BLKGETSIZE nr 512 byte blocks = %ld (0x%ld)\n", size,
537 return (s64)size * 512 / block_size;
541 { struct floppy_struct this_floppy;
543 if (dev->d_ops->ioctl(dev, FDGETPRM, &this_floppy) >= 0) {
544 Dprintf("FDGETPRM nr 512 byte blocks = %ld (0x%ld)\n",
545 this_floppy.size, this_floppy.size);
546 return (s64)this_floppy.size * 512 / block_size;
551 * We couldn't figure it out by using a specialized ioctl,
552 * so do binary search to find the size of the device.
555 for (high = 1024LL; !ntfs_device_offset_valid(dev, high); high <<= 1)
557 while (low < high - 1LL) {
558 const s64 mid = (low + high) / 2;
560 if (!ntfs_device_offset_valid(dev, mid))
565 dev->d_ops->seek(dev, 0LL, SEEK_SET);
566 return (low + 1LL) / block_size;