298 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			298 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
| /* fhandler_floppy.cc.  See fhandler.h for a description of the
 | |
|    fhandler classes.
 | |
| 
 | |
|    Copyright 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
 | |
| 
 | |
| This file is part of Cygwin.
 | |
| 
 | |
| This software is a copyrighted work licensed under the terms of the
 | |
| Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 | |
| details. */
 | |
| 
 | |
| #include "winsup.h"
 | |
| #include <sys/termios.h>
 | |
| #include <unistd.h>
 | |
| #include <winioctl.h>
 | |
| #include <asm/socket.h>
 | |
| #include <cygwin/hdreg.h>
 | |
| #include <cygwin/fs.h>
 | |
| #include "cygerrno.h"
 | |
| #include "security.h"
 | |
| #include "path.h"
 | |
| #include "fhandler.h"
 | |
| 
 | |
| /**********************************************************************/
 | |
| /* fhandler_dev_floppy */
 | |
| 
 | |
| int
 | |
| fhandler_dev_floppy::is_eom (int win_error)
 | |
| {
 | |
|   int ret = (win_error == ERROR_INVALID_PARAMETER);
 | |
|   if (ret)
 | |
|     debug_printf ("end of medium");
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_dev_floppy::is_eof (int)
 | |
| {
 | |
|   int ret = 0;
 | |
|   if (ret)
 | |
|     debug_printf ("end of file");
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| fhandler_dev_floppy::fhandler_dev_floppy ()
 | |
|   : fhandler_dev_raw ()
 | |
| {
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_dev_floppy::open (int flags, mode_t)
 | |
| {
 | |
|   /* The correct size of the buffer would be 512 bytes,
 | |
|    * which is the atomic size, supported by WinNT.
 | |
|    * Unfortunately, the performance is worse than
 | |
|    * access to file system on same device!
 | |
|    * Setting buffer size to a relatively big value
 | |
|    * increases performance by means.
 | |
|    * The new ioctl call with 'rdevio.h' header file
 | |
|    * supports changing this value.
 | |
|    *
 | |
|    * Let's be smart: Let's take a multiplier of typical tar
 | |
|    * and cpio buffer sizes by default!
 | |
|   */
 | |
|   devbufsiz = 61440L; /* 512L; */
 | |
|   return fhandler_dev_raw::open (flags);
 | |
| }
 | |
| 
 | |
| _off64_t
 | |
| fhandler_dev_floppy::lseek (_off64_t offset, int whence)
 | |
| {
 | |
|   char buf[512];
 | |
|   _off64_t drive_size = 0;
 | |
|   _off64_t lloffset = offset;
 | |
|   _off64_t current_position;
 | |
|   _off64_t sector_aligned_offset;
 | |
|   _off64_t bytes_left;
 | |
|   DWORD low;
 | |
|   LONG high = 0;
 | |
| 
 | |
|   DISK_GEOMETRY di;
 | |
|   PARTITION_INFORMATION pi;
 | |
|   DWORD bytes_read;
 | |
| 
 | |
|   if (!DeviceIoControl (get_handle (),
 | |
| 			  IOCTL_DISK_GET_DRIVE_GEOMETRY,
 | |
| 			  NULL, 0,
 | |
| 			  &di, sizeof (di),
 | |
| 			  &bytes_read, NULL))
 | |
|     {
 | |
|       __seterrno ();
 | |
|       return -1;
 | |
|     }
 | |
|   debug_printf ("disk geometry: (%ld cyl)*(%ld trk)*(%ld sec)*(%ld bps)",
 | |
| 		 di.Cylinders.LowPart,
 | |
| 		 di.TracksPerCylinder,
 | |
| 		 di.SectorsPerTrack,
 | |
| 		 di.BytesPerSector);
 | |
|   if (DeviceIoControl (get_handle (),
 | |
| 			 IOCTL_DISK_GET_PARTITION_INFO,
 | |
| 			 NULL, 0,
 | |
| 			 &pi, sizeof (pi),
 | |
| 			 &bytes_read, NULL))
 | |
|     {
 | |
|       debug_printf ("partition info: %ld (%ld)",
 | |
| 		      pi.StartingOffset.LowPart,
 | |
| 		      pi.PartitionLength.LowPart);
 | |
|       drive_size = pi.PartitionLength.QuadPart;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       drive_size = di.Cylinders.QuadPart * di.TracksPerCylinder *
 | |
| 		   di.SectorsPerTrack * di.BytesPerSector;
 | |
|     }
 | |
|   debug_printf ("drive size: %ld", drive_size);
 | |
| 
 | |
|   if (whence == SEEK_END && drive_size > 0)
 | |
|     {
 | |
|       lloffset = offset + drive_size;
 | |
|       whence = SEEK_SET;
 | |
|     }
 | |
| 
 | |
|   if (whence == SEEK_CUR)
 | |
|     {
 | |
|       low = SetFilePointer (get_handle (), 0, &high, FILE_CURRENT);
 | |
|       if (low == INVALID_SET_FILE_POINTER && GetLastError ())
 | |
| 	{
 | |
| 	  __seterrno ();
 | |
| 	  return -1;
 | |
| 	}
 | |
|       current_position = low + ((_off64_t) high << 32);
 | |
|       /* devbufend and devbufstart are always 0 when writing. */
 | |
|       current_position -= devbufend - devbufstart;
 | |
| 
 | |
|       lloffset += current_position;
 | |
|       whence = SEEK_SET;
 | |
|     }
 | |
| 
 | |
|   if (lloffset < 0 ||
 | |
|       drive_size > 0 && lloffset > drive_size)
 | |
|     {
 | |
|       set_errno (EINVAL);
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|   /* FIXME: sector can possibly be not 512 bytes long */
 | |
|   sector_aligned_offset = (lloffset / 512) * 512;
 | |
|   bytes_left = lloffset - sector_aligned_offset;
 | |
| 
 | |
|   if (whence == SEEK_SET)
 | |
|     {
 | |
|       /* Invalidate buffer. */
 | |
|       devbufstart = devbufend = 0;
 | |
| 
 | |
|       low = sector_aligned_offset & UINT32_MAX;
 | |
|       high = sector_aligned_offset >> 32;
 | |
|       if (SetFilePointer (get_handle (), low, &high, FILE_BEGIN)
 | |
| 	  == INVALID_SET_FILE_POINTER && GetLastError ())
 | |
| 	{
 | |
| 	  __seterrno ();
 | |
| 	  return -1;
 | |
| 	}
 | |
| 
 | |
|       eom_detected (false);
 | |
|       size_t len = bytes_left;
 | |
|       raw_read (buf, len);
 | |
|       return sector_aligned_offset + bytes_left;
 | |
|     }
 | |
| 
 | |
|   set_errno (EINVAL);
 | |
|   return -1;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_dev_floppy::ioctl (unsigned int cmd, void *buf)
 | |
| {
 | |
|   DISK_GEOMETRY di;
 | |
|   PARTITION_INFORMATION pi;
 | |
|   DWORD bytes_read;
 | |
|   _off64_t drive_size = 0;
 | |
|   _off64_t start = 0;
 | |
|   switch (cmd)
 | |
|     {
 | |
|     case HDIO_GETGEO:
 | |
|       {
 | |
| 	debug_printf ("HDIO_GETGEO");
 | |
| 	if (!DeviceIoControl (get_handle (),
 | |
| 			      IOCTL_DISK_GET_DRIVE_GEOMETRY,
 | |
| 			      NULL, 0,
 | |
| 			      &di, sizeof (di),
 | |
| 			      &bytes_read, NULL))
 | |
| 	  {
 | |
| 	    __seterrno ();
 | |
| 	    return -1;
 | |
| 	  }
 | |
| 	debug_printf ("disk geometry: (%ld cyl)*(%ld trk)*(%ld sec)*(%ld bps)",
 | |
| 		      di.Cylinders.LowPart,
 | |
| 		      di.TracksPerCylinder,
 | |
| 		      di.SectorsPerTrack,
 | |
| 		      di.BytesPerSector);
 | |
| 	if (DeviceIoControl (get_handle (),
 | |
| 			     IOCTL_DISK_GET_PARTITION_INFO,
 | |
| 			     NULL, 0,
 | |
| 			     &pi, sizeof (pi),
 | |
| 			     &bytes_read, NULL))
 | |
| 	  {
 | |
| 	    debug_printf ("partition info: %ld (%ld)",
 | |
| 			  pi.StartingOffset.LowPart,
 | |
| 			  pi.PartitionLength.LowPart);
 | |
| 	    start = pi.StartingOffset.QuadPart >> 9ULL;
 | |
| 	  }
 | |
| 	struct hd_geometry *geo = (struct hd_geometry *) buf;
 | |
| 	geo->heads = di.TracksPerCylinder;
 | |
| 	geo->sectors = di.SectorsPerTrack;
 | |
| 	geo->cylinders = di.Cylinders.LowPart;
 | |
| 	geo->start = start;
 | |
| 	return 0;
 | |
|       }
 | |
|     case BLKGETSIZE:
 | |
|     case BLKGETSIZE64:
 | |
|       {
 | |
| 	debug_printf ("BLKGETSIZE");
 | |
| 	if (!DeviceIoControl (get_handle (),
 | |
| 			      IOCTL_DISK_GET_DRIVE_GEOMETRY,
 | |
| 			      NULL, 0,
 | |
| 			      &di, sizeof (di),
 | |
| 			      &bytes_read, NULL))
 | |
| 	  {
 | |
| 	    __seterrno ();
 | |
| 	    return -1;
 | |
| 	  }
 | |
| 	debug_printf ("disk geometry: (%ld cyl)*(%ld trk)*(%ld sec)*(%ld bps)",
 | |
| 		      di.Cylinders.LowPart,
 | |
| 		      di.TracksPerCylinder,
 | |
| 		      di.SectorsPerTrack,
 | |
| 		      di.BytesPerSector);
 | |
| 	if (DeviceIoControl (get_handle (),
 | |
| 			     IOCTL_DISK_GET_PARTITION_INFO,
 | |
| 			     NULL, 0,
 | |
| 			     &pi, sizeof (pi),
 | |
| 			     &bytes_read, NULL))
 | |
| 	  {
 | |
| 	    debug_printf ("partition info: %ld (%ld)",
 | |
| 			  pi.StartingOffset.LowPart,
 | |
| 			  pi.PartitionLength.LowPart);
 | |
| 	    drive_size = pi.PartitionLength.QuadPart;
 | |
| 	  }
 | |
| 	else
 | |
| 	  {
 | |
| 	    drive_size = di.Cylinders.QuadPart * di.TracksPerCylinder *
 | |
| 			 di.SectorsPerTrack * di.BytesPerSector;
 | |
| 	  }
 | |
| 	if (cmd == BLKGETSIZE)
 | |
| 	  *(long *)buf = drive_size >> 9UL;
 | |
| 	else
 | |
| 	  *(_off64_t *)buf = drive_size;
 | |
| 	return 0;
 | |
|       }
 | |
|     case BLKRRPART:
 | |
|       {
 | |
| 	debug_printf ("BLKRRPART");
 | |
| 	if (!DeviceIoControl (get_handle (),
 | |
| 			      IOCTL_DISK_UPDATE_DRIVE_SIZE,
 | |
| 			      NULL, 0,
 | |
| 			      &di, sizeof (di),
 | |
| 			      &bytes_read, NULL))
 | |
| 	  {
 | |
| 	    __seterrno ();
 | |
| 	    return -1;
 | |
| 	  }
 | |
| 	return 0;
 | |
|       }
 | |
|     case BLKSSZGET:
 | |
|       {
 | |
| 	debug_printf ("BLKSSZGET");
 | |
| 	if (!DeviceIoControl (get_handle (),
 | |
| 			      IOCTL_DISK_GET_DRIVE_GEOMETRY,
 | |
| 			      NULL, 0,
 | |
| 			      &di, sizeof (di),
 | |
| 			      &bytes_read, NULL))
 | |
| 	  {
 | |
| 	    __seterrno ();
 | |
| 	    return -1;
 | |
| 	  }
 | |
| 	debug_printf ("disk geometry: (%ld cyl)*(%ld trk)*(%ld sec)*(%ld bps)",
 | |
| 		      di.Cylinders.LowPart,
 | |
| 		      di.TracksPerCylinder,
 | |
| 		      di.SectorsPerTrack,
 | |
| 		      di.BytesPerSector);
 | |
| 	*(int *)buf = di.BytesPerSector;
 | |
| 	return 0;
 | |
|       }
 | |
|     default:
 | |
|       return fhandler_dev_raw::ioctl (cmd, buf);
 | |
|     }
 | |
| }
 | |
| 
 |