Write two short programs which implement a file copy routine. One of your programs should use Unix System calls and one should use Win32 APIs. Both will take two arguments. The first argument will be the name of the file to be copied (the source), the second should be the name of the new file to be created (the destination) which will have the same contents as the source. In both cases, if the source file does not exist, your program should display a suitable error message and exit. If the destination file already exists, your program should ask the user if he/she wants to overwrite the contents, and if the user answers No, your program should terminate without doing anything.
Unix
Your Unix program must use the following three system calls
int open(const char *path, int oflag, /* mode_t mode */) ssize_t read(int fildes, void *buf, size_t nbyte); ssize_t write(int fildes, const void *buf, size_t nbyte);The open system call takes either two or three arguments. The first is the pathname of the file that you want to open. The second is the mode. There are a number of symbolic names, defined in the header file
fcntl.h
which can be
or'ed together for the mode. Here are the ones that you might
need for this assignment.
O_RDONLY
open the file for reading
O_WRONLY
open the file for writing
O_CREAT
Create the file if it does not exist.
If the file exists, this flag has no effect except as
noted under O_EXCL
below.
O_EXCL
If this flag and the O_CREAT flag are
set, the open will fail if the file already exists. if
the O_CREAT
flag is not set, this flag has
no effect.
O_TRUNC
If the file is open for writing and this flag
is set, the size of the file is set to zero, and the old
contents are lost.
If you do not understand the concept of bitwise or, read this.
The third argument to the open call is optional. It sets
the permission flags if the file is being created. It should not
be used in the case where the file already exists. Permission flags
will be discussed in more detail later; for this assignment, use
0200 | 0400
This will give you read and write permissions.
The open call returns a file descriptor. This is a positive integer. We will discuss these in more detail later. You will need to pass this value to the read and write system calls. If the system call fails, it will return a negative value, and errno will be set to an error code.
The read system call reads data from a file which has been opened for reading by a call to open. It takes three arguments. The first is the file descriptor (the value returned by a successful call to open), the second is a pointer to a buffer of memory, and the third argument nbytes is the maximum number of bytes to read. This value is typically the size of the buffer.
The read call will read a number of bytes from the file, copying them to the buffer pointed to by the second argument. It will never read more than nbytes but it may return less than that. The number of bytes actually read will be returned by the call.
Successive calls to read will return successive bytes in the file. For example, if nbytes is set to 100, but the file has 365 bytes, the first call to read will read the first 100 bytes (although it may read less), the second call will read the second 100 bytes, the third call will read the third 100 byte, and the fourth call will read the remaining 65 bytes.
On success, read will return the number of bytes actually read. It will return 0 on an end of file condition, and it will return a negative value if an error occurs.
Alert: The size of the memory pointed to by the second argument should always be at least nbytes. Otherwise, you will overwrite other memory or get a memory exception error.
The write system call writes data from memory to a file. It takes the same three arguments as read. The first is a file descriptor, which should be the value returned by a call to open in which the file is open for writing. The second is a pointer to the buffer which contains the data to be written, and the third is the number of bytes to be written. The call returns the number of bytes actually written. In contrast with read, the number of bytes written should always be nbytes unless an error occurs. If an error occurs, write will return a negative value.
Successive calls to write with the same file descriptor will write successive data to memory.
Here are links to the Unix man pages for these three system calls.
open
read
write
Win32 APIs
The Win32 API which corresponds to open is
HANDLE CreateFile( LPCTSTR lpFileName, // pointer to name of the file DWORD dwDesiredAccess, // access (read-write) mode DWORD dwShareMode, // share mode LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes DWORD dwCreationDisposition, // how to create DWORD dwFlagsAndAttributes, // file attributes HANDLE hTemplateFile // handle to file with attributes to // copy );
Don't be put off by this ugly function prototype. Most of the arguments can be set to reasonable defaults.
The first argument lpFileName is a pointer to the pathname of the file. This can be either a relative or an absolute pathname.
The second argument dwDesiredAccess should be either GENERIC_READ or GENERIC_WRITE depending on whether the file will be opened for input or output.
The third argument dwShareMode determines whether other processes can have the file opened at the same time. If you set this to 0 (zero), no other process can access the file until you close it, but that is OK for this assignment.
The fourth argument lpSecurityAttributes should be set to NULL.
The fifth argument dwCreationDisposition should be one of the following three keywords
The last argument hTemplateFile should be set to NULL.
This function will return a HANDLE to the open file if successful. If it fails, the return value will be INVALID_HANDLE_VALUE.
Here is a link to the CreateFile documentation.
The Win32 API that corresponds to read is
BOOL ReadFile( HANDLE hFile, // handle of file to read LPVOID lpBuffer, // pointer to buffer that receives data DWORD nNumberOfBytesToRead, // number of bytes to read LPDWORD lpNumberOfBytesRead, // pointer to number of bytes read LPOVERLAPPED lpOverlapped // pointer to structure for data );The first argument hFile is the handle which is returned from CreateFile
The second and third arguments are exactly the same as the second and third arguments of read
The fourth argument lpNumberOfBytesRead is a pointer to an int. This will contain the number of bytes actually read, the value will be copied here upon return.
The last argument should be NULL.
This function returns a non-zero value on success, and FALSE (zero) on failure.
The Win32 API equivalent of the Unix write is
BOOL WriteFile( HANDLE hFile, // handle to file to write to LPCVOID lpBuffer, // pointer to data to write to file DWORD nNumberOfBytesToWrite, // number of bytes to write LPDWORD lpNumberOfBytesWritten, // pointer to number of bytes written LPOVERLAPPED lpOverlapped // pointer to structure for overlapped I/O );This works in the same way as ReadFile except that it writes instead of reading.
Here are links to the online help for these two functions
ReadFile
WriteFile