90 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			90 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C++
		
	
	
	
| /* ipc.cc: Single unix specification IPC interface for Cygwin
 | |
| 
 | |
|    Originally written by Robert Collins <robert.collins@hotmail.com>
 | |
|    Updated to 64 bit key_t by Charles Wilson <cygwin@cwilson.fastmail.fm>
 | |
| 
 | |
|    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/stat.h>
 | |
| 
 | |
| /* Notes: we return a valid key even if id's low order 8 bits are 0. */
 | |
| extern "C" key_t
 | |
| ftok (const char *path, int id)
 | |
| {
 | |
|   struct stat statbuf;
 | |
|   key_t tmp;
 | |
|   if (stat64 (path, &statbuf))
 | |
|     {
 | |
|       /* stat set the appropriate errno for us */
 | |
|       return (key_t) -1;
 | |
|     }
 | |
| 
 | |
|   /* Since Cygwin 1.5
 | |
|      dev_t is 32bits for cygwin
 | |
|      ino_t is 64bits for cygwin
 | |
|      and we need 8 bits for the id.
 | |
|      thus key_t needs 104 bits total -- but we only have 64 (long long)
 | |
|      We will have to alias; leaving open the possibility that the same
 | |
|      key will be returned for multiple files.  This possibility exists
 | |
|      also on Linux; the question is, how to minimize this possibility.
 | |
| 
 | |
|      How to solve?  Well, based on C. Vinschen's research, the nFileIndex*
 | |
|      words vary as follows, on a partition with > 110,000 files
 | |
|      nFileIndexHigh:    564 values between 0x00010000 -- 0xffff0000
 | |
|      nFileIndexLow : 103812 values between 0x00000000 -- 0x0003ffff
 | |
|      R. Collins suggests that these may represent a tree path,
 | |
|      and that it would require ~2.9M files to force the tree depth
 | |
|      to increase and reveal more bit usage.
 | |
| 
 | |
|      Implementation details: dev_t is 32bits, but is formed by
 | |
| 	device(32bits) << 16 | unit(32bits)
 | |
|      But device is ACTUALLY == status & FH_DEVMASK, where FH_DEVMASK
 | |
|      is 0x00000fff --> 12 bits
 | |
| 
 | |
|      As it happens, the maximum number of devices is actually
 | |
|      FH_NDEV, not FH_DEVMASK, where FH_NDEV is currently 0x0000001d.
 | |
|      However, FH_NDEV grows as new device types are added.  So
 | |
|      currently the device number needs 5 bits, but later?  Let's
 | |
|      take a cue from Linux, and use the lower 8 bits (instead of the
 | |
|      lower 12 or 16) for the device (major?) number.
 | |
| 
 | |
|      Similarly, while 'units' is an int (32bits), it is unclear
 | |
|      how many of these are significant. For most devices, it seems that
 | |
|      'units' is equivalent to 'minor'.  For FH_TAPE, it's obvious that
 | |
|      only 8 bits are important.  However, for FH_SOCKET...it might be
 | |
|      as high as 16 significant bits.
 | |
| 
 | |
|      Let's assume that we only need 8 bits from device (major) and
 | |
|      only 8 bits from unit (minor). (On linux, only 8 bits of minor
 | |
|      are used, and none from major).
 | |
|      ---> so, we only need 0x00ff00ff (16 bits) of dev_t
 | |
| 
 | |
|      ---> we MUST have all 8 bits of id.
 | |
| 
 | |
|      ---> So, we only have 64 - 8 - 16 = 40 bits for ino_t.  But, we
 | |
|      need 0xffff0000 for nFileIndexHigh and 0x0003ffff for nFileIndexLow
 | |
|      minimum, or 16 + 18 = 34 bits.  Lucky us - we have 6 more bits
 | |
|      to distribute.
 | |
| 
 | |
|      For lack of a better idea, we'll allocate 2 of the extra bits to
 | |
|      nFileIndexHigh and 4 to nFileIndexLow.  */
 | |
| 
 | |
|   /* get 8 bits from dev_t (major), put into 0xff00000000000000L */
 | |
|   tmp  = (((key_t) statbuf.st_dev) & 0x0000000000ff0000LL) << 40;
 | |
|   /* get 8 bits from dev_t (minor), put into 0x00ff000000000000L */
 | |
|   tmp |= (((key_t) statbuf.st_dev) & 0x00000000000000ffLL) << 48;
 | |
|   /* get upper 16+2 bits from nFileInfoHigh, put into 0x0000ffffc0000000L
 | |
|      shift down first, then mask, to avoid sign extension on rightshift  */
 | |
|   tmp |= (((key_t) statbuf.st_ino) & 0xffffc00000000000LL) >> 16;
 | |
|   /* get lower 18+4 bits from nFileInfoLow, put into  0x000000003fffff00L  */
 | |
|   tmp |= (((key_t) statbuf.st_ino) & 0x00000000003fffffLL) << 8;
 | |
|   /* use all 8 bits of id, and put into 0x00000000000000ffL */
 | |
|   tmp |= (id & 0x00ff);
 | |
|   return tmp;
 | |
| }
 |