home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 1999 January / dppcpro0199a.iso / January / Fp98 / SDK / WebBot / votebot / server / votefile.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-18  |  7.4 KB  |  329 lines

  1. //
  2. // Copyright (c) 1997 Vermeer Technologies, Inc., a wholly owned
  3. //               subsidiary of Microsoft Corp.  All Rights Reserved
  4.  
  5. // CVote implementation
  6. #include "votefile.h"
  7.  
  8. #ifdef WIN32
  9. #include <windows.h>
  10. #include <io.h>
  11. #include <share.h>
  12. #endif 
  13.  
  14. #ifdef UNIX
  15. #include <signal.h>
  16. #include <unistd.h>
  17. #include <sys/types.h>
  18. #endif
  19.  
  20. #include <errno.h>
  21. #include <sys/stat.h>
  22. #include <fcntl.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <stdio.h>
  26.  
  27. CVote::CVote(const char *filename, BOOL create)
  28. {
  29.  
  30.     // Assume the worst
  31.     m_vote1count = 1;
  32.     m_vote2count = 1;
  33.     error = TRUE;
  34.  
  35.     MakeWritable(filename);
  36.  
  37.     // Open the file and lock it.  Timeout for waiting for lock is 10 sec
  38.     if (!OpenAndLock(filename, 10, create))    
  39.         return;
  40.     
  41.     m_vote1count = ReadVoteCount("vote1type");
  42.     m_vote2count = ReadVoteCount("vote2type");
  43.     error = FALSE;
  44. }
  45.  
  46. CVote::~CVote()
  47. {
  48.     WriteVoteCount("vote1type", m_vote1count);
  49.     WriteVoteCount("vote2type", m_vote2count);
  50.     Close();            // Closes and unlocks the file    
  51. }
  52.  
  53. long CVote::GetVoteCount(const char* votetype)
  54. {
  55.     if (!strcmp(votetype,"vote1type"))
  56.     {    return m_vote1count;    }
  57.     else if (!strcmp(votetype,"vote2type"))
  58.     {    return m_vote2count;    };
  59.     
  60.     // if votetype is something else, this function doesn't support it
  61.     // so return a 0.
  62.     return 0; 
  63. }
  64.  
  65. void CVote::SetVoteCount(const char* votetype, long votecount)
  66. {
  67.     if (!strcmp(votetype,"vote1type"))
  68.     {    m_vote1count = votecount;    }
  69.     else if (!strcmp(votetype,"vote2type"))
  70.     {    m_vote2count = votecount;    };
  71. }
  72.  
  73. void CVote::Increment(const char* votetype, long amount)
  74. {
  75.     if (!strcmp(votetype,"vote1type"))
  76.     {    m_vote1count += amount;        }
  77.     else if (!strcmp(votetype,"vote2type"))
  78.     {    m_vote2count += amount;        };
  79. }
  80.  
  81.  
  82. #ifdef UNIX
  83.  
  84. #ifdef SGI
  85. void alarm_handler(...)
  86. #else
  87. void alarm_handler(int /*sig*/)
  88. #endif 
  89. {
  90.     // catch alarm signal and ignore
  91. }
  92. #endif
  93.  
  94. void CVote::MakeWritable(const char *filename)
  95. {
  96. #ifdef WIN32
  97.     chmod(filename, _S_IREAD | _S_IWRITE);
  98. #endif
  99. #ifdef UNIX
  100.     struct stat statBuf;
  101.  
  102.     if (stat(filename, &statBuf))
  103.         return;
  104.  
  105.     int fileMode = statBuf.st_mode;
  106.     fileMode |= S_IWUSR;
  107.  
  108.     if (fileMode & S_IRGRP)
  109.         fileMode |= S_IWGRP;
  110.     if (fileMode & S_IROTH)
  111.         fileMode |= S_IWOTH;
  112.  
  113.     chmod(filename, fileMode);
  114. #endif
  115. }
  116.  
  117.  
  118. BOOL CVote::OpenAndLock(const char *filename, int nTimeoutSec, BOOL create)
  119. {
  120.  
  121. #ifdef WIN32
  122.     DWORD startTime = GetTickCount();
  123.     DWORD nTimeout = nTimeoutSec * 1000;        // Timeout in milleseconds
  124.     for (fd = -1; nTimeoutSec == 0 || GetTickCount() - startTime < nTimeout;)
  125.     {
  126.         // Try to open the file in locked mode 
  127.         fd = _sopen(filename, _O_RDWR, _SH_DENYWR);
  128.  
  129.         // Success, exit the for loop
  130.         if (fd != -1)
  131.             break;
  132.  
  133.         // No success. If file was not found, and create is specified, then
  134.         // create it, lock it, and write a 0 to it
  135.         if (errno == ENOENT && create)
  136.         {
  137.             fd = _sopen(filename, _O_RDWR | _O_CREAT, _SH_DENYWR, _S_IREAD | _S_IWRITE);
  138.             
  139.             InitializeFile();
  140.  
  141.             break;
  142.         }
  143.  
  144.         // Otherwise, delay half a second, and try again.
  145.         Sleep(500);
  146.     }
  147.     if (fd == -1)
  148.         return FALSE;        // Timed out
  149.  
  150. #endif /* WIN32 */
  151.  
  152.  
  153. #ifdef UNIX
  154.     fd = open(filename, O_RDWR);
  155.     if (fd == -1)
  156.     {
  157.         if (errno == ENOENT && create)
  158.         {
  159.             // If it's okay to create it, try to do so
  160.             fd = open(filename, O_RDWR | O_CREAT, 0666);
  161.             if (fd == -1)        // still failed, abort
  162.                 return FALSE;
  163.             InitializeFile();    // Fill in with count of 0
  164.         }
  165.         else
  166.             return FALSE;
  167.     }
  168.  
  169.     // Setup the alarm handler
  170.     #ifdef SGI
  171.     void (*func)(...) = 0;
  172.     #else
  173.     void (*func)(int) = 0;
  174.     #endif
  175.     func = signal(SIGALRM, alarm_handler);
  176.     if ((void *)(func) == (void *)(SIG_ERR))
  177.     {
  178.         close(fd);
  179.         fd = -1;
  180.         return FALSE;
  181.     }
  182.     
  183.     // Set number of seconds for alarm:
  184.     alarm(nTimeoutSec);
  185.  
  186.     // Setup the lock to be the whole file
  187.     struct flock sflock;
  188.     sflock.l_type = F_WRLCK;
  189.     sflock.l_whence = 0;
  190.     sflock.l_start = 0;
  191.     sflock.l_len = 0;
  192.  
  193.     // Try to do the lock.  This blocks until lock is achieved
  194.     // or the alarm goes off.
  195.     int ret = fcntl(fd, F_SETLKW, &sflock);
  196.  
  197.     // If ret=-1, it failed
  198.     if (ret == -1)
  199.     {
  200.         close(fd);
  201.         fd = -1;
  202.         return FALSE;
  203.     }
  204. #endif /* UNIX */
  205.  
  206.     // Check validity of the count file
  207.     if (!IsValid())
  208.     {
  209.         fd = -1;
  210.         return FALSE;
  211.     }
  212.     return TRUE;
  213. }
  214.  
  215. void CVote::InitializeFile()
  216. {  
  217.     // called whenever the votefile needs to be created from scratch
  218.     // (when file is first saved w/ votebot on it, or when a recalc
  219.     // links occurs and .vot file isn't found
  220.     lseek(fd, 0, SEEK_SET);
  221.     
  222.     write (fd, KEY1_STR, KEY_LEN);
  223.     write (fd, "=", 1);
  224.     char buffer[MAX_NUM];
  225.     sprintf(buffer, "%011ld", 0L);
  226.     int nStrLen = strlen(buffer);
  227.     write(fd, buffer, nStrLen);
  228.  
  229. #ifdef UNIX
  230.     write (fd, "\r", 1);
  231. #endif
  232.  
  233.     write (fd, "\n", 1);
  234.     
  235.     write(fd, KEY2_STR, KEY_LEN);
  236.     write(fd, "=", 1);
  237.     sprintf(buffer, "%011ld", 0L);
  238.     write(fd, buffer, nStrLen);
  239.  
  240. };
  241.  
  242.  
  243. void CVote::Close()
  244. {
  245.     // close the .vot file
  246.     close(fd);
  247. }
  248.  
  249.  
  250. long CVote::ReadVoteCount(const char* votetype)
  251. {
  252.     
  253.     char buffer[MAX_NUM];
  254.     int nBytesRead;
  255.  
  256.     // go to the beginning of the file represented by handle fd
  257.     long pos = lseek( fd, 0L, SEEK_SET );
  258.     
  259.     if( pos == -1L )           // file has been corrupted. Give up.
  260.     {    error = TRUE; return 0;     }
  261.     
  262.     // position the file pointer according to the key we've received.
  263.     if (!strcmp(votetype,"vote1type"))
  264.     {    
  265.         lseek(fd, KEY_LEN + 1, SEEK_SET);
  266.     }
  267.     else if (!strcmp(votetype,"vote2type"))
  268.     {
  269.         lseek(fd, (KEY_LEN*2) + 3 + MAX_NUM, SEEK_SET);    
  270.     }
  271.     
  272.     // file pointer should be at location of VoteCount for corresponding
  273.     // key, so read it into the buffer and return it.
  274.     nBytesRead = read(fd, buffer, MAX_NUM);
  275.     if (nBytesRead == -1)             // no VoteCount? file is corrupted!
  276.     {
  277.         error = TRUE;
  278.         return 0;
  279.     }
  280.  
  281.     buffer[nBytesRead] = '\0';        // Close off the string
  282.     
  283.     return atol(buffer);            // convert to number
  284.     //delete[] buffer;
  285. }
  286.  
  287. void CVote::WriteVoteCount(const char* votetype, long count)
  288. {    
  289.     
  290.     // before we do any file parsing, 
  291.     // go to the beginning of the file (handle fd)
  292.     lseek( fd, 0L, SEEK_SET );
  293.     
  294.     // position the file pointer according to the key we've received.
  295.     if (!strcmp(votetype,"vote1type"))
  296.     {    
  297.         lseek(fd, KEY_LEN + 1, SEEK_SET);
  298.     }
  299.     else if (!strcmp(votetype,"vote2type"))
  300.     {
  301.         lseek(fd, (KEY_LEN*2) + 3 + MAX_NUM, SEEK_SET);    
  302.     }
  303.             
  304.     // file pointer has been positioned; write count to the file.
  305.     char buffer[MAX_NUM];
  306.     sprintf(buffer, "%011ld", count);
  307.     int nStrLen = strlen(buffer);
  308.     write(fd, buffer, nStrLen);
  309. }
  310.  
  311.  
  312.  
  313. BOOL CVote::IsValid()
  314. {
  315.     // determine whether or not .vot file is a valid one.
  316.     // if it's corrupted, calling function should create a new one.
  317.     lseek(fd, 0, SEEK_SET);
  318.     char buffer[KEY_LEN];
  319.     int nBytesRead = read(fd, buffer, KEY_LEN);
  320.     if (nBytesRead == -1)
  321.     {
  322.         error = TRUE;
  323.         return FALSE;
  324.     }
  325.     return (strncmp(buffer, KEY1_STR, KEY_LEN) == 0);
  326. }
  327.  
  328.             
  329.