Advertisement
Phr0zen_Penguin

When A File MUST Exist

Nov 30th, 2013
244
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.15 KB | None | 0 0
  1. /*============================================================================
  2.   ----------------------------------------------------------------------------
  3.   myFile.c - When a file MUST exist (with absolute error checking).
  4.                  (c) Damion 'Phr0z3n.Dev' Tapper, 2013.
  5.                  Email: Phr0z3n.Dev@Gmail.com
  6.   ----------------------------------------------------------------------------
  7.   ============================================================================*/
  8.  
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <io.h>
  12. #include <time.h>
  13.  
  14. /*=====================================--=====================================
  15.                 VARIABLE NAME DEFINITIONS
  16.   ----------------------------------------------------------------------------*/
  17. #define MY_FIND_DATA            myFindData
  18. #define FILE_SEARCH_HANDLE      hFile
  19. #define FILE_POINTER            pFile
  20.  
  21. #define FILE_BUFFER         fileBuffer
  22. #define FILE_BUFFER_SIZE        150
  23.  
  24. #define FILE_FIND_ERROR         0x01
  25. #define FILE_SET_ATTRIB_ERROR       0x02
  26. #define FILE_ATTRIB_ERROR_SYS       0x03
  27. #define FILE_OPEN_ERROR         0x10
  28. #define FILE_WRITE_ERROR        0x20
  29. #define FILE_CLOSE_ERROR        0x30
  30.  
  31. #define FILE_NAME           fileName
  32. #define FILE_ERROR_NO_1         fileErrNo1
  33. #define FILE_ERROR_NO_2         fileErrNo2
  34.  
  35. #define ERROR_BUFFER_1          errorBuffer1
  36. #define ERROR_BUFFER_2          errorBuffer2
  37. #define SPRINTFS_BUFFER         75
  38. #define ERROR_BUFFER_SIZE       75
  39.  
  40. /*=====================================--=====================================
  41.             FILE ATTRIBUTES DEFINITIONS (Just In Case)
  42.   ----------------------------------------------------------------------------*/
  43.  
  44. /*
  45.  * Some compilers 'may' define these constants with different names.
  46.  */
  47.  
  48. #ifndef ENOENT
  49.     #define ENOENT          2   /* No such file or directory    */
  50.     #define EACCES          5   /* Permission denied        */
  51.     #define EINVAL          22  /* Invalid argument     */
  52. #endif
  53.  
  54. #ifndef _A_NORMAL
  55.     #define _A_NORMAL       0x00    /* Normal file, no attributes   */
  56.     #define _A_RDONLY       0x01    /* Read only attribute      */
  57.     #define _A_HIDDEN       0x02    /* Hidden file          */
  58.     #define _A_SYSTEM       0x04    /* System file          */
  59.     #define _A_SUBDIR       0x10    /* Sub-directory.       */
  60.     #define _A_ARCH         0x20    /* Archive          */
  61. #endif
  62.  
  63. #ifndef _S_IREAD
  64.     #define _S_IFMT         0xF000
  65.     #define _S_IFDIR        0x4000
  66.     #define _S_IFCHR        0x2000
  67.     #define _S_IFIFO        0x1000
  68.     #define _S_IFREG        0x8000
  69.     #define _S_IREAD        0x0100
  70.     #define _S_IWRITE       0x0080
  71.     #define _S_IEXEC        0x0040
  72. #endif
  73.  
  74. /*=====================================--=====================================
  75.                 TYPE DEFINITIONS
  76.   ----------------------------------------------------------------------------*/
  77. typedef struct  _finddata_t     FD;
  78. typedef struct  _finddata_t*    PFD; /* Hungarian notation. */
  79.  
  80. /*=====================================--=====================================
  81.             FUNCTION PROTOTYPE DEFINITIONS
  82.   ----------------------------------------------------------------------------*/
  83. static void openFile(void);
  84. static void fileError(const char *, const int, errno_t);
  85.  
  86. int main(void)
  87. {
  88.     openFile();
  89.  
  90.     return 0;
  91. }
  92.  
  93. /*=====================================--=====================================
  94.                 FILE OPEN FUNCTION
  95.   ----------------------------------------------------------------------------*/
  96. static void openFile(void)
  97. {
  98. /* The limited scope of this definition is for security reasons. */
  99. #ifndef MY_FILE
  100.     /*
  101.      * The first step in making sure your program operates correctly is to verify
  102.      * that the path and filename stated here is absolutely valid.
  103.      */
  104.     #define MY_FILE "logFile.log"
  105.     /*
  106.      * When the absolute path to the file is not stated, file operations take
  107.      * place in the directory where the program itself is located.
  108.      *
  109.      * Being that this program is 'mainly' for demonstration...
  110.      */
  111. #endif
  112. /*
  113.  * WARNING: Avoid obvious names such as LOG_FILE, _LOG_FILE or even __LOG_FILE.
  114.  */
  115.  
  116.     PFD     myFindData;
  117.     intptr_t    hFile;      /* Needed to (at least) close the search handle. */
  118.     FILE        *pFile;
  119.     /*
  120.      * NOTE: fclose requires a pointer while fopen_s requires a pointer to a file
  121.      * pointer so the address of the file pointer (pfile) will have to be passed
  122.      * to fopen_s.
  123.      */
  124.     char        *fileBuffer;
  125.  
  126.     myFindData = calloc(1, sizeof(FD));
  127.  
  128.         /*
  129.          * Check if the file exists by trying to find it.
  130.          */
  131.         if((hFile = _findfirst(MY_FILE, myFindData)) == -1)
  132.         {
  133.             /*
  134.              * The errno generated in the previous statement is copied so that it
  135.              * doesn't get changed when _findclose resets the errno value.
  136.              */
  137.             errno_t fileErrNo2 = errno;
  138.  
  139.                 switch(errno)
  140.                 {
  141.    
  142.                     /* If the file just doesn't exist... */
  143.                     case ENOENT:
  144.                         /* Being that the find task is completed... */
  145.                         _findclose(hFile);
  146.                         free(myFindData);
  147.    
  148.                             if(fopen_s(&FILE_POINTER, MY_FILE, "w"))
  149.                             {
  150.                                 fileError(MY_FILE, FILE_OPEN_ERROR, errno);
  151.                             }
  152.                         break;
  153.    
  154.                     /* ...under any other condition. */                
  155.                     default:
  156.                         /* .. */
  157.                         _findclose(hFile);
  158.                         free(myFindData);
  159.    
  160.                         fileError(MY_FILE, FILE_FIND_ERROR, FILE_ERROR_NO_2);
  161.                         break;
  162.                 }
  163.         }
  164.         /*
  165.          * If for any specific reason the (log) file attributes indicate that it
  166.          * is a system file...
  167.          *
  168.          * Such a file should not be altered without personal intervention.
  169.          */
  170.         else if(myFindData->attrib & _A_SYSTEM)
  171.         {
  172.             /* .. */
  173.             _findclose(hFile);
  174.             free(myFindData);
  175.  
  176.             /*
  177.              * errno is not used here because a system file attribute is not a
  178.              * system error per se.
  179.              */
  180.             fileError(MY_FILE, FILE_ATTRIB_ERROR_SYS, errno);
  181.         }
  182.         else
  183.         {
  184.             /*
  185.              * If the (log) file attributes indicate that it is read-only...
  186.              */
  187.             if(myFindData->attrib & _A_RDONLY)
  188.             {
  189.                 /* .. */
  190.                 _findclose(hFile);
  191.                 free(myFindData);
  192.  
  193.                     /*
  194.                      * For program execution to reach this point, the file's
  195.                      * existence is already verified so no further check needs
  196.                      * to be done.
  197.                      */
  198.                     if(_chmod(MY_FILE, _S_IREAD | _S_IWRITE) == -1)
  199.                     {
  200.                         fileError(MY_FILE, FILE_SET_ATTRIB_ERROR, errno);
  201.                     }
  202.             }
  203.  
  204.             /*
  205.              * And if fopen_s fails regardless...
  206.              */
  207.             if(fopen_s(&FILE_POINTER, MY_FILE, "a"))
  208.             {
  209.                 fileError(MY_FILE, FILE_OPEN_ERROR, errno);
  210.             }
  211.         }
  212.  
  213.     /*
  214.      * FILE_BUFFER needs to be allocated only when it's needed and freed as soon
  215.      * as it is not for increased security of the code.
  216.      */
  217.     FILE_BUFFER = calloc(FILE_BUFFER_SIZE, sizeof(char));
  218.  
  219.  
  220. /*-------------------------------------++-------------------------------------
  221.                 TEST CODE
  222.   ----------------------------------------------------------------------------*/
  223.     /*
  224.      * This section is not meant to be a part of the code. Its just there for
  225.      * testing purposes.
  226.      */
  227.     {
  228.         #define TIME_STRUCTURE      pTm
  229.         #define MY_TIME_VALUE       pMyTimeValue
  230.         #define TIME_BUFFER     timeBuffer
  231.         #define TIME_BUFFER_SIZE    32
  232.         #define CHARS_WRITTEN       cw
  233.  
  234.         typedef struct tm   TM;
  235.         typedef struct tm*  PTM;
  236.         typedef __time64_t  TV;
  237.         typedef __time64_t* PTV;
  238.  
  239.         PTM         pTm;
  240.         PTV         pMyTimeValue;
  241.         char            *timeBuffer;
  242.         int         cw;
  243.  
  244.         TIME_STRUCTURE = calloc(1, sizeof(TM));
  245.         MY_TIME_VALUE = calloc(1, sizeof(TV));
  246.         TIME_BUFFER = calloc(TIME_BUFFER_SIZE, sizeof(char));
  247.  
  248.         /* Get the time value. */
  249.         _time64(MY_TIME_VALUE);
  250.  
  251.         /* Populate the time structure. */
  252.         _localtime64_s(TIME_STRUCTURE, MY_TIME_VALUE);
  253.  
  254.         /* Convert the time and date to a character string. */
  255.         asctime_s(TIME_BUFFER, TIME_BUFFER_SIZE, TIME_STRUCTURE);
  256.  
  257.         /* Print to the FILE_BUFFER string that will be written to the file. */
  258.         CHARS_WRITTEN = sprintf_s(FILE_BUFFER, FILE_BUFFER_SIZE, ">>     Log File Access:     <<\n");
  259.         CHARS_WRITTEN += sprintf_s(FILE_BUFFER + CHARS_WRITTEN, FILE_BUFFER_SIZE - CHARS_WRITTEN, "   %s", TIME_BUFFER); /* Pointer arithmetic. */
  260.         CHARS_WRITTEN += sprintf_s(FILE_BUFFER + CHARS_WRITTEN, FILE_BUFFER_SIZE - CHARS_WRITTEN, ">> ------------------------ <<\n\n");
  261.  
  262.         free(TIME_BUFFER);
  263.         free(MY_TIME_VALUE);
  264.         free(TIME_STRUCTURE);
  265.     }
  266. /*----------------------------------------------------------------------------*/
  267.  
  268.         /* TEST WRITE (to the file). */
  269.         if(fprintf_s(FILE_POINTER, FILE_BUFFER) < 0)
  270.         {
  271.             fileError(MY_FILE, FILE_WRITE_ERROR, errno);
  272.         }
  273.         else
  274.         {
  275.             /*
  276.              * At the same time, print the contents of the FILE_BUFFER string to
  277.              * the screen.
  278.              */
  279.             printf_s("%s", FILE_BUFFER);
  280.         }
  281.  
  282.     /* This is not needed anymore. */
  283.     free(FILE_BUFFER);
  284.  
  285.     /*
  286.      * Can fclose fail?
  287.      *
  288.      * And why is there no fclose_s?
  289.      */
  290.     fclose(FILE_POINTER);
  291.  
  292. #ifdef MY_FILE
  293.     #undef  MY_FILE
  294. #endif
  295. }
  296.  
  297. static void fileError(const char *fileName, const int fileErrNo1, errno_t fileErrNo2)
  298. {
  299.     char    *errorBuffer1;
  300.     char    *errorBuffer2;
  301.  
  302.     ERROR_BUFFER_1 = calloc(1, SPRINTFS_BUFFER);
  303.     ERROR_BUFFER_2 = calloc(1, ERROR_BUFFER_SIZE);
  304.  
  305.         if(FILE_ERROR_NO_1 == FILE_ATTRIB_ERROR_SYS)
  306.         {
  307.             printf_s(">> %s is a system file. <<", FILE_NAME);
  308.             printf_s("\n   Please verify the file location/attributes.");
  309.         }
  310.         else
  311.         {
  312.             switch(FILE_ERROR_NO_1)
  313.             {
  314.                 case FILE_FIND_ERROR:
  315.                     sprintf_s(ERROR_BUFFER_1, SPRINTFS_BUFFER, ">> Cannot find %s. <<", FILE_NAME);
  316.                     break;
  317.  
  318.                 case FILE_SET_ATTRIB_ERROR:
  319.                     sprintf_s(ERROR_BUFFER_1, SPRINTFS_BUFFER, ">> Cannot prepare %s for writing. <<", FILE_NAME);
  320.                     break;
  321.  
  322.                 case FILE_OPEN_ERROR:
  323.                     sprintf_s(ERROR_BUFFER_1, SPRINTFS_BUFFER, ">> Cannot open %s. <<", FILE_NAME);
  324.                     break;
  325.  
  326.                 case FILE_WRITE_ERROR:
  327.                     sprintf_s(ERROR_BUFFER_1, SPRINTFS_BUFFER, ">> Cannot write to %s. <<", FILE_NAME);
  328.                     break;
  329.             }
  330.    
  331.             /*
  332.              * Keeping a duplicated value of errno is always a smart idea especially
  333.              * in cases where the function it is passed to will perform some
  334.              * intermediate operations, before it is used, that could reset the
  335.              * original value.  Such is the case with the fileError function.
  336.              */
  337.             if(strerror_s(ERROR_BUFFER_2, ERROR_BUFFER_SIZE, FILE_ERROR_NO_2))
  338.             {
  339.                 printf_s("%s", ERROR_BUFFER_1);
  340.                 printf_s("\n   Error message #: %d", FILE_ERROR_NO_1);
  341.                
  342.                 printf_s("\n\n>> Error generating error message. <<");
  343.                 printf_s("\n   Error message #: %d", errno);
  344.             }
  345.             else
  346.             {
  347.                 printf_s("%s", ERROR_BUFFER_1);
  348.                 printf_s("\n   %s.", ERROR_BUFFER_2);
  349.             }
  350.         }
  351.  
  352.     free(ERROR_BUFFER_1);
  353.     free(ERROR_BUFFER_2);
  354.     exit(EXIT_FAILURE);
  355. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement