Chaoes

                   When chaos begin...

    1. test dup and lseek:

    Question: If you dup an open file with another file-descriptor, does it lseek operation affects the read-write of

    file descriptor which it dups from?

    Answer: Of course, since they are actually pointing to the same file tables.

    (Hint: You have to compile it with g++ instead of gcc in "sunset". Sucks!)

    //#include	<sys/types.h>
    #include 	<stdio.h>
    #include        <stdlib.h>
    #include	<string.h>
    #include 	<unistd.h>
    #include	<fcntl.h>
    #include 	<errno.h>
    #define  MaxBuf    20

    int main(int argc, char *argv[])
    {

    	int fd1, fd2, n;
    	char buf[MaxBuf+1];
    	if (argc!=2)
    	{
    		printf("usage: file1.o file2\n");
    		exit(errno);
    	}
    	if ((fd1=open(argv[1], O_RDONLY))==-1)
    	{
    		//perror(atoi(buf, fd1, 10));
    		printf("open error\n");
    	}

    	fd2=dup(fd1);
    	printf("%d read first %d\n", fd1,  MaxBuf);
    	if ((n=read(fd1, buf, MaxBuf))==-1)
    	{
    		printf("file descriptor %d read error", fd1);
    	}
    	buf[n]='\0';
    	printf("%d read this %s\n", fd1, buf);
    	if ((n=read(fd1, buf, MaxBuf))==-1)
    	{
    		printf("file descriptor %d read error", fd1);
    	}
    	buf[n]='\0';

    	printf("%d should read this line next %s\n", fd1, buf);
    	printf("%d now seek back %d\n", fd1, n);
    	if (lseek(fd1, -n, SEEK_CUR)==-1)
    	{
    		printf("%d seek back error\n", fd1);
    	}
    	printf(" %d seek to beginning again\n", fd2);

    	if (lseek(fd2, 0, SEEK_SET)==-1)
    	{
    		printf("seek error of %d\n", fd2);
    	}
    	printf("%d begin to read again\n", fd1);

    	if ((n=read(fd1, buf, MaxBuf))==-1)
    	{
    		printf("%d read error\n", fd1);
    	}
    	buf[n]='\0';
    	printf("%d read this line %s\n", fd1, buf);
    }

    Result:

    3 read first 20
    3 read this //#include <sys/type
    3 should read this line next s.h>
    #include <stdi
    3 now seek back 20
    4 seek to beginning again
    3 begin to read again
    3 read this line //#include <sys/type

    2. test dup and lseek:

    Question: How do we implement "ls"? Actually this is just a re-do of my comp229 assignment. However, I just implement part of it.

    #include <sys/types.h>
    #include <dirent.h>
    #include <sys/stat.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>

    const int MaxPathLength=128;
    void dirView(char* dirName, char* pathName);
    void errHandle(char* msg);
    void myls();

    int main(int argc, char* argv[])
    {
    	char fullPath[MaxPathLength];
    	if (argc!=2)
    	{
    		printf("usage: dirview dirName\n");
    		exit(1);
    	}
    	if (getcwd(fullPath, MaxPathLength)==NULL)
    	{
    		errHandle("getcwd error\n");
    	}
    	dirView(argv[1], fullPath);

    	return 0;
    }

    void myls()
    {
    	char fullPath[MaxPathLength];
    	if (getcwd(fullPath, MaxPathLength)==NULL)
    	{
    		errHandle("getcwd error\n");
    	}
    	dirView(".", fullPath);
    }

    void dirView(char* dirName, char* pathName)
    {
    	char fullPath[MaxPathLength];
    	char fileName[MaxPathLength];
    	DIR* dp;
    	char* ptr;
    	dirent* dirNode;
    	struct stat statBuf;
    	strcpy(fullPath, pathName);
    	ptr=fullPath+strlen(fullPath);
    	*ptr='/';
    	ptr++;
    	*ptr='\0';
    	strcat(fullPath, dirName);
    	if ((dp=opendir(fullPath))==NULL)
    	{
    		printf("fullpath=%s\n", fullPath);
    		errHandle("error open directory\n");
    	}
    	printf("print directory of %s\n", fullPath);
    	while ((dirNode=readdir(dp))!=NULL)
    	{
    		if (strcmp(dirNode->d_name, ".")==0
    		|| strcmp(dirNode->d_name, "..")==0)
    		{
    			continue;
    		}
    		strcpy(fileName, fullPath);
    		ptr=fileName+strlen(fileName);
    		*ptr='/';
    		ptr++;
    		*ptr='\0';
    		strcat(fileName, dirNode->d_name);
    		if (lstat(fileName, &statBuf)<0)
    		{
    			printf("fileName=%s\n", fileName);
    			errHandle("lstat error\n");
    		}
    		if (S_ISDIR(statBuf.st_mode))
    		{
    			//now fullPath is including the name
    			dirView(dirNode->d_name, fullPath);
    		}
    		else
    		{
    			printf("regular file: %s\n", dirNode->d_name);
    		}
    	}
    }

    void errHandle(char* msg)
    {
    	perror(msg);
    	exit(errno);
    }

    Result:

    print directory of /nfs/home/q/qingz_hu/comp444/files/mytest/mydir
    regular file: arena.cpp
    regular file: arena.o
    regular file: arena.txt
    regular file: dirview.c
    regular file: dirview.o
    regular file: io.c
    regular file: io.c~
    regular file: io.out
    regular file: myhead.h
    regular file: myhead.h~
    regular file: mylib.c
    regular file: mylib.c~
    regular file: mylib.h
    regular file: ourhdr.h
    regular file: result.txt
    regular file: test.txt
    regular file: test.txt~
    print directory of /nfs/home/q/qingz_hu/comp444/files/mytest/mydir/mynewdir
    regular file: dirview.c
    regular file: io.c
    regular file: mylib.c

    ¡¡

    3. copy files:

    Question: Does a copy file system call exist in UNIX? Amazingly the answer is NO! And it is fairly straight-forward to do it.

    The only difference between my implementation and standard "cp" is that I will generate an error if target file already exists.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <errno.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>

    const int MaxBufLength=1024;
    const int MaxPathLength=128;
    //const int MaxMsgLength=32;
    void copyfile(char* fullPath, char* newPath);

    void errHandle(char* msg);

    //char msg[MaxMsgLength];

    int main(int argc, char* argv[])
    {
    	if (argc!=3)
    	{
    		errHandle("usage: copyfile source target");
    	}

    	copyfile(argv[1], argv[2]);
    	return 0;
    }

    void errHandle(char* msg)
    {
    	perror(msg);
    	exit(errno);
    }

    void copyfile(char* fullPath, char* newPath)
    {
    	int fdOld, fdNew, n;
    	char buf[MaxBufLength];
    	struct stat statBuf;
    	if ((fdOld=open(fullPath, O_RDONLY))<0)
    	{
    		//perror("file not exists");
    		//exit(errno);
    		errHandle("file not exists");
    	}
    	if (lstat(fullPath, &statBuf)<0)
    	{
    		errHandle("stat error");
    	}

    	if ((fdNew=open(newPath, O_WRONLY|O_CREAT |O_EXCL, statBuf.st_mode))==-1)
    	{
    		errHandle("creat error or file already exists");
    	}

    	while ((n=read(fdOld, buf, MaxBufLength))!=0)
    	{
    		if (n<0)
    		{
    			errHandle("read old file error");
    		}
    		if (write(fdNew, buf, n)!=n)
    		{
    			errHandle("write new file error");
    		}
    	}
    	if (close(fdOld)<0)
    	{
    		errHandle("cannot close old file");
    	}
    	if (close(fdNew)<0)
    	{
    		errHandle("cannot close new file");
    	}
    }

    Result: Originally I worried a lot about the path of both source and target file because I am not sure if I need

    require user to give full path name of both source and target because it would be inconvenient to ask user to copy

    some file in current working directory and give the long path name. After testing I was relieved since "lstat" is

    NOT a basic system call and it can do a simple parsing job to see if the file name is relative or absolute. This

    is something I discovered unexpectedly.

    To run, just type ./copyfile.o source target

    ¡¡

    4. binary formats:

    Question: I suspect that the UNIX programmers are either lazy or arrogant because they even didn't bother to implement a simple

    format of "printf()" which print the binary format of an integer. I use it quite often on windows version of "printf()" and

    logically assume it is also implemented in UNIX. It is not. So, I just practice by writing a simple one. The only reason I mention

    this simple code is that the problem of signed and unsigned integer. It takes me nearly one hour to figure out the problem is

    the "atoi" only return signed integer. Therefore in argument to "main" from command line, I cannot pass the biggest unsigned

    integer  4294967295. Before find this, I nearly begin suspect my memory about 2's complement. And indeed my memory  is as bad as

    that. You see, I even call this "Euclid algorithm". What a joke? It is not GCD problem! Sigh... My memory!

    ¡¡

    #include <stdlib.h>
    #include <stdio.h>

    void binary(unsigned int number, char* buf);

    int main(int argc, char* argv[])
    {
    	unsigned int num=4294967295;
    	char* buf=(char*)malloc(sizeof(int)*8+1);
    	if (argc==1)
    	{
    		printf("because atoi function will not work with unsigned int, I cannot input biggest int by argument\n");
    		binary(num, buf);
    		printf("So, I have to display the largest number:%d like this %s\n", num, buf);
    		exit(0);
    	}
    	if (argc==2)
    	{
    		num=atoi(argv[1]);
    		printf("%u\n", num);
    		//one byte equals 8 bits and extral byte for NULL
    		binary(num, buf);
    		printf("%s\n");
    	}

    	return 0;
    }

    void binary(unsigned int number, char* buf)
    {
    	unsigned int size=sizeof(int)*8;
    	unsigned int quotion=number, modulo=0;
    	buf[size]='\0';
    	//euclid algorithm goes from end to beginning
    	do
    	{
    		size--;
    		modulo=quotion%2;
    		quotion/=2;
    		buf[size]='0'+modulo;
    	}
    	while (size>0);
    }

    ¡¡

    ¡¡

    ¡¡

    This is the contents of running script file "test":

    ./printftest.o 12
    ./printftest.o 1024
    ./printftest.o 4294967295
    ./printftest.o

    And I run it to redirect result to a result file:

    [qingz_hu@alamanni ~/mywork] % chmod +x test
    [qingz_hu@alamanni ~/mywork] % ./test >myresult.txt

    Then you will see the running result as following:

    (Please note that the biggest unsigned int 4294967295 is interpreted by "atoi" as a signed int as 2147483647 which is roughly half

    of original one. I cannot find a unsigned version of "atoi". I cannot even find help by "man atoi". ????)

    12
    00000000000000000000000000001100
    1024
    00000000000000000000010000000000
    2147483647
    01111111111111111111111111111111
    because atoi function will not work with unsigned int, I cannot input biggest int by argument
    So, I have to display the largest number:-1 like this 11111111111111111111111111111111

    	The strange behaviour of "readlink"

    In class professor showed us the strange behaviour of "readlink". But I cannot re-do it myself:

    I feel very curious of the strange behaviour of "readlink" during demo. So, I tried to redo it myself as following:

    Create a symbolic link and then read the contents of it. However, it seems that "readlink" behaves normally by returning the number of bytes it read. Since the source code is not posted, I wonder if I missed something:

    #include "myhead.h"
    //I don't like Steven's head file, so I define my own little one with included headers, constants

    void myreadlink(char* pathName);

    int main(int argc, char* argv[])
    {
            //this little test first create a symbolic link and then read it
            if (argc!=3)
            {
                    errHandle("usage: myreadlink.o targetPath, symlinkname\n");
            }
            if (symlink(argv[1], argv[2])<0)
            {
                    errHandle("symlink error\n");
            }
            printf("now read symbolic link %s\n", argv[2]);
            myreadlink(argv[2]);
            return 0;
    }

    void myreadlink(char* pathName)
    {
            char buf[BuffSize];
            int n;
            if ((n=readlink(pathName, buf, BuffSize))<0)
            {
                    errHandle("readlink error\n");
            }
            buf[n]='\0';
            printf("%s is a softlink with contents of length of %d:%s\n", pathName,n, buf);
    }

    The running result is like this:

    [qingz_hu@alamanni ~/mywork] % gcc myreadlink.c -o myreadlink.o

    [qingz_hu@alamanni ~/mywork] % ./myreadlink.o ./nicktest mynewlink

    now read symbolic link mynewlink

    mynewlink is a softlink with contents of length of 10:./nicktest

    [qingz_hu@alamanni ~/mywork] %

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <dirent.h>
    #include <unistd.h>

    const int BuffSize=128;

    void errHandle(char* msg);

    void errHandle(char* msg)
    {
            if (msg!=NULL)
            {
                    perror(msg);
            }
            else
            {
                    strerror(errno);
            }
            exit(errno);
    }

    ¡¡

    ¡¡