home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 6 File / 06-File.zip / spaceh17.zip / space.c < prev    next >
C/C++ Source or Header  |  2000-06-14  |  38KB  |  767 lines

  1. /*---------------------------------------------------------------------------*/
  2. /* File: SPACE.C                                          Date: 01/20/2000   */
  3. /*---------------------------------------------------------------------------*/
  4. /* Description: This PUBLIC DOMAIN program helps you maintain the amount     */
  5. /*              of free space in the specified drive to under 2G-512 bytes   */
  6. /*              Thus stopping programs using 32-bit signed integer math      */
  7. /*              from seeing space above 2Gb as negative.                     */
  8. /*                                                                           */
  9. /*              See Welcome() for details.                                   */
  10. /* Assumptions:                                                              */
  11. /*                                                                           */
  12. /* Programmers: Wing F Yuen, wfyuen@bestweb.net                              */
  13. /*                                                                           */
  14. /* Compiler   : IBM VisualAge C++ compiles with:                             */
  15. /*                icc space.c                                                */
  16. /*                                                                           */
  17. /*              Microsoft C6 compiles with:                                  */
  18. /*                cl /AS /Lp space.c os2.lib /link /pm:vio                   */
  19. /*                                                                           */
  20. /*              Watcom C/C++ v11.0 compiles with:                            */
  21. /*                wcl386 -3 space.c                                          */
  22. /*                wcl -i=\watcom\h\os21x -x -2 -lp -bt=os2 space.c           */
  23. /*                                                                           */
  24. /*              EMX/GCC v2.7.2.1 compiles (minimal testing) with:            */
  25. /*                gcc space.c                                                */
  26. /*                                                                           */
  27. /*              A batch file BUILD.CMD is provided for your convenience.     */
  28. /*                                                                           */
  29. /* Notes      : All local   variables begin with a Capital letter            */
  30. /*              All global  variables are prefixed with the letter 'g'       */
  31. /*              All pointer variables are prefixed with the letter 'p'       */
  32. /*              All user-supplied functions begin with a Capital letter;     */
  33. /*                the only exception is main()                               */
  34. /*---------------------------------------------------------------------------*/
  35. /* Change Log:                                                               */
  36. /* 1.00  - First release.                                                    */
  37. /* 1.01  - ArgV[0] doesn't include the path of the EXE except under 4OS2.    */
  38. /*       - Added support for Watcom C/C++ v11                                */
  39. /* 1.02  - Clean up conditional compile preprocessor directives.             */
  40. /*       - Watcom version not reading Drive Serial Number properly.          */
  41. /*       - Use double to track freespace and file sizes, D-U-H !!!           */
  42. /* 1.03  - Change Advantis email address                                     */
  43. /* 1.04  - Keep maximum free space to 2G-2 bytes. Seem to compile okay       */
  44. /*         with EMX/GCC v2.7.2.1 without any change!                         */
  45. /* 1.05  - Keep maximum free space to 2G-512 bytes.                          */
  46. /* 1.06  - Fixed space calculation for partitions above 4GB.                 */
  47. /* 1.06a - Changed email address to wfyuen@bestweb.net                       */
  48. /* 1.07  - Display file system type and/or LAN alias                         */
  49. /*---------------------------------------------------------------------------*/
  50. #define NDEBUG                                   /* define for production    */
  51.  
  52. #ifdef NDEBUG
  53.   #define MAX_BYTES_FREE (0x7FFFFE00*1.0)        /* 2G - 512                 */
  54.   #define MAX_FILE_SIZE  (0x7FFFFFFF*1.0)        /* 2G - 1                   */
  55. #else
  56.   #define MAX_BYTES_FREE (0x20000000*1.0)        /* 0.5G for testing         */
  57.   #define MAX_FILE_SIZE  (100.0*1024*1024)       /* 100 MB for testing       */
  58. #endif
  59.  
  60. #define INCL_DOSERRORS                           /* Error codes              */
  61. #define INCL_DOSFILEMGR                          /* File Manager values      */
  62. #include <os2.h>
  63. #include <stdio.h>                               /* fileno()                 */
  64. #include <ctype.h>                               /* toupper()                */
  65. #include <string.h>
  66. #include <io.h>                                  /* filelength()             */
  67. #include <errno.h>                               /* errno                    */
  68.  
  69. /*---------------------------------------------------------------------------*/
  70. /* Identify the compiler                                                     */
  71. /*                                                                           */
  72. /* Microsoft C                #ifdef  _MSC_VER                               */
  73. /* IBM Visuage C++            #ifdef  __IBMC__                               */
  74. /* Watcom C/C++               #ifdef  __WATCOMC__                            */
  75. /* Watcom C/C++ 32bit         #ifdef  __386__         in addition to above   */
  76. /*---------------------------------------------------------------------------*/
  77. #if defined(__WATCOMC__)
  78.   #if defined(__386__)
  79.     #define WC32_
  80.   #else
  81.     #define WC16_
  82.   #endif
  83. #endif
  84.  
  85. /*---------------------------------------------------------------------------*/
  86. /* Global variables are used extensively to reduce the stack size and make   */
  87. /* it cheaper to separate code blocks into functions. This is okay because   */
  88. /* this is not a multithreading program.                                     */
  89. /*---------------------------------------------------------------------------*/
  90. #if (defined(_MSC_VER) || defined(WC16_))
  91.  
  92. static USHORT     gDriveNumber=0;                /* Drive number             */
  93. static USHORT     gFSInfoLevel;                  /* File system data required*/
  94. static USHORT     gRcApi;
  95. #else
  96.  
  97. static ULONG      gDriveNumber=0;                /* Drive number             */
  98. static ULONG      gFSInfoLevel;                  /* File system data required*/
  99. static APIRET     gRcApi;                        /* Return code              */
  100. #endif
  101.  
  102. static FSALLOCATE gFSInfoBuf;                    /* File system info buffer  */
  103. static FSINFO     gFSVolBuf;
  104. static ULONG      gCluster;
  105. static FILE       *gHog;
  106. static double     gTotal, gUsed, gFree;
  107. static double     gOldHogSize, gNewHogSize;      /* old and new sizes        */
  108. static USHORT     gOldHogCount;                  /* old hog file count       */
  109. static char       gDriveVolume[256];
  110. static char       gDriveSerial[10];
  111. static char       gDriveFormat[8];               /* FAT, HPFS, or LAN        */
  112. static char       gDriveLetter;
  113.  
  114. /*---------------------------------------------------------------------------*/
  115. /* I reserve 256 bytes here so that those without compilers can move the     */
  116. /* holding directory by patching here with a hex editor. It must *NOT*       */
  117. /* include a trailing backslash.                                             */
  118. /*---------------------------------------------------------------------------*/
  119. static char       gHogFilePath[256] = {"?:\\spacehog"};  /* holding directory*/
  120.  
  121. /*---------------------------------------------------------------------------*/
  122. /* Local function prototypes                                                 */
  123. /*---------------------------------------------------------------------------*/
  124. int    CollectFileInfo  (void);
  125. void   CollectVolInfo   (void);
  126. long   FileSize         (const char *FileSpec);
  127. void   QueryFileSystem  (char driveLetter);
  128. char   *Split000        (double Number, char Separator);
  129. double TotalHogSize     (void);
  130. void   Welcome          (char *MyName);
  131. int    WriteNewHogFiles (void);
  132.  
  133. /*---------------------------------------------------------------------------*/
  134. /* main()                                                                    */
  135. /*---------------------------------------------------------------------------*/
  136. int main (int ArgC, char *ArgV[])
  137. {
  138.   ULONG      DriveMap;
  139.   FILESTATUS PathBuf;
  140.  
  141.   if (ArgC < 2) {
  142.       #if (defined(_MSC_VER) || defined(WC16_))
  143.  
  144.       gRcApi = DosQCurDisk( &gDriveNumber, &DriveMap);
  145.       #else
  146.  
  147.       gRcApi = DosQueryCurrentDisk( &gDriveNumber, &DriveMap);
  148.       #endif
  149.       if (gRcApi)
  150.            gDriveLetter = '\0';
  151.       else gDriveLetter = 'A' + gDriveNumber - 1;
  152.       gDriveNumber = 0L;                         /* current partition        */
  153.   }
  154.   else if (!strcmp( "/?", ArgV[1])) {
  155.       Welcome( ArgV[0]);
  156.       return 0;
  157.   }                                              /* End if                   */
  158.   else {
  159.       /*---------------------------------------------------------------------*/
  160.       /* Assume the user entered a drive letter                              */
  161.       /*---------------------------------------------------------------------*/
  162.       gDriveLetter = toupper( *ArgV[1]);
  163.       if (NULL == strchr( "ABCDEFGHIJKLMNOPQRSTUVWXYZ", gDriveLetter)) {
  164.           Welcome( ArgV[0]);
  165.           return 0;
  166.       }
  167.       gDriveNumber = (ULONG)(gDriveLetter - 'A' + 1);
  168.   }                                              /* End if                   */
  169.  
  170.   if (CollectFileInfo()) {
  171.       return gRcApi;
  172.   }
  173.   gCluster = gFSInfoBuf.cSectorUnit * gFSInfoBuf.cbSector;
  174.   gFree    = (gFSInfoBuf.cUnitAvail  * 1.0) * gCluster;
  175.  
  176.   gHogFilePath[0] = gDriveLetter;
  177.   /*-------------------------------------------------------------------------*/
  178.   /* Did the user create the \SPACEHOG path?                                 */
  179.   /*-------------------------------------------------------------------------*/
  180.   #if (defined(_MSC_VER) || defined(WC16_))
  181.  
  182.   gRcApi = DosQPathInfo( gHogFilePath,
  183.                          FIL_STANDARD,
  184.                          (PBYTE)&PathBuf,
  185.                          sizeof PathBuf,
  186.                          0L);                    /* reserved                 */
  187.   #else
  188.  
  189.   gRcApi = DosQueryPathInfo( gHogFilePath,
  190.                              FIL_STANDARD,
  191.                              &PathBuf,
  192.                              sizeof PathBuf);
  193.   #endif
  194.  
  195.   if (NO_ERROR == gRcApi) {
  196.       gOldHogSize = TotalHogSize();
  197.       /*---------------------------------------------------------------------*/
  198.       /* The actual amount of free disk space is (gFree + gOldHogSize)       */
  199.       /*---------------------------------------------------------------------*/
  200.       gNewHogSize = (gOldHogSize + gFree) - MAX_BYTES_FREE;
  201.       if (gNewHogSize < 0.0) {
  202.           gNewHogSize = 0.0;
  203.       }
  204.       #ifndef NDEBUG
  205.  
  206.       printf( "OldHogSize     = %.0f\n", gOldHogSize);
  207.       printf( "NewHogSize     = %.0f\n", gNewHogSize);
  208.       printf( "Free           = %.0f\n", gFree      );
  209.       printf( "MAX_BYTES_FREE = %.0f\n", MAX_BYTES_FREE);
  210.       #endif
  211.  
  212.       if (gNewHogSize != gOldHogSize) {
  213.           /*-----------------------------------------------------------------*/
  214.           /* Resize HogFileName                                              */
  215.           /*-----------------------------------------------------------------*/
  216.           if (WriteNewHogFiles()) {
  217.               printf( __FILE__"/main(): Can't resize holding " \
  218.                       "files in %s\n", gHogFilePath);
  219.           }
  220.       }
  221.   }
  222.   /*-------------------------------------------------------------------------*/
  223.   /* Refresh the space usage                                                 */
  224.   /*-------------------------------------------------------------------------*/
  225.   if (CollectFileInfo()) {
  226.       return gRcApi;
  227.   }
  228.   gFree  = (gFSInfoBuf.cUnitAvail * 1.0) * gCluster;
  229.   gTotal = (gFSInfoBuf.cUnit      * 1.0) * gCluster;
  230.   gUsed  = gTotal - gFree;
  231.  
  232.   CollectVolInfo();
  233.  
  234.   QueryFileSystem( gDriveLetter);
  235.  
  236.   printf( "\n SpaceHog v1.07 by Wing Yuen                            " \
  237.           "compiled on %s", __DATE__);
  238.   printf( "\n %s Volume in drive %c is %-11s\n Serial number is %s",
  239.           gDriveFormat, gDriveLetter, gDriveVolume, gDriveSerial);
  240.   printf( "\n --------------------------------------------------------------" \
  241.           "----------------");
  242.   printf( "\n%16s bytes per sector",       Split000( gFSInfoBuf.cbSector, ','));
  243.   printf( "\n%16s bytes per cluster",      Split000( gCluster,            ','));
  244.   printf( "\n%16s bytes total disk space", Split000( gTotal,              ','));
  245.   printf( "\n%16s bytes used",             Split000( gUsed ,              ','));
  246.   if (0.0 != gNewHogSize) {
  247.       printf( "\n*%15s bytes reserved in %s directory",
  248.               Split000( gNewHogSize, ','), gHogFilePath);
  249.   }
  250.   printf( "\n%16s bytes free\n",           Split000( gFree ,              ','));
  251.  
  252.   return 0;
  253. }                                                /* main()                   */
  254.  
  255. /*---------------------------------------------------------------------------*/
  256. /* CollectFileInfo()                                      Date: 03/15/1999   */
  257. /*---------------------------------------------------------------------------*/
  258. /* Description: Collect file information of gDriveNumber                     */
  259. /* Returns    : Nothing                                                      */
  260. /* Assumptions: None                                                         */
  261. /* Programmers: Wing F Yuen                                                  */
  262. /*---------------------------------------------------------------------------*/
  263. int CollectFileInfo (void)
  264. {
  265.   gFSInfoLevel = FSIL_ALLOC;          /* requests file system allocation info*/
  266.   #if (defined(_MSC_VER) || defined(WC16_))
  267.  
  268.   gRcApi = DosQFSInfo( gDriveNumber,
  269.                        gFSInfoLevel,
  270.                        (PBYTE)&gFSInfoBuf,
  271.                        sizeof gFSInfoBuf);
  272.   if (gRcApi) {
  273.       printf( "DosQFSInfo error: Rc%ld", gRcApi);
  274.       return 2;
  275.   }
  276.   #else
  277.  
  278.   gRcApi = DosQueryFSInfo( gDriveNumber,
  279.                            gFSInfoLevel,
  280.                            &gFSInfoBuf,
  281.                            sizeof gFSInfoBuf);
  282.   if (gRcApi) {
  283.       printf( "DosQueryFSInfo error: Rc%ld", gRcApi);
  284.       return 2;
  285.   }
  286.   #endif
  287.  
  288.   /*-------------------------------------------------------------------------*/
  289.   /* On successful return, the data buffer gFSInfoBuf contains a set of      */
  290.   /* information about space allocation within the specified file system.    */
  291.   /*-------------------------------------------------------------------------*/
  292.   #if 0
  293.  
  294.   printf( "\nCollectFileInfo():\n");
  295.   printf( "  gFSInfoBuf.cSectorUnit  = %lu\n", gFSInfoBuf.cSectorUnit );
  296.   printf( "  gFSInfoBuf.cUnit        = %lu\n", gFSInfoBuf.cUnit       );
  297.   printf( "  gFSInfoBuf.cUnitAvail   = %lu\n", gFSInfoBuf.cUnitAvail  );
  298.   printf( "  gFSInfoBuf.cbSector     = %hu\n", gFSInfoBuf.cbSector    );
  299.   #endif
  300.   return 0;
  301. }                                                /* CollectFileInfo()        */
  302.  
  303. /*---------------------------------------------------------------------------*/
  304. /* CollectVolInfo()                                       Date: 04/16/1998   */
  305. /*---------------------------------------------------------------------------*/
  306. /* Description: Collect volume information of gDriveNumber                   */
  307. /* Returns    : Nothing                                                      */
  308. /* Assumptions: None                                                         */
  309. /* Programmers: Wing F Yuen                                                  */
  310. /*---------------------------------------------------------------------------*/
  311. void CollectVolInfo (void)
  312. {
  313.   #if (defined(_MSC_VER) || defined(WC16_))
  314.  
  315.   ULONG  VolSer;
  316.   #else
  317.  
  318.   UINT   VolSer;
  319.   #endif
  320.  
  321.   gFSInfoLevel = FSIL_VOLSER;           /* requests volume/serial number info*/
  322.   #if (defined(_MSC_VER) || defined(WC16_))
  323.  
  324.   gRcApi = DosQFSInfo( gDriveNumber,
  325.                        gFSInfoLevel,
  326.                        (PBYTE)&gFSVolBuf,
  327.                        sizeof gFSVolBuf);
  328.   if (gRcApi) {
  329.       printf( "DosQFSInfo error: Rc%ld", gRcApi);
  330.       strcpy( gDriveSerial, "unknown");
  331.       strcpy( gDriveVolume, "unknown");
  332.       return;
  333.   }
  334.  
  335.     #if defined(WC16_)                        /* see \watcom\h\os21x\bsedos.h*/
  336.  
  337.   VolSer = *((ULONG *)(&gFSVolBuf.fdateCreation));
  338.     #else
  339.  
  340.   VolSer = *((ULONG *)(&gFSVolBuf.ulVSN));       /* Microsoft C              */
  341.     #endif
  342.  
  343.   sprintf( gDriveSerial, "%04X:%04X",
  344.            (USHORT)(VolSer >>16),
  345.            (USHORT)(VolSer     ));
  346.   #else                                          /* 32 bit API               */
  347.  
  348.   gRcApi = DosQueryFSInfo( gDriveNumber,
  349.                            gFSInfoLevel,
  350.                            &gFSVolBuf,
  351.                            sizeof gFSVolBuf);
  352.  
  353.   if (gRcApi) {
  354.       printf( "DosQueryFSInfo error: Rc%ld", gRcApi);
  355.       strcpy( gDriveSerial, "unknown");
  356.       strcpy( gDriveVolume, "unknown");
  357.       return;
  358.   }
  359.   VolSer = *((UINT *)(&gFSVolBuf.fdateCreation));
  360.   sprintf( gDriveSerial, "%04X:%04X",
  361.            (USHORT)(VolSer >>16),
  362.            (USHORT)(VolSer     ));
  363.   #endif                             /* (defined(_MSC_VER) || defined(WC16_))*/
  364.  
  365.   /*-------------------------------------------------------------------------*/
  366.   /* On successful return, the data buffer gFSVolBuf contains a set of       */
  367.   /* information about the volume/serial number of the drive.                */
  368.   /*-------------------------------------------------------------------------*/
  369.   strcpy( gDriveVolume, gFSVolBuf.vol.szVolLabel);
  370.   if ('\0' == gDriveVolume[0]) {
  371.       strcpy( gDriveVolume, "unlabeled");
  372.   }
  373.   return;
  374. }                                                /* CollectVolInfo()         */
  375.  
  376. /*---------------------------------------------------------------------------*/
  377. /* FileSize()                                             Date: 04/15/1998   */
  378. /*---------------------------------------------------------------------------*/
  379. /* Description: Return the size of the specified file.                       */
  380. /* Returns    : Nothing                                                      */
  381. /* Assumptions: None                                                         */
  382. /* Programmers: Wing F Yuen                                                  */
  383. /*---------------------------------------------------------------------------*/
  384. long FileSize (const char *FileSpec)
  385. {
  386.   FILE *Tmp;
  387.   long FileLen;
  388.  
  389.   if (NULL == (Tmp = fopen( FileSpec, "rb"))) {
  390.       return -1L;
  391.   }
  392.   #if (defined(_MSC_VER) || defined (__WATCOMC__))
  393.  
  394.   FileLen = filelength( fileno( Tmp));
  395.   #else                                          /* VisualAge C++            */
  396.  
  397.   FileLen = _filelength( fileno( Tmp));          /* needs /Se                */
  398.  
  399.   #endif
  400.   fclose( Tmp);
  401.   return FileLen;
  402. }                                                /* FileSize()               */
  403.  
  404. /*---------------------------------------------------------------------------*/
  405. /* QueryFileSystem()                                      Date: 06/14/2000   */
  406. /*---------------------------------------------------------------------------*/
  407. /* Description: Store the name of the file system attached to the specified  */
  408. /*              drive letter in gDriveFormat. If it is a LAN drive, its      */
  409. /*              alias will be stored in gDriveVolumn.                        */
  410. /* Returns    : Nothing                                                      */
  411. /* Assumptions: None                                                         */
  412. /* Programmers: Wing F Yuen                                                  */
  413. /*---------------------------------------------------------------------------*/
  414. void QueryFileSystem (char driveLetter)
  415. {
  416.   #if (defined(_MSC_VER) || defined(WC16_))
  417.  
  418.   UCHAR  szDeviceName[8];               /* Device name or drive letter string*/
  419.   USHORT ulOrdinal       = 0;                /* Ordinal of entry in name list*/
  420.   BYTE   *pszFSDName     = NULL;                 /* pointer to FS name       */
  421.   BYTE   *prgFSAData     = NULL;                 /* pointer to FS data       */
  422.   USHORT rcApi           = NO_ERROR;             /* Return code              */
  423.   BYTE   *pByte;
  424.  
  425.   /*-------------------------------------------------------------------------*/
  426.   /* Return-data buffer should be large enough to hold FSQBUFFER2 and the    */
  427.   /* maximum data for szName, szFSDName, and rgFSAData. Typically, the data  */
  428.   /* isn't that large.                                                       */
  429.   /*-------------------------------------------------------------------------*/
  430.   BYTE         fsqBuffer[sizeof(FSQBUFFER) + (3 * CCHMAXPATH)] = {0};
  431.   USHORT       cbBuffer    = sizeof(fsqBuffer);  /* Buffer length)           */
  432.   FSQBUFFER    *pfsqBuffer = (FSQBUFFER *)fsqBuffer;
  433.   USHORT       cbFSDName;
  434.   USHORT       cbFSAData;
  435.  
  436.   szDeviceName[0] = driveLetter;                 /* change drive letter      */
  437.   szDeviceName[1] = ':';
  438.   szDeviceName[2] = '\0';
  439.  
  440.   rcApi = DosQFSAttach(
  441.               szDeviceName,                   /* Logical drive of attached FS*/
  442.               ulOrdinal,                       /* ignored for FSAIL_QUERYNAME*/
  443.               FSAIL_QUERYNAME,           /* Return data for a Drive or Device*/
  444.               fsqBuffer,                         /* returned data            */
  445.               &cbBuffer,                         /* returned data length     */
  446.               0L
  447.           );
  448.  
  449.   /*-------------------------------------------------------------------------*/
  450.   /* On successful return, the fsqBuffer structure contains a set of         */
  451.   /* information describing the specified attached file system and the       */
  452.   /* DataBufferLen variable contains the size of information within the      */
  453.   /* structure.                                                              */
  454.   /*-------------------------------------------------------------------------*/
  455.   if (NO_ERROR == rcApi) {
  456.       /*---------------------------------------------------------------------*/
  457.       /* The data for the variable fields in the FSQBUFFER structure are as  */
  458.       /* follow:                                                             */
  459.       /*                                                                     */
  460.       /*   USHORT  iType;                                                    */
  461.       /*   USHORT  cbName;                                                   */
  462.       /*   UCHAR   szName[1];                                                */
  463.       /*   USHORT  cbFSDName;                                                */
  464.       /*   UCHAR   szFSDName[1];                                             */
  465.       /*   USHORT  cbFSAData;                                                */
  466.       /*   UCHAR   rgFSAData[1];                                             */
  467.       /*                                                                     */
  468.       /* They wised up an move the variable fields to the end of the         */
  469.       /* structure in the 32 bit version of OS/2.                            */
  470.       /*---------------------------------------------------------------------*/
  471.       pByte      = pfsqBuffer->szName +
  472.                    pfsqBuffer->cbName + 1;       /* ->cbFSDName              */
  473.       cbFSDName  = *((USHORT *)pByte);
  474.  
  475.       pszFSDName = pByte + sizeof cbFSDName;     /* -> szFSDName             */
  476.  
  477.       pByte      = pszFSDName + cbFSDName + 1;   /* -> cbFSAData             */
  478.       cbFSAData  = *((USHORT *)pByte);
  479.  
  480.       prgFSAData = pByte + sizeof cbFSAData;     /* ->rgFSAData              */
  481.  
  482.         #if 0
  483.  
  484.       printf("iType     = %hu\n", pfsqBuffer->iType);
  485.       printf("szName    = %s\n",  pfsqBuffer->szName);
  486.       printf("szFSDName = %s\n",  pszFSDName);
  487.       printf("cbFSDName = %hu\n",  cbFSDName);
  488.       printf("rgFSAData = %s\n",  prgFSAData);
  489.       printf("cbFSAData = %hu\n",  cbFSAData);
  490.  
  491.       printf( "gDriveFormat            = <%s>\n", gDriveFormat);
  492.         #endif
  493.  
  494.       strncpy( gDriveFormat, pszFSDName, sizeof gDriveFormat - 1);
  495.       gDriveFormat[sizeof gDriveFormat - 1] = '\0';
  496.  
  497.       if (!strcmp( pszFSDName, "LAN")) {
  498.           strncpy( gDriveVolume, prgFSAData, sizeof gDriveVolume - 1);
  499.           gDriveVolume[sizeof gDriveVolume - 1] = '\0';
  500.       }
  501.   } else {
  502.       printf("DosQFSAttach error: return code = %hu\n", rcApi);
  503.   }
  504.   return;
  505.   #else
  506.  
  507.   UCHAR  szDeviceName[8];
  508.   ULONG  ulOrdinal       = 0;
  509.   PBYTE  pszFSDName      = NULL;
  510.   PBYTE  prgFSAData      = NULL;
  511.   APIRET rcApi           = NO_ERROR;
  512.  
  513.   BYTE         fsqBuffer[sizeof(FSQBUFFER2) + (3 * CCHMAXPATH)] = {0};
  514.   ULONG        cbBuffer   = sizeof(fsqBuffer);        /* Buffer length) */
  515.   PFSQBUFFER2  pfsqBuffer = (PFSQBUFFER2) fsqBuffer;
  516.  
  517.   szDeviceName[0] = driveLetter;                 /* change drive letter      */
  518.   szDeviceName[1] = ':';
  519.   szDeviceName[2] = '\0';
  520.  
  521.   rcApi = DosQueryFSAttach(
  522.               szDeviceName,                   /* Logical drive of attached FS*/
  523.               ulOrdinal,                       /* ignored for FSAIL_QUERYNAME*/
  524.               FSAIL_QUERYNAME,           /* Return data for a Drive or Device*/
  525.               pfsqBuffer,                        /* returned data            */
  526.               &cbBuffer                          /* returned data length     */
  527.           );
  528.  
  529.   /*-------------------------------------------------------------------------*/
  530.   /* On successful return, the fsqBuffer structure contains a set of         */
  531.   /* information describing the specified attached file system and the       */
  532.   /* DataBufferLen variable contains the size of information within the      */
  533.   /* structure.                                                              */
  534.   /*-------------------------------------------------------------------------*/
  535.   if (NO_ERROR == rcApi) {
  536.       /*---------------------------------------------------------------------*/
  537.       /* The data for the last three fields in the FSQBUFFER2 structure are  */
  538.       /* stored at the offset of fsqBuffer.szName. Each data field following */
  539.       /* fsqBuffer.szName begins immediately after the previous item.        */
  540.       /*---------------------------------------------------------------------*/
  541.       pszFSDName = pfsqBuffer->szName + pfsqBuffer->cbName + 1;
  542.       prgFSAData = pszFSDName + pfsqBuffer->cbFSDName + 1;
  543.  
  544.       strncpy( gDriveFormat, pszFSDName, sizeof gDriveFormat - 1);
  545.       gDriveFormat[sizeof gDriveFormat - 1] = '\0';
  546.  
  547.       if (!strcmp( pszFSDName, "LAN")) {
  548.           strncpy( gDriveVolume, prgFSAData, sizeof gDriveVolume - 1);
  549.           gDriveVolume[sizeof gDriveVolume - 1] = '\0';
  550.       }
  551.       #if 0
  552.  
  553.       printf("iType     = %d\n", pfsqBuffer->iType);
  554.       printf("szName    = %s\n", pfsqBuffer->szName);
  555.       printf("szFSDName = %s\n", pszFSDName);
  556.       printf("rgFSAData = %s\n", prgFSAData);
  557.       #endif
  558.  
  559.   } else {
  560.       printf("DosQueryFSAttach error: return code = %u\n", rcApi);
  561.   }
  562.   return;
  563.   #endif
  564.  
  565. }                                                /* QueryFileSystem()        */
  566.  
  567. /*---------------------------------------------------------------------------*/
  568. /* Split000()                                             Date: 04/17/1998   */
  569. /*---------------------------------------------------------------------------*/
  570. /* Description: Add commas as separators between the thousands, millions &   */
  571. /*              billions. This is accomplished by shifting trailing digits   */
  572. /*              three at a time, then inserting a comma before repeating.    */
  573. /* Returns    : Nothing                                                      */
  574. /* Assumptions: Partition size < 1,000,000,000,000 bytes                     */
  575. /* Programmers: Wing F Yuen                                                  */
  576. /*---------------------------------------------------------------------------*/
  577. char *Split000 (double Bytes, char Separator)
  578. {
  579.   int    CommaCnt, DigitCnt, i;
  580.   static
  581.   char   Buffer[16];                   /* HPFS 64GB limit needs only 14 bytes*/
  582.   char   *Src, *Dst;
  583.  
  584.   sprintf( Buffer, "%.0f", Bytes);
  585.   DigitCnt = strlen( Buffer);
  586.   CommaCnt = (DigitCnt-1) / 3;
  587.   Dst = Buffer + DigitCnt + CommaCnt;
  588.   Src = Buffer + DigitCnt;
  589.   *Dst = *Src;
  590.   for (i = 0; i < CommaCnt; i++) {
  591.       *--Dst = *--Src;
  592.       *--Dst = *--Src;
  593.       *--Dst = *--Src;
  594.       *--Dst = Separator;
  595.   }                                              /* End for                  */
  596.   return Buffer;
  597. }                                                /* Split000()               */
  598.  
  599. /*---------------------------------------------------------------------------*/
  600. /* TotalHogSize()                                         Date: 04/17/1998   */
  601. /*---------------------------------------------------------------------------*/
  602. /* Description: Count the number of Hog Files and add up their total.        */
  603. /* Returns    : Total size as a double, and updated gOldHogCount.            */
  604. /* Assumptions:                                                              */
  605. /* Programmers: Wing F Yuen                                                  */
  606. /*---------------------------------------------------------------------------*/
  607. double TotalHogSize (void)
  608. {
  609.   double Sum=0;
  610.   long   HogSize;
  611.   char   HogName[256];
  612.  
  613.   gOldHogCount = 0;
  614.   do {
  615.       sprintf( HogName, "%s\\%d", gHogFilePath, gOldHogCount);
  616.       HogSize = FileSize( HogName);
  617.       Sum += HogSize;
  618.       ++gOldHogCount;
  619.   } while (-1L != HogSize);                      /* End do                   */
  620.   --gOldHogCount;
  621.   return Sum + 1.0;                              /* undo final HogSize       */
  622. }                                                /* TotalHogSize()           */
  623.  
  624. /*---------------------------------------------------------------------------*/
  625. /* Welcome()                                              Date: 01/20/2000   */
  626. /*---------------------------------------------------------------------------*/
  627. /* Description: Show syntax and usage                                        */
  628. /* Returns    : Nothing                                                      */
  629. /* Assumptions: None                                                         */
  630. /* Programmers: Wing F Yuen                                                  */
  631. /*---------------------------------------------------------------------------*/
  632. void Welcome (char *MyName)
  633. {
  634.   printf( "\nSyntax: %s [DriveLetter[:]]\n"                                   \
  635.           "\nThe current drive will be used if no DriveLetter is given."      \
  636.           "\nThe trailing colon is also optional.\n"                          \
  637.           "\nThis PUBLIC DOMAIN program helps you maintain the amount"        \
  638.           "\nof free space in the specified drive to under 2G-512 Bytes."     \
  639.           "\n(Because HPFS allocates space in 512 byte units.)"               \
  640.           "\nThus stopping programs using 32-bit signed integer math"         \
  641.           "\nfrom seeing space above 2G-512 bytes as negative.\n"             \
  642.           "\nIf it can't find the \\SPACEHOG directory in the specified"      \
  643.           "\npartition, it behaves like a run-of-the-mill freespace"          \
  644.           "\nreporting utility, albeit it can handle disk partitions up"      \
  645.           "\nto 999,999,999,999 bytes in size. (see Split000())\n"            \
  646.           "\nIf it sees the \\SPACEHOG directory, which you have to"          \
  647.           "\ncreate explicitly, it will create dummy files there as"          \
  648.           "\nneeded to maintain the 2G-512 byte freespace ceiling for"        \
  649.           "\nthat disk partition (you may have to run this twice). The"       \
  650.           "\ndummy files are named with simple integers, from 0 thru"         \
  651.           "\n99999999...\n"                                                   \
  652.           "\nIf the amount of reserved space needed is less than 2G-512"      \
  653.           "\nbytes, it will shrink or expand the size of the \\SPACEHOG\\0"   \
  654.           "\nfile instead.\n"                                                 \
  655.           "\nWarning: You use this program and its source code at your"       \
  656.           "\n         own risk. I provide no warranty of any kind. But"       \
  657.           "\n         I *do* welcome bug FIXES/reports via email to:\n"       \
  658.           "\n         wfyuen@bestweb.net\n"                                   \
  659.           "\nPatches: If you don't have any of the four compilers I used,"    \
  660.           "\n         you can change the \\SPACEHOG directory to some place"  \
  661.           "\n         else by patching the 256 byte variable I reserved"      \
  662.           "\n         with a binary editor. Search for this string:\n"        \
  663.           "\n         \"?:\\spacehog\"\n"                                     \
  664.           "\n         The '?' will be replaced by the program with the"       \
  665.           "\n         drive letter passed from the command line. Therefore,"  \
  666.           "\n         you need not patch that. Please make sure you end the"  \
  667.           "\n         new directory name with a binary 0 byte. It must not"   \
  668.           "\n         end with a backslash ('\\')!!!\n"                       \
  669.           "\nWing Yuen                                      %s\n"
  670.           , MyName, __DATE__);
  671.   return;
  672. }                                                /* Welcome()                */
  673.  
  674. /*---------------------------------------------------------------------------*/
  675. /* WriteNewHogFiles()                                     Date: 06/25/1998   */
  676. /*---------------------------------------------------------------------------*/
  677. /* Description: Replace the Hog Files                                        */
  678. /* Returns    : Nothing                                                      */
  679. /* Assumptions: None                                                         */
  680. /* Programmers: Wing F Yuen                                                  */
  681. /*---------------------------------------------------------------------------*/
  682. int WriteNewHogFiles (void)
  683. {
  684.   #if (defined(_MSC_VER) || defined(WC16_))
  685.  
  686.   USHORT     ActionTaken;
  687.   #else                                          /* 32 bit API               */
  688.  
  689.   ULONG      ActionTaken;
  690.   #endif
  691.   HFILE      Hog;
  692.   int        i, HogCount, NewHogCount=1;
  693.   double     HogSize, Overhead;
  694.   char       HogName[256];
  695.  
  696.   HogSize = gNewHogSize;
  697.   #ifndef NDEBUG
  698.  
  699.   printf( "MaxFileSize = %.0f\n", MAX_FILE_SIZE);
  700.   printf( "gNewHogSize = %.0f\n", gNewHogSize);
  701.   #endif
  702.  
  703.   if (HogSize > MAX_FILE_SIZE) {
  704.       do {
  705.           HogSize = HogSize - MAX_FILE_SIZE;
  706.           ++NewHogCount;
  707.       } while (HogSize > MAX_FILE_SIZE);         /* End do                   */
  708.   }
  709.  
  710.   /*-------------------------------------------------------------------------*/
  711.   /* When gOldHogCount differs from NewHogCount, the first run of SpaceHog   */
  712.   /* will not maximize the free disk space. I haven't figure this puzzle     */
  713.   /* out yet. If you do, please email me.                                    */
  714.   /*-------------------------------------------------------------------------*/
  715.  
  716.   #ifndef NDEBUG
  717.  
  718.   printf( "gOldHogCount = %d\n",   gOldHogCount);
  719.   printf( "NewHogCount  = %d\n",   NewHogCount );
  720.   #endif
  721.  
  722.   for (i = 0; i < NewHogCount; i++) {
  723.       /*---------------------------------------------------------------------*/
  724.       /* Rewriting the entire file with DosOpen() is much faster than        */
  725.       /* adjusting its size with chsize().                                   */
  726.       /*---------------------------------------------------------------------*/
  727.       sprintf( HogName, "%s\\%d", gHogFilePath, i);
  728.       #ifndef NDEBUG
  729.  
  730.       printf( "\nRewriting %s\n",  HogName );
  731.       printf( "HogSize  = %.0f\n", HogSize );
  732.       #endif
  733.       gRcApi = DosOpen( HogName,
  734.                         &Hog,
  735.                         &ActionTaken,
  736.                         (ULONG)HogSize,
  737.                         FILE_NORMAL,
  738.                         OPEN_ACTION_CREATE_IF_NEW |
  739.                         OPEN_ACTION_REPLACE_IF_EXISTS,
  740.                         OPEN_SHARE_DENYREADWRITE |
  741.                         OPEN_ACCESS_WRITEONLY,
  742.                         0L);
  743.       if (gRcApi) {
  744.           printf( __FILE__"/WriteNewHogFiles(): DosOpen() returns %u\n",
  745.                   gRcApi);
  746.           return 1;
  747.       }
  748.  
  749.       gRcApi = DosClose( Hog);
  750.       if (gRcApi) {
  751.           printf( __FILE__"/WriteNewHogFiles(): DosClose() returns %u\n",
  752.                   gRcApi);
  753.           return 1;
  754.       }
  755.       HogSize = MAX_FILE_SIZE;
  756.   }                                              /* End for                  */
  757.   /*-------------------------------------------------------------------------*/
  758.   /* Delete any un-needed old hog files                                      */
  759.   /*-------------------------------------------------------------------------*/
  760.   for (i = NewHogCount; i < gOldHogCount; i++) {
  761.       sprintf( HogName, "%s\\%d", gHogFilePath, i);
  762.       remove( HogName);
  763.   }                                              /* End for                  */
  764.  
  765.   return 0;
  766. }                                                /* WriteNewHogFiles()       */
  767.