0
  • I have this function for initializing admin account,

  • the adminAcc.txt should be initialized only once, regardless of how many times the program has been executed. .

  • The code does not work tho, it still initializes the file everytime i run the program,

anyone can help? ty...

static int file_initialized = 0; //global variable

void initAdmin(){
  struct form adminAcc;

  FILE *fptr;
  
  if((fptr = fopen("adminAcc.txt", "a")) == NULL){
    printf("\nError Opening Admin File!");
    getch();
    system("cls");  
    main();
  }

  if(file_initialized != 1){
    strcpy(adminAcc.username, "admin@gmail.com");
    strcpy(adminAcc.password, "admin");
    strcpy(adminAcc.roles, "admin");

    fwrite(&adminAcc, sizeof(struct form), 1, fptr);
    file_initialized = 1;
  }else{
    return;
  }

  fclose(fptr);
}

int main(){
  initAdmin();

  return 0;
}
  • 1
    Duplicate of https://stackoverflow.com/questions/1951791/how-to-check-if-a-file-is-already-open-by-another-process-in-c, maybe? – L_R Dec 25 '22 at 06:05
  • 4
    `file_initialized` is a local variable. It will be initialized to 0 every time this function is called. There is no way for it to ever be anything but 0 when this check `if(file_initialized != 1)` is made. – Retired Ninja Dec 25 '22 at 06:06
  • @L_R Perhaps this is not a duplicate, at least of that question; different instances of the program might or might not run in parallel. I think they just might want to know how to persist the "file has been initialized" state. – Yang Hanlin Dec 25 '22 at 06:12
  • 1
    Please explain exactly what you mean with "initialize". If the file `adminAcc.txt` does not already exist, do you want that file to be created with a specific content? And if the file already exists, do you want to do nothing? – Andreas Wenzel Dec 25 '22 at 06:12
  • well the program should have a pre-initialized admin account that could be updated if changes are made.... the only way to do this is to write on file. the only thing is, the file has to be initialized only once – wanmoranIwhaledye Dec 25 '22 at 06:15
  • 3
    The recursive call to `main()` is dubious at best. – Jonathan Leffler Dec 25 '22 at 06:16
  • 1
    @wanmoranIwhaledye Clarify question instead of answering with a comment. You want to tell us if that "once" is per program execution or of any number of executions of your program. – Allan Wind Dec 25 '22 at 06:22
  • @wanmoranIwhaledye, I think you are trying to check if file is 'initialised', whatever 'initialised' means to you, in a previous run of your program. If that is what you want, then you can create a config file after initialisation. You could check its presence to understand if the file has been initialised or not. – L_R Dec 25 '22 at 17:07

3 Answers3

1

If you want to retain the value of file_initialized across calls (as your code implies) you need to make it static:

  static int file_initialized = 0;

If you only want to initialize it once across multiple program executions, then you need to persist the initialization state. Below I inspect the position of newly opened file and initialize it if empty:

#include <errno.h>
#include <stdio.h>

#define FILENAME "adminAcc.txt"
#define LEN 64

struct form {
    char username[LEN];
    char password[LEN];
    char roles[LEN];
};

int initAdmin(){
    FILE *fptr = fopen(FILENAME, "a");
    if(!fptr) {
        printf("Error Opening Admin File!\n");
        return 1;
    }
    if(!ftell(fptr)) {
        printf("initialize\n");
        fwrite(
            &(struct form) { "admin@gmail.com", "admin", "admin" },
            sizeof(struct form),
            1,
            fptr
        );
    }
    fclose(fptr);
    return 0;
}

int main() {
    initAdmin();
}

and example runs:

$ ./a.out
initialize
$ ./a.out
$
Allan Wind
  • 23,068
  • 5
  • 28
  • 38
0

sorry for not updating...

this is how i solved the problem:

  • I included the library below, to use access() function.
#include <unistd.h> 
  • The access() function checks to see if the file or directory specified by path exists and if it can be accessed with the file access permissions given by amode.

  • the function will only create and initialize a file named(filename) if the file does not exists, otherwise skip the initialization

void initAdmin(){
  struct form adminAcc;

  if(access("adminAcc.txt", F_OK) == -1){
    FILE *fptr = fopen("adminAcc.txt", "w");

    strcpy(adminAcc.username, "admin@gmail.com");
    strcpy(adminAcc.password, "admin");
    strcpy(adminAcc.roles, "admin");

    fwrite(&adminAcc, sizeof(struct form), 1, fptr);
    fclose(fptr);
  }
}
  • 1
    There is a race condition between `access()` and `fopen()`. This is why it's safe to check the file of a file handle you already have open outlined in both my and @JohnBoillinger's answer. – Allan Wind Dec 26 '22 at 18:09
0

The code does not work tho, it still initializes the file everytime i run the program

You cannot retain program state in the program across multiple runs. Every run of the program starts with a clean slate. Depending on the system on which it runs, however, you can generally retain state in the system. In this case, the natural state is whether the adminAcc.txt file exists, and possibly whether it has valid contents.

Although it is possible to check that before trying to open the file, a better paradigm is usually simply to attempt an operation (such as opening the file) and seeing whether that works. Because you need to do that anyway, and it's always possible for the system to be modified at just the right time such that the wanted operation fails even though an appropriate pre-check predicts that it will succeed.

So, something along these lines would make sense, then:

#include <stdio.h>
#include <string.h>

void initAdminIfNecessary(){
  struct form adminAcc;

  FILE *fptr;
  
  if((fptr = fopen("adminAcc.txt", "ab")) == NULL){
    fprintf(stderr, "\nError Opening Admin File!\n");
    abort();
  }

  long fileSize = ftell(fptr);

  if (fileSize == -1) {
    fprintf(stderr, "\nError determining Admin File length!\n");
    abort();
  else if (fileSize == 0) {
    strcpy(adminAcc.username, "admin@gmail.com");
    strcpy(adminAcc.password, "admin");
    strcpy(adminAcc.roles, "admin");

    fwrite(&adminAcc, sizeof(struct form), 1, fptr);
    // TODO: check return value
  } else if (fileSize < sizeof(struct form)) {
    fprintf(stderr, "\nAdmin File has invalid content\n");
    abort();
  }

  fclose(fptr);
}

int main(){
  initAdminIfNecessary();

  return 0;
}

That opens the file as a binary (b) file in append (a) mode, which creates it if it does not already exist, but does not modify it if it does exist. The file is initially positioned at its end (and each write will go to the then-end of the file).

It uses ftell() to determine the length of the file, and acts accordingly.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157