• Please review our updated Terms and Rules here

Low Level Call for Copying a File on DOS System

kkaos

New Member
Joined
Aug 18, 2024
Messages
8
Is there a low level call that I can use in a C program to copy a file on a DOS system?

I have tried using either fgets() with fputs() or read() with write() in my C program to copy text files on a DOS system. With multiple text editors, if I use any of them to create the source text file, all bytes in the file will get copied as expected; however, if I use certain text editors (e.g. Brief) to create that source text file, either of those copy solutions will somehow miss what appears to be an EOF byte when performing the copy. Using the DIR command, I can see that the copy has one less byte than the source; however, if I either view the copy with an editor or use TYPE to output the contents of the file to the console, I see nothing missing.

I know that the DOS COPY command copies all bytes without fail. I have tried to use one of the C exec() functions in my program before to call the COPY utility; however, it would silently fail to copy the file. I'd love to know what the DOS COPY command is doing that any solution I have implemented is not doing, and I figure it must be something at a lower level.
 
I suspect that your C library is opening the files in text mode. Are you selecting binary mode on open
Code:
fopen(file, "rb")
?
 
There is no such lower level call. DOS's internal copy command works by doing read() and write() (in binary mode, as John said). If you'd prefer to call into DOS to do the copy, you'll need to use system() instead of exec() as it's a internal command.
 
Very few operating systems have a "copy file" primitive, you have to open/open read/write/loop close/close yourself.

But yeah, if you're using C, and you're using fopen, you probably want to be sure to use binary mode.
 
It would be interesting to 'hexdump' the two types of text files that the various editors produce.

From what I remember - and this is going back too long to remember clearly now - MSDOS does NOT use a specific character as the end of file. It uses the file size stored in the metadata (directory) to understand where the end of file actually is.

CP/M used a ^Z (at the end of a text file) to act as an EOF character.

Many MSDOS programs still, however, used a ^Z to signify end of file.

If the above is all true (...) then you may have found a text editor that does not use a ^Z as the EOF marker for a text file.

Opening the source file as a binary file will just cause all characters to be treated as file bytes by the 'C' program.

Before making any further 'guesses' it would be sensible to see some evidence of:

1. A hexdump of two (simple) text files - created with two of your editors - that exhibit your problem

2. A very simple character-by-character text copy program written in 'C' that you are using.

3. A hexdump of the resultant files after they have been copied using your simple program.

4. An MSDOS "DIR" of the files (source and copied).

End of lines and end of files are always fun :)!

Dave
 
I suspect that your C library is opening the files in text mode. Are you selecting binary mode on open
Code:
fopen(file, "rb")
?

Indeed, I am opening the files in text mode. IIRC, I tried that when I was using open() for read() and write() but not sure if I did that with fopen() for fgets() and fputs(). I'll have to give that a shot.

There is no such lower level call. DOS's internal copy command works by doing read() and write() (in binary mode, as John said). If you'd prefer to call into DOS to do the copy, you'll need to use system() instead of exec() as it's a internal command.

Thank you for confirming that. I had looked at a list of interrupts online yesterday and never saw one for copying a file. That said, I was definitely not aware of system(). I'll be looking into that.

It would be interesting to 'hexdump' the two types of text files that the various editors produce.

From what I remember - and this is going back too long to remember clearly now - MSDOS does NOT use a specific character as the end of file. It uses the file size stored in the metadata (directory) to understand where the end of file actually is.

CP/M used a ^Z (at the end of a text file) to act as an EOF character.

Many MSDOS programs still, however, used a ^Z to signify end of file.

If the above is all true (...) then you may have found a text editor that does not use a ^Z as the EOF marker for a text file.

Opening the source file as a binary file will just cause all characters to be treated as file bytes by the 'C' program.

Before making any further 'guesses' it would be sensible to see some evidence of:

1. A hexdump of two (simple) text files - created with two of your editors - that exhibit your problem

2. A very simple character-by-character text copy program written in 'C' that you are using.

3. A hexdump of the resultant files after they have been copied using your simple program.

4. An MSDOS "DIR" of the files (source and copied).

End of lines and end of files are always fun :)!

Dave

Oh, it has been soooo much fun trying to figure this one out. I was definitely not aware about ^Z. For some reason, I was thinking that 0xFF was used. I will have to hexdump a file from a "good" editor and one from a "bad" editor (e.g. Brief) to see if that is the problem. I bet it is.
 
What you need to do in C is open the file with fopen and use "rb" - for writing use "wb". Both are binary mode where no line translation will occur.

Then you need to use fread/fwrite functions to read and write blocks of binary data until the file is complete.

DOS API"s calls are like open, close, write, read, etc. The C functions are a layer on top of that. Neither has a copy file command.

Give me a few minutes and I'll write a function to do this for you.
 
Figured it out. Using fopen() with the "b" mode flag was what was needed. I thought I had tried this before, at least with open() when used with read() and write(), but apparently not. Guess I just thought, "Well, it's a text file so it doesn't make sense to open in binary mode." Clearly, some of these old editor programs like to add an extra byte or two at the end that does not show up in text mode.

Thanks, folks!
 
Correction, my fwrite was not using size for the amount:

Code:
#include <stdio.h>
#include <malloc.h>

#define BUFFER_SIZE 16384

//returns 1 for success or 0 for failure
int CopyFile(const char *ATargetName, const char *ASourceName)
{
  FILE *target, *source;
  unsigned char *buffer;
  int ret, size, size2;

  //clear
  target=NULL;
  source=NULL;
  buffer=NULL;

  //allocate
  buffer=(unsigned char*)malloc(BUFFER_SIZE);
  if (buffer==NULL)
    {
      //failure
      fail1:
      ret=0;
      goto end1;
    }

  //open files
  target=fopen(ATargetName, "wb");
  source=fopen(ASourceName, "rb");
  if (target==NULL || source==NULL)
    goto fail1;

  //copy data
  do
    {
      size=fread(buffer, 1, BUFFER_SIZE, source);
      if (ferror(source))
        goto fail1;
      if (size)
        {
          size2=fwrite(buffer, 1, size, target);
          if (ferror(target) || size2!=size)
            goto fail1;
        }
    } while (size);

  //success
  ret=1;

  end1:
  //deallocate and close files
  if (buffer!=NULL)
    free(buffer);
  if (target!=NULL)
    fclose(target);
  if (source!=NULL)
    fclose(source);
  return ret;
}


int main()
{
  printf("result %d\n", CopyFile("2.dat", "1.dat"));
  return 0;
}
 
FWIW if you're using POSIX-like file manipulation (I assume you are based on open, read, write, etc.) then the earliest C source of the UNIX cp(I) command is here: https://www.tuhs.org/cgi-bin/utree.pl?file=V5/usr/source/s1/cp.c

Granted this assumes again the syscalls you are using claim to behave identically to their UNIX counterparts.

As others have suggested too, if you want it done in the most "DOS-y" way possible, system(III) or equivalent should allow you to call out to the OS command interpreter synchronously.
 
If you want to emulate COPY exactly, don't forget to set the timestamp and attributes (RASH) when done.
 
Back
Top