CSCI.4210 Operating Systems
Week 1 Programming Assignment
Unix System Calls and Win32 APIs
Due Wednesday, Sept 8, at 11:59PM

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 sixth argument dwFlagsAndAttributes should be set to 0 (zero).

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