Implement three routines: insert, delete, and extract w/o issues when operating in the middle of a file.
1. System calls
open(), lseek(), read(), write().
ftruncate() to modify file size.
See detail in UNIX manual document.
2. Writing header file
A standard set of instructions to make programming easier. A header file is generally used to define all of the functions, variables and constants contained in any function library that you might want to use.
#ifndef _UFSEXT_H_
#define _UFSEXT_H_
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int insert(int fd, void *buf, size_t bytes, size_t offset);
int extract(int fd, void *buf, size_t bytes, size_t offset);
int delete(int fd, size_t bytes, size_t offset);
#endif
3. Makefile
all: shared
libufsext.so: //Create dynamic library
gcc -fPIC -c insert.c
gcc -fPIC -c delete.c
gcc -fPIC -c extract.c
gcc -shared -o libufsext.so insert.o delete.o extract.o
shared:libufsext.so //link test programs to the dynamic library
gcc -o inserttst inserttst.c -L. -lufsext
gcc -o deletetst deletetst.c -L. -lufsext
gcc -o extracttst extracttst.c -L. -lufsext
gcc -o mixtest mixtest.c -L. -lufsext
libufsext.a: //Create static library
gcc -c insert.c
gcc -c delete.c
gcc -c extract.c
ar -cq libufsext.a insert.o delete.o extract.o
static:libufsext.a //link test programs to the static library
gcc -o inserttst inserttst.c libufsext.a
gcc -o deletetst deletetst.c libufsext.a
gcc -o extracttst extracttst.c libufsext.a
gcc -o mixtest mixtest.c libufsext.a
test: //set current environment
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./inserttst
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./deletetst
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./extracttst
clean:
rm -f *.o inserttst deletetst extracttst mixtest libufsext.a libufsext.so
Static libraries: Separate object files combined into single library file. Object code incorporated into executable at link time. Use
ar (see manual page)
ar -cq libufsext.a insert.o delete.o extract.o
to create library and add functions.
Dynamic library: Stub included in binary program image for each library-routine reference. Stub is code to locate memory-resident routine or load it if library routine not present. Stub replaces itself with address of routine and executes routine
gcc -shared -o libufsext.so insert.o delete.o extract.o\
4.Secure programming
Check every function invoked and return -1 if error occurs. Free allocated memory in every possible case. (More attention on pointer usage.)
#include "ufsext.h"
int extract(int fd, void *buf, size_t bytes, size_t offset){
char *tmp;
int length=lseek(fd, 0L,SEEK_END);
if(offset>length){
printf("Out of the file.\n");
free(buf);
return -1;
}
if(length<=0){
printf("Cannot extract from empty file,\n");
free(buf);
return -1;
}
if(bytes < 0 || offset < 0){
printf("Invaild inputs\n");
free(buf);
return -1;
}
if(lseek(fd, offset, SEEK_SET)==-1){
perror("lseek");
free(buf);
return -1;
}
if(read(fd,buf,bytes)==-1){
perror("read");
free(buf);
return -1;
}
if(lseek(fd, (offset + bytes), SEEK_SET) == -1){
free(buf);
perror("lseek");
return -1;
}
if(!(tmp=malloc((length-offset-bytes+1)*sizeof(char)))){
perror("malloc");
free(buf);
return -1;
}
memset(tmp, 0, (length-offset-bytes+1));
if(read(fd, tmp, length-offset-bytes)==-1){
perror("read");
free(buf);
free(tmp);
return -1;
}
if(lseek(fd, offset, SEEK_SET)==-1){
perror("lseek");
free(buf);
free(tmp);
return -1;
}
if(write(fd, tmp, length-offset-bytes)==-1){
perror("write");
free(buf);
free(tmp);
return -1;
}
free(tmp);
if(ftruncate(fd, length-bytes)==-1){
perror("ftruncate");
return -1;
}
return bytes;
}
#include "ufsext.h"
int main(int argc, char *argv[]){
char filename[] = "testExtract.txt";
int fd = 0;
int ret = 0;
void *buf;
fd = open(filename, O_EXCL|O_RDWR);
if(fd == -1){
perror("open");
exit(EXIT_FAILURE);
}
int length=lseek(fd, 0L,SEEK_END);
buf = malloc(length * sizeof(char));
if(!buf){
perror("malloc");
exit(EXIT_FAILURE);
}
memset(buf, 0, length);
ret = extract(fd, buf, 2, 4);
if (ret == -1){
printf("extract Error\n");
free(buf);
exit(EXIT_FAILURE);
}
else{
printf("Prints %s\n",buf);
printf("extract Successful, extract %d bytes of data\n\n", ret);
}
ret = extract(fd, buf, 2, 4);
if (ret == -1){
printf("extract Error\n");
free(buf);
exit(EXIT_FAILURE);
}
else{
printf("Prints %s\n",buf);
printf("extract Successful, extract %d bytes of data\n\n", ret);
}
ret = extract(fd, buf, 2, 0);
if (ret == -1){
printf("extract Error\n");
free(buf);
exit(EXIT_FAILURE);
}
else{
printf("Prints %s\n",buf);
printf("extract Successful, extract %d bytes of data\n\n", ret);
}
free(buf);
close(fd);
return 0;
}