2

I have the following C function:

int vacateDir(const INODE *pParDirInode)
{
  FILE *fp = fopen("fs560", "rb+");
  if (fp == NULL) {
    fprintf(stderr, "Parent directory could not be opened.\n");
    return 0;
  }

  int i;
  char line[MAX_ENTRY_LENGTH];

  // Move the file pointer to the start of the directory's first data block.
  fseek(fp, DATA_SECTION_HEAD+BLOCK_SIZE*pParDirInode->directBlocks[0] , SEEK_SET);

  // Advance the file pointer to the first real entry of the directory.
  for (i = 0; i < 4; i++) {
    line[0] = '\0';
    fgets(line, MAX_ENTRY_LENGTH, fp);
  }

  printf("The file pointer is now at %lx.\n", ftell(fp));
  printf("fputc returned %d.\n", fputc(0, fp));
  printf("The file pointer is now at %lx.\n", ftell(fp));

  // Alternative approach, which doesn't work either.
  //char x[1];
  //x[0] = 0;
  //fwrite(x, 1, 1, fp);

  fclose(fp);
  return 1;
}

What I am expecting this function to do is write a 0 to a single byte and advance the file pointer by one. I have verified with the first printf statement and with hexdump that the file pointer is at the correct position just before the fputc call.

What happens is that the intended byte is not changed to 0, and the file pointer jumps ahead 4081-bytes. The indicated return value of fputc is 0, which is what I expect. (EOF is 0xFF on my system, so I don't think it's returning an error.) Here is the output:

The file pointer is now at 2f247.
fputc returned 0.
The file pointer is now at 30238.

By changing the character written to 65 (A), I have verified that there is a character being written to 0x30237. I have also tried using putc, and opening the file in r+ mode, neither to any effect.

I would really like to know what is happening here, and how to work around it. I have reviewed available documentation on fputc in places like here, but I don't see any reason for this issue.

Mark
  • 55
  • 1
  • 5
  • Your code is not a [MCVE](http://stackoverflow.com/help/mcve). – Iharob Al Asimi Feb 25 '15 at 01:22
  • 1
    See this: http://stackoverflow.com/questions/1713819/why-fseek-or-fflush-is-always-required-between-reading-and-writing-in-the-read-w – user58697 Feb 25 '15 at 01:22
  • 1
    Or this: http://stackoverflow.com/questions/28228509/function-for-bmp-color-inverting-doesnt-work/28228841#28228841 – user3386109 Feb 25 '15 at 01:23
  • Questions beginning " is broken" are usually entertaining, but in this case, you're kind of right, but it's the `ftell()s` that are kind-of broken, not the `fputc()`...the I/O here is buffered, and switching between reading and writing causes ftell to report strange numbers. Put some flushes in there to de-confuse it. – Lee Daniel Crocker Feb 25 '15 at 01:28
  • the returned value from fseek needs to be checked to assure the operation was successful – user3629249 Feb 25 '15 at 17:05

1 Answers1

1

Okay, good work, team! (Seriously, thanks.)

Here is what I got to work:

int vacateDir(const INODE *pParDirInode)
{
  FILE *fp = fopen("fs560", "rb+");
  if (fp == NULL) {
    fprintf(stderr, "Parent directory could not be opened.\n");
    return 0;
  }

  int i, pos;
  char line[MAX_ENTRY_LENGTH];

  // Move the file pointer to the start of the directory's first data block.
  fseek(fp, DATA_SECTION_HEAD+BLOCK_SIZE*pParDirInode->directBlocks[0] , SEEK_SET);

  // Advance the file pointer to the first real entry of the directory.
  for (i = 0; i < 4; i++) {
    line[0] = '\0';
    fgets(line, MAX_ENTRY_LENGTH, fp);
  }

  pos = ftell(fp);

  fseek(fp, pos, SEEK_SET);
  fputc(0, fp);
  printf("The file pointer is now at %lx.\n", ftell(fp));

  fclose(fp);
  return 1;
}

I am sure some application of fflush would have worked as well.

So the lesson I take from this issue is that if you read from a file (like I am with fgets and ftell) and then write to a file (as with fputc), you must call fseek and reset the position of the file pointer.

Mark
  • 55
  • 1
  • 5