Thread: Problem reading from file stream

  1. #1
    Registered User
    Join Date
    Feb 2011
    Posts
    3

    Problem reading from file stream

    I'm working on a simple implementation of a CVS/RCS version control program. The checkin/checkout work except on the third checkin the program contsistently produces an unreadable binary file but works fine otherwise. I'm assuming that its because the program is writing beyond an array's somewhere, but I don't understand why it would only behave this way after 2 checkin/checkout's.
    When I run it in eclipse debug, I can see that it after it finishes read from the file into the array, eclipse's value for the array will look something like:
    "file content <incomplete sequence \371>"
    then when the array contents to another file and look at the file stream's _IO_written_base property in the debugger if will read something like this:
    "file content\371\n"

    EDIT: I'm using Ubuntu 10.10

    I realize its kind of daunting to look through my code but I appreciate any help you can provide see as my project is due tonight. The problem is in the checkin function
    Also, before you say I need to check return values of library functions, I have wrapper classes that handle that.

    also if your feeling ambitious this link contains my entire project so far and instructions on usage of the program:
    to check a file in:
    <executable name> checkin <filename>
    to check a file out:
    <executable name> checkout <filename>
    PROJECT

    Code:
    #define __EXTENSIONS__
    #include <stdio.h>
    #include <time.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    
    #include "safe_utilities.h"
    
    #define ARB_BUFF_SZ 100
    #define VC_SUB_DIR "./vc/"
    #define PATH_LNGTH 5
    #define FIRST_LINE 8
    #define CURVER "({VC_CURRENT_VERSION)}"
    #define END_CURVER "({VC_END_CURRENT_VERSION)}"
    #define DIFFS "({VC_VERSION_DIFFERENCES)}"
    #define END_DIFFS "({VC_END_VERSION_DIFFERENCES)}"
    #define DIFF_VER "({VC_VERSION)}"
    #define END_DIFF_VER "({VC_END_VERSION)}"
    #define LOG "({VC_ACTIVITY_LOG)}"
    #define END_LOG "({VC_END_ACTIVITY_LOG)}"
    #define SED "sed -n -e :a -e '/({VC_CURRENT_VERSION)}/bb' -e 'n;ba' -e :b -e 'n' -e :c -e '/({VC_END_CURRENT_VERSION)}/ba' -e 'p;n;bc'"
    #define RED_FILE "vc/vc_temporary_file"
    
    typedef enum {sucessful = 0, failed = 1} sucess_t;
    
    char *diff_command(char *f1, char *f2)
    {
        int size = (5 + strlen(f1) + 1 + strlen(f2) + 1)*sizeof(char);
        char *diff = malloc( size );
        snprintf(diff, size, "diff %s %s", f1, f2);
        return diff;
    }
    char *sed_command(char *redirect)
    {
        char *s = SED;
        int size = (strlen(s) + 3 + strlen(redirect) + 1) * sizeof(char);
        char *sedcom = malloc( size );
        snprintf(sedcom, size, "%s > %s", s, redirect);
        return sedcom;
    }
    
    char *rel_path(char *path)
    {
        int size = (PATH_LNGTH + strlen(path) + 1) * sizeof(char);
        char *filename = malloc(size);
        snprintf(filename, size, "%s%s", VC_SUB_DIR, path);
        return filename;
    }
    
    int checkout(char* path)
    {
        time_t t;                                          /* non-readable time from function call*/
        char* sed;                                         /* the sed command to isolate the current version from 'path' */
        char *date;                                        /* current date string */
    	char *file_content;                                /* string of 'file' content */
        char *filename = rel_path(path);                   /* includes "./vc/" infront of 'path' */
    	char *locked   = malloc(FIRST_LINE*sizeof(char));  /* contains "locked" or "unlocked" */
    	FILE *file = fopen(filename, "r");                 /* file to be checked out */
        FILE *command;                                     /* sed command used to isolate newest version */
        struct stat fstatus;                               /* status information of 'file' */
        sucess_t sucess;                                   /* indicates a successful run */
        int sizeread;                                      /* size of data already read from file */
    
        fgets(locked, FIRST_LINE, file);            /* get first line (indicates lock) */
        sizeread = strlen(locked);
        if( strcmp(locked, "locked\n") == 0)        /* file is locked (previously checked out */
        {
            locked = realloc(locked, ARB_BUFF_SZ);          /* reallocate memory to an arbitrary but safe length to obtain checkout info from next line */
            fgets(locked, ARB_BUFF_SZ, file);
            fprintf(stderr, "'%s' has been locked by %s", path, locked);
    
            sucess = sucessful;
        }
        else if( strcmp(locked, "unlock\n") == 0)   /* file is available for checkout */
        {
            stat_safe(filename, &fstatus);                                     /* get file statistics (specifically file size) */
            file_content = malloc(sizeof(char)*(fstatus.st_size-sizeread));    /* holds 'file' contents */
            sed          = sed_command(path);                                  /* string form of sed command to isolate current version within 'file' */
            command      = popen(sed, "w");                                    /* command stream */
    
            fread(file_content, sizeof(char), (fstatus.st_size-sizeread)*sizeof(char), file);  /* read file into 'file_content' */
            fputs(file_content, command);                                                      /* execute command with 'file' contents */
            fclose(file);                                                                      /* close file to be re-opened for writing */
    
            /* re-write file with "locked" and user's checkout information */
            file = fopen(filename, "w");
            time(&t);
            date = ctime(&t);
            fprintf(file, "locked\n%s", date);                                               /* write check out information */
            fwrite(file_content, sizeof(char), strlen(file_content)*sizeof(char), file);     /* write back whole file */
    
            pclose(command);
            free(sed);
            free(file_content);
            sucess = sucessful;
        }
        else{
            fputs("Could not determine lock on target file.\n", stderr);
            sucess = failed;
        }
        fclose(file);
        free(filename);
        free(locked);
        return (int)sucess;
    }
    
    int checkin(char *path)
    {
        char *lock_version = malloc(ARB_BUFF_SZ*sizeof(char));    /* throw away lines */
        int erased_size;                                          /* size of erased data */
        char *vcfilename = rel_path(path);                        /* relative path to 'path' in vc directory */
        char *curversion;                                         /* checked in version */
        char *vcfile_content;                                     /* content in the vc file */
        char *username = malloc(ARB_BUFF_SZ*sizeof(char));        /* name of user checking in */
        char *usernotes = malloc((ARB_BUFF_SZ+1)*sizeof(char)*3); /* user's notes on checkin */
        char *sed = sed_command(RED_FILE);                        /* string form of sed command to isolate current version within 'file' */
        char *diff = diff_command(RED_FILE, path);                /* string form of the diff command of user version and vc's version */
        char *diff_content;                                       /* output from diff utility */
        char *start;                                              /* start of section being left from vc file re-write */
        char *end;                                                /* end of section being left from vc file re-write */
        int  writesize;                                           /* end of section being left from vc file re-write */
        FILE *vcfile = fopen(vcfilename, "a+");                   /* version in vc directory */
        FILE *ufile = fopen(path, "r");                           /* version in user's directory */
        FILE *sed_comm = popen(sed, "w");                         /* piped shell command */
        FILE *diff_comm;                                          /* piped diff command */
        struct stat vcfstat;                                      /* targeted file's status info */
        struct stat ufstat;                                       /* user's file status info */
        int version = 0;                                          /* current version of file */
        int buff;
    
        stat_safe(path, &ufstat);               /* user file stats */
        stat_safe(vcfilename, &vcfstat);        /* vc file stats */
        /* file is NOT the first version being checked in */
        if(vcfstat.st_size != 0)
        {
            rewind(vcfile);                                           /* reposition file stream position to beginning */
            fgets(lock_version, ARB_BUFF_SZ, vcfile);                 /* get lock information */
            erased_size = strlen(lock_version);                       /* track file position */
            /*file has not been checked out yet */
            if(strcmp(lock_version, "unlock\n") == 0){
                printf("'%s' has not been checked out.\n", path);
                return sucessful;
            }
            /* OK to check in because file has been checked in */
            else if(strcmp(lock_version, "locked\n") == 0){
                fgets(lock_version, ARB_BUFF_SZ, vcfile);           /* this line will contain the date of the checkout */
                erased_size += strlen(lock_version);                /* track file position */
            }
            /* file must have been tampered with and formatting changed */
            else
                {printf("could not determine lock on '%s'.\n", path);}
    
            int ret = fscanf(vcfile, "%d", &version);                   /* get file version */
            erased_size += ret;                                         /* track file position */
            curversion = malloc(ufstat.st_size * sizeof(char));
            vcfile_content = malloc( (vcfstat.st_size-erased_size) * sizeof(char));
    
            fread(vcfile_content, sizeof(char), (vcfstat.st_size-erased_size)*sizeof(char), vcfile);    /* get vc's version of the file */
    
    /*******************PRETTY SURE THIS IS THE PROBLEM**********/
            fread(curversion, sizeof(char), ufstat.st_size*sizeof(char), ufile);                        /* get the user's version of the file */
    /********************************************************/
    
            fputs(vcfile_content, sed_comm);                        /* run sed command to isolate old version into temp file from vc's file */
            sleep(1);                                               /* pause or else sed command will not finish before diff call */
            diff_comm = popen(diff, "r");                           /* run diff on user file and temp file from sed command */
            diff_content = malloc((ARB_BUFF_SZ+1)*sizeof(char));
            buff = ARB_BUFF_SZ+1;
            char c;
            int index = 0;
            /* get output from diff */
            while( (c = fgetc(diff_comm)) != EOF)
            {
                if(index == buff-1)
                {
                    diff_content = (char*)realloc(diff_content, 2*buff+1);
                    buff = buff*2 + 1;
                }
                diff_content[index] = c;
                index++;
            }
            diff_content[index] = '\0';
            pclose(diff_comm);
        }
        /* file was the first version */
        else{
            curversion = malloc(ufstat.st_size * sizeof(char));
            fread(curversion, sizeof(char), ufstat.st_size*sizeof(char), ufile);
        }
        fclose(vcfile);
        vcfile = fopen(vcfilename, "w");
        fprintf(vcfile, "unlock\n%d\n", version+1);                         /* lock and version information */
        fprintf(vcfile, "%s\n%s\n%s\n", CURVER, curversion, END_CURVER);    /* updated version information */
    
         if( version > 1 )  /* diff information is only present in versions 2 and above */
         {
             start = strstr(vcfile_content, DIFFS);
             end = strstr(vcfile_content, END_DIFFS);
             writesize = end - start;
             fwrite(start, sizeof(char), writesize, vcfile);
             fprintf(vcfile, "%s %d\n%s\n%s\n%s\n", DIFF_VER, version, diff_content, END_DIFF_VER, END_DIFFS);  /* print diffs to file */
             free(diff_content);
         }
        /* diff formatting is slightly different if this is the first diff */
        if(version == 1){
            fprintf(vcfile, "%s\n%s %d\n%s\n%s\n%s\n", DIFFS, DIFF_VER, version, diff_content, END_DIFF_VER, END_DIFFS);
            free(diff_content);
        }
        if(version != 0)    /* if first version there is no previous log */
        {
            start = strstr(vcfile_content, LOG);
            end = strstr(vcfile_content, END_LOG);
            writesize = end - start;
            fwrite(start, sizeof(char), writesize, vcfile);
            free(vcfile_content);
        }
        /* get username and description of checkin from developer */
        printf("Enter username: ");
        fgets(username, ARB_BUFF_SZ, stdin);
        printf("Enter comments (300 characters or less):\n");
        fgets(usernotes, ARB_BUFF_SZ*3, stdin);
        username[ strlen(username)-1 ] = '\0';
        if(version == 0)
            {fprintf(vcfile, "%s\n", LOG);}
        fprintf(vcfile, "%s: %s\n%s", username, usernotes, END_LOG);
        remove(path);
        remove(RED_FILE);
        free(vcfilename);
        free(lock_version);
        free(username);
        free(usernotes);
        free(sed);
        free(diff);
        fclose(vcfile);
        fclose(ufile);
        pclose(sed_comm);
        free(curversion);
        return 0;
    }
    Last edited by shmitson; 04-05-2011 at 05:11 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. a problem with reading from a FILE
    By Makaila in forum C Programming
    Replies: 2
    Last Post: 01-13-2010, 04:15 AM
  2. Problem reading a password from a file.
    By medeshago in forum C Programming
    Replies: 15
    Last Post: 12-21-2008, 07:20 AM
  3. C++ std routines
    By siavoshkc in forum C++ Programming
    Replies: 33
    Last Post: 07-28-2006, 12:13 AM
  4. Problem reading from a file..
    By Candelier in forum C Programming
    Replies: 4
    Last Post: 04-23-2006, 12:42 AM
  5. Possible circular definition with singleton objects
    By techrolla in forum C++ Programming
    Replies: 3
    Last Post: 12-26-2004, 10:46 AM