SHARE
TWEET

When A File MUST Exist

Phr0zen_Penguin Nov 30th, 2013 133 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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. }
RAW Paste Data
Top