0

I'm making an archive program in C - I've got it traversing and writing the file contents to a single file, but I can't seem to get the fileHeader structure I've created (using fwrite()) to write into the file (only using two attributes for testing at the moment, I know more will be required). Here's my code:

struct fileHeader {
        char name[50];
        char path[50];  
};

void addToArch(char *inPath, char *archPath, struct fileHeader header) {
        FILE *in, *arch;
        int ch;
        arch = fopen(archPath, "ab");

        struct stat sb;
        stat(inPath, &sb);

        if(S_ISREG(sb.st_mode) == 0) {
                fprintf(arch, "\n%s\n", inPath);
                printf("Directory detected - skipped");
        }

        else {
                in = fopen(inPath, "rb");
                ch = fgetc(in);
                fwrite(&header, 1, sizeof(struct fileHeader), in);
                while (ch != EOF) {
                        fputc(ch, arch);
                        ch = fgetc(in);
                }
                fclose(in);
                fclose(arch);
                printf("File copied successfully!\n");
        }
}

My calling code is here:

//Create new file header
struct fileHeader header;
//Populate struct fields
snprintf(header.name, 50, "%s", entry->d_name);
snprintf(header.path, 50, "%s", buffer);

addToArch(buffer, "out.txt", header);

I've printed entry->d_name and buffer and they are definitely the strings I want going into the struct. There are no compiler errors, but no header is showing in my archive file, along with the contents.

5
  • You're mixing in and arch. Name your variables more clearly. You can do both, but for clarity and sanity, don't. Commented Dec 19, 2018 at 15:50
  • Two code review comments: (1) You can pass a pointer to const struct instead of passing the struct by value. Should be faster. (2) Writing binary data is brittle; changing from debug to relase build may already change the struct layout, let alone changing the compiler. Especially if you really want to persist data long-term ("archive program") you should take care to be language, platform and compiler independent. The canonical method would be to choose a text format of your choice like XML or JASON and write 7 bit ascii text representations. Commented Dec 19, 2018 at 15:55
  • It's writing fine now, but with ^@^@^@ between attributes - is this fine? I've memsetted the structure before filling Commented Dec 19, 2018 at 16:31
  • Thanks @PeterA.Schneider, noted Commented Dec 19, 2018 at 16:32
  • ^@ is the null character. The struct has gaps between the members which are undefined (in your case: are 0 because you zeroed the memory before). This padding is one of the reasons (besides integer sizes and float formats) why the same struct definition can differ binarily. Commented Dec 19, 2018 at 19:05

2 Answers 2

4

Your fwrite is trying to write to in, not arch. Since you don't check the return value of fwrite, this error (trying to write to a file that's opened for read) is undetected.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for this, apologies for such a basic mistake, I thought it was something semantically I was doing wrong. I'll implement the error checks throughout
It's writing fine now, but with ^@^@^@ between attributes - is this fine? I've memsetted the structure before filling
^@ is actually the NUL byte
-2

It seems the fwrite() call switched the number of items and size of items fields. I think it should be fwrite(&header, sizeof(struct fileHeader), 1, arch);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.