Low-Level I/O and Incremental Read/Write
#include <stdio.h> /****** open1.c ******/
#include <sys/stat.h>
#include <fcntl.h>
main()
{
int fd;
fd = open("junk", O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
write(fd, "hello\n", 6);
close(fd);
}
/******************************************************************************/
$ open1
$ ls -l junk
-rw------- 1 jwp2286 staff 6 Jan 31 17:02 junk /* What's wrong? */
/******************************************************************************/
#include <sys/types.h> /***** open2.c *****/
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
main()
{
int fd;
umask(0);
fd = open("junk", O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
write(fd, "hello\n", 6);
close(fd);
}
/******************************************************************************/
$ open2
$ ls -l junk
-rw-r--r-- 1 jwp2286 staff 6 Jan 31 17:02 junk /* O.K. now!! */
/*****************************************************************************/
File permissions: S_IRUSR Read for file owner.
S_IWUSR Write for file owner.
S_IXUSR Execute for file owner.
S_IRGRP Read for group.
S_IWGRP Write for group.
S_IXGRP Execute for group.
S_IROTH Read for others.
S_IWOTH Write for others.
S_IXOTH Execute for others.
Open modes: O_RDONLY Like fopen's "r" mode.
O_WRONLY Like fopen's "w" mode.
O_RDWR If file exists, it's like fopen's "r+" mode.
If file doesn't exist, it's like fopen's "w+" mode.
O_CREAT Create the file if it does not exist. Requires that
open have a third argument -- file permissions.
O_APPEND Append to the end of the file on every write.
O_TRUNC Truncate file to zero length upon opening.
Example open: open("foo.bar", O_CREAT | O_WRONLY | O_APPEND, S_IRUSR);
Opens file like fopen's "a" mode.
#include <sys/types.h> /************** chmod demo #1 *****************/
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
main()
{
chmod("junk", S_IRWXU);
}
/*****************************************************************************/
$ ls -l junk
-rwxr-xr-x 1 jwp2286 staff 6 Jan 31 17:02 junk
$ chmod1
$ ls -l junk
-rwx------ 1 jwp2286 staff 6 Jan 31 17:02 junk
#include <sys/types.h> /********** chmod demo #2 ************/
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
main()
{
struct stat status;
stat("junk", &status);
chmod("junk", (status.st_mode & ~S_IRGRP) | S_IXOTH);
}
/*****************************************************************************/
$ chmod2
$ ls -l junk
-rwx-----x 1 jwp2286 staff 6 Jan 31 17:02 junk
/*****************************************************************************/
#include <fcntl.h> /**** stat and fstat demo ****/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <time.h>
main()
{
int status, fd;
struct stat fs;
if ((fd = open("foo", O_RDONLY )) < 0)
{
printf("Open error on foo!\n");
exit(1);
}
if ( (status = fstat(fd, &fs)) < 0) /** Stat is for closed files **/
{
printf("Status error! Status = %d\n", status);
exit(1);
}
/****
**** Status info. printed below.
****/
printf("Inode = %ld\nLinks = %ld\n", fs.st_ino, fs.st_nlink);
printf("Owner uid = %ld\nOwner gid = %ld\n", fs.st_uid, fs.st_gid);
printf("File size = %ld\n", fs.st_size);
printf("Last modification = %ld mins. ago\n", (time(NULL) - fs.st_mtime)/60);
if (S_ISREG(fs.st_mode)) /**** S_ISDIR is also used frequently. ****/
{
if ( fs.st_mode & S_IRUSR) printf("User can read!\n");
if ( fs.st_mode & S_IWUSR) printf("User can write!\n");
if ( fs.st_mode & S_IXUSR) printf("User can execute!\n");
/******
****** See Lewine page 539 for all st_mode values.
******/
}
}
/*************************** Program Output Below **************************/
Inode = 43097
Links = 1
Owner uid = 2286
Owner gid = 24
File size = 22
Last modification = 21 mins. ago /***** 'Cause I just made it! *****/
User can read!
User can write!
/************************ ls -il of the foo file ****************************/
43097 -rw------- 1 jwp2286 staff 22 Oct 5 23:23 foo
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
main()
{
char buf[256];
int count = 0, fd;
while ( read(STDIN_FILENO, buf, 80))
{
count++;
printf("Cycle %d\n", count);
write(STDOUT_FILENO, buf,80);
}
fd = open("foo", O_RDONLY);
count = 0;
while ( read(fd, buf, 80))
{
count++;
printf("Cycle %d\n", count);
write(STDOUT_FILENO, buf, 80);
}
}
/************************** SAMPLE EXECUTION *******************************/
abcd
Cycle 1 /* Input from terminal is still line buffered. */
abcd
efgh
Cycle 2
efgh
Cycle 1 /* Input from file is not!! */
abcdefg
hijklmn
/******************** CONTENTS OF FILE FOO ******************************/
abcdefg
hijklmn
#include <unistd.h> /******** Blocking Versus Nonblocking Read ********/
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <fcntl.h>
sigjmp_buf env;
int flags;
main()
{
char buf[256] = "ARG!", outbuf[256];
void handler(void);
struct sigaction sa;
sigfillset(&sa.sa_mask);
sa.sa_handler = handler;
sa.sa_flags = 0;
sigaction(SIGALRM, &sa, NULL);
alarm(10);
printf("Enter stuff followed by CR: ");
if (sigsetjmp(env, 1) == 0) printf("First time through!\n");
else printf("Second time through!\n");
read(STDIN_FILENO, buf, 80);
sprintf(outbuf, "User typed: %s\n", buf);
write(STDOUT_FILENO, outbuf, 90);
}
void handler(void)
{
printf("I got here because time expired!!\n");
alarm(0);
flags = fcntl(STDIN_FILENO, F_GETFL, 0); /***** Get flags for stdin ****/
flags |= O_NONBLOCK; /***** Set O_NONBLOCK bit in flags *****/
fcntl(STDIN_FILENO, F_SETFL, flags); /*** Activate nonblocking read ***/
sleep(3);
siglongjmp(env, 5);
}
/********************* SEVERAL EXAMPLE EXECUTIONS ************************/
$ a.out
Enter stuff followed by CR: First time through!
I got here because time expired!!
Second time through!
User typed: ARG! /* No he didn't!! Read fell through because I made it
non-blocking AND because I typed nothing during sleep!*/
$ a.out
Enter stuff followed by CR: First time through!
hello
User typed: hello /* Alarm never invoked! Stuff entered in < 10 secs. */
$ a.out
Enter stuff followed by CR: First time through!
I got here because time expired!!
hello
Second time through!
User typed: hello /* Hello got typed in during sleep!! */
$ a.out
Enter stuff followed by CR: First time through!
h
User typed: h
G! /* A quiz! What happened here? What're the implications? */
/******************************************************************************/
#include <unistd.h> /********** Errno's associated with read. *********/
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
int flags;
main()
{
char buf[256] = "ARG!", outbuf[256];
int count = 0, retval;
void handler(void);
signal(SIGINT, handler);
flags = fcntl(STDIN_FILENO, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(STDIN_FILENO, F_SETFL, flags);
retval = read(STDIN_FILENO, buf, 80);
if (errno == EWOULDBLOCK) printf("Nothing in terminal buffer!\n");
printf("Read return value: %d\n", retval);
sprintf(outbuf, "User typed: %s\n", buf);
write(STDOUT_FILENO, outbuf, 90);
flags = fcntl(STDIN_FILENO, F_GETFL, 0);
flags &= ~O_NONBLOCK;
fcntl(STDIN_FILENO, F_SETFL, flags);
memset(buf, 0, 80); /****** Always do this in read loops!! ******/
errno = 0;
retval = read(STDIN_FILENO, buf, 80);
printf("User typed: %s\n : Read return value: %d\n", buf, retval);
}
void handler(void)
{
if (errno == EINTR) printf("Read terminated by signal!\n");
printf("In signal handler!\n");
exit(1);
}
/************************* Sample Program Executions ***********************/
$ read3
Nothing in terminal buffer!
Read return value: -1
User typed: ARG!
hello
User typed: hello
: Read return value: 6
$ read3
Nothing in terminal buffer!
Read return value: -1
User typed: ARG!
User typed: /* I hit a CTRL-D (Unix EOF) here! */
: Read return value: 0
$ read3
Nothing in terminal buffer!
Read return value: -1
User typed: ARG!
/* I hit CTRL-C here to interrupt second read! */
In signal handler! /* Notice that errno is NOT set to EINTR! */
/* This is an operating system bug! */
/****************** Incremental Read/Write Code ***********************/
/****************** Works on fixed-length packets.***********************/
#include <stdio.h>
int readn(int fd, char *buf, int bytes)
{
int nleft;
int nread;
char *mover = buf;
nleft = bytes;
while (nleft > 0){
if ((nread = read(fd,mover,nleft)) < 0)
return -1; /**** Error!! ****/
else if (nread == 0)
break; /**** EOF! ****/
nleft -= nread;
mover += nread;
}
return (bytes - nleft);
}
int writen(int fd, char *buf, int bytes)
{
int nleft;
int nwritten;
char *mover = buf;
nleft = bytes;
while (nleft > 0){
if ((nwritten = read(fd,mover,nleft)) < 0)
return -1; /**** Error!! ****/
nleft -= nwritten;
mover += nwritten;
}
return bytes;
}