Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*============================================================================
- ----------------------------------------------------------------------------
- myFile.c - When a file MUST exist (with absolute error checking).
- (c) Damion 'Phr0z3n.Dev' Tapper, 2013.
- Email: Phr0z3n.Dev@Gmail.com
- ----------------------------------------------------------------------------
- ============================================================================*/
- #include <stdio.h>
- #include <stdlib.h>
- #include <io.h>
- #include <time.h>
- /*=====================================--=====================================
- VARIABLE NAME DEFINITIONS
- ----------------------------------------------------------------------------*/
- #define MY_FIND_DATA myFindData
- #define FILE_SEARCH_HANDLE hFile
- #define FILE_POINTER pFile
- #define FILE_BUFFER fileBuffer
- #define FILE_BUFFER_SIZE 150
- #define FILE_FIND_ERROR 0x01
- #define FILE_SET_ATTRIB_ERROR 0x02
- #define FILE_ATTRIB_ERROR_SYS 0x03
- #define FILE_OPEN_ERROR 0x10
- #define FILE_WRITE_ERROR 0x20
- #define FILE_CLOSE_ERROR 0x30
- #define FILE_NAME fileName
- #define FILE_ERROR_NO_1 fileErrNo1
- #define FILE_ERROR_NO_2 fileErrNo2
- #define ERROR_BUFFER_1 errorBuffer1
- #define ERROR_BUFFER_2 errorBuffer2
- #define SPRINTFS_BUFFER 75
- #define ERROR_BUFFER_SIZE 75
- /*=====================================--=====================================
- FILE ATTRIBUTES DEFINITIONS (Just In Case)
- ----------------------------------------------------------------------------*/
- /*
- * Some compilers 'may' define these constants with different names.
- */
- #ifndef ENOENT
- #define ENOENT 2 /* No such file or directory */
- #define EACCES 5 /* Permission denied */
- #define EINVAL 22 /* Invalid argument */
- #endif
- #ifndef _A_NORMAL
- #define _A_NORMAL 0x00 /* Normal file, no attributes */
- #define _A_RDONLY 0x01 /* Read only attribute */
- #define _A_HIDDEN 0x02 /* Hidden file */
- #define _A_SYSTEM 0x04 /* System file */
- #define _A_SUBDIR 0x10 /* Sub-directory. */
- #define _A_ARCH 0x20 /* Archive */
- #endif
- #ifndef _S_IREAD
- #define _S_IFMT 0xF000
- #define _S_IFDIR 0x4000
- #define _S_IFCHR 0x2000
- #define _S_IFIFO 0x1000
- #define _S_IFREG 0x8000
- #define _S_IREAD 0x0100
- #define _S_IWRITE 0x0080
- #define _S_IEXEC 0x0040
- #endif
- /*=====================================--=====================================
- TYPE DEFINITIONS
- ----------------------------------------------------------------------------*/
- typedef struct _finddata_t FD;
- typedef struct _finddata_t* PFD; /* Hungarian notation. */
- /*=====================================--=====================================
- FUNCTION PROTOTYPE DEFINITIONS
- ----------------------------------------------------------------------------*/
- static void openFile(void);
- static void fileError(const char *, const int, errno_t);
- int main(void)
- {
- openFile();
- return 0;
- }
- /*=====================================--=====================================
- FILE OPEN FUNCTION
- ----------------------------------------------------------------------------*/
- static void openFile(void)
- {
- /* The limited scope of this definition is for security reasons. */
- #ifndef MY_FILE
- /*
- * The first step in making sure your program operates correctly is to verify
- * that the path and filename stated here is absolutely valid.
- */
- #define MY_FILE "logFile.log"
- /*
- * When the absolute path to the file is not stated, file operations take
- * place in the directory where the program itself is located.
- *
- * Being that this program is 'mainly' for demonstration...
- */
- #endif
- /*
- * WARNING: Avoid obvious names such as LOG_FILE, _LOG_FILE or even __LOG_FILE.
- */
- PFD myFindData;
- intptr_t hFile; /* Needed to (at least) close the search handle. */
- FILE *pFile;
- /*
- * NOTE: fclose requires a pointer while fopen_s requires a pointer to a file
- * pointer so the address of the file pointer (pfile) will have to be passed
- * to fopen_s.
- */
- char *fileBuffer;
- myFindData = calloc(1, sizeof(FD));
- /*
- * Check if the file exists by trying to find it.
- */
- if((hFile = _findfirst(MY_FILE, myFindData)) == -1)
- {
- /*
- * The errno generated in the previous statement is copied so that it
- * doesn't get changed when _findclose resets the errno value.
- */
- errno_t fileErrNo2 = errno;
- switch(errno)
- {
- /* If the file just doesn't exist... */
- case ENOENT:
- /* Being that the find task is completed... */
- _findclose(hFile);
- free(myFindData);
- if(fopen_s(&FILE_POINTER, MY_FILE, "w"))
- {
- fileError(MY_FILE, FILE_OPEN_ERROR, errno);
- }
- break;
- /* ...under any other condition. */
- default:
- /* .. */
- _findclose(hFile);
- free(myFindData);
- fileError(MY_FILE, FILE_FIND_ERROR, FILE_ERROR_NO_2);
- break;
- }
- }
- /*
- * If for any specific reason the (log) file attributes indicate that it
- * is a system file...
- *
- * Such a file should not be altered without personal intervention.
- */
- else if(myFindData->attrib & _A_SYSTEM)
- {
- /* .. */
- _findclose(hFile);
- free(myFindData);
- /*
- * errno is not used here because a system file attribute is not a
- * system error per se.
- */
- fileError(MY_FILE, FILE_ATTRIB_ERROR_SYS, errno);
- }
- else
- {
- /*
- * If the (log) file attributes indicate that it is read-only...
- */
- if(myFindData->attrib & _A_RDONLY)
- {
- /* .. */
- _findclose(hFile);
- free(myFindData);
- /*
- * For program execution to reach this point, the file's
- * existence is already verified so no further check needs
- * to be done.
- */
- if(_chmod(MY_FILE, _S_IREAD | _S_IWRITE) == -1)
- {
- fileError(MY_FILE, FILE_SET_ATTRIB_ERROR, errno);
- }
- }
- /*
- * And if fopen_s fails regardless...
- */
- if(fopen_s(&FILE_POINTER, MY_FILE, "a"))
- {
- fileError(MY_FILE, FILE_OPEN_ERROR, errno);
- }
- }
- /*
- * FILE_BUFFER needs to be allocated only when it's needed and freed as soon
- * as it is not for increased security of the code.
- */
- FILE_BUFFER = calloc(FILE_BUFFER_SIZE, sizeof(char));
- /*-------------------------------------++-------------------------------------
- TEST CODE
- ----------------------------------------------------------------------------*/
- /*
- * This section is not meant to be a part of the code. Its just there for
- * testing purposes.
- */
- {
- #define TIME_STRUCTURE pTm
- #define MY_TIME_VALUE pMyTimeValue
- #define TIME_BUFFER timeBuffer
- #define TIME_BUFFER_SIZE 32
- #define CHARS_WRITTEN cw
- typedef struct tm TM;
- typedef struct tm* PTM;
- typedef __time64_t TV;
- typedef __time64_t* PTV;
- PTM pTm;
- PTV pMyTimeValue;
- char *timeBuffer;
- int cw;
- TIME_STRUCTURE = calloc(1, sizeof(TM));
- MY_TIME_VALUE = calloc(1, sizeof(TV));
- TIME_BUFFER = calloc(TIME_BUFFER_SIZE, sizeof(char));
- /* Get the time value. */
- _time64(MY_TIME_VALUE);
- /* Populate the time structure. */
- _localtime64_s(TIME_STRUCTURE, MY_TIME_VALUE);
- /* Convert the time and date to a character string. */
- asctime_s(TIME_BUFFER, TIME_BUFFER_SIZE, TIME_STRUCTURE);
- /* Print to the FILE_BUFFER string that will be written to the file. */
- CHARS_WRITTEN = sprintf_s(FILE_BUFFER, FILE_BUFFER_SIZE, ">> Log File Access: <<\n");
- CHARS_WRITTEN += sprintf_s(FILE_BUFFER + CHARS_WRITTEN, FILE_BUFFER_SIZE - CHARS_WRITTEN, " %s", TIME_BUFFER); /* Pointer arithmetic. */
- CHARS_WRITTEN += sprintf_s(FILE_BUFFER + CHARS_WRITTEN, FILE_BUFFER_SIZE - CHARS_WRITTEN, ">> ------------------------ <<\n\n");
- free(TIME_BUFFER);
- free(MY_TIME_VALUE);
- free(TIME_STRUCTURE);
- }
- /*----------------------------------------------------------------------------*/
- /* TEST WRITE (to the file). */
- if(fprintf_s(FILE_POINTER, FILE_BUFFER) < 0)
- {
- fileError(MY_FILE, FILE_WRITE_ERROR, errno);
- }
- else
- {
- /*
- * At the same time, print the contents of the FILE_BUFFER string to
- * the screen.
- */
- printf_s("%s", FILE_BUFFER);
- }
- /* This is not needed anymore. */
- free(FILE_BUFFER);
- /*
- * Can fclose fail?
- *
- * And why is there no fclose_s?
- */
- fclose(FILE_POINTER);
- #ifdef MY_FILE
- #undef MY_FILE
- #endif
- }
- static void fileError(const char *fileName, const int fileErrNo1, errno_t fileErrNo2)
- {
- char *errorBuffer1;
- char *errorBuffer2;
- ERROR_BUFFER_1 = calloc(1, SPRINTFS_BUFFER);
- ERROR_BUFFER_2 = calloc(1, ERROR_BUFFER_SIZE);
- if(FILE_ERROR_NO_1 == FILE_ATTRIB_ERROR_SYS)
- {
- printf_s(">> %s is a system file. <<", FILE_NAME);
- printf_s("\n Please verify the file location/attributes.");
- }
- else
- {
- switch(FILE_ERROR_NO_1)
- {
- case FILE_FIND_ERROR:
- sprintf_s(ERROR_BUFFER_1, SPRINTFS_BUFFER, ">> Cannot find %s. <<", FILE_NAME);
- break;
- case FILE_SET_ATTRIB_ERROR:
- sprintf_s(ERROR_BUFFER_1, SPRINTFS_BUFFER, ">> Cannot prepare %s for writing. <<", FILE_NAME);
- break;
- case FILE_OPEN_ERROR:
- sprintf_s(ERROR_BUFFER_1, SPRINTFS_BUFFER, ">> Cannot open %s. <<", FILE_NAME);
- break;
- case FILE_WRITE_ERROR:
- sprintf_s(ERROR_BUFFER_1, SPRINTFS_BUFFER, ">> Cannot write to %s. <<", FILE_NAME);
- break;
- }
- /*
- * Keeping a duplicated value of errno is always a smart idea especially
- * in cases where the function it is passed to will perform some
- * intermediate operations, before it is used, that could reset the
- * original value. Such is the case with the fileError function.
- */
- if(strerror_s(ERROR_BUFFER_2, ERROR_BUFFER_SIZE, FILE_ERROR_NO_2))
- {
- printf_s("%s", ERROR_BUFFER_1);
- printf_s("\n Error message #: %d", FILE_ERROR_NO_1);
- printf_s("\n\n>> Error generating error message. <<");
- printf_s("\n Error message #: %d", errno);
- }
- else
- {
- printf_s("%s", ERROR_BUFFER_1);
- printf_s("\n %s.", ERROR_BUFFER_2);
- }
- }
- free(ERROR_BUFFER_1);
- free(ERROR_BUFFER_2);
- exit(EXIT_FAILURE);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement