diff -ruN linux/Documentation/Configure.help linux-mona/Documentation/Configure.help --- linux/Documentation/Configure.help Mon Jan 29 16:16:00 2001 +++ linux-mona/Documentation/Configure.help Fri Jun 22 20:41:06 2001 @@ -10875,6 +10875,13 @@ compiled as a module, and so this could be dangerous. Most everyone wants to say Y here. +Modify-on-Access (MonA) fs support +CONFIG_MONA_FS + The mona file system is an extension of the de facto linux partition, + ext2. It is completely compatible with ext2 (a partition can be + mounted as either mona or ext2 without modification) but supports + extended file operations. + BFS file system support (EXPERIMENTAL) CONFIG_BFS_FS Boot File System (BFS) is a file system used under SCO UnixWare to diff -ruN linux/fs/Config.in linux-mona/fs/Config.in --- linux/fs/Config.in Mon Jan 15 15:42:32 2001 +++ linux-mona/fs/Config.in Fri Jun 22 20:41:15 2001 @@ -62,6 +62,8 @@ tristate 'Second extended fs support' CONFIG_EXT2_FS +tristate 'Modify-on-Access (Mona) fs support' CONFIG_MONA_FS + tristate 'System V and Coherent file system support (read only)' CONFIG_SYSV_FS dep_mbool ' SYSV file system write support (DANGEROUS)' CONFIG_SYSV_FS_WRITE $CONFIG_SYSV_FS $CONFIG_EXPERIMENTAL diff -ruN linux/fs/Makefile linux-mona/fs/Makefile --- linux/fs/Makefile Mon Jan 15 15:42:32 2001 +++ linux-mona/fs/Makefile Fri Jun 22 20:41:22 2001 @@ -27,6 +27,7 @@ # Do not add any filesystems before this line subdir-$(CONFIG_EXT2_FS) += ext2 +subdir-$(CONFIG_MONA_FS) += mona subdir-$(CONFIG_CRAMFS) += cramfs subdir-$(CONFIG_RAMFS) += ramfs subdir-$(CONFIG_CODA_FS) += coda diff -ruN linux/fs/mona/Export/Makefile linux-mona/fs/mona/Export/Makefile --- linux/fs/mona/Export/Makefile Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/Export/Makefile Wed Jun 27 00:47:31 2001 @@ -0,0 +1,36 @@ +# +# Makefile for mona/export -- +# the mona daemon and userlevel (export) transformations +# + + +CC = gcc + +MACROS = +INCPATH = -I../../../include +LIBPATH = +DBFLAGS = -Wall +OPTFLAGS = -Wstrict-prototypes -O2 -fomit-frame-pointer \ + -fno-strength-reduce -pipe +LIBS = + +CFLAGS = $(MACROS) $(INCPATH) $(DBFLAGS) $(OPTFLAGS) + +XFORMSRCS = xforms.c command.c ftp_utils.c ftpfs_xforms.c \ + tar_xforms.c tcp_xforms.c + +# this is what we call 'letting make perform it's magic' +XFORMOBJS = $(XFORMSRCS:.c=.o) + +all: monad lib + +monad : monad.o + $(CC) -rdynamic -o monad -ldl -Wall monad.o + +clean : + \rm -f *.o monad monalib.so + + +lib : $(XFORMOBJS) + ld -shared -o monalib.so $(XFORMOBJS) -lc + diff -ruN linux/fs/mona/Export/chdir.c linux-mona/fs/mona/Export/chdir.c --- linux/fs/mona/Export/chdir.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/Export/chdir.c Tue Jun 26 09:17:20 2001 @@ -0,0 +1,11 @@ +#include +#include + +int main(int argc, char **argv) +{ + char buffer[256]; + chdir(argv[1]); + getcwd(buffer, 256); + fprintf(stderr, "cwd = %s\n", buffer); + return(0); +} diff -ruN linux/fs/mona/Export/command.c linux-mona/fs/mona/Export/command.c --- linux/fs/mona/Export/command.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/Export/command.c Wed Jun 27 00:32:28 2001 @@ -0,0 +1,131 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef mona_debug +#define mona_debug printf + +#define DEBUG + +#if defined DEBUG +#define dbprint(x, y) fprintf(stderr, x, y) +#define dbwrite(x, y, z) fwrite(x, y, z, stderr) +#else +#define dbprint(x, y) /* x y */ +#define dbwrite(x, y, z) /* x y z */ +#endif + + +struct pipeinfo { + int pd0[2]; + int pd1[2]; +}; + +int command(XformInfoPtr xf_ptr, int num_bytes, + char *buffer) +{ + int status, total_bytes_sent = num_bytes, pdflags; + pid_t pid; + struct pipeinfo *buf; + + /* PWR: is this necessary? */ + if(num_bytes < 0) { + return(total_bytes_sent); + } + + buf = xf_ptr->private_data; + if(buf == NULL) { + buf = (struct pipeinfo *)malloc(sizeof(struct pipeinfo)); + xf_ptr->private_data = buf; + if(xf_ptr->private_data == NULL) { + fprintf(stderr, "Oops, buf is NULL\n"); + } + if(pipe(buf->pd0) < 0) { + perror("pipe"); + } + if(pipe(buf->pd1) < 0) { + perror("pipe"); + } + if((pid = fork()) < 0) { + perror("fork"); + exit(1); + } + + else if(pid == 0) { + if(dup2(buf->pd0[1], STDOUT_FILENO) < 0) { + perror("dup2"); + } + if(dup2(buf->pd1[0], STDIN_FILENO) < 0) { + perror("dup2"); + } + close(buf->pd0[0]); + close(buf->pd0[1]); + close(buf->pd1[0]); + close(buf->pd1[1]); + if(execlp(xf_ptr->argv[0], xf_ptr->argv[0], NULL) < 0) { + perror("execlp"); + } + fprintf(stderr, "Oops, execlp must've failed somwhow.\n"); + exit(1); + } + else { + close(buf->pd0[1]); + close(buf->pd1[0]); + } + } else if (xf_ptr->state == XF_READY) + return 0; + + if((pdflags = fcntl(buf->pd0[0], F_GETFL, 0)) < 0) { + perror("fcntl"); + } + pdflags |= O_NONBLOCK; + if(fcntl(buf->pd0[0], F_SETFL, pdflags) < 0) { + perror("fcntl"); + } + + if (num_bytes > 0) + write(buf->pd1[1], buffer, num_bytes); + + close(buf->pd1[1]); + + total_bytes_sent = read(buf->pd0[0], buffer, 4096); + + if((pdflags = fcntl(buf->pd0[0], F_GETFL, 0)) < 0) { + perror("fcntl"); + } + pdflags &= ~O_NONBLOCK; + if(fcntl(buf->pd0[0], F_SETFL, pdflags) < 0) { + perror("fcntl"); + } + + + if (total_bytes_sent < 1) { + if(errno == EAGAIN) { + xf_ptr->state = XF_HAS_DATA; + } else { + xf_ptr->state = XF_READY; + close(buf->pd0[0]); + close(buf->pd1[1]); + wait(&status); + } + } else { + xf_ptr->state = XF_HAS_DATA; + } + + return total_bytes_sent; +} diff -ruN linux/fs/mona/Export/ftp_utils.c linux-mona/fs/mona/Export/ftp_utils.c --- linux/fs/mona/Export/ftp_utils.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/Export/ftp_utils.c Tue Jun 26 09:17:20 2001 @@ -0,0 +1,412 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef mona_debug +#define mona_debug printf + +#define BLOCK 4096 +#define XF_READY 0 +#define XF_UNSENT_DATA 1 +#define DEBUG + +#if defined DEBUG +#define dbprint(x, y) fprintf(stderr, x, y) +#define dbwrite(x, y, z) fwrite(x, y, z, stderr) +#else +#define dbprint(x, y) /* x y */ +#define dbwrite(x, y, z) /* x y z */ +#endif + +int ftpget(char *linkname, char *ftpaddr, char *filename, char *path, + char *subpath) +{ + int rd, wr, fd, sd1, sd2, sd3, size, pid; + int a, b, c, d; + int val1, val2, val3; + int total_bytes_sent = 1; + time_t *t, snum; + struct sockaddr_in comaddr, dataddr1, dataddr2; + char inbuf[4096]; + char cmd1[80], cmd2[80], myname[80]; + struct hostent *hp; + char fullname[256]; + + size = sizeof(struct sockaddr_in); + snum = time(t); + srand((unsigned) snum); + val1 = (int)(5000 * (rand() / (RAND_MAX / + 1.0))); + val1 += 5000; + val2 = val1 / 256; + val3 = val1 % 256; + bzero((char *)&comaddr, size); + comaddr.sin_family = AF_INET; + hp = gethostbyname(ftpaddr); + memcpy((char *)&comaddr.sin_addr, hp->h_addr_list[0], hp->h_length); + comaddr.sin_port = htons(21); + bzero((char *)&dataddr1, size); + dataddr1.sin_family = AF_INET; + dataddr1.sin_addr.s_addr = htonl(INADDR_ANY); + dataddr1.sin_port = htons(val1); + if((pid = fork()) < 0) { + perror("fork"); + return total_bytes_sent; + } + else if(pid == 0) { + sprintf(fullname, "%s%s%s", path, subpath, linkname); + remove(fullname); + if((fd = creat(fullname, S_IRUSR | S_IWUSR)) < 0) { + perror("creat 1"); + exit(1); + } + if((sd2 = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket"); + exit(1); + } + if(bind(sd2, (struct sockaddr *) &dataddr1, size) < 0) { + + perror("bind"); + exit(1); + } + listen(sd2, 5); + if((sd3 = accept(sd2, (struct sockaddr *) &dataddr2, &size)) < 0) { + perror("accept"); + exit(1); + } + do { + if((rd = read(sd3, inbuf, BLOCK)) < 0) { + perror("read 1"); + exit(1); + } + if((wr = write(fd, inbuf, rd)) < 0) { + perror("write"); + exit(1); + } + } while(rd != 0); + close(sd2); + close(sd3); + close(fd); + exit(0); + } + else { + if((sd1 = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket"); + return total_bytes_sent; + } + if(connect(sd1, (struct sockaddr *)&comaddr, size) < 0) { + perror("connect"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 2"); + return total_bytes_sent; + } + dbwrite(inbuf, 1, rd); + strcpy(cmd1, "USER ftp\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 3"); + return total_bytes_sent; + } + dbwrite(inbuf, 1, rd); + strcpy(cmd1, "PASS pscherm1@nd.edu\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 4"); + return total_bytes_sent; + } + dbwrite(inbuf, 1, rd); + strcpy(cmd1, "TYPE I\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 5"); + return total_bytes_sent; + } + strcpy(cmd1, "RETR /pub/test.tar\n"); + dbwrite(inbuf, 1, rd); + gethostname(myname, 80); + hp = gethostbyname(myname); + if((a = hp->h_addr_list[0][0]) < 0) + a += 256; + if((b = hp->h_addr_list[0][1]) < 0) + b += 256; + if((c = hp->h_addr_list[0][2]) < 0) + c += 256; + if((d = hp->h_addr_list[0][3]) < 0) + d += 256; + sprintf(cmd1, "PORT %d,%d,%d,%d,", a, b, c, d); + sprintf(cmd2, "%d,%d\n", val2, val3); + strcat(cmd1, cmd2); + fprintf(stderr, "%s", cmd1); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 5"); + return total_bytes_sent; + } + dbwrite(inbuf, 1, rd); + sprintf(cmd1, "RETR %s%s\n", subpath, filename); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 6"); + return total_bytes_sent; + } + dbwrite(inbuf, 1, rd); + strcpy(cmd1, "QUIT\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 6"); + return total_bytes_sent; + } + dbwrite(inbuf, 1, rd); + waitpid(pid, NULL, (int)NULL); + close(sd1); + } + return(1); + +} + +int ftplist(char *tempname, char *linkname, char *ftpaddr, char *filename, + char *path, char *subpath) +{ + int rd, wr, fd, sd1, sd2, sd3, size, pid; + int a, b, c, d; + long val1, val2, val3; + time_t *t, snum; + struct sockaddr_in comaddr, dataddr1, dataddr2; + char inbuf[4096]; + char cmd1[80], cmd2[80], myname[80]; + struct hostent *hp; + //char fullname[256]; + + size = sizeof(struct sockaddr_in); + snum = time(t); + srand((unsigned) snum); + val1 = (int)(5000 * (rand() / (RAND_MAX / + 1.0))); + val1 += 5000; + val2 = val1 / 256; + val3 = val1 % 256; + bzero((char *)&comaddr, size); + comaddr.sin_family = AF_INET; + hp = gethostbyname(ftpaddr); + memcpy((char *)&comaddr.sin_addr, hp->h_addr_list[0], hp->h_length); + comaddr.sin_port = htons(21); + bzero((char *)&dataddr1, size); + dataddr1.sin_family = AF_INET; + dataddr1.sin_addr.s_addr = htonl(INADDR_ANY); + dataddr1.sin_port = htons(val1); + if((pid = fork()) < 0) { + perror("fork"); + return(0); + } + else if(pid == 0) { + fprintf(stderr, "ftplist using file: %s\n", tempname); + if((fd = creat(tempname, S_IRUSR | S_IWUSR)) < 0) { + perror("creat"); + exit(1); + } + if((sd2 = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket"); + exit(1); + } + if(bind(sd2, (struct sockaddr *) &dataddr1, size) < 0) { + perror("bind"); + exit(1); + } + listen(sd2, 5); + if((sd3 = accept(sd2, (struct sockaddr *) &dataddr2, &size)) < 0) { + perror("accept"); + exit(1); + } + do { + if((rd = read(sd3, inbuf, BLOCK)) < 0) { + perror("read 1"); + exit(1); + } + fprintf(stderr, "%d bytes read:\n", rd); + dbwrite(inbuf, 1, rd); + if((wr = write(fd, inbuf, rd)) < 0) { + perror("write"); + exit(1); + } + } while(rd != 0); + close(sd2); + close(sd3); + close(fd); + exit(0); + } + else { + if((sd1 = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket"); + return(0); + } + if(connect(sd1, (struct sockaddr *)&comaddr, size) < 0) { + perror("connect"); + return(0); + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 2"); + return(0); + } + dbwrite(inbuf, 1, rd); + strcpy(cmd1, "USER ftp\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return(0); + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 3"); + return(0); + } + dbwrite(inbuf, 1, rd); + strcpy(cmd1, "PASS pscherm1@nd.edu\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return(0); + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 4"); + return(0); + } + dbwrite(inbuf, 1, rd); + strcpy(cmd1, "TYPE I\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return(0); + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 5"); + return(0); + } + dbwrite(inbuf, 1, rd); + gethostname(myname, 80); + hp = gethostbyname(myname); + if((a = hp->h_addr_list[0][0]) < 0) + a += 256; + if((b = hp->h_addr_list[0][1]) < 0) + b += 256; + if((c = hp->h_addr_list[0][2]) < 0) + c += 256; + if((d = hp->h_addr_list[0][3]) < 0) + d += 256; + sprintf(cmd1, "PORT %d,%d,%d,%d,", a, b, c, d); + sprintf(cmd2, "%ld,%ld\n", val2, val3); + strcat(cmd1, cmd2); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return(0); + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 5"); + return(0); + } + dbwrite(inbuf, 1, rd); + sprintf(cmd1, "LIST %s%s\n", subpath, filename); + fprintf(stderr, "LIST command: %s\n", cmd1); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return(0); + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 6"); + return(0); + } + dbwrite(inbuf, 1, rd); + strcpy(cmd1, "QUIT\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return(0); + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 4"); + return(0); + } + dbwrite(inbuf, 1, rd); + waitpid(pid, NULL, (int)NULL); + close(sd1); + } + return(1); + +} + +int list_parse(char *tempname, char *linkname, char *ftpaddr, char *filename, + char *path, char *subpath) +{ + FILE *fp; + char line[256], *newfile, temp[256], dotname[256]; + int i; + void *handle; + int (*s1dl)(char *, char *, char *, char *, char *); + int (*s1fl)(char *, char *, char *, char *, char *); + char fullname[256]; + + //sprintf(fullname, "%s/%s", path, tempname); + fprintf(stderr, "list_parse opening file: %s\n", tempname); + if((fp = fopen(tempname, "r")) < 0) + perror("fopen"); + fprintf(stderr, "now opening dl\n"); + handle = dlopen("/junk_libname.so", RTLD_LAZY); + s1dl = dlsym(handle, "s1dl"); + s1fl = dlsym(handle, "s1fl"); + + for(i = 0; i < 3; i++) { + fprintf(stderr, "getting rid of junk lines\n"); + fgets(line, 256, fp); + fprintf(stderr, "%s\n", line); + } + fprintf(stderr, "entering main loop\n"); + while(fgets(line, 256, fp) != NULL) { + memcpy(temp, line, 256); + newfile = strtok(temp, " "); + for(i = 0; i < 8; i++) { + newfile = strtok((char *)NULL, " "); + } + if(line[0] == 'd') { + fprintf(stdout, "Call stage1 directory link for: %s\n", newfile); + sprintf(dotname, ".%s", newfile); + sprintf(fullname, "%s%s/", subpath, filename); + s1dl(dotname, ftpaddr, newfile, path, fullname); + } + else if(line[0] == '-') { + fprintf(stdout, "Call stage1 file link for: %s\n", newfile); + sprintf(dotname, ".%s", newfile); + sprintf(fullname, "%s%s/", subpath, filename); + s1fl(dotname, ftpaddr, newfile, path, fullname); + } + } + fclose(fp); + return(1); +} + + diff -ruN linux/fs/mona/Export/ftpfs_xforms.c linux-mona/fs/mona/Export/ftpfs_xforms.c --- linux/fs/mona/Export/ftpfs_xforms.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/Export/ftpfs_xforms.c Wed Jun 27 01:14:16 2001 @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAXTIME 3600 + +int uftpfs_file_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer) +{ + struct stat buff; /* fstat struct */ + long diff; + char *link, *ftpaddr, *file, *path, *subpath; + void *handle; + int (*ftpget)(char *, char *, char *, char *, char *); + char fullname[256]; + char fullname2[256]; + + link = xf_ptr->argv[0]; + ftpaddr = xf_ptr->argv[1]; + file = xf_ptr->argv[2]; + path = xf_ptr->argv[3]; + subpath = xf_ptr->argv[4]; + + fprintf("link = %s\n, ftpaddr = %s\n, file = %s\n, path = %s\n, subpath = %s\n", + link, ftpaddr, file, path, subpath); + + sprintf(fullname, "%s%s%s", path, subpath, link); + fprintf(stderr, "performing stat on: %s\n", fullname); + if (stat(fullname, &buff) < 0 ) { /* fstat for mod time */ + perror("stat"); + return(0); + } + + diff = time(NULL) - buff.st_mtime; /* compare dates */ + fprintf(stderr, "diff time : %ld \n", diff); + + if (diff > MAXTIME) { + fprintf(stderr, "overlimit\n"); + sprintf(fullname2, "rm -r %s%s%s", path, subpath, link); + system(fullname2); + sprintf(fullname2, "%s%s%s", path, subpath, link); + if(creat(fullname2, S_IRUSR | S_IWUSR | S_IXUSR ) < 0) { + perror("creat"); + } + handle = dlopen("/junk_libname.so", RTLD_LAZY); + ftpget = dlsym(handle, "ftpget"); + fprintf(stderr, "calling ftpget on %s\n", subpath); + utime(fullname, (struct utimbuf *)NULL); + ftpget(link, ftpaddr, file, path, subpath); + dlclose(handle); + } + return(1); +} + +int uftpfs_dir_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer, int *state) +{ + struct stat buff; /* fstat struct */ + long diff; + char *link2, *ftpaddr, *file, *path, *tempname, *subpath; + void *handle; + int (*ftplist)(char *, char *, char *, char *, char *, char *); + int (*list_parse)(char *, char *, char *, char *, char *, char *); + char fullname[256]; + char fullname2[256]; + + link2 = xf_ptr->argv[0]; + ftpaddr = xf_ptr->argv[1]; + file = xf_ptr->argv[2]; + path = xf_ptr->argv[3]; + subpath = xf_ptr->argv[4]; + + fprintf(stderr, "doing lstat on %s\n", link2); + sprintf(fullname, "%s%s%s", path, subpath, link2); + if (stat(fullname, &buff) < 0 ) { /* fstat for mod time */ + perror("stat"); + return(0); + } + + diff = time(NULL) - buff.st_mtime; /* compare dates */ + printf("diff time : %ld \n", diff); + + if ( diff > MAXTIME) { + fprintf(stderr, "overlimit\n"); + sprintf(fullname2, "rm -r %s%s%s", path, subpath, link2); + system(fullname2); + sprintf(fullname2, "%s%s%s", path, subpath, link2); + mkdir(fullname2, S_IRUSR | S_IWUSR | S_IXUSR ); + handle = dlopen("/junk_libname.so", RTLD_LAZY); + ftplist = dlsym(handle, "ftplist"); + list_parse = dlsym(handle, "list_parse"); + sprintf(fullname2, "%s%s", path, subpath); + tempname = tempnam(fullname2, NULL); + fprintf(stderr, "calling ftplist on %s\n", subpath); + utime(fullname, (struct utimbuf *)NULL); + ftplist(tempname, link2, ftpaddr, file, path, subpath); + list_parse(tempname, link2, ftpaddr, file, path, subpath); + remove(tempname); + dlclose(handle); + } + return(1); +} Binary files linux/fs/mona/Export/monad and linux-mona/fs/mona/Export/monad differ diff -ruN linux/fs/mona/Export/monad.c linux-mona/fs/mona/Export/monad.c --- linux/fs/mona/Export/monad.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/Export/monad.c Wed Jun 27 01:05:53 2001 @@ -0,0 +1,365 @@ +/*\ + * + * monad.c + * + * The mona daemon + * + * this is the user space daemon that handles export transformations + * in the mona file system + * +\*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static int child(char*); +static int killd(void); +static int write_pid(void); +static void TERM_handler(int); +static void CHLD_handler(int); +static void SEGV_handler(int); + +/* PWR: we should probably use the logging stuff we set up, + * instead of fprintf(stderr, ...) */ +static int monad_log_mode; + +int +main (int argc, char *argv[]) +{ + int k2u_fd; + int bytes; + int i; + pid_t pid; + char input_buf[U_K_MESSAGE_SIZE]; + struct mona_u2k k2u_st; + char mident[16]; /* string that holds our ident (for syslog) */ + struct sigaction sa; + + + /* parse command line args: + * -d -- print debugging to stderr + * -k -- kill running monad + */ + if (argc > 1) { + if (!strcmp(argv[1],"-d")) + monad_log_mode = LOG_CONS | LOG_PERROR; + else if (!strcmp(argv[1],"-k")) + return killd(); + else { + fprintf(stderr, "Invalid command line argument: %s\n",argv[1]); + fprintf(stderr, "Usage: %s [-d]\n",argv[0]); + } + } else + monad_log_mode = LOG_CONS; + + setpriority(PRIO_PROCESS, 0, -20); + k2u_st.id = -1; + + if ((k2u_fd = open(MONA_K2U, O_RDWR)) < 0) { + fprintf(stderr, "Error: couldn't open kernel-to-user buffer\n"); + exit(1); + } + + /* fork the daemon into background and exit */ + if ((pid = fork()) < 0) { + fprintf(stderr, "%s: failed to fork daemon process\n",argv[0]); + exit(1); + } else if (pid > 0) { + /* open the system log and inform it of our starting up */ + snprintf(mident,16,"monad[%d]",pid); + openlog(mident,monad_log_mode,LOG_DAEMON); + syslog(LOG_NOTICE,"starting up"); + return 0; + } + + /* install signal handlers to take care of sigterm and returning children */ + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + + sa.sa_handler = TERM_handler; + sigaction(SIGTERM, &sa, NULL); + sa.sa_handler = SEGV_handler; + sigaction(SIGSEGV, &sa, NULL); + + sa.sa_handler = CHLD_handler; + sa.sa_flags = SA_RESTART; + sigaction(SIGCHLD, &sa, NULL); + + + /* store our pid in a file (for monad -k) */ + write_pid(); + + while (1) { + k2u_st.buffer = input_buf; + i = ioctl(k2u_fd, MONA_IOC_K2U_MASTER, &k2u_st); + if ((i < 0) || (i == KU_NO_DATA)) + continue; + else if (i == KU_NOT_ROOT) { + fprintf(stderr, "Must be root to open k2u buffer as master\n"); + exit(1); + } + + bytes = k2u_st.size; + + if ((pid = fork()) < 0) + perror("fork"); + else if (pid == 0) { + child(input_buf); + } + + } +} + + +static int +child (char* input_buf) +{ + int k2u_fd; + int i; + int bytes; + char *pbuf; + int total_len, buf_len, id; + pid_t mypid; + char fn_name[MAX_FILENAME_LEN], lib_name[MAX_FILENAME_LEN]; + XformInfo export_xform; + void *xform_fn_handle = NULL; + char *error; + char *strtmp; + + struct mona_u2k u2k_st; + uid_t xuid; + gid_t xgid; + struct passwd* xpw; + + setpriority(PRIO_PROCESS, 0, 0); + + if ((k2u_fd = open(MONA_K2U, O_RDWR)) < 0) { + fprintf(stderr, "Child error: couldn't open kernel-to-user buffer\n"); + perror("..."); + exit(1); + } + + /* initialize the xform information structures */ + export_xform.private_data = NULL; + export_xform.filp = NULL; + export_xform.inodep = NULL; + export_xform.xform = NULL; + export_xform.argc = 0; + export_xform.argv = NULL; + export_xform.stream_dir = 0; + + mypid = getpid(); + + /* PWR: rid the world of strtok! */ + total_len = *((int*)input_buf); + pbuf = input_buf + sizeof(int); + + while (1) { /* poll the kernel for more data */ + + /* generate message to user space of the following form: + * + * int total size of message + * int export xform id number + * int uid + * int gid + * int state + * int stream_dir + * int size of buffer + * int argc + * string xform function name (terminating char on string) + * * argc parameter strings + * string buffer (no terminating char) + */ + + u2k_st.id = id = atoi(strtok(pbuf, " ")); + + /* PWR: we probably don't need/want to be doing this inside while(1) */ + xuid = atoi(strtok(NULL, " ")); + setuid(xuid); + xgid = atoi(strtok(NULL, " ")); + setgid(xgid); + + export_xform.state = atoi(strtok(NULL, " ")); + + export_xform.stream_dir = atoi(strtok(NULL, " ")); + + buf_len = atoi(strtok(NULL, " ")); + + export_xform.argc = atoi(strtok(NULL, " ")); + + strcpy(fn_name, strtok(NULL, " ")); + + /* allocate space for and read the argv array, if it exists */ + if (export_xform.argc > 0) { + export_xform.argv = (char **) malloc(export_xform.argc*sizeof(char *)); + for (i=0; i < export_xform.argc; ++i) { + strtmp = strtok(NULL, " "); + export_xform.argv[i] = (char *)malloc(sizeof(char)*(strlen(strtmp)+1)); + strcpy(export_xform.argv[i], strtmp); + } + } + + if (export_xform.xform == NULL) { + if (xform_fn_handle == NULL) { + /* we haven't opened the user xform yet. so open it! */ + xpw = getpwuid(xuid); + sprintf(lib_name, "%s/.mona/%s.so", xpw->pw_dir, fn_name); + xform_fn_handle = dlopen(lib_name, RTLD_LAZY); + if (!xform_fn_handle) { + xform_fn_handle = dlopen("/lib/monalib.so", RTLD_LAZY); + } + + if (!xform_fn_handle) { + fprintf(stderr, "Failed to find mona libraries in %s " + "or /lib/libmona.so\n", lib_name); + ioctl(k2u_fd, MONA_IOC_DAEMON_FAIL, &u2k_st); + exit(1); + } + + } + + export_xform.xform = dlsym(xform_fn_handle, fn_name); + if((error = dlerror()) != NULL) { + fputs(error, stderr); + ioctl(k2u_fd, MONA_IOC_DAEMON_FAIL, &u2k_st); + exit(1); + } + + } + + /* if buf_len < 0, what do we do? */ + if (buf_len < 0) { + fprintf(stderr, "I'm sorry!!!\n"); + ioctl(k2u_fd, MONA_IOC_DAEMON_FAIL, &u2k_st); + exit(1); + } + + u2k_st.offset = total_len - buf_len - 1; + + bytes = export_xform.xform(&export_xform, buf_len, + &input_buf[u2k_st.offset + 1]); + u2k_st.buffer = input_buf; + + /* return msg: first char is state, then the buffer follows */ + u2k_st.buffer[u2k_st.offset] = (char) export_xform.state; + + ++bytes; + /* send a message back to the kernel */ + u2k_st.size = bytes; + u2k_st.id = id; + + bytes = ioctl(k2u_fd, MONA_IOC_U2K, &u2k_st); + + while (bytes != KU_SUCCESS) { + if (bytes == KU_INVALID_ID) { /* id is now invalid, slave is finished */ + exit(0); + } + + bytes = ioctl(k2u_fd, MONA_IOC_K2U_SLAVE, &u2k_st); + } + + /* data should be in k2u_st */ + bytes = u2k_st.size; + //total_len = atoi(strtok(input_buf, " ")); + total_len = *((int*) input_buf); + pbuf = input_buf + sizeof(int); + + /* continue the loop, most parsing is done at top of loop */ + } + _exit(0); +} + +static int +write_pid(void) +{ + FILE *pid_file; + pid_t my_pid; + + my_pid = getpid(); + + if ((pid_file = fopen("/var/run/monad.pid","w")) == NULL) { + fprintf(stderr, "Error... failed to write pid\n"); + return -1; + } + + fprintf(pid_file,"%d",(int)my_pid); + + fclose(pid_file); + + return 0; + +} + +static int +killd(void) +{ + FILE *pid_file; + pid_t pid_to_kill; + + /* PWR: pid file should not be hard coded. */ + if ((pid_file = fopen("/var/run/monad.pid","r")) == NULL) { + fprintf(stderr, "Error... bad stuff\n"); + return -1; + } + + fscanf(pid_file,"%d",(int *)&pid_to_kill); + + if (kill(pid_to_kill,SIGTERM) < 0) { + perror("kill"); + return -1; + } + + if (unlink("/var/run/monad.pid") < 0) { + perror("unlink"); + return -1; + } + + fclose(pid_file); + + return 0; +} + +static void +TERM_handler(int foo) +{ + char mident[16]; + + snprintf(mident,16,"monad[%d]",(int)getpid()); + openlog(mident,monad_log_mode,LOG_DAEMON); + syslog(LOG_NOTICE,"received SIGTERM... exiting"); + closelog(); + exit(0); +} + +static void +CHLD_handler(int foo) +{ + waitpid(-1, NULL, WNOHANG); +} + +static void +SEGV_handler(int foo) +{ + /* PWR: should really be more informative here, but this is better + * than nothing right now */ + fprintf(stderr, "segfault!\n"); + _exit(1); +} + diff -ruN linux/fs/mona/Export/tar_xforms.c linux-mona/fs/mona/Export/tar_xforms.c --- linux/fs/mona/Export/tar_xforms.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/Export/tar_xforms.c Tue Jun 26 09:17:20 2001 @@ -0,0 +1,1271 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef mona_debug +#define mona_debug printf + +#define BLOCK 4096 +#define XF_READY 0 +#define XF_UNSENT_DATA 1 +typedef struct xform_info { + int num_inputs; + int num_outputs; + struct xform_info *next_xform; + int (*xform) (struct xform_info *, int, char *, int *); + int unsent_data; + int unsent_data_size; + int id; + int stream_dir; + int argc; + char **argv; + void *private_data; + struct file *filp; + struct inode *inodep; +} XformInfo, *XformInfoPtr; + + +int utarext2_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer, int *state) +{ + int total_bytes_sent=0; + int csize; + + typedef struct finfo { + long index; + long size; + char name[101]; + char sizest[13]; + int stage; + long pos; + int found; + int pad; + } fileinfo; + fileinfo *buf; + + if(xf_ptr->unsent_data > 1) { + xf_ptr->unsent_data -= 2; + if (xf_ptr->next_xform != NULL) + total_bytes_sent = xf_ptr->next_xform->xform(xf_ptr->next_xform, + num_bytes, buffer, state); + else + state[0] = XF_READY; + + if (state[0] == XF_UNSENT_DATA) + xf_ptr->unsent_data += 2; + else + state[0] += xf_ptr->unsent_data; + return total_bytes_sent; + } + if(num_bytes < 0) { + free(xf_ptr->private_data); + return total_bytes_sent = 0; + } + if(xf_ptr->private_data == NULL) { + xf_ptr->private_data = (fileinfo *)malloc(sizeof(fileinfo)); + buf = xf_ptr->private_data; + buf->stage = 1; + buf->sizest[12] = '\0'; + buf->name[100] = '\0'; + buf->pos = 0; + buf->found = 0; + } + else + buf = xf_ptr->private_data; + + buf->index = 0; + total_bytes_sent = 0; + while(buf->index < num_bytes) { + switch(buf->stage) { + case 1: + csize = 100 - buf->pos; + if ((buf->index + csize) < num_bytes) { + memcpy((buf->name + buf->pos), (buffer + buf->index), csize); + buf->index += csize; + buf->stage = 2; + buf->pos = 0; + buf->found = strcmp("tmp1/copy2.c", buf->name); + } + else { + csize = num_bytes - buf->index; + memcpy((buf->name + buf->pos), (buffer + buf->index), csize); + buf->index += csize; + buf->pos += csize; + } + break; + case 2: + csize = 24 - buf->pos; + if ((buf->index + csize) < num_bytes) { + buf->index += csize; + buf->stage = 3; + buf->pos = 0; + } + else { + csize = num_bytes - buf->index; + buf->index += csize; + buf->pos += csize; + } + break; + case 3: + csize = 12 - buf->pos; + if ((buf->index + csize) < num_bytes) { + memcpy((buf->sizest + buf->pos), (buffer + buf->index), csize); + buf->index += csize; + buf->stage = 4; + buf->pos = 0; + buf->size = strtol(buf->sizest, NULL, 8); + buf->pad = 512 - ((buf->size + 512) % 512); + } + else { + csize = num_bytes - buf->index; + memcpy((buf->sizest + buf->pos), (buffer + buf->index), csize); + buf->index += csize; + buf->pos += csize; + } + break; + case 4: + csize = 376 - buf->pos; + if ((buf->index + csize) < num_bytes) { + buf->index += csize; + buf->stage = 5; + buf->pos = 0; + } + else { + csize = num_bytes - buf->index; + buf->index += csize; + buf->pos += csize; + } + break; + case 5: + csize = buf->size - buf->pos; + if ((buf->index + csize) < num_bytes) { + if(!(buf->found)) { + memmove(buffer, (buffer + buf->index), csize); + total_bytes_sent += csize; + } + buf->index += csize; + buf->stage = 6; + buf->pos = 0; + } + else { + csize = num_bytes - buf->index; + if(!(buf->found)) { + memmove(buffer, (buffer + buf->index), csize); + total_bytes_sent += csize; + } + buf->index += csize; + buf->pos += csize; + } + break; + case 6: + csize = buf->pad - buf->pos; + if(buf->name[strlen(buf->name) - 1] == '/') { + buf->stage = 1; + buf->pos = 0; + break; + } + if ((buf->index + csize) < num_bytes) { + buf->index += csize; + buf->stage = 1; + buf->pos = 0; + } + else { + csize = num_bytes - buf->index; + buf->index += csize; + buf->pos += csize; + } + break; + } + } + /* continue on to the next xform if one exists... */ + if(xf_ptr->next_xform != NULL) + total_bytes_sent = xf_ptr->next_xform->xform(xf_ptr->next_xform, + total_bytes_sent, buffer, state); + else + state[0] = XF_READY; + if(state[0] == XF_UNSENT_DATA) + xf_ptr->unsent_data += 2; + else + state[0] += xf_ptr->unsent_data; + return total_bytes_sent; +} + +int utarlist_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer, int *state) +{ + int total_bytes_sent = num_bytes; + int i, csize; + char *tmpptr; + + typedef struct finfo { + int bufind; /* position in current output buffer */ + long index; /* position in current input buffer */ + long size; /* size of current archived file */ + char name[101]; /* name of current archived file */ + char sizest[13];/* string form of size */ + int stage; /* stage of header parse */ + long pos; /* position in current stage */ + int pad; /* padding at end of current file */ + int type; /* type of current file (dir, reg, etc. */ + char typestr[4];/* string form of type */ + char uperm; /* user perms */ + char gperm; /* group perms */ + char operm; /* other perms */ + char uname[33]; /* user name */ + char gname[33]; /* group name */ + char otime[13]; /* octal string form of time */ + time_t tval; /* unix time */ + struct tm tstruct; /* broken down time */ + struct tm *tsptr; /* ptr to broken down time */ + char tstring[20]; /* formatted time string */ + } fileinfo; + fileinfo *buf; + + if(xf_ptr->unsent_data > 1) { + xf_ptr->unsent_data -= 2; + if (xf_ptr->next_xform != NULL) + total_bytes_sent = xf_ptr->next_xform->xform(xf_ptr->next_xform, + num_bytes, buffer, state); + else + state[0] = XF_READY; + + if (state[0] == XF_UNSENT_DATA) + xf_ptr->unsent_data += 2; + else + state[0] += xf_ptr->unsent_data; + return total_bytes_sent; + } + if(num_bytes < 0) { + free(xf_ptr->private_data); + return total_bytes_sent; + } + if(xf_ptr->private_data == NULL) { + xf_ptr->private_data = (fileinfo *)malloc(sizeof(fileinfo)); + buf = xf_ptr->private_data; + buf->stage = 1; + buf->sizest[12] = '\0'; + buf->name[100] = '\0'; + buf->uname[32] = '\0'; + buf->gname[32] = '\0'; + buf->otime[12] = '\0'; + buf->typestr[3] = '\0'; + buf->pos = 0; + } + else + buf = xf_ptr->private_data; + + tmpptr = (char *)malloc(num_bytes); + buf->bufind = 0; + buf->index = 0; + total_bytes_sent = 0; + while(buf->index < num_bytes) { + switch(buf->stage) { + /* name */ + case 1: + /* we may have been here before, subtract buf->pos so we only read + what we need to */ + csize = 100 - buf->pos; + /* if what's left to read is wholly contained in the buffer... */ + if ((buf->index + csize) < num_bytes) { + /* copy the name to buf->name (xf_ptr->private_data->name) */ + memcpy((buf->name + buf->pos), (buffer + buf->index), csize); + /* update the index for this iteration's buffer */ + buf->index += csize; + /* move on to stage two */ + buf->stage = 2; + /* no bytes yet read in stage two, so buf->pos is zero */ + buf->pos = 0; + } + /* if we're not given all that's left... */ + else { + /* set size to the amount given */ + csize = num_bytes - buf->index; + /* copy that to buf->name */ + memcpy((buf->name + buf->pos), (buffer + buf->index), csize); + /* update the index for this iteration's buffer */ + buf->index += csize; + /* update our position within the name for next iteration */ + buf->pos += csize; + /* no update to buf->stage since we want to come back to + stage one */ + } + break; + /* file type */ + case 2: + csize = 3 - buf->pos; + if((buf->index + csize) < num_bytes) { + memcpy((buf->typestr + buf->pos), (buffer + buf->index), csize); + buf->index += csize; + buf->stage = 3; + buf->pos = 0; + buf->type = atoi(buf->typestr); + } + else { + csize = num_bytes - buf->index; + memcpy((buf->typestr + buf->pos), (buffer + buf->index), csize); + buf->index += csize; + buf->pos += csize; + } + break; + /* owner perms */ + case 3: + csize = 1 - buf->pos; + if((buf->index + csize) < num_bytes) { + memcpy(&buf->uperm, (buffer + buf->index), csize); + buf->index += csize; + buf->stage = 4; + buf->pos = 0; + } + else { + csize = num_bytes - buf->index; + memcpy(&buf->uperm, (buffer + buf->index), csize); + buf->index += csize; + buf->pos += csize; + } + break; + /* group perms */ + case 4: + csize = 1 - buf->pos; + if((buf->index + csize) < num_bytes) { + memcpy(&buf->gperm, (buffer + buf->index), csize); + buf->index += csize; + buf->stage = 5; + buf->pos = 0; + } + else { + csize = num_bytes - buf->index; + memcpy(&buf->gperm, (buffer + buf->index), csize); + buf->index += csize; + buf->pos += csize; + } + break; + /* other perms */ + case 5: + csize = 1 - buf->pos; + if((buf->index + csize) < num_bytes) { + memcpy(&buf->operm, (buffer + buf->index), csize); + buf->index += csize; + buf->stage = 6; + buf->pos = 0; + } + else { + csize = num_bytes - buf->index; + memcpy(&buf->operm, (buffer + buf->index), csize); + buf->index += csize; + buf->pos += csize; + } + break; + /* uid, gid (unused) */ + case 6: + csize = 18 - buf->pos; + if ((buf->index + csize) < num_bytes) { + buf->index += csize; + buf->stage = 7; + buf->pos = 0; + } + else { + csize = num_bytes - buf->index; + buf->index += csize; + buf->pos += csize; + } + break; + /* size */ + case 7: + csize = 12 - buf->pos; + if ((buf->index + csize) < num_bytes) { + memcpy((buf->sizest + buf->pos), (buffer + buf->index), csize); + buf->index += csize; + buf->stage = 8; + buf->pos = 0; + buf->size = strtol(buf->sizest, NULL, 8); + /* in the end of archive padding, no sense calculating a pad + for a nonexistent archived file + if(strlen(buf->name) == 0) + buf->pad = 0; + if it's a directory entry, we need no pad, since it's + already on a 512 byte boundary */ + if(buf->name[strlen(buf->name) - 1] == '/') + buf->pad = 0; + else + buf->pad = 512 - ((buf->size + 512) % 512); + } + else { + csize = num_bytes - buf->index; + memcpy((buf->sizest + buf->pos), (buffer + buf->index), csize); + buf->index += csize; + buf->pos += csize; + } + break; + /* time */ + case 8: + csize = 12 - buf->pos; + if ((buf->index + csize) < num_bytes) { + memcpy((buf->otime + buf->pos), (buffer + buf->index), csize); + buf->index += csize; + buf->stage = 9; + buf->pos = 0; + buf->tval = strtol(buf->otime, NULL, 8); + buf->tsptr = &(buf->tstruct); + buf->tsptr = localtime(&(buf->tval)); + strftime(buf->tstring, 19, "%Y-%m-%d %H:%M ", buf->tsptr); + } + else { + csize = num_bytes - buf->index; + memcpy((buf->otime + buf->pos), (buffer + buf->index), csize); + buf->index += csize; + buf->pos += csize; + } + break; + /* checksum, etc. (unused) */ + case 9: + csize = 117 - buf->pos; + if ((buf->index + csize) < num_bytes) { + buf->index += csize; + buf->stage = 10; + buf->pos = 0; + } + else { + csize = num_bytes - buf->index; + buf->index += csize; + buf->pos += csize; + } + break; + /* username */ + case 10: + csize = 32 - buf->pos; + if((buf->index + csize) < num_bytes) { + memcpy((buf->uname + buf->pos), (buffer + buf->index), csize); + buf->index += csize; + buf->stage = 11; + buf->pos = 0; + } + else { + csize = num_bytes - buf->index; + memcpy((buf->uname + buf->pos), (buffer + buf->index), csize); + buf->index += csize; + buf->pos += csize; + } + break; + /* group name */ + case 11: + csize = 32 - buf->pos; + if((buf->index + csize) < num_bytes) { + memcpy((buf->gname + buf->pos), (buffer + buf->index), csize); + buf->index += csize; + buf->stage = 12; + buf->pos = 0; + } + else { + csize = num_bytes - buf->index; + memcpy((buf->gname + buf->pos), (buffer + buf->index), csize); + buf->index += csize; + buf->pos += csize; + } + break; + /* etc. (unused) */ + case 12: + csize = 183 - buf->pos; + if ((buf->index + csize) < num_bytes) { + buf->index += csize; + buf->stage = 13; + buf->pos = 0; + } + else { + csize = num_bytes - buf->index; + buf->index += csize; + buf->pos += csize; + } + break; + /* data (size bytes) */ + case 13: + csize = buf->size - buf->pos; + if ((buf->index + csize) < num_bytes) { + buf->index += csize; + buf->stage = 14; + buf->pos = 0; + } + else { + csize = num_bytes - buf->index; + buf->index += csize; + buf->pos += csize; + } + break; + /* pad (out to 512 byte boundary) and write output */ + case 14: + csize = buf->pad - buf->pos; + /* if the length of name is zero, we're probably in the end of + file padding, and at any rate aren't interested in reporting + about a file with no name */ + if(strlen(buf->name) < 1) { + buf->stage = 1; + buf->pos = 0; + } + else if ((buf->index + csize) < num_bytes) { + buf->index += csize; + buf->stage = 1; + buf->pos = 0; + switch (buf->type) { + case 40: + *(tmpptr + buf->bufind) = 'd'; + buf->bufind += 1; + break; + case 100: + *(tmpptr + buf->bufind) = '-'; + buf->bufind += 1; + break; + case 120: + *(tmpptr + buf->bufind) = 'l'; + buf->bufind += 1; + break; + default: + *(tmpptr + buf->bufind) = '?'; + buf->bufind += 1; + } + switch (buf->uperm) { + case '1': + *(tmpptr + buf->bufind) = '-'; + *(tmpptr + buf->bufind + 1) = '-'; + *(tmpptr + buf->bufind + 2) = 'x'; + buf->bufind += 3; + break; + case '2': + *(tmpptr + buf->bufind) = '-'; + *(tmpptr + buf->bufind + 1) = 'w'; + *(tmpptr + buf->bufind + 2) = '-'; + buf->bufind += 3; + break; + case '3': + *(tmpptr + buf->bufind) = '-'; + *(tmpptr + buf->bufind + 1) = 'w'; + *(tmpptr + buf->bufind + 2) = 'x'; + buf->bufind += 3; + break; + case '4': + *(tmpptr + buf->bufind) = 'r'; + *(tmpptr + buf->bufind + 1) = '-'; + *(tmpptr + buf->bufind + 2) = '-'; + buf->bufind += 3; + break; + case '5': + *(tmpptr + buf->bufind) = 'r'; + *(tmpptr + buf->bufind + 1) = '-'; + *(tmpptr + buf->bufind + 2) = 'x'; + buf->bufind += 3; + break; + case '6': + *(tmpptr + buf->bufind) = 'r'; + *(tmpptr + buf->bufind + 1) = 'w'; + *(tmpptr + buf->bufind + 2) = '-'; + buf->bufind += 3; + break; + case '7': + *(tmpptr + buf->bufind) = 'r'; + *(tmpptr + buf->bufind + 1) = 'w'; + *(tmpptr + buf->bufind + 2) = 'x'; + buf->bufind += 3; + break; + default: + *(tmpptr + buf->bufind) = '?'; + *(tmpptr + buf->bufind + 1) = '?'; + *(tmpptr + buf->bufind + 2) = '?'; + buf->bufind += 3; + } + switch (buf->gperm) { + case '1': + *(tmpptr + buf->bufind) = '-'; + *(tmpptr + buf->bufind + 1) = '-'; + *(tmpptr + buf->bufind + 2) = 'x'; + buf->bufind += 3; + break; + case '2': + *(tmpptr + buf->bufind) = '-'; + *(tmpptr + buf->bufind + 1) = 'w'; + *(tmpptr + buf->bufind + 2) = '-'; + buf->bufind += 3; + break; + case '3': + *(tmpptr + buf->bufind) = '-'; + *(tmpptr + buf->bufind + 1) = 'w'; + *(tmpptr + buf->bufind + 2) = 'x'; + buf->bufind += 3; + break; + case '4': + *(tmpptr + buf->bufind) = 'r'; + *(tmpptr + buf->bufind + 1) = '-'; + *(tmpptr + buf->bufind + 2) = '-'; + buf->bufind += 3; + break; + case '5': + *(tmpptr + buf->bufind) = 'r'; + *(tmpptr + buf->bufind + 1) = '-'; + *(tmpptr + buf->bufind + 2) = 'x'; + buf->bufind += 3; + break; + case '6': + *(tmpptr + buf->bufind) = 'r'; + *(tmpptr + buf->bufind + 1) = 'w'; + *(tmpptr + buf->bufind + 2) = '-'; + buf->bufind += 3; + break; + case '7': + *(tmpptr + buf->bufind) = 'r'; + *(tmpptr + buf->bufind + 1) = 'w'; + *(tmpptr + buf->bufind + 2) = 'x'; + buf->bufind += 3; + break; + default: + *(tmpptr + buf->bufind) = '?'; + *(tmpptr + buf->bufind + 1) = '?'; + *(tmpptr + buf->bufind + 2) = '?'; + buf->bufind += 3; + } + switch (buf->operm) { + case '1': + *(tmpptr + buf->bufind) = '-'; + *(tmpptr + buf->bufind + 1) = '-'; + *(tmpptr + buf->bufind + 2) = 'x'; + buf->bufind += 3; + break; + case '2': + *(tmpptr + buf->bufind) = '-'; + *(tmpptr + buf->bufind + 1) = 'w'; + *(tmpptr + buf->bufind + 2) = '-'; + buf->bufind += 3; + break; + case '3': + *(tmpptr + buf->bufind) = '-'; + *(tmpptr + buf->bufind + 1) = 'w'; + *(tmpptr + buf->bufind + 2) = 'x'; + buf->bufind += 3; + break; + case '4': + *(tmpptr + buf->bufind) = 'r'; + *(tmpptr + buf->bufind + 1) = '-'; + *(tmpptr + buf->bufind + 2) = '-'; + buf->bufind += 3; + break; + case '5': + *(tmpptr + buf->bufind) = 'r'; + *(tmpptr + buf->bufind + 1) = '-'; + *(tmpptr + buf->bufind + 2) = 'x'; + buf->bufind += 3; + break; + case '6': + *(tmpptr + buf->bufind) = 'r'; + *(tmpptr + buf->bufind + 1) = 'w'; + *(tmpptr + buf->bufind + 2) = '-'; + buf->bufind += 3; + break; + case '7': + *(tmpptr + buf->bufind) = 'r'; + *(tmpptr + buf->bufind + 1) = 'w'; + *(tmpptr + buf->bufind + 2) = 'x'; + buf->bufind += 3; + break; + default: + *(tmpptr + buf->bufind) = '?'; + *(tmpptr + buf->bufind + 1) = '?'; + *(tmpptr + buf->bufind + 2) = '?'; + buf->bufind += 3; + } + *(tmpptr + buf->bufind) = ' '; + buf->bufind += 1; + i = strlen(buf->uname); + memcpy((tmpptr + buf->bufind), buf->uname, i); + buf->bufind += i; + *(tmpptr + buf->bufind) = '/'; + buf->bufind += 1; + i = strlen(buf->gname); + memcpy((tmpptr + buf->bufind), buf->gname, i); + buf->bufind += i; + *(tmpptr + buf->bufind) = ' '; + buf->bufind += 1; + sprintf(buf->sizest, "%10ld", buf->size); + memcpy((tmpptr + buf->bufind), buf->sizest, 10); + buf->bufind += 10; + *(tmpptr + buf->bufind) = ' '; + buf->bufind += 1; + memcpy((tmpptr + buf->bufind), buf->tstring, 16); + buf->bufind += 16; + *(tmpptr + buf->bufind) = ' '; + buf->bufind += 1; + i = strlen(buf->name); + memcpy((tmpptr + buf->bufind), buf->name, i); + buf->bufind += i; + *(tmpptr + buf->bufind) = '\n'; + buf->bufind += 1; + } + else { + csize = num_bytes - buf->index; + buf->index += csize; + buf->pos += csize; + } + } + } + total_bytes_sent = buf->bufind; + memcpy(buffer, tmpptr, total_bytes_sent); + free(tmpptr); + /* continue on to the next xform if one exists... */ + if(xf_ptr->next_xform != NULL) + total_bytes_sent = xf_ptr->next_xform->xform(xf_ptr->next_xform, + total_bytes_sent, buffer, state); + else + state[0] = XF_READY; + if(state[0] == XF_UNSENT_DATA) + xf_ptr->unsent_data += 2; + else + state[0] += xf_ptr->unsent_data; + return total_bytes_sent; +} + +int utarins_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer, int *state) +{ + int total_bytes_sent = 0; + int i, fd1, rd, wr, pad, newpad, uid, cksum = 0, found = 1; + long lsk, source = 0, dest = 0; + char namestr[4096]; + char sizestr[12]; + char newfile[] = "newfile"; + struct stat stat; + struct passwd *passwd; + struct group *group; + time_t timeval; + + typedef struct finfo { + long index; + long size; + long tsize; + int state; + int found; + long lastfile; + long target; + } fileinfo; + fileinfo *buf; + + if(xf_ptr->unsent_data > 1) { + xf_ptr->unsent_data -= 2; + if (xf_ptr->next_xform != NULL) + total_bytes_sent = xf_ptr->next_xform->xform(xf_ptr->next_xform, + num_bytes, buffer, state); + else + state[0] = XF_READY; + + if (state[0] == XF_UNSENT_DATA) + xf_ptr->unsent_data += 2; + else + state[0] += xf_ptr->unsent_data; + return total_bytes_sent; + } + if(num_bytes < 0) { + free(xf_ptr->private_data); + return total_bytes_sent; + } + for(i = 0; i < 20; i++) + fprintf(stderr, "%c", buffer[i]); + fprintf(stderr, "\n"); + fprintf(stderr, "num_bytes is: %d\n", num_bytes); + if(xf_ptr->private_data == NULL) { + xf_ptr->private_data = (fileinfo *)malloc(sizeof(fileinfo)); + buf = xf_ptr->private_data; + buf->target = -1; + if((fd1 = open("/test.tar", O_RDWR)) < 0) { + perror("open"); + return total_bytes_sent; + } + fstat(fd1, &stat); + while(rd != 0) { + if((rd = read(fd1, namestr, 100)) < 0) { + perror("read"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, 24, SEEK_CUR)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if((rd = read(fd1, sizestr, 12)) < 0) { + perror("read"); + return total_bytes_sent; + } + buf->size = strtol(sizestr, NULL, 8); + if((lsk = lseek(fd1, 376, SEEK_CUR)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if(!(found = strcmp(newfile, namestr))) { + buf->found = found; + buf->target = lsk - 512; + buf->tsize = buf->size; + fprintf(stderr, "Found %s.\n", newfile); + } + if(namestr[strlen(namestr) - 1] != '/') { + pad = 512 - ((buf->size + 512) % 512); + if((lsk = lseek(fd1, buf->size + pad, SEEK_CUR)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + } + if(strlen(namestr) > 0) { + buf->lastfile = lsk; + } + } + if(buf->target < 0) + buf->target = buf->lastfile; + if(!buf->found) { + buf->tsize = num_bytes; + if((lsk = lseek(fd1, buf->target, SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if((wr = write(fd1, newfile, strlen(newfile))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, (buf->target + 100), SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + strcpy(namestr, "100644"); + if((wr = write(fd1, namestr, strlen(namestr))) < 0) { + perror("write 1"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, (buf->target + 108), SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + uid = getuid(); + passwd = getpwuid(uid); + group = getgrgid(passwd->pw_gid); + sprintf(namestr, "%07o", uid); + if((wr = write(fd1, namestr, strlen(namestr))) < 0) { + perror("write 2"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, (buf->target + 116), SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + sprintf(namestr, "%07o", passwd->pw_gid); + if((wr = write(fd1, namestr, strlen(namestr))) < 0) { + perror("write 3"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, (buf->target + 124), SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + sprintf(namestr, "%011o", num_bytes); + if((wr = write(fd1, namestr, strlen(namestr))) < 0) { + perror("write 4"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, (buf->target + 136), SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + time(&timeval); + sprintf(namestr, "%011lo", timeval); + if((wr = write(fd1, namestr, strlen(namestr))) < 0) { + perror("write 5"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, (buf->target + 156), SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if((wr = write(fd1, "0", 1)) < 0) { + perror("write 6"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, (buf->target + 257), SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if((wr = write(fd1, "ustar\0", 6)) < 0) { + perror("write 7"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, (buf->target + 263), SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if((wr = write(fd1, "00", 2) < 0)) { + perror("write 8"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, (buf->target + 265), SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + i = strlen(passwd->pw_name); + if((wr = write(fd1, passwd->pw_name, i)) < 0) { + perror("write 9"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, (buf->target + 297), SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if((wr = write(fd1, group->gr_name, sizeof(group->gr_name))) < 0) { + perror("write 10"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, buf->target, SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if((rd = read(fd1, namestr, 512)) < 0) { + perror("read"); + return total_bytes_sent; + } + for(i = 0; i < 512; i++) { + if(i > 146 && i < 155) + cksum += ' '; + else + cksum += namestr[i]; + } + sprintf(namestr, "%07o", cksum); + if((lsk = lseek(fd1, (buf->target + 148), SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if((wr = write(fd1, namestr, strlen(namestr))) < 0) { + perror("write 11"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, (buf->target + 512), SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if((wr = write(fd1, buffer, num_bytes)) < 0) { + perror("write 12"); + return total_bytes_sent; + } + pad = 512 - ((num_bytes + 512) % 512); + if((lsk = lseek(fd1, pad, SEEK_CUR)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if(lsk > stat.st_size){ + i = ((lsk / 10240) + 1) * 10240; + if((lsk = lseek(fd1, i, SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + } + + } + else { + fprintf(stderr, "Entered found block.\n"); + if((lsk = lseek(fd1, buf->target + 124, SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + sprintf(namestr, "%011o", num_bytes); + if((wr = write(fd1, namestr, strlen(namestr))) < 0) { + perror("write 13"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, buf->target + 136, SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + time(&timeval); + sprintf(namestr, "%011lo", timeval); + if((wr = write(fd1, namestr, strlen(namestr))) < 0) { + perror("write 14"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, buf->target, SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if((rd = read(fd1, namestr, 512)) < 0) { + perror("read"); + return total_bytes_sent; + } + for(i = 0; i < 512; i++) { + if(i > 146 && i < 155) + cksum += ' '; + else + cksum += namestr[i]; + } + sprintf(namestr, "%07o", cksum); + if((lsk = lseek(fd1, buf->target + 148, SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if((wr = write(fd1, namestr, strlen(namestr))) < 0) { + perror("write 15"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, buf->target + 512, SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + newpad = 512 - ((num_bytes + 512) % 512); + pad = 512 - ((buf->tsize + 512) % 512); /* CHECKME */ + if(num_bytes == buf->tsize) { + if((wr = write(fd1, buffer, num_bytes)) < 0) { + perror("write 16"); + return total_bytes_sent; + } + } + else if((buf->tsize + pad) == (num_bytes + newpad)) { + if((wr = write(fd1, buffer, num_bytes)) < 0) { + perror("write 17"); + return total_bytes_sent; + } + if(num_bytes < buf->tsize) { + lsk = buf->target + 512 + num_bytes; + for(i = lsk; i < lsk + (buf->tsize - num_bytes); i++) { + if((wr = write(fd1, "\0", 1)) < 0) { + perror("write 18"); + return total_bytes_sent; + } + } + } + } + else if((buf->tsize + pad) > (num_bytes + newpad)) { + if((wr = write(fd1, buffer, num_bytes)) < 0) { + perror("write 17"); + return total_bytes_sent; + } + memset(namestr, '\0', newpad); + if((wr = write(fd1, namestr, newpad)) < 0) { + perror("write 18"); + return total_bytes_sent; + } + dest = buf->target + 512 + num_bytes + newpad; + source = dest + buf->tsize + pad - num_bytes - newpad; + while(rd != 0) { + if((lsk = lseek(fd1, source, SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if((rd = read(fd1, namestr, 4096)) < 0) { + perror("read"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, dest, SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if((wr = write(fd1, namestr, rd)) < 0) { + perror("write 18"); + return total_bytes_sent; + } + source += rd; + dest += wr; + } + pad = 512 - ((buf->size + 512) % 512); + i = buf->lastfile + 512 + buf->size + pad; + i = ((i / 10240) + 1) * 10240; + if(i < stat.st_size) { + if((lsk = ftruncate(fd1, i)) < 0) { + perror("ftruncate"); + return total_bytes_sent; + } + } + else { + if((lsk = ftruncate(fd1, stat.st_size)) < 0) { + perror("ftruncate"); + return total_bytes_sent; + } + } + } + else if((buf->tsize + pad) < (num_bytes + newpad)) { + source = stat.st_size - 4096; + dest = source + num_bytes + newpad - buf->tsize - pad; + do { + if((lsk = lseek(fd1, source, SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if((rd = read(fd1, namestr, 4096)) < 0) { + perror("read"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, dest, SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if((wr = write(fd1, namestr, rd)) < 0) { + perror("write 18"); + return total_bytes_sent; + } + source -= rd; + dest -= wr; + } while(dest > (buf->target + 512 + buf->tsize + pad)); + if((lsk = lseek(fd1, buf->target + 512, SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if((wr = write(fd1, buffer, num_bytes)) < 0) { + perror("write 18"); + return total_bytes_sent; + } + memset(namestr, '\0', newpad); + if((wr = write(fd1, namestr, newpad)) < 0) { + perror("write 19"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, 0, SEEK_END)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if(lsk > stat.st_size) { + i = ((lsk / 10240) + 1) * 10240; + if((lsk = lseek(fd1, i, SEEK_SET)) < 0) { + perror("lseek"); + return total_bytes_sent; + } + } + } + } + } + else { + buf = xf_ptr->private_data; + if((fd1 = open("/test.tar", O_RDWR)) < 0) { + perror("open"); + return total_bytes_sent; + } + if(fstat(fd1, &stat) < 0) { + perror("fstat"); + } + if((lsk = lseek(fd1, buf->target + 124, SEEK_SET)) < 0) { + perror("lseek 1"); + return total_bytes_sent; + } + i = num_bytes + buf->tsize; + sprintf(namestr, "%011o", i); + if((wr = write(fd1, namestr, strlen(namestr))) < 0) { + perror("write 13"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, buf->target + 136, SEEK_SET)) < 0) { + perror("lseek 2"); + return total_bytes_sent; + } + time(&timeval); + sprintf(namestr, "%011lo", timeval); + if((wr = write(fd1, namestr, strlen(namestr))) < 0) { + perror("write 14"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, buf->target, SEEK_SET)) < 0) { + perror("lseek 3"); + return total_bytes_sent; + } + if((rd = read(fd1, namestr, 512)) < 0) { + perror("read"); + return total_bytes_sent; + } + for(i = 0; i < 512; i++) { + if(i > 146 && i < 155) + cksum += ' '; + else + cksum += namestr[i]; + } + sprintf(namestr, "%07o", cksum); + if((lsk = lseek(fd1, buf->target + 148, SEEK_SET)) < 0) { + perror("lseek 4"); + return total_bytes_sent; + } + if((wr = write(fd1, namestr, strlen(namestr))) < 0) { + perror("write 15"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, buf->target + 512 + buf->tsize, SEEK_SET)) < 0) { + perror("lseek 5"); + return total_bytes_sent; + } + newpad = 512 - ((buf->tsize + num_bytes + 512) % 512); + pad = 512 - ((buf->tsize + 512) % 512); /* CHECKME */ + if(pad == (num_bytes + newpad)) { + if((wr = write(fd1, buffer, num_bytes)) < 0) { + perror("write 17"); + return total_bytes_sent; + } + } + else if(pad < (num_bytes + newpad)) { + source = stat.st_size - 4096; + dest = source + num_bytes + newpad - pad; + i = 0; + do { + if(source <= (buf->target + 512 + buf->tsize + pad)) { + source = buf->target + 512 + buf->tsize + pad; + dest = source + num_bytes + newpad - pad; + } + if((lsk = lseek(fd1, source, SEEK_SET)) < 0) { + perror("lseek 6"); + return total_bytes_sent; + } + if((rd = read(fd1, namestr, 4096)) < 0) { + perror("read"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, dest, SEEK_SET)) < 0) { + perror("lseek 7"); + return total_bytes_sent; + } + if((wr = write(fd1, namestr, rd)) < 0) { + perror("write 18"); + return total_bytes_sent; + } + source -= rd; + dest -= wr; + } while(source > (buf->target + 512 + buf->tsize + pad)); + i = buf->target + 512 + buf->tsize; + if((lsk = lseek(fd1, i, SEEK_SET)) < 0) { + perror("lseek 8"); + return total_bytes_sent; + } + if((wr = write(fd1, buffer, num_bytes)) < 0) { + perror("write 18"); + return total_bytes_sent; + } + memset(namestr, '\0', newpad); + if((wr = write(fd1, namestr, newpad)) < 0) { + perror("write 19"); + return total_bytes_sent; + } + if((lsk = lseek(fd1, 0, SEEK_END)) < 0) { + perror("lseek 9"); + return total_bytes_sent; + } + if(lsk > stat.st_size) { + i = ((lsk / 10240) + 1) * 10240; + if((lsk = lseek(fd1, i, SEEK_SET)) < 0) { + perror("lseek 10"); + return total_bytes_sent; + } + } + } + buf->tsize += num_bytes; + } + total_bytes_sent = 0; + close(fd1); + + + /* continue on to the next xform if one exists... */ + if(xf_ptr->next_xform != NULL) + total_bytes_sent = xf_ptr->next_xform->xform(xf_ptr->next_xform, + total_bytes_sent, buffer, state); + else + state[0] = XF_READY; + if(state[0] == XF_UNSENT_DATA) + xf_ptr->unsent_data += 2; + else + state[0] += xf_ptr->unsent_data; + return total_bytes_sent; +} diff -ruN linux/fs/mona/Export/tcp_xforms.c linux-mona/fs/mona/Export/tcp_xforms.c --- linux/fs/mona/Export/tcp_xforms.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/Export/tcp_xforms.c Tue Jun 26 09:17:20 2001 @@ -0,0 +1,788 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef mona_debug +#define mona_debug printf + +#define BLOCK 4096 +#define XF_READY 0 +#define XF_UNSENT_DATA 1 +#define DEBUg + +#if defined DEBUG +#define dbprint(x, y) fprintf(stderr, x, y) +#define dbwrite(x, y, z) fwrite(x, y, z, stderr) +#else +#define dbprint(x, y) /* x y */ +#define dbwrite(x, y, z) /* x y z */ +#endif + +typedef struct xform_info { + int num_inputs; + int num_outputs; + struct xform_info *next_xform; + int (*xform) (struct xform_info *, int, char *, int *); + int unsent_data; + int unsent_data_size; + int id; + int stream_dir; + int argc; + char **argv; + void *private_data; + struct file *filp; + struct inode *inodep; +} XformInfo, *XformInfoPtr; + +int uftpget_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer, int *state) +{ + int rd, wr, fd, sd1, sd2, sd3, size, pid; + int total_bytes_sent = num_bytes; + int a, b, c, d; + int val1, val2, val3; + time_t *t, snum; + struct sockaddr_in comaddr, dataddr1, dataddr2; + char inbuf[4096], ftpaddr[] = "centipede.dcrl.nd.edu"; + char cmd1[80], cmd2[80], myname[80]; + struct hostent *hp; + struct stat status; + + typedef struct finfo { + long index; + char tempfile[L_tmpnam]; + } fileinfo; + fileinfo *buf; + + fprintf(stderr, "Entered ftpget xform.\n"); + if(xf_ptr->unsent_data > 1) { + xf_ptr->unsent_data -= 2; + if(xf_ptr->next_xform != NULL) + total_bytes_sent = xf_ptr->next_xform->xform(xf_ptr->next_xform, + num_bytes, buffer, state); + else + state[0] = XF_READY; + if(state[0] == XF_UNSENT_DATA) + xf_ptr->unsent_data += 2; + else + state[0] += xf_ptr->unsent_data; + return total_bytes_sent; + } + if(num_bytes < 0) + return total_bytes_sent; + dbprint("num_bytes = %d\n", num_bytes); + if(xf_ptr->private_data == NULL) { + fprintf(stderr, "private_data == NULL\n"); + size = sizeof(struct sockaddr_in); + xf_ptr->private_data = (fileinfo *)malloc(sizeof(fileinfo)); + /* xf_ptr->unsent_data = 0; */ + buf = xf_ptr->private_data; + buf->index = 0; + tmpnam(buf->tempfile); + snum = time(t); + srand((unsigned) snum); + val1 = (int)(5000 * (rand() / (RAND_MAX / + 1.0))); + dbprint("val1 = %d\n", val1); + val1 += 5000; + val2 = val1 / 256; + val3 = val1 % 256; + bzero((char *)&comaddr, size); + comaddr.sin_family = AF_INET; + hp = gethostbyname(ftpaddr); + memcpy((char *)&comaddr.sin_addr, hp->h_addr_list[0], hp->h_length); + comaddr.sin_port = htons(21); + bzero((char *)&dataddr1, size); + dataddr1.sin_family = AF_INET; + dataddr1.sin_addr.s_addr = htonl(INADDR_ANY); + dataddr1.sin_port = htons(val1); + if((pid = fork()) < 0) { + perror("fork"); + return total_bytes_sent; + } + else if(pid == 0) { + if((fd = open(buf->tempfile, O_WRONLY | O_CREAT)) < 0) { + perror("open 1"); + exit(1); + } + if((sd2 = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket"); + exit(1); + } + if(bind(sd2, (struct sockaddr *) &dataddr1, size) < 0) { + perror("bind"); + exit(1); + } + listen(sd2, 5); + if((sd3 = accept(sd2, (struct sockaddr *) &dataddr2, &size)) < 0) { + perror("accept"); + exit(1); + } + do { + if((rd = read(sd3, inbuf, BLOCK)) < 0) { + perror("read 1"); + exit(1); + } + if((wr = write(fd, inbuf, rd)) < 0) { + perror("write"); + exit(1); + } + } while(rd != 0); + close(sd2); + close(sd3); + close(fd); + exit(0); + } + else { + if((sd1 = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket"); + return total_bytes_sent; + } + if(connect(sd1, (struct sockaddr *)&comaddr, size) < 0) { + perror("connect"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 2"); + return total_bytes_sent; + } + dbwrite(inbuf, 1, rd); + strcpy(cmd1, "USER ftp\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 3"); + return total_bytes_sent; + } + dbwrite(inbuf, 1, rd); + strcpy(cmd1, "PASS pscherm1@nd.edu\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 4"); + return total_bytes_sent; + } + dbwrite(inbuf, 1, rd); + strcpy(cmd1, "TYPE I\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 5"); + return total_bytes_sent; + } + dbwrite(inbuf, 1, rd); + gethostname(myname, 80); + hp = gethostbyname(myname); + if((a = hp->h_addr_list[0][0]) < 0) + a += 256; + if((b = hp->h_addr_list[0][1]) < 0) + b += 256; + if((c = hp->h_addr_list[0][2]) < 0) + c += 256; + if((d = hp->h_addr_list[0][3]) < 0) + d += 256; + sprintf(cmd1, "PORT %d,%d,%d,%d,", a, b, c, d); + sprintf(cmd2, "%d,%d\n", val2, val3); + strcat(cmd1, cmd2); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 5"); + return total_bytes_sent; + } + dbwrite(inbuf, 1, rd); + strcpy(cmd1, "RETR /pub/test.tar\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 6"); + return total_bytes_sent; + } + dbwrite(inbuf, 1, rd); + strcpy(cmd1, "QUIT\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 6"); + return total_bytes_sent; + } + dbwrite(inbuf, 1, rd); + waitpid(pid, NULL, (int)NULL); + close(sd1); + } + + } + else { + buf = xf_ptr->private_data; + fprintf(stderr, "Well, private_data != NULL\n"); + } + if((fd = open(buf->tempfile, O_RDONLY)) < 0) { + perror("open 2"); + return total_bytes_sent; + } + fstat(fd, &status); + if(lseek(fd, buf->index, SEEK_SET) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if((rd = read(fd, buffer, BLOCK)) < 0) { + perror("read 7"); + return total_bytes_sent; + } + buf->index += rd; + total_bytes_sent = rd; + close(fd); + if(buf->index >= status.st_size) { + unlink(buf->tempfile); + xf_ptr->unsent_data = 0; + free(xf_ptr->private_data); + } + else { + xf_ptr->unsent_data = 1; + xf_ptr->unsent_data_size = status.st_size - buf->index; + state[0] = xf_ptr->unsent_data; + } + + /* continue on to the next xform if one exists... */ + if(xf_ptr->next_xform != NULL) + total_bytes_sent = xf_ptr->next_xform->xform(xf_ptr->next_xform, + total_bytes_sent, buffer, state); + else + state[0] = XF_READY; + if(state[0] == XF_UNSENT_DATA) + xf_ptr->unsent_data += 2; + else + state[0] += xf_ptr->unsent_data; + return total_bytes_sent; +} + +int uftplist_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer, int *state) +{ + int rd, wr, fd, sd1, sd2, sd3, size, pid; + int total_bytes_sent = num_bytes; + int a, b, c, d; + long val1, val2, val3; + time_t *t, snum; + struct sockaddr_in comaddr, dataddr1, dataddr2; + char inbuf[4096], ftpaddr[] = "centipede.dcrl.nd.edu"; + char cmd1[80], cmd2[80], myname[80]; + struct stat stat; + struct hostent *hp; + + typedef struct finfo { + long index; + char tempfile[L_tmpnam]; + } fileinfo; + fileinfo *buf; + + if(xf_ptr->unsent_data > 1) { + xf_ptr->unsent_data -= 2; + if(xf_ptr->next_xform != NULL) + total_bytes_sent = xf_ptr->next_xform->xform(xf_ptr->next_xform, + num_bytes, buffer, state); + else + state[0] = XF_READY; + if(state[0] == XF_UNSENT_DATA) + xf_ptr->unsent_data += 2; + else + state[0] += xf_ptr->unsent_data; + return total_bytes_sent; + } + if(num_bytes < 0) + return total_bytes_sent; + if(xf_ptr->private_data == NULL) { + fprintf(stderr, "private_data == NULL\n"); + size = sizeof(struct sockaddr_in); + xf_ptr->private_data = (fileinfo *)malloc(sizeof(fileinfo)); + buf = xf_ptr->private_data; + buf->index = 0; + tmpnam(buf->tempfile); + snum = time(t); + srand((unsigned) snum); + val1 = (int)(5000 * (rand() / (RAND_MAX / + 1.0))); + val1 += 5000; + val2 = val1 / 256; + val3 = val1 % 256; + bzero((char *)&comaddr, size); + comaddr.sin_family = AF_INET; + hp = gethostbyname(ftpaddr); + memcpy((char *)&comaddr.sin_addr, hp->h_addr_list[0], hp->h_length); + comaddr.sin_port = htons(21); + bzero((char *)&dataddr1, size); + dataddr1.sin_family = AF_INET; + dataddr1.sin_addr.s_addr = htonl(INADDR_ANY); + dataddr1.sin_port = htons(val1); + if((pid = fork()) < 0) { + perror("fork"); + return total_bytes_sent; + } + else if(pid == 0) { + if((fd = open(buf->tempfile, O_WRONLY | O_CREAT)) < 0) { + perror("open"); + exit(1); + } + if((sd2 = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket"); + exit(1); + } + if(bind(sd2, (struct sockaddr *) &dataddr1, size) < 0) { + perror("bind"); + exit(1); + } + listen(sd2, 5); + if((sd3 = accept(sd2, (struct sockaddr *) &dataddr2, &size)) < 0) { + perror("accept"); + exit(1); + } + do { + if((rd = read(sd3, inbuf, BLOCK)) < 0) { + perror("read 1"); + exit(1); + } + if((wr = write(fd, inbuf, rd)) < 0) { + perror("write"); + exit(1); + } + } while(rd != 0); + close(sd2); + close(sd3); + close(fd); + exit(0); + } + else { + if((sd1 = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket"); + return total_bytes_sent; + } + if(connect(sd1, (struct sockaddr *)&comaddr, size) < 0) { + perror("connect"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 2"); + return total_bytes_sent; + } + strcpy(cmd1, "USER ftp\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 3"); + return total_bytes_sent; + } + strcpy(cmd1, "PASS pscherm1@nd.edu\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 4"); + return total_bytes_sent; + } + strcpy(cmd1, "TYPE I\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 5"); + return total_bytes_sent; + } + gethostname(myname, 80); + hp = gethostbyname(myname); + if((a = hp->h_addr_list[0][0]) < 0) + a += 256; + if((b = hp->h_addr_list[0][1]) < 0) + b += 256; + if((c = hp->h_addr_list[0][2]) < 0) + c += 256; + if((d = hp->h_addr_list[0][3]) < 0) + d += 256; + sprintf(cmd1, "PORT %d,%d,%d,%d,", a, b, c, d); + sprintf(cmd2, "%ld,%ld\n", val2, val3); + strcat(cmd1, cmd2); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 5"); + return total_bytes_sent; + } + strcpy(cmd1, "LIST /pub\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 6"); + return total_bytes_sent; + } + strcpy(cmd1, "QUIT\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 4"); + return total_bytes_sent; + } + waitpid(pid, NULL, (int)NULL); + close(sd1); + } + + } + else + buf = xf_ptr->private_data; + if((fd = open(buf->tempfile, O_RDONLY)) < 0) { + perror("open"); + return total_bytes_sent; + } + fstat(fd, &stat); + if(lseek(fd, buf->index, SEEK_SET) < 0) { + perror("lseek"); + return total_bytes_sent; + } + if((rd = read(fd, buffer, 4096)) < 0) { + perror("read 7"); + return total_bytes_sent; + } + buf->index += rd; + total_bytes_sent = rd; + close(fd); + if(buf->index >= stat.st_size) { + unlink(buf->tempfile); + xf_ptr->unsent_data = 0; + free(xf_ptr->private_data); + } + else { + xf_ptr->unsent_data = 1; + xf_ptr->unsent_data_size = stat.st_size - buf->index; + } + state[0] = xf_ptr->unsent_data; + + /* continue on to the next xform if one exists... */ + if(xf_ptr->next_xform != NULL) + total_bytes_sent = xf_ptr->next_xform->xform(xf_ptr->next_xform, + total_bytes_sent, buffer, state); + else + state[0] = XF_READY; + if(state[0] == XF_UNSENT_DATA) + xf_ptr->unsent_data += 2; + else + state[0] += xf_ptr->unsent_data; + dbprint("Made it to the end! %d\n", (int)NULL); + return total_bytes_sent; +} + +int uftpput_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer, int *state) +{ + int rd, wr, fd, sd1, sd2, sd3, size, pid; + int total_bytes_sent = num_bytes; + int a, b, c, d; + long val1, val2, val3; + time_t *t, snum; + struct sockaddr_in comaddr, dataddr1, dataddr2; + char inbuf[4096], ftpaddr[] = "centipede.dcrl.nd.edu"; + char cmd1[80], cmd2[80], myname[80]; + struct hostent *hp; + + typedef struct finfo { + long index; + char tempfile[L_tmpnam]; + int rep; + } fileinfo; + fileinfo *buf; + + if(xf_ptr->unsent_data > 1) { + xf_ptr->unsent_data -= 2; + if(xf_ptr->next_xform != NULL) + total_bytes_sent = xf_ptr->next_xform->xform(xf_ptr->next_xform, + num_bytes, buffer, state); + else + state[0] = XF_READY; + if(state[0] == XF_UNSENT_DATA) + xf_ptr->unsent_data += 2; + else + state[0] += xf_ptr->unsent_data; + return total_bytes_sent; + } + if(xf_ptr->private_data == NULL) { + xf_ptr->private_data = (fileinfo *)malloc(sizeof(fileinfo)); + buf = xf_ptr->private_data; + buf->index = 0; + buf->rep = 0; + tmpnam(buf->tempfile); + } + else + buf = xf_ptr->private_data; + if(num_bytes >= 0) { + dbwrite(buffer, 1, num_bytes); + if((fd = open(buf->tempfile, O_WRONLY | O_CREAT | O_APPEND)) < 0) { + perror("open"); + return total_bytes_sent; + } + if((wr = write(fd, buffer, num_bytes)) < 0) { + perror("write"); + return total_bytes_sent; + } + close(fd); + } + else { + if(buf->rep == 1) + return total_bytes_sent; + buf->rep = 1; + size = sizeof(struct sockaddr_in); + snum = time(t); + srand((unsigned) snum); + val1 = (int)(5000 * (rand() / (RAND_MAX / + 1.0))); + val1 += 5000; + val2 = val1 / 256; + val3 = val1 % 256; + bzero((char *)&comaddr, size); + comaddr.sin_family = AF_INET; + hp = gethostbyname(ftpaddr); + memcpy((char *)&comaddr.sin_addr, hp->h_addr_list[0], hp->h_length); + comaddr.sin_port = htons(21); + bzero((char *)&dataddr1, size); + dataddr1.sin_family = AF_INET; + dataddr1.sin_addr.s_addr = htonl(INADDR_ANY); + dataddr1.sin_port = htons(val1); + if((pid = fork()) < 0) { + perror("fork"); + return total_bytes_sent; + } + else if(pid == 0) { + if((fd = open(buf->tempfile, O_RDONLY)) < 0) { + perror("open"); + exit(1); + } + if((sd2 = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket"); + exit(1); + } + if(bind(sd2, (struct sockaddr *) &dataddr1, size) < 0) { + perror("bind"); + exit(1); + } + listen(sd2, 5); + if((sd3 = accept(sd2, (struct sockaddr *) &dataddr2, &size)) < 0) { + perror("accept"); + exit(1); + } + do { + if((rd = read(fd, inbuf, BLOCK)) < 0) { + perror("read 1"); + exit(1); + } + dbprint("rd = %d\n", rd); + dbwrite(inbuf, 1, rd); + if((wr = write(sd3, inbuf, rd)) < 0) { + perror("write"); + exit(1); + } + } while(rd != 0); + //shutdown(sd3, 1); + close(sd2); + close(sd3); + close(fd); + exit(0); + } + else { + if((sd1 = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket"); + return total_bytes_sent; + } + if(connect(sd1, (struct sockaddr *)&comaddr, size) < 0) { + perror("connect"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 2"); + return total_bytes_sent; + } + dbwrite(inbuf, 1, rd); + strcpy(cmd1, "USER pscherm1\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 3"); + return total_bytes_sent; + } + dbwrite(inbuf, 1, rd); + strcpy(cmd1, "PASS tg0pws0\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 4"); + return total_bytes_sent; + } + dbwrite(inbuf, 1, rd); + strcpy(cmd1, "TYPE I\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 5"); + return total_bytes_sent; + } + dbwrite(inbuf, 1, rd); + gethostname(myname, 80); + hp = gethostbyname(myname); + if((a = hp->h_addr_list[0][0]) < 0) + a += 256; + if((b = hp->h_addr_list[0][1]) < 0) + b += 256; + if((c = hp->h_addr_list[0][2]) < 0) + c += 256; + if((d = hp->h_addr_list[0][3]) < 0) + d += 256; + sprintf(cmd1, "PORT %d,%d,%d,%d,", a, b, c, d); + sprintf(cmd2, "%ld,%ld\n", val2, val3); + strcat(cmd1, cmd2); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 5"); + return total_bytes_sent; + } + dbwrite(inbuf, 1, rd); + strcpy(cmd1, "STOR tempfile\n"); + if((wr = write(sd1, cmd1, strlen(cmd1))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd1, inbuf, BLOCK)) < 0) { + perror("read 6"); + return total_bytes_sent; + } + dbwrite(inbuf, 1, rd); + waitpid(pid, NULL, (int)NULL); + close(sd1); + free(xf_ptr->private_data); + dbprint("Made it past wait. %d\n", (int)NULL); + } + + } + + /* continue on to the next xform if one exists... */ + if(xf_ptr->next_xform != NULL) + total_bytes_sent = xf_ptr->next_xform->xform(xf_ptr->next_xform, + total_bytes_sent, buffer, state); + else + state[0] = XF_READY; + if(state[0] == XF_UNSENT_DATA) + xf_ptr->unsent_data += 2; + else + state[0] += xf_ptr->unsent_data; + dbprint("Made it to the end! %d\n", (int)NULL); + return total_bytes_sent; +} + +int uhttpget_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer, int *state) +{ + int rd, wr, sd, size; + int total_bytes_sent = num_bytes; + struct sockaddr_in sockadd; + char cmd[80]; + + typedef struct finfo { + long index; + } fileinfo; + fileinfo *buf; + + if(xf_ptr->unsent_data > 1) { + xf_ptr->unsent_data -= 2; + if(xf_ptr->next_xform != NULL) + total_bytes_sent = xf_ptr->next_xform->xform(xf_ptr->next_xform, + num_bytes, buffer, state); + else + state[0] = XF_READY; + if(state[0] == XF_UNSENT_DATA) + xf_ptr->unsent_data += 2; + else + state[0] += xf_ptr->unsent_data; + return total_bytes_sent; + } + if(num_bytes < 0) + return total_bytes_sent; + if(xf_ptr->private_data == NULL) { + size = sizeof(struct sockaddr_in); + xf_ptr->private_data = (fileinfo *)malloc(sizeof(fileinfo)); + buf = xf_ptr->private_data; + buf->index = 0; + bzero((char *)&sockadd, size); + sockadd.sin_family = AF_INET; + sockadd.sin_addr.s_addr = inet_addr("129.74.250.105"); + sockadd.sin_port = htons(80); + if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket"); + return total_bytes_sent; + } + if(connect(sd, (struct sockaddr *)&sockadd, size) < 0) { + perror("connect"); + return total_bytes_sent; + } + strcpy(cmd, "GET http://www.nd.edu/index.html\n"); + if((wr = write(sd, cmd, strlen(cmd))) < 0) { + perror("write"); + return total_bytes_sent; + } + if((rd = read(sd, buffer, BLOCK)) < 0) { + perror("read"); + return total_bytes_sent; + } + close(sd); + free(xf_ptr->private_data); + } + else + buf = xf_ptr->private_data; + total_bytes_sent = rd; + /* continue on to the next xform if one exists... */ + if(xf_ptr->next_xform != NULL) + total_bytes_sent = xf_ptr->next_xform->xform(xf_ptr->next_xform, + total_bytes_sent, buffer, state); + else + state[0] = XF_READY; + if(state[0] == XF_UNSENT_DATA) + xf_ptr->unsent_data += 2; + else + state[0] += xf_ptr->unsent_data; + return total_bytes_sent; +} + diff -ruN linux/fs/mona/Export/xforms.c linux-mona/fs/mona/Export/xforms.c --- linux/fs/mona/Export/xforms.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/Export/xforms.c Tue Jun 26 16:41:08 2001 @@ -0,0 +1,340 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef mona_debug +#define mona_debug printf + +#define BLOCK 4096 + +typedef struct Dbl { + int bytes; + char* data; +} dbl, *dblPtr; + +int udoubling_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer) +{ + int i; + dblPtr ptr = (dblPtr) xf_ptr->private_data; + + if(ptr == NULL) { + xf_ptr->private_data = malloc(sizeof(dblPtr)); + ptr = xf_ptr->private_data; + ptr->bytes = num_bytes; + ptr->data = (char*) malloc(num_bytes); + for(i = 0; i < num_bytes; i++) + ptr->data[i] = buffer[i]; + + xf_ptr->state = XF_HAS_DATA; + return num_bytes; + } + else { + for(i = 0; i < num_bytes; i++) + buffer[i] = ptr->data[i]; + free(ptr->data); + free(ptr); + xf_ptr->private_data = NULL; + xf_ptr->state = XF_READY; + return i; + } +} + +int uxor100_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer) { + + int total_bytes_sent = num_bytes; + int i, j; + + for(i=0; i < 101; ++i) + for(j=0; j= 'A')) + buffer[i] += ('a' - 'A'); + ++i; + } + + return total_bytes_sent; +} + + +int ulower2upper_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer) { + int i=0; + int total_bytes_sent = num_bytes; + + while(i < num_bytes) { + if ((buffer[i] <= 'z') && (buffer[i] >= 'a')) + buffer[i] -= ('a' - 'A'); + ++i; + } + + return total_bytes_sent; + +} + +int uswap2_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer) { + int i=1; + char tmp; + int total_bytes_sent = num_bytes; + + while(i < num_bytes) { + tmp = buffer[i-1]; + buffer[i-1] = buffer[i]; + buffer[i] = tmp; + i += 2; + } + + return total_bytes_sent; +} + +int uop100_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer) { + int total_bytes_sent = num_bytes; + int i, j; + + for (i=0; i 0) { + /* open the hitcount file with permissions (octal, 666) = (dec, 438) */ + if ((fd = open("/hits", (O_RDWR | O_CREAT), 438)) >= 0) { + + /* read the old hit count */ + bytes = read(fd, hitcount, 10); + hitcount[bytes] = '\0'; /* terminate the string */ + + /* increment the hitcount */ + hc_int = atoi(hitcount); + ++hc_int; + sprintf(hitcount, "%d", hc_int); + + /* write the incremented hit count to the start of the file */ + lseek(fd, 0, SEEK_SET); + bytes = write(fd, hitcount, strlen(hitcount)); + + /* close the file */ + close(fd); + } + + i=17; + sprintf(&buffer[17], "%s \n", hitcount); + total_bytes_sent = strlen(buffer); + /* @@@ Shouldn't terminate the string, but oh well...it's throwaway code */ + } + + return total_bytes_sent; +} + +/* word count inserted by PS 06-02-98 */ +int uwc_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer) +{ + int i=0; + int total_bytes_sent = num_bytes; + + struct info { + int count; + int word; + int state; + } *info; + + if (xf_ptr->private_data == NULL) { + xf_ptr->private_data = (struct info *)malloc(sizeof(struct info)); + info = xf_ptr->private_data; + info->count = 0; + } + else + info = xf_ptr->private_data; + + while (i < num_bytes) { + if ((buffer[i] == ' ') || (buffer[i] == '\t') || (buffer[i] == '\n')) { + if(info->word == 1) { + info->count++; + info->word = 0; + } + } + else + info->word = 1; + ++i; + } + + if(num_bytes < BLOCK) { + if(buffer[i - 1] != ' ' && buffer[i - 1] != '\t' && buffer[i - 1] != '\n') + info->count++; + sprintf(buffer, "Total number of words: %d.\n", info->count); + total_bytes_sent = strlen(buffer); + } + else + total_bytes_sent = 0; + + return total_bytes_sent; +} + +/* swap pair inserted by PS 06-03-98 */ +int uswappair_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer) +{ + int i=0; + char tempbuffer[2]; + int total_bytes_sent = num_bytes; + + if(num_bytes < 0) { + free(xf_ptr->private_data); + return total_bytes_sent = 0; + } + while (i < num_bytes) { + tempbuffer[0] = buffer[i]; + tempbuffer[1] = buffer[i + 1]; + buffer[i] = buffer[i + 2]; + buffer[i + 1] = buffer[i + 3]; + buffer[i + 2] = tempbuffer[0]; + buffer[i + 3] = tempbuffer[1]; + i += 4; + } + + return total_bytes_sent; +} + +int uverctl_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer) +{ + int i, fd1, fd2; + FILE *fp; + char outfile[80]; + char version[10]; + int total_bytes_sent = num_bytes; + + void *buf; + int amount_read = -2; + int amount_written; + + if(num_bytes < 0) { + free(xf_ptr->private_data); + return total_bytes_sent = 0; + } + fp = fopen("foo1.raw.ver", "r"); + if(fp == NULL) { + strcpy(outfile, "foo1.raw.1"); + sprintf(version, "%s", "1"); + fp = fopen("foo1.raw.ver", "w"); + fprintf(fp, "%s", version); + } + else { + fscanf(fp, "%s", version); + i = atoi(version); + i++; + sprintf(version, "%d", i); + strcpy(outfile, "foo1.raw."); + strcat(outfile, version); + fclose(fp); + fp = fopen("foo1.raw.ver", "w"); + fprintf(fp, "%s", version); + } + + fclose(fp); + + fd1 = open("foo1.raw", O_RDONLY); + if (fd1 == -1) { + perror("open 1"); + return total_bytes_sent; + } + fd2 = creat(outfile, 0744); + if (fd2 == -1) { + perror("creat"); + return total_bytes_sent; + } + fd2 = open(outfile, O_WRONLY); + if (fd2 == -1) { + perror("open 2"); + return total_bytes_sent; + } + buf = (void *)malloc(BLOCK); + while(amount_read != 0) { + amount_read = read(fd1, buf, BLOCK); + if(amount_read == -1) + perror("read"); + amount_written = write(fd2, buf, amount_read); + if(amount_written == -1) + perror("write"); + } + close(fd1); + close(fd2); + + return total_bytes_sent; +} + + + diff -ruN linux/fs/mona/Makefile linux-mona/fs/mona/Makefile --- linux/fs/mona/Makefile Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/Makefile Tue Jun 26 00:24:42 2001 @@ -0,0 +1,18 @@ +# +# Makefile for the linux mona-filesystem routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +O_TARGET := mona.o + +obj-y := acl.o balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ + mioctl.o mopen.o mread.o mrelease.o mwrite.o namei.o super.o \ + symlink.o xforms.o k2u.o + +obj-m := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff -ruN linux/fs/mona/Utilities/lnx.c linux-mona/fs/mona/Utilities/lnx.c --- linux/fs/mona/Utilities/lnx.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/Utilities/lnx.c Fri Jun 15 16:21:05 2001 @@ -0,0 +1,179 @@ +#include +#include +#include +#include + +int i; +char *xlptr; +char xlink[4096]; + +void xform(int, char **); + +void params(int argc, char **argv) +{ + int size, num; + + // Only process as many arguments as we get + if(i >= argc) + return; + // If there are parameters, process them + if((argv[i][0] == '-') && (argv[i][1] == 'p')) { + // Make sure we don't overflow buffer + if(((xlptr + 3) - xlink) >= 4096) { + fprintf(stderr, "lnx: too many arguments\n"); + exit(1); + } + // Copy param flag, add space, increment pointer and counter + xlptr[0] = '-'; + xlptr[1] = 'p'; + xlptr[2] = ' '; + xlptr += 3; + i++; + size = strlen(argv[i]); + // Make sure we don't overflow buffer + if(((xlptr + size + 1) - xlink) >= 4096) { + fprintf(stderr, "lnx: too many arguments\n"); + exit(1); + } + // Copy param number, add space, increment pointer and counter + memcpy(xlptr, argv[i], size); + xlptr += size; + *xlptr = ' '; + xlptr++; + num = atoi(argv[i]) + i + 1; + i++; + for( ; i < num; i++) { + size = strlen(argv[i]); + // Make sure we don't overflow buffer + if(((xlptr + size + 1) - xlink) >= 4096) { + fprintf(stderr, "lnx: too many arguments\n"); + exit(1); + } + // Copy parameter, add space, increment pointer and counter + memcpy(xlptr, argv[i], size); + xlptr += size; + *xlptr = ' '; + xlptr++; + } + } +} + +void optxform(int argc, char **argv, char type) +{ + // Only process as many arguments as we get + if(i >= argc) + return; + // Check for optional xforms + if(argv[i][0] == '-') + return; + // Make sure we don't overflow buffer + if(((xlptr + 3) - xlink) >= 4096) { + fprintf(stderr, "lnx: too many arguments\n"); + exit(1); + } + // Copy type flag, add space, increment pointer and counter + xlptr[0] = '-'; + xlptr[1] = type; + xlptr[2] = ' '; + xlptr += 3; + // Let the xform function do the work + xform(argc, argv); + // Check for more optional xforms on this stream + optxform(argc, argv, type); +} + +void xform(int argc, char **argv) +{ + int size; + + // Only process as many arguments as we get + if(i >= argc) + return; + // Shouldn't be a '-' flag here + if(argv[i][0] == '-') { + fprintf(stderr, "Unexpected input: %s\n", argv[i]); + exit(1); + } + size = strlen(argv[i]); + // Make sure we don't overflow buffer + if(((xlptr + size + 1) - xlink) >= 4096) { + fprintf(stderr, "lnx: too many arguments\n"); + exit(1); + } + // Copy xform, add space, increment pointer and counter + memcpy(xlptr, argv[i], size); + xlptr += size; + *xlptr = ' '; + xlptr++; + i++; + // Process parameters + params(argc, argv); +} + +void streamarg(int argc, char **argv) +{ + char type; + + // Process xform arguments + while(1) { + // Only process as many arguments as we get + if(i >= argc) + return; + // Looking for a "-r," "-w," or "-o" + if(argv[i][0] == '-') { + if((argv[i][1] == 'r') || (argv[i][1] == 'w') || (argv[i][1] == 'o')) { + // Make sure we don't overflow buffer + if(((xlptr + 3) - xlink) >= 4096) { + fprintf(stderr, "lnx: too many arguments\n"); + exit(1); + } + // Copy type flag, add space, increment pointer and counter + xlptr[0] = '-'; + xlptr[1] = type = argv[i][1]; + xlptr[2] = ' '; + xlptr += 3; + i++; + // Process first transform and optional others + xform(argc, argv); + optxform(argc, argv, type); + } + else { + fprintf(stderr, "lnx: unexpected input (%s)\n", argv[i]); + exit(1); + } + } + else { + fprintf(stderr, "lnx: unexpected input (%s)\n", argv[i]); + exit(1); + } + } +} + +int main(int argc, char **argv) +{ + int size = 0; + + i = 1; + xlptr = xlink; + // Make sure it's at least a normal symlink + if(argc < 3) { + fprintf(stderr, "Usage: lnx \n"); + exit(1); + } + // Copy basefile, add space, increment pointer and counter + size = strlen(argv[i]); + memcpy(xlptr, argv[i], size); + xlptr += size; + *xlptr = '\n'; + xlptr++; + i += 2; + // Process transforms, if any + if(argc > 3) + streamarg(argc, argv); + // Create symlink: xlink == contents, argv[2] == linkname + if(symlink(xlink, argv[2]) < 0) { + perror("lnx"); + exit(1); + } + return 0; +} diff -ruN linux/fs/mona/acl.c linux-mona/fs/mona/acl.c --- linux/fs/mona/acl.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/acl.c Mon Feb 19 23:23:00 2001 @@ -0,0 +1,17 @@ +/* + * linux/fs/mona/acl.c + * + * Copyright (C) 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + */ + +#include +#include + + +/* + * This file will contain the Access Control Lists management for the + * Mona file system. + */ diff -ruN linux/fs/mona/balloc.c linux-mona/fs/mona/balloc.c --- linux/fs/mona/balloc.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/balloc.c Thu Jun 21 14:17:38 2001 @@ -0,0 +1,773 @@ +/* + * linux/fs/mona/balloc.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * Enhanced block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + */ + +/* + * balloc.c contains the blocks allocation and deallocation routines + */ + +/* + * The free blocks are managed by bitmaps. A file system contains several + * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap + * block for inodes, N blocks for the inode table and data blocks. + * + * The file system contains group descriptors which are located after the + * super block. Each descriptor contains the number of the bitmap block and + * the free blocks count in the block. The descriptors are loaded in memory + * when a file system is mounted (see mona_read_super). + */ + +#include +#include +#include +#include +#include + + +#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1) + +struct mona_group_desc * mona_get_group_desc(struct super_block * sb, + unsigned int block_group, + struct buffer_head ** bh) +{ + unsigned long group_desc; + unsigned long desc; + struct mona_group_desc * gdp; + + if (block_group >= sb->u.mona_sb.s_groups_count) { + mona_error (sb, "mona_get_group_desc", + "block_group >= groups_count - " + "block_group = %d, groups_count = %lu", + block_group, sb->u.mona_sb.s_groups_count); + + return NULL; + } + + group_desc = block_group / MONA_DESC_PER_BLOCK(sb); + desc = block_group % MONA_DESC_PER_BLOCK(sb); + if (!sb->u.mona_sb.s_group_desc[group_desc]) { + mona_error (sb, "mona_get_group_desc", + "Group descriptor not loaded - " + "block_group = %d, group_desc = %lu, desc = %lu", + block_group, group_desc, desc); + return NULL; + } + + gdp = (struct mona_group_desc *) + sb->u.mona_sb.s_group_desc[group_desc]->b_data; + if (bh) + *bh = sb->u.mona_sb.s_group_desc[group_desc]; + return gdp + desc; +} + +/* + * Read the bitmap for a given block_group, reading into the specified + * slot in the superblock's bitmap cache. + * + * Return >=0 on success or a -ve error code. + */ + +static int read_block_bitmap (struct super_block * sb, + unsigned int block_group, + unsigned long bitmap_nr) +{ + struct mona_group_desc * gdp; + struct buffer_head * bh = NULL; + int retval = -EIO; + + gdp = mona_get_group_desc (sb, block_group, NULL); + if (!gdp) + goto error_out; + retval = 0; + bh = bread (sb->s_dev, le32_to_cpu(gdp->bg_block_bitmap), sb->s_blocksize); + if (!bh) { + mona_error (sb, "read_block_bitmap", + "Cannot read block bitmap - " + "block_group = %d, block_bitmap = %lu", + block_group, (unsigned long) gdp->bg_block_bitmap); + retval = -EIO; + } + /* + * On IO error, just leave a zero in the superblock's block pointer for + * this group. The IO will be retried next time. + */ +error_out: + sb->u.mona_sb.s_block_bitmap_number[bitmap_nr] = block_group; + sb->u.mona_sb.s_block_bitmap[bitmap_nr] = bh; + return retval; +} + +/* + * load_block_bitmap loads the block bitmap for a blocks group + * + * It maintains a cache for the last bitmaps loaded. This cache is managed + * with a LRU algorithm. + * + * Notes: + * 1/ There is one cache per mounted file system. + * 2/ If the file system contains less than MONA_MAX_GROUP_LOADED groups, + * this function reads the bitmap without maintaining a LRU cache. + * + * Return the slot used to store the bitmap, or a -ve error code. + */ +static int __load_block_bitmap (struct super_block * sb, + unsigned int block_group) +{ + int i, j, retval = 0; + unsigned long block_bitmap_number; + struct buffer_head * block_bitmap; + + if (block_group >= sb->u.mona_sb.s_groups_count) + mona_panic (sb, "load_block_bitmap", + "block_group >= groups_count - " + "block_group = %d, groups_count = %lu", + block_group, sb->u.mona_sb.s_groups_count); + + if (sb->u.mona_sb.s_groups_count <= MONA_MAX_GROUP_LOADED) { + if (sb->u.mona_sb.s_block_bitmap[block_group]) { + if (sb->u.mona_sb.s_block_bitmap_number[block_group] == + block_group) + return block_group; + mona_error (sb, "__load_block_bitmap", + "block_group != block_bitmap_number"); + } + retval = read_block_bitmap (sb, block_group, block_group); + if (retval < 0) + return retval; + return block_group; + } + + for (i = 0; i < sb->u.mona_sb.s_loaded_block_bitmaps && + sb->u.mona_sb.s_block_bitmap_number[i] != block_group; i++) + ; + if (i < sb->u.mona_sb.s_loaded_block_bitmaps && + sb->u.mona_sb.s_block_bitmap_number[i] == block_group) { + block_bitmap_number = sb->u.mona_sb.s_block_bitmap_number[i]; + block_bitmap = sb->u.mona_sb.s_block_bitmap[i]; + for (j = i; j > 0; j--) { + sb->u.mona_sb.s_block_bitmap_number[j] = + sb->u.mona_sb.s_block_bitmap_number[j - 1]; + sb->u.mona_sb.s_block_bitmap[j] = + sb->u.mona_sb.s_block_bitmap[j - 1]; + } + sb->u.mona_sb.s_block_bitmap_number[0] = block_bitmap_number; + sb->u.mona_sb.s_block_bitmap[0] = block_bitmap; + + /* + * There's still one special case here --- if block_bitmap == 0 + * then our last attempt to read the bitmap failed and we have + * just ended up caching that failure. Try again to read it. + */ + if (!block_bitmap) + retval = read_block_bitmap (sb, block_group, 0); + } else { + if (sb->u.mona_sb.s_loaded_block_bitmaps < MONA_MAX_GROUP_LOADED) + sb->u.mona_sb.s_loaded_block_bitmaps++; + else + brelse (sb->u.mona_sb.s_block_bitmap[MONA_MAX_GROUP_LOADED - 1]); + for (j = sb->u.mona_sb.s_loaded_block_bitmaps - 1; j > 0; j--) { + sb->u.mona_sb.s_block_bitmap_number[j] = + sb->u.mona_sb.s_block_bitmap_number[j - 1]; + sb->u.mona_sb.s_block_bitmap[j] = + sb->u.mona_sb.s_block_bitmap[j - 1]; + } + retval = read_block_bitmap (sb, block_group, 0); + } + return retval; +} + +/* + * Load the block bitmap for a given block group. First of all do a couple + * of fast lookups for common cases and then pass the request onto the guts + * of the bitmap loader. + * + * Return the slot number of the group in the superblock bitmap cache's on + * success, or a -ve error code. + * + * There is still one inconsistency here --- if the number of groups in this + * filesystems is <= MONA_MAX_GROUP_LOADED, then we have no way of + * differentiating between a group for which we have never performed a bitmap + * IO request, and a group for which the last bitmap read request failed. + */ +static inline int load_block_bitmap (struct super_block * sb, + unsigned int block_group) +{ + int slot; + + /* + * Do the lookup for the slot. First of all, check if we're asking + * for the same slot as last time, and did we succeed that last time? + */ + if (sb->u.mona_sb.s_loaded_block_bitmaps > 0 && + sb->u.mona_sb.s_block_bitmap_number[0] == block_group && + sb->u.mona_sb.s_block_bitmap[0]) { + return 0; + } + /* + * Or can we do a fast lookup based on a loaded group on a filesystem + * small enough to be mapped directly into the superblock? + */ + else if (sb->u.mona_sb.s_groups_count <= MONA_MAX_GROUP_LOADED && + sb->u.mona_sb.s_block_bitmap_number[block_group] == block_group && + sb->u.mona_sb.s_block_bitmap[block_group]) { + slot = block_group; + } + /* + * If not, then do a full lookup for this block group. + */ + else { + slot = __load_block_bitmap (sb, block_group); + } + + /* + * <0 means we just got an error + */ + if (slot < 0) + return slot; + + /* + * If it's a valid slot, we may still have cached a previous IO error, + * in which case the bh in the superblock cache will be zero. + */ + if (!sb->u.mona_sb.s_block_bitmap[slot]) + return -EIO; + + /* + * Must have been read in OK to get this far. + */ + return slot; +} + +void mona_free_blocks (const struct inode * inode, unsigned long block, + unsigned long count) +{ + struct buffer_head * bh; + struct buffer_head * bh2; + unsigned long block_group; + unsigned long bit; + unsigned long i; + int bitmap_nr; + unsigned long overflow; + struct super_block * sb; + struct mona_group_desc * gdp; + struct mona_super_block * ms; + + sb = inode->i_sb; + if (!sb) { + printk ("mona_free_blocks: nonexistent device"); + return; + } + lock_super (sb); + ms = sb->u.mona_sb.s_ms; + if (block < le32_to_cpu(ms->s_first_data_block) || + (block + count) > le32_to_cpu(ms->s_blocks_count)) { + mona_error (sb, "mona_free_blocks", + "Freeing blocks not in datazone - " + "block = %lu, count = %lu", block, count); + goto error_return; + } + + +do_more: + overflow = 0; + block_group = (block - le32_to_cpu(ms->s_first_data_block)) / + MONA_BLOCKS_PER_GROUP(sb); + bit = (block - le32_to_cpu(ms->s_first_data_block)) % + MONA_BLOCKS_PER_GROUP(sb); + /* + * Check to see if we are freeing blocks across a group + * boundary. + */ + if (bit + count > MONA_BLOCKS_PER_GROUP(sb)) { + overflow = bit + count - MONA_BLOCKS_PER_GROUP(sb); + count -= overflow; + } + bitmap_nr = load_block_bitmap (sb, block_group); + if (bitmap_nr < 0) + goto error_return; + + bh = sb->u.mona_sb.s_block_bitmap[bitmap_nr]; + gdp = mona_get_group_desc (sb, block_group, &bh2); + if (!gdp) + goto error_return; + + if( in_range (le32_to_cpu(gdp->bg_block_bitmap), block, count) || + in_range (le32_to_cpu(gdp->bg_inode_bitmap), block, count) || + in_range (block, le32_to_cpu(gdp->bg_inode_table), + sb->u.mona_sb.s_itb_per_group) || + in_range (block + count - 1, le32_to_cpu(gdp->bg_inode_table), + sb->u.mona_sb.s_itb_per_group)) + mona_error (sb, "mona_free_blocks", + "Freeing blocks in system zones - " + "Block = %lu, count = %lu", + block, count); + + for (i = 0; i < count; i++) { + if (!mona_clear_bit (bit + i, bh->b_data)) + mona_error (sb, "mona_free_blocks", + "bit already cleared for block %lu", + block); + else { + DQUOT_FREE_BLOCK(sb, inode, 1); + gdp->bg_free_blocks_count = + cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)+1); + ms->s_free_blocks_count = + cpu_to_le32(le32_to_cpu(ms->s_free_blocks_count)+1); + } + } + + mark_buffer_dirty(bh2); + mark_buffer_dirty(sb->u.mona_sb.s_sbh); + + mark_buffer_dirty(bh); + if (sb->s_flags & MS_SYNCHRONOUS) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + if (overflow) { + block += count; + count = overflow; + goto do_more; + } + sb->s_dirt = 1; +error_return: + unlock_super (sb); + return; +} + +/* + * mona_new_block uses a goal block to assist allocation. If the goal is + * free, or there is a free block within 32 blocks of the goal, that block + * is allocated. Otherwise a forward search is made for a free block; within + * each block group the search first looks for an entire free byte in the block + * bitmap, and then for any free bit if that fails. + */ +int mona_new_block (const struct inode * inode, unsigned long goal, + u32 * prealloc_count, u32 * prealloc_block, int * err) +{ + struct buffer_head * bh; + struct buffer_head * bh2; + char * p, * r; + int i, j, k, tmp; + int bitmap_nr; + struct super_block * sb; + struct mona_group_desc * gdp; + struct mona_super_block * ms; + +#ifdef MONAFS_DEBUG + static int goal_hits = 0, goal_attempts = 0; +#endif + *err = -ENOSPC; + sb = inode->i_sb; + if (!sb) { + printk ("mona_new_block: nonexistent device"); + return 0; + } + + lock_super (sb); + ms = sb->u.mona_sb.s_ms; + if (le32_to_cpu(ms->s_free_blocks_count) <= le32_to_cpu(ms->s_r_blocks_count) && + ((sb->u.mona_sb.s_resuid != current->fsuid) && + (sb->u.mona_sb.s_resgid == 0 || + !in_group_p (sb->u.mona_sb.s_resgid)) && + !capable(CAP_SYS_RESOURCE))) { + unlock_super(sb); + goto out; + } + +repeat: + /* + * First, test whether the goal block is free. + */ + if (goal < le32_to_cpu(ms->s_first_data_block) || + goal >= le32_to_cpu(ms->s_blocks_count)) + goal = le32_to_cpu(ms->s_first_data_block); + i = (goal - le32_to_cpu(ms->s_first_data_block)) / MONA_BLOCKS_PER_GROUP(sb); + gdp = mona_get_group_desc (sb, i, &bh2); + if (!gdp) + goto io_error; + + if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) { + j = ((goal - le32_to_cpu(ms->s_first_data_block)) % MONA_BLOCKS_PER_GROUP(sb)); +#ifdef MONAFS_DEBUG + if (j) + goal_attempts++; +#endif + bitmap_nr = load_block_bitmap (sb, i); + if (bitmap_nr < 0) + goto io_error; + + bh = sb->u.mona_sb.s_block_bitmap[bitmap_nr]; + + if (!mona_test_bit(j, bh->b_data)) { +#ifdef MONAFS_DEBUG + goal_hits++; +#endif + goto got_block; + } + if (j) { + /* + * The goal was occupied; search forward for a free + * block within the next XX blocks. + * + * end_goal is more or less random, but it has to be + * less than MONA_BLOCKS_PER_GROUP. Aligning up to the + * next 64-bit boundary is simple.. + */ + int end_goal = (j + 63) & ~63; + j = mona_find_next_zero_bit(bh->b_data, end_goal, j); + if (j < end_goal) + goto got_block; + } + + /* + * There has been no free block found in the near vicinity + * of the goal: do a search forward through the block groups, + * searching in each group first for an entire free byte in + * the bitmap and then for any free bit. + * + * Search first in the remainder of the current group; then, + * cyclicly search through the rest of the groups. + */ + p = ((char *) bh->b_data) + (j >> 3); + r = memscan(p, 0, (MONA_BLOCKS_PER_GROUP(sb) - j + 7) >> 3); + k = (r - ((char *) bh->b_data)) << 3; + if (k < MONA_BLOCKS_PER_GROUP(sb)) { + j = k; + goto search_back; + } + + k = mona_find_next_zero_bit ((unsigned long *) bh->b_data, + MONA_BLOCKS_PER_GROUP(sb), + j); + if (k < MONA_BLOCKS_PER_GROUP(sb)) { + j = k; + goto got_block; + } + } + + /* + * Now search the rest of the groups. We assume that + * i and gdp correctly point to the last group visited. + */ + for (k = 0; k < sb->u.mona_sb.s_groups_count; k++) { + i++; + if (i >= sb->u.mona_sb.s_groups_count) + i = 0; + gdp = mona_get_group_desc (sb, i, &bh2); + if (!gdp) { + *err = -EIO; + unlock_super(sb); + goto out; + } + if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) + break; + } + if (k >= sb->u.mona_sb.s_groups_count) + unlock_super(sb); + goto out; + bitmap_nr = load_block_bitmap (sb, i); + if (bitmap_nr < 0) + goto io_error; + + bh = sb->u.mona_sb.s_block_bitmap[bitmap_nr]; + r = memscan(bh->b_data, 0, MONA_BLOCKS_PER_GROUP(sb) >> 3); + j = (r - bh->b_data) << 3; + if (j < MONA_BLOCKS_PER_GROUP(sb)) + goto search_back; + else + j = mona_find_first_zero_bit ((unsigned long *) bh->b_data, + MONA_BLOCKS_PER_GROUP(sb)); + if (j >= MONA_BLOCKS_PER_GROUP(sb)) { + mona_error (sb, "mona_new_block", + "Free blocks count corrupted for block group %d", i); + unlock_super(sb); + goto out; + } + +search_back: + /* + * We have succeeded in finding a free byte in the block + * bitmap. Now search backwards up to 7 bits to find the + * start of this group of free blocks. + */ + for (k = 0; k < 7 && j > 0 && !mona_test_bit (j - 1, bh->b_data); k++, j--); + +got_block: + + /* + * Check quota for allocation of this block. + */ + if(DQUOT_ALLOC_BLOCK(sb, inode, 1)) { + unlock_super(sb); + *err = -EDQUOT; + goto out; + } + + tmp = j + i * MONA_BLOCKS_PER_GROUP(sb) + le32_to_cpu(ms->s_first_data_block); + + if(tmp == le32_to_cpu(gdp->bg_block_bitmap) || + tmp == le32_to_cpu(gdp->bg_inode_bitmap) || + in_range (tmp, le32_to_cpu(gdp->bg_inode_table), + sb->u.mona_sb.s_itb_per_group)) + mona_error (sb, "mona_new_block", + "Allocating block in system zone - " + "block = %u", tmp); + + if (mona_set_bit (j, bh->b_data)) { + mona_warning (sb, "mona_new_block", + "bit already set for block %d", j); + DQUOT_FREE_BLOCK(sb, inode, 1); + goto repeat; + } + + /* + * Do block preallocation now if required. + */ +#ifdef MONA_PREALLOCATE + /* Writer: ->i_prealloc* */ + if (prealloc_block) { + int prealloc_goal; + + prealloc_goal = ms->s_prealloc_blocks ? + ms->s_prealloc_blocks : MONA_DEFAULT_PREALLOC_BLOCKS; + + *prealloc_count = 0; + *prealloc_block = tmp + 1; + /* Writer: end */ + for (k = 1; + k < prealloc_goal && (j + k) < MONA_BLOCKS_PER_GROUP(sb); + k++) { + if (DQUOT_PREALLOC_BLOCK(sb, inode, 1)) + break; + if(mona_set_bit(j + k, bh->b_data)) { + DQUOT_FREE_BLOCK(sb, inode, 1); + break; + } + (*prealloc_count)++; + } + gdp->bg_free_blocks_count = + cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - + *prealloc_count); + ms->s_free_blocks_count = + cpu_to_le32(le32_to_cpu(ms->s_free_blocks_count) - + *prealloc_count); + } +#endif + + j = tmp; + + mark_buffer_dirty(bh); + if (sb->s_flags & MS_SYNCHRONOUS) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + + if (j >= le32_to_cpu(ms->s_blocks_count)) { + mona_error (sb, "mona_new_block", + "block -> blocks count - " + "block_group = %d, block=%d", i, j); + unlock_super(sb); + goto out; + } + + gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1); + mark_buffer_dirty(bh2); + ms->s_free_blocks_count = cpu_to_le32(le32_to_cpu(ms->s_free_blocks_count) - 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh); + sb->s_dirt = 1; + unlock_super (sb); + *err = 0; + return j; + +io_error: + *err = -EIO; + +out: + unlock_super (sb); + return 0; +} + +unsigned long mona_count_free_blocks (struct super_block * sb) +{ +#ifdef MONAFS_DEBUG + struct mona_super_block * ms; + unsigned long desc_count, bitmap_count, x; + int bitmap_nr; + struct mona_group_desc * gdp; + int i; + + lock_super (sb); + ms = sb->u.mona_sb.s_ms; + desc_count = 0; + bitmap_count = 0; + gdp = NULL; + for (i = 0; i < sb->u.mona_sb.s_groups_count; i++) { + gdp = mona_get_group_desc (sb, i, NULL); + if (!gdp) + continue; + desc_count += le16_to_cpu(gdp->bg_free_blocks_count); + bitmap_nr = load_block_bitmap (sb, i); + if (bitmap_nr < 0) + continue; + + x = mona_count_free (sb->u.mona_sb.s_block_bitmap[bitmap_nr], + sb->s_blocksize); + printk ("group %d: stored = %d, counted = %lu\n", + i, le16_to_cpu(gdp->bg_free_blocks_count), x); + bitmap_count += x; + } + printk("mona_count_free_blocks: stored = %du, computed = %lu, %lu\n", + le32_to_cpu(ms->s_free_blocks_count), desc_count, bitmap_count); + unlock_super (sb); + return bitmap_count; +#else + return le32_to_cpu(sb->u.mona_sb.s_ms->s_free_blocks_count); +#endif +} + +static inline int block_in_use (unsigned long block, + struct super_block * sb, + unsigned char * map) +{ + return mona_test_bit ((block - le32_to_cpu(sb->u.mona_sb.s_ms->s_first_data_block)) % + MONA_BLOCKS_PER_GROUP(sb), map); +} + +static int test_root(int a, int b) +{ + if (a == 0) + return 1; + while (1) { + if (a == 1) + return 1; + if (a % b) + return 0; + a = a / b; + } +} + +int mona_group_sparse(int group) +{ + return (test_root(group, 3) || test_root(group, 5) || + test_root(group, 7)); +} + +/** + * mona_bg_has_super - number of blocks used by the superblock in group + * @sb: superblock for filesystem + * @group: group number to check + * + * Return the number of blocks used by the superblock (primary or backup) + * in this group. Currently this will be only 0 or 1. + */ +int mona_bg_has_super(struct super_block *sb, int group) +{ + if (MONA_HAS_RO_COMPAT_FEATURE(sb,MONA_FEATURE_RO_COMPAT_SPARSE_SUPER)&& + !mona_group_sparse(group)) + return 0; + return 1; +} + +/** + * mona_bg_num_gdb - number of blocks used by the group table in group + * @sb: superblock for filesystem + * @group: group number to check + * + * Return the number of blocks used by the group descriptor table + * (primary or backup) in this group. In the future there may be a + * different number of descriptor blocks in each group. + */ +unsigned long mona_bg_num_gdb(struct super_block *sb, int group) +{ + if (MONA_HAS_RO_COMPAT_FEATURE(sb,MONA_FEATURE_RO_COMPAT_SPARSE_SUPER)&& + !mona_group_sparse(group)) + return 0; + return MONA_SB(sb)->s_gdb_count; +} + + + +void mona_check_blocks_bitmap (struct super_block * sb) +{ + struct buffer_head * bh; + struct mona_super_block * ms; + unsigned long desc_count, bitmap_count, x; + unsigned long desc_blocks; + int bitmap_nr; + struct mona_group_desc * gdp; + int i, j; + + lock_super(sb); + ms = sb->u.mona_sb.s_ms; + desc_count = 0; + bitmap_count = 0; + gdp = NULL; + desc_blocks=(sb->u.mona_sb.s_groups_count + MONA_DESC_PER_BLOCK(sb) - 1) / + MONA_DESC_PER_BLOCK(sb); + for (i = 0; i < sb->u.mona_sb.s_groups_count; i++) { + gdp = mona_get_group_desc (sb, i, NULL); + if (!gdp) + continue; + desc_count += le16_to_cpu(gdp->bg_free_blocks_count); + bitmap_nr = load_block_bitmap (sb, i); + if (bitmap_nr < 0) + continue; + + bh = MONA_SB(sb)->s_block_bitmap[bitmap_nr]; + + if (!(sb->u.mona_sb.s_feature_ro_compat & + MONA_FEATURE_RO_COMPAT_SPARSE_SUPER) || + mona_group_sparse(i)) { + if (!mona_test_bit (0, bh->b_data)) + mona_error (sb, "mona_check_blocks_bitmap", + "Superblock in group %d " + "is marked free", i); + + for (j = 0; j < desc_blocks; j++) + if (!mona_test_bit (j + 1, bh->b_data)) + mona_error (sb, + "mona_check_blocks_bitmap", + "Descriptor block #%d in group " + "%d is marked free", j, i); + } + + if (!block_in_use (le32_to_cpu(gdp->bg_block_bitmap), sb, bh->b_data)) + mona_error (sb, "mona_check_blocks_bitmap", + "Block bitmap for group %d is marked free", + i); + + if (!block_in_use (le32_to_cpu(gdp->bg_inode_bitmap), sb, bh->b_data)) + mona_error (sb, "mona_check_blocks_bitmap", + "Inode bitmap for group %d is marked free", + i); + + for (j = 0; j < sb->u.mona_sb.s_itb_per_group; j++) + if (!block_in_use (le32_to_cpu(gdp->bg_inode_table) + j, sb, bh->b_data)) + mona_error (sb, "mona_check_blocks_bitmap", + "Block #%d of the inode table in " + "group %d is marked free", j, i); + + x = mona_count_free (bh, sb->s_blocksize); + if (le16_to_cpu(gdp->bg_free_blocks_count) != x) + mona_error (sb, "mona_check_blocks_bitmap", + "Wrong free blocks count for group %d, " + "stored = %d, counted = %lu", i, + le16_to_cpu(gdp->bg_free_blocks_count), x); + bitmap_count += x; + } + if (le32_to_cpu(ms->s_free_blocks_count) != bitmap_count) + mona_error (sb, "mona_check_blocks_bitmap", + "Wrong free blocks count in super block, " + "stored = %lu, counted = %lu", + (unsigned long) le32_to_cpu(ms->s_free_blocks_count), bitmap_count); +} diff -ruN linux/fs/mona/bitmap.c linux-mona/fs/mona/bitmap.c --- linux/fs/mona/bitmap.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/bitmap.c Thu Jan 11 15:36:15 2001 @@ -0,0 +1,27 @@ +/* + * linux/fs/mona/bitmap.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + */ + +#include +#include + + +static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; + +unsigned long mona_count_free (struct buffer_head * map, unsigned int numchars) +{ + unsigned int i; + unsigned long sum = 0; + + if (!map) + return (0); + for (i = 0; i < numchars; i++) + sum += nibblemap[map->b_data[i] & 0xf] + + nibblemap[(map->b_data[i] >> 4) & 0xf]; + return (sum); +} diff -ruN linux/fs/mona/dir.c linux-mona/fs/mona/dir.c --- linux/fs/mona/dir.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/dir.c Mon Feb 12 17:10:14 2001 @@ -0,0 +1,185 @@ +/* + * linux/fs/mona/dir.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/dir.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Mona directory handling functions + * + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + */ + +#include +#include + +static unsigned char mona_filetype_table[] = { + DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK +}; + +static int mona_readdir(struct file *, void *, filldir_t); + +struct file_operations mona_dir_operations = { + read: generic_read_dir, + readdir: mona_readdir, + ioctl: mona_ioctl, + fsync: mona_sync_file, +}; + +int mona_check_dir_entry (const char * function, struct inode * dir, + struct mona_dir_entry_2 * de, + struct buffer_head * bh, + unsigned long offset) +{ + const char * error_msg = NULL; + + if (le16_to_cpu(de->rec_len) < MONA_DIR_REC_LEN(1)) + error_msg = "rec_len is smaller than minimal"; + else if (le16_to_cpu(de->rec_len) % 4 != 0) + error_msg = "rec_len % 4 != 0"; + else if (le16_to_cpu(de->rec_len) < MONA_DIR_REC_LEN(de->name_len)) + error_msg = "rec_len is too small for name_len"; + else if (dir && ((char *) de - bh->b_data) + le16_to_cpu(de->rec_len) > + dir->i_sb->s_blocksize) + error_msg = "directory entry across blocks"; + else if (dir && le32_to_cpu(de->inode) > le32_to_cpu(dir->i_sb->u.mona_sb.s_ms->s_inodes_count)) + error_msg = "inode out of bounds"; + + if (error_msg != NULL) + mona_error (dir->i_sb, function, "bad entry in directory #%lu: %s - " + "offset=%lu, inode=%lu, rec_len=%d, name_len=%d", + dir->i_ino, error_msg, offset, + (unsigned long) le32_to_cpu(de->inode), + le16_to_cpu(de->rec_len), de->name_len); + return error_msg == NULL ? 1 : 0; +} + +static int mona_readdir(struct file * filp, + void * dirent, filldir_t filldir) +{ + int error = 0; + unsigned long offset, blk; + int i, num, stored; + struct buffer_head * bh, * tmp, * bha[16]; + struct mona_dir_entry_2 * de; + struct super_block * sb; + int err; + struct inode *inode = filp->f_dentry->d_inode; + + sb = inode->i_sb; + + stored = 0; + bh = NULL; + offset = filp->f_pos & (sb->s_blocksize - 1); + + while (!error && !stored && filp->f_pos < inode->i_size) { + blk = (filp->f_pos) >> MONA_BLOCK_SIZE_BITS(sb); + bh = mona_bread (inode, blk, 0, &err); + if (!bh) { + mona_error (sb, "mona_readdir", + "directory #%lu contains a hole at offset %lu", + inode->i_ino, (unsigned long)filp->f_pos); + filp->f_pos += sb->s_blocksize - offset; + continue; + } + + /* + * Do the readahead + */ + if (!offset) { + for (i = 16 >> (MONA_BLOCK_SIZE_BITS(sb) - 9), num = 0; + i > 0; i--) { + tmp = mona_getblk (inode, ++blk, 0, &err); + if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp)) + bha[num++] = tmp; + else + brelse (tmp); + } + if (num) { + ll_rw_block (READA, num, bha); + for (i = 0; i < num; i++) + brelse (bha[i]); + } + } + +revalidate: + /* + * If the dir block has changed since the last call to + * readdir(2), then we might be pointing to an invalid + * dirent right now. Scan from the start of the block + * to make sure. + */ + if (filp->f_version != inode->i_version) { + for (i = 0; i < sb->s_blocksize && i < offset; ) { + de = (struct mona_dir_entry_2 *) + (bh->b_data + i); + /* It's too expensive to do a full + * dirent test each time round this + * loop, but we do have to test at + * least that it is non-zero. A + * failure will be detected in the + * dirent test below. */ + if (le16_to_cpu(de->rec_len) < MONA_DIR_REC_LEN(1)) + break; + i += le16_to_cpu(de->rec_len); + } + offset = i; + filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) + | offset; + filp->f_version = inode->i_version; + } + + while (!error && filp->f_pos < inode->i_size + && offset < sb->s_blocksize) { + de = (struct mona_dir_entry_2 *) (bh->b_data + offset); + if (!mona_check_dir_entry ("mona_readdir", inode, de, + bh, offset)) { + /* On error, skip the f_pos to the + next block. */ + filp->f_pos = (filp->f_pos | (sb->s_blocksize - 1)) + + 1; + brelse (bh); + return stored; + } + offset += le16_to_cpu(de->rec_len); + if (le32_to_cpu(de->inode)) { + /* + * We might block in the next section + * if the data destination is + * currently swapped out. So, use a + * version stamp to detect whether or + * not the directory has been modified + * during the copy operation. + */ + unsigned long version = filp->f_version; + unsigned char d_type = DT_UNKNOWN; + + if (MONA_HAS_INCOMPAT_FEATURE(sb, MONA_FEATURE_INCOMPAT_FILETYPE) + && de->file_type < MONA_FT_MAX) + d_type = mona_filetype_table[de->file_type]; + error = filldir(dirent, de->name, + de->name_len, + filp->f_pos, le32_to_cpu(de->inode), + d_type); + if (error) + break; + if (version != filp->f_version) + goto revalidate; + stored ++; + } + filp->f_pos += le16_to_cpu(de->rec_len); + } + offset = 0; + brelse (bh); + } + UPDATE_ATIME(inode); + return 0; +} diff -ruN linux/fs/mona/file.c linux-mona/fs/mona/file.c --- linux/fs/mona/file.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/file.c Mon Jun 18 09:54:11 2001 @@ -0,0 +1,91 @@ +/* + * linux/fs/mona/file.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/file.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Mona fs regular file handling primitives + * + * 64-bit file support on 64-bit platforms by Jakub Jelinek + * (jj@sunsite.ms.mff.cuni.cz) + */ + +#include +#include +#include + +static loff_t mona_file_lseek(struct file *, loff_t, int); +extern int mona_open_file (struct inode *, struct file *); +extern ssize_t mona_file_read(struct file * filp, char * buf, size_t count, + loff_t *ppos); +extern ssize_t mona_file_write (struct file * file, const char * buf,size_t count,loff_t *ppos); + + +#define MONA_MAX_SIZE(bits) \ + (((MONA_NDIR_BLOCKS + (1LL << (bits - 2)) + \ + (1LL << (bits - 2)) * (1LL << (bits - 2)) + \ + (1LL << (bits - 2)) * (1LL << (bits - 2)) * (1LL << (bits - 2))) * \ + (1LL << bits)) - 1) + +static long long mona_max_sizes[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + MONA_MAX_SIZE(10), MONA_MAX_SIZE(11), MONA_MAX_SIZE(12), MONA_MAX_SIZE(13) +}; + +/* + * Make sure the offset never goes beyond the 32-bit mark.. + */ +static loff_t mona_file_lseek( + struct file *file, + loff_t offset, + int origin) +{ + struct inode *inode = file->f_dentry->d_inode; + + switch (origin) { + case 2: + offset += inode->i_size; + break; + case 1: + offset += file->f_pos; + } + if (offset<0) + return -EINVAL; + if (((unsigned long long) offset >> 32) != 0) { + if (offset > mona_max_sizes[MONA_BLOCK_SIZE_BITS(inode->i_sb)]) + return -EINVAL; + } + if (offset != file->f_pos) { + file->f_pos = offset; + file->f_reada = 0; + file->f_version = ++event; + } + return offset; +} + +/* + * Since we do work on the transformation stream, we cannot many of + * the generic file routines as ext2 does. + */ +struct file_operations mona_file_operations = { + llseek: mona_file_lseek, + read: mona_file_read, + write: mona_file_write, + ioctl: mona_ioctl, + mmap: generic_file_mmap, + open: mona_file_open, + release: mona_release_file, + fsync: mona_sync_file, +}; + +struct inode_operations mona_file_inode_operations = { + truncate: mona_truncate, +}; diff -ruN linux/fs/mona/fsync.c linux-mona/fs/mona/fsync.c --- linux/fs/mona/fsync.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/fsync.c Mon Feb 12 17:10:14 2001 @@ -0,0 +1,55 @@ +/* + * linux/fs/mona/fsync.c + * + * Copyright (C) 1993 Stephen Tweedie (sct@dcs.ed.ac.uk) + * from + * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * from + * linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds + * + * ext2fs fsync primitive + * + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + * + * Removed unnecessary code duplication for little endian machines + * and excessive __inline__s. + * Andi Kleen, 1997 + * + * Major simplications and cleanup - we only need to do the metadata, because + * we can depend on generic_block_fdatasync() to sync the data blocks. + */ + +#include +#include +#include +#include + +/* + * File may be NULL when we are called. Perhaps we shouldn't + * even pass file to fsync ? + */ + +int mona_sync_file(struct file * file, struct dentry *dentry, int datasync) +{ + struct inode *inode = dentry->d_inode; + return mona_fsync_inode(inode, datasync); +} + +int mona_fsync_inode(struct inode *inode, int datasync) +{ + int err; + + err = fsync_inode_buffers(inode); + if (!(inode->i_state & I_DIRTY)) + return err; + if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) + return err; + + err |= mona_sync_inode(inode); + return err ? -EIO : 0; +} + + diff -ruN linux/fs/mona/ialloc.c linux-mona/fs/mona/ialloc.c --- linux/fs/mona/ialloc.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/ialloc.c Mon Feb 12 17:10:14 2001 @@ -0,0 +1,545 @@ +/* + * linux/fs/mona/ialloc.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * BSD ufs-inspired inode and directory allocation by + * Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + */ + +#include +#include +#include +#include /* for testopt declaration */ +#include +#include + +/* + * ialloc.c contains the inodes allocation and deallocation routines + */ + +/* + * The free inodes are managed by bitmaps. A file system contains several + * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap + * block for inodes, N blocks for the inode table and data blocks. + * + * The file system contains group descriptors which are located after the + * super block. Each descriptor contains the number of the bitmap block and + * the free blocks count in the block. The descriptors are loaded in memory + * when a file system is mounted (see mona_read_super). + */ + + +/* + * Read the inode allocation bitmap for a given block_group, reading + * into the specified slot in the superblock's bitmap cache. + * + * Return >=0 on success or a -ve error code. + */ +static int read_inode_bitmap (struct super_block * sb, + unsigned long block_group, + unsigned int bitmap_nr) +{ + struct mona_group_desc * gdp; + struct buffer_head * bh = NULL; + int retval = 0; + + gdp = mona_get_group_desc (sb, block_group, NULL); + if (!gdp) { + retval = -EIO; + goto error_out; + } + bh = bread (sb->s_dev, le32_to_cpu(gdp->bg_inode_bitmap), sb->s_blocksize); + if (!bh) { + mona_error (sb, "read_inode_bitmap", + "Cannot read inode bitmap - " + "block_group = %lu, inode_bitmap = %lu", + block_group, (unsigned long) gdp->bg_inode_bitmap); + retval = -EIO; + } + /* + * On IO error, just leave a zero in the superblock's block pointer for + * this group. The IO will be retried next time. + */ +error_out: + sb->u.mona_sb.s_inode_bitmap_number[bitmap_nr] = block_group; + sb->u.mona_sb.s_inode_bitmap[bitmap_nr] = bh; + return retval; +} + +/* + * load_inode_bitmap loads the inode bitmap for a blocks group + * + * It maintains a cache for the last bitmaps loaded. This cache is managed + * with a LRU algorithm. + * + * Notes: + * 1/ There is one cache per mounted file system. + * 2/ If the file system contains less than MONA_MAX_GROUP_LOADED groups, + * this function reads the bitmap without maintaining a LRU cache. + * + * Return the slot used to store the bitmap, or a -ve error code. + */ +static int load_inode_bitmap (struct super_block * sb, + unsigned int block_group) +{ + int i, j, retval = 0; + unsigned long inode_bitmap_number; + struct buffer_head * inode_bitmap; + + if (block_group >= sb->u.mona_sb.s_groups_count) + mona_panic (sb, "load_inode_bitmap", + "block_group >= groups_count - " + "block_group = %d, groups_count = %lu", + block_group, sb->u.mona_sb.s_groups_count); + if (sb->u.mona_sb.s_loaded_inode_bitmaps > 0 && + sb->u.mona_sb.s_inode_bitmap_number[0] == block_group && + sb->u.mona_sb.s_inode_bitmap[0] != NULL) + return 0; + if (sb->u.mona_sb.s_groups_count <= MONA_MAX_GROUP_LOADED) { + if (sb->u.mona_sb.s_inode_bitmap[block_group]) { + if (sb->u.mona_sb.s_inode_bitmap_number[block_group] != block_group) + mona_panic (sb, "load_inode_bitmap", + "block_group != inode_bitmap_number"); + else + return block_group; + } else { + retval = read_inode_bitmap (sb, block_group, + block_group); + if (retval < 0) + return retval; + return block_group; + } + } + + for (i = 0; i < sb->u.mona_sb.s_loaded_inode_bitmaps && + sb->u.mona_sb.s_inode_bitmap_number[i] != block_group; + i++) + ; + if (i < sb->u.mona_sb.s_loaded_inode_bitmaps && + sb->u.mona_sb.s_inode_bitmap_number[i] == block_group) { + inode_bitmap_number = sb->u.mona_sb.s_inode_bitmap_number[i]; + inode_bitmap = sb->u.mona_sb.s_inode_bitmap[i]; + for (j = i; j > 0; j--) { + sb->u.mona_sb.s_inode_bitmap_number[j] = + sb->u.mona_sb.s_inode_bitmap_number[j - 1]; + sb->u.mona_sb.s_inode_bitmap[j] = + sb->u.mona_sb.s_inode_bitmap[j - 1]; + } + sb->u.mona_sb.s_inode_bitmap_number[0] = inode_bitmap_number; + sb->u.mona_sb.s_inode_bitmap[0] = inode_bitmap; + + /* + * There's still one special case here --- if inode_bitmap == 0 + * then our last attempt to read the bitmap failed and we have + * just ended up caching that failure. Try again to read it. + */ + if (!inode_bitmap) + retval = read_inode_bitmap (sb, block_group, 0); + + } else { + if (sb->u.mona_sb.s_loaded_inode_bitmaps < MONA_MAX_GROUP_LOADED) + sb->u.mona_sb.s_loaded_inode_bitmaps++; + else + brelse (sb->u.mona_sb.s_inode_bitmap[MONA_MAX_GROUP_LOADED - 1]); + for (j = sb->u.mona_sb.s_loaded_inode_bitmaps - 1; j > 0; j--) { + sb->u.mona_sb.s_inode_bitmap_number[j] = + sb->u.mona_sb.s_inode_bitmap_number[j - 1]; + sb->u.mona_sb.s_inode_bitmap[j] = + sb->u.mona_sb.s_inode_bitmap[j - 1]; + } + retval = read_inode_bitmap (sb, block_group, 0); + } + return retval; +} + +/* + * NOTE! When we get the inode, we're the only people + * that have access to it, and as such there are no + * race conditions we have to worry about. The inode + * is not on the hash-lists, and it cannot be reached + * through the filesystem because the directory entry + * has been deleted earlier. + * + * HOWEVER: we must make sure that we get no aliases, + * which means that we have to call "clear_inode()" + * _before_ we mark the inode not in use in the inode + * bitmaps. Otherwise a newly created file might use + * the same inode number (not actually the same pointer + * though), and then we'd have two inodes sharing the + * same inode number and space on the harddisk. + */ +void mona_free_inode (struct inode * inode) +{ + struct super_block * sb = inode->i_sb; + int is_directory; + unsigned long ino; + struct buffer_head * bh; + struct buffer_head * bh2; + unsigned long block_group; + unsigned long bit; + int bitmap_nr; + struct mona_group_desc * gdp; + struct mona_super_block * ms; + + ino = inode->i_ino; + mona_debug ("freeing inode %lu\n", ino); + + /* + * Note: we must free any quota before locking the superblock, + * as writing the quota to disk may need the lock as well. + */ + DQUOT_FREE_INODE(sb, inode); + DQUOT_DROP(inode); + + lock_super (sb); + ms = sb->u.mona_sb.s_ms; + if (ino < MONA_FIRST_INO(sb) || + ino > le32_to_cpu(ms->s_inodes_count)) { + mona_error (sb, "free_inode", + "reserved inode or nonexistent inode"); + goto error_return; + } + block_group = (ino - 1) / MONA_INODES_PER_GROUP(sb); + bit = (ino - 1) % MONA_INODES_PER_GROUP(sb); + bitmap_nr = load_inode_bitmap (sb, block_group); + if (bitmap_nr < 0) + goto error_return; + + bh = sb->u.mona_sb.s_inode_bitmap[bitmap_nr]; + + is_directory = S_ISDIR(inode->i_mode); + + /* Do this BEFORE marking the inode not in use */ + clear_inode (inode); + + /* Ok, now we can actually update the inode bitmaps.. */ + if (!mona_clear_bit (bit, bh->b_data)) + mona_error (sb, "mona_free_inode", + "bit already cleared for inode %lu", ino); + else { + gdp = mona_get_group_desc (sb, block_group, &bh2); + if (gdp) { + gdp->bg_free_inodes_count = + cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) + 1); + if (is_directory) + gdp->bg_used_dirs_count = + cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) - 1); + } + mark_buffer_dirty(bh2); + ms->s_free_inodes_count = + cpu_to_le32(le32_to_cpu(ms->s_free_inodes_count) + 1); + mark_buffer_dirty(sb->u.mona_sb.s_sbh); + } + mark_buffer_dirty(bh); + if (sb->s_flags & MS_SYNCHRONOUS) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + sb->s_dirt = 1; +error_return: + unlock_super (sb); +} + +/* + * There are two policies for allocating an inode. If the new inode is + * a directory, then a forward search is made for a block group with both + * free space and a low directory-to-inode ratio; if that fails, then of + * the groups with above-average free space, that group with the fewest + * directories already is chosen. + * + * For other inodes, search forward from the parent directory\'s block + * group to find a free inode. + */ +struct inode * mona_new_inode (const struct inode * dir, int mode) +{ + struct super_block * sb; + struct buffer_head * bh; + struct buffer_head * bh2; + int i, j, avefreei; + struct inode * inode; + int bitmap_nr; + struct mona_group_desc * gdp; + struct mona_group_desc * tmp; + struct mona_super_block * ms; + int err; + + /* Cannot create files in a deleted directory */ + if (!dir || !dir->i_nlink) + return ERR_PTR(-EPERM); + + sb = dir->i_sb; + inode = new_inode(sb); + if (!inode) + return ERR_PTR(-ENOMEM); + + lock_super (sb); + ms = sb->u.mona_sb.s_ms; +repeat: + gdp = NULL; i=0; + + if (S_ISDIR(mode)) { + avefreei = le32_to_cpu(ms->s_free_inodes_count) / + sb->u.mona_sb.s_groups_count; +/* I am not yet convinced that this next bit is necessary. + i = dir->u.ext2_i.i_block_group; + for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) { + tmp = ext2_get_group_desc (sb, i, &bh2); + if (tmp && + (le16_to_cpu(tmp->bg_used_dirs_count) << 8) < + le16_to_cpu(tmp->bg_free_inodes_count)) { + gdp = tmp; + break; + } + else + i = ++i % sb->u.ext2_sb.s_groups_count; + } +*/ + if (!gdp) { + for (j = 0; j < sb->u.mona_sb.s_groups_count; j++) { + tmp = mona_get_group_desc (sb, j, &bh2); + if (tmp && + le16_to_cpu(tmp->bg_free_inodes_count) && + le16_to_cpu(tmp->bg_free_inodes_count) >= avefreei) { + if (!gdp || + (le16_to_cpu(tmp->bg_free_blocks_count) > + le16_to_cpu(gdp->bg_free_blocks_count))) { + i = j; + gdp = tmp; + } + } + } + } + } + else + { + /* + * Try to place the inode in its parent directory + */ + i = dir->u.mona_i.i_block_group; + tmp = mona_get_group_desc (sb, i, &bh2); + if (tmp && le16_to_cpu(tmp->bg_free_inodes_count)) + gdp = tmp; + else + { + /* + * Use a quadratic hash to find a group with a + * free inode + */ + for (j = 1; j < sb->u.mona_sb.s_groups_count; j <<= 1) { + i += j; + if (i >= sb->u.mona_sb.s_groups_count) + i -= sb->u.mona_sb.s_groups_count; + tmp = mona_get_group_desc (sb, i, &bh2); + if (tmp && + le16_to_cpu(tmp->bg_free_inodes_count)) { + gdp = tmp; + break; + } + } + } + if (!gdp) { + /* + * That failed: try linear search for a free inode + */ + i = dir->u.mona_i.i_block_group + 1; + for (j = 2; j < sb->u.mona_sb.s_groups_count; j++) { + if (++i >= sb->u.mona_sb.s_groups_count) + i = 0; + tmp = mona_get_group_desc (sb, i, &bh2); + if (tmp && + le16_to_cpu(tmp->bg_free_inodes_count)) { + gdp = tmp; + break; + } + } + } + } + + err = -ENOSPC; + if (!gdp) + goto fail; + + err = -EIO; + bitmap_nr = load_inode_bitmap (sb, i); + if (bitmap_nr < 0) + goto fail; + + bh = sb->u.mona_sb.s_inode_bitmap[bitmap_nr]; + if ((j = mona_find_first_zero_bit ((unsigned long *) bh->b_data, + MONA_INODES_PER_GROUP(sb))) < + MONA_INODES_PER_GROUP(sb)) { + if (mona_set_bit (j, bh->b_data)) { + mona_error (sb, "mona_new_inode", + "bit already set for inode %d", j); + goto repeat; + } + mark_buffer_dirty(bh); + if (sb->s_flags & MS_SYNCHRONOUS) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + } else { + if (le16_to_cpu(gdp->bg_free_inodes_count) != 0) { + mona_error (sb, "mona_new_inode", + "Free inodes count corrupted in group %d", + i); + err = -ENOSPC; + if (sb->s_flags & MS_RDONLY) + goto fail; + + gdp->bg_free_inodes_count = 0; + mark_buffer_dirty(bh2); + } + goto repeat; + } + j += i * MONA_INODES_PER_GROUP(sb) + 1; + if (j < MONA_FIRST_INO(sb) || j > le32_to_cpu(ms->s_inodes_count)) { + mona_error (sb, "mona_new_inode", + "reserved inode or inode > inodes count - " + "block_group = %d,inode=%d", i, j); + err = -EIO; + goto fail; + } + gdp->bg_free_inodes_count = + cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1); + if (S_ISDIR(mode)) + gdp->bg_used_dirs_count = + cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1); + mark_buffer_dirty(bh2); + ms->s_free_inodes_count = + cpu_to_le32(le32_to_cpu(ms->s_free_inodes_count) - 1); + mark_buffer_dirty(sb->u.mona_sb.s_sbh); + sb->s_dirt = 1; + inode->i_mode = mode; + inode->i_uid = current->fsuid; + if (test_opt (sb, GRPID)) + inode->i_gid = dir->i_gid; + else if (dir->i_mode & S_ISGID) { + inode->i_gid = dir->i_gid; + if (S_ISDIR(mode)) + mode |= S_ISGID; + } else + inode->i_gid = current->fsgid; + + inode->i_ino = j; + inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */ + inode->i_blocks = 0; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->u.mona_i.i_new_inode = 1; + inode->u.mona_i.i_flags = dir->u.mona_i.i_flags; + if (S_ISLNK(mode)) + inode->u.mona_i.i_flags &= ~(MONA_IMMUTABLE_FL | MONA_APPEND_FL); + inode->u.mona_i.i_faddr = 0; + inode->u.mona_i.i_frag_no = 0; + inode->u.mona_i.i_frag_size = 0; + inode->u.mona_i.i_file_acl = 0; + inode->u.mona_i.i_dir_acl = 0; + inode->u.mona_i.i_dtime = 0; + inode->u.mona_i.i_block_group = i; + if (inode->u.mona_i.i_flags & MONA_SYNC_FL) + inode->i_flags |= S_SYNC; + insert_inode_hash(inode); + inode->i_generation = event++; + mark_inode_dirty(inode); + + unlock_super (sb); + if(DQUOT_ALLOC_INODE(sb, inode)) { + sb->dq_op->drop(inode); + inode->i_nlink = 0; + iput(inode); + return ERR_PTR(-EDQUOT); + } + mona_debug ("allocating inode %lu\n", inode->i_ino); + return inode; + +fail: + unlock_super(sb); + iput(inode); + return ERR_PTR(err); +} + +unsigned long mona_count_free_inodes (struct super_block * sb) +{ +#ifdef MONAFS_DEBUG + struct mona_super_block * ms; + unsigned long desc_count, bitmap_count, x; + int bitmap_nr; + struct mona_group_desc * gdp; + int i; + + lock_super (sb); + ms = sb->u.mona_sb.s_ms; + desc_count = 0; + bitmap_count = 0; + gdp = NULL; + for (i = 0; i < sb->u.mona_sb.s_groups_count; i++) { + gdp = mona_get_group_desc (sb, i, NULL); + if (!gdp) + continue; + desc_count += le16_to_cpu(gdp->bg_free_inodes_count); + bitmap_nr = load_inode_bitmap (sb, i); + if (bitmap_nr < 0) + continue; + + x = mona_count_free (sb->u.mona_sb.s_inode_bitmap[bitmap_nr], + MONA_INODES_PER_GROUP(sb) / 8); + printk ("group %d: stored = %d, counted = %lu\n", + i, le16_to_cpu(gdp->bg_free_inodes_count), x); + bitmap_count += x; + } + printk("mona_count_free_inodes: stored = %du, computed = %lu, %lu\n", + le32_to_cpu(ms->s_free_inodes_count), desc_count, bitmap_count); + unlock_super (sb); + return desc_count; +#else + return le32_to_cpu(sb->u.mona_sb.s_ms->s_free_inodes_count); +#endif +} + +#ifdef CONFIG_MONA_CHECK +/* Called at mount-time, super-block is locked */ +void mona_check_inodes_bitmap (struct super_block * sb) +{ + struct mona_super_block * ms; + unsigned long desc_count, bitmap_count, x; + int bitmap_nr; + struct mona_group_desc * gdp; + int i; + + ms = sb->u.mona_sb.s_ms; + desc_count = 0; + bitmap_count = 0; + gdp = NULL; + for (i = 0; i < sb->u.mona_sb.s_groups_count; i++) { + gdp = mona_get_group_desc (sb, i, NULL); + if (!gdp) + continue; + desc_count += le16_to_cpu(gdp->bg_free_inodes_count); + bitmap_nr = load_inode_bitmap (sb, i); + if (bitmap_nr < 0) + continue; + + x = mona_count_free (sb->u.mona_sb.s_inode_bitmap[bitmap_nr], + MONA_INODES_PER_GROUP(sb) / 8); + if (le16_to_cpu(gdp->bg_free_inodes_count) != x) + mona_error (sb, "mona_check_inodes_bitmap", + "Wrong free inodes count in group %d, " + "stored = %d, counted = %lu", i, + le16_to_cpu(gdp->bg_free_inodes_count), x); + bitmap_count += x; + } + if (le32_to_cpu(ms->s_free_inodes_count) != bitmap_count) + mona_error (sb, "mona_check_inodes_bitmap", + "Wrong free inodes count in super block, " + "stored = %lu, counted = %lu", + (unsigned long) le32_to_cpu(ms->s_free_inodes_count), + bitmap_count); +} +#endif + diff -ruN linux/fs/mona/inode.c linux-mona/fs/mona/inode.c --- linux/fs/mona/inode.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/inode.c Mon Jun 18 13:04:06 2001 @@ -0,0 +1,1299 @@ +/* + * linux/fs/mona/inode.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/inode.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Goal-directed blmonaock allocation by Stephen Tweedie + * (sct@dcs.ed.ac.uk), 1993, 1998 + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + * 64-bit file support on 64-bit platforms by Jakub Jelinek + * (jj@sunsite.ms.mff.cuni.cz) + * + * Assorted race fixes, rewrite of mona_get_block() by Al Viro, 2000 + */ + +#include +#include +#include /* for testopt declaration */ +#include +#include +#include +#include + +static int mona_update_inode(struct inode * inode, int do_sync); + +/* + * Called at each iput() + */ +void mona_put_inode (struct inode * inode) +{ + mona_discard_prealloc (inode); +} + +/* + * Called at the last iput() if i_nlink is zero. + */ +void mona_delete_inode (struct inode * inode) +{ + lock_kernel(); + + if (is_bad_inode(inode) || + inode->i_ino == MONA_ACL_IDX_INO || + inode->i_ino == MONA_ACL_DATA_INO) + goto no_delete; + inode->u.mona_i.i_dtime = CURRENT_TIME; + mark_inode_dirty(inode); + mona_update_inode(inode, IS_SYNC(inode)); + inode->i_size = 0; + if (inode->i_blocks) + mona_truncate (inode); + mona_free_inode (inode); + + unlock_kernel(); + return; +no_delete: + unlock_kernel(); + clear_inode(inode); /* We must guarantee clearing of inode... */ +} + +void mona_discard_prealloc (struct inode * inode) +{ +#ifdef MONA_PREALLOCATE + lock_kernel(); + /* Writer: ->i_prealloc* */ + if (inode->u.mona_i.i_prealloc_count) { + unsigned short total = inode->u.mona_i.i_prealloc_count; + unsigned long block = inode->u.mona_i.i_prealloc_block; + inode->u.mona_i.i_prealloc_count = 0; + inode->u.mona_i.i_prealloc_block = 0; + /* Writer: end */ + mona_free_blocks (inode, block, total); + } + unlock_kernel(); +#endif +} + +static int mona_alloc_block (struct inode * inode, unsigned long goal, int *err) +{ +#ifdef MONAFS_DEBUG + static unsigned long alloc_hits = 0, alloc_attempts = 0; +#endif + unsigned long result; + +#ifdef MONA_PREALLOCATE + /* Writer: ->i_prealloc* */ + if (inode->u.mona_i.i_prealloc_count && + (goal == inode->u.mona_i.i_prealloc_block || + goal + 1 == inode->u.mona_i.i_prealloc_block)) + { + result = inode->u.mona_i.i_prealloc_block++; + inode->u.mona_i.i_prealloc_count--; + /* Writer: end */ +#ifdef MONAFS_DEBUG + mona_debug ("preallocation hit (%lu/%lu).\n", + ++alloc_hits, ++alloc_attempts); +#endif + } else { + mona_discard_prealloc (inode); +#ifdef MONAFS_DEBUG + mona_debug ("preallocation miss (%lu/%lu).\n", + alloc_hits, ++alloc_attempts); +#endif + if (S_ISREG(inode->i_mode)) + result = mona_new_block (inode, goal, + &inode->u.mona_i.i_prealloc_count, + &inode->u.mona_i.i_prealloc_block, err); + else + result = mona_new_block (inode, goal, 0, 0, err); + } +#else + result = mona_new_block (inode, goal, 0, 0, err); +#endif + return result; +} + +typedef struct { + u32 *p; + u32 key; + struct buffer_head *bh; +} Indirect; + +static inline void add_chain(Indirect *p, struct buffer_head *bh, u32 *v) +{ + p->key = *(p->p = v); + p->bh = bh; +} + +static inline int verify_chain(Indirect *from, Indirect *to) +{ + while (from <= to && from->key == *from->p) + from++; + return (from > to); +} + +/** +* mona_block_to_path - parse the block number into array of offsets +* @inode: inode in question (we are only interested in its superblock) +* @i_block: block number to be parsed +* @offsets: array to store the offsets in +* +* To store the locations of file's data mona uses a data structure common +* for UNIX filesystems - tree of pointers anchored in the inode, with +* data blocks at leaves and indirect blocks in intermediate nodes. +* This function translates the block number into path in that tree - +* return value is the path length and @offsets[n] is the offset of +* pointer to (n+1)th node in the nth one. If @block is out of range +* (negative or too large) warning is printed and zero returned. +* +* Note: function doesn't find node addresses, so no IO is needed. All +* we need to know is the capacity of indirect blocks (taken from the +* inode->i_sb). +*/ + +/* +* Portability note: the last comparison (check that we fit into triple +* indirect block) is spelled differently, because otherwise on an +* architecture with 32-bit longs and 8Kb pages we might get into trouble +* if our filesystem had 8Kb blocks. We might use long long, but that would +* kill us on x86. Oh, well, at least the sign propagation does not matter - +* i_block would have to be negative in the very beginning, so we would not +* get there at all. +*/ + +static int mona_block_to_path(struct inode *inode, long i_block, int offsets[4]) +{ + int ptrs = MONA_ADDR_PER_BLOCK(inode->i_sb); + int ptrs_bits = MONA_ADDR_PER_BLOCK_BITS(inode->i_sb); + const long direct_blocks = MONA_NDIR_BLOCKS, + indirect_blocks = ptrs, + double_blocks = (1 << (ptrs_bits * 2)); + int n = 0; + + if (i_block < 0) { + mona_warning (inode->i_sb, "mona_block_to_path", "block < 0"); + } else if (i_block < direct_blocks) { + offsets[n++] = i_block; + } else if ( (i_block -= direct_blocks) < indirect_blocks) { + offsets[n++] = MONA_IND_BLOCK; + offsets[n++] = i_block; + } else if ((i_block -= indirect_blocks) < double_blocks) { + offsets[n++] = MONA_DIND_BLOCK; + offsets[n++] = i_block >> ptrs_bits; + offsets[n++] = i_block & (ptrs - 1); + } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) { + offsets[n++] = MONA_TIND_BLOCK; + offsets[n++] = i_block >> (ptrs_bits * 2); + offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1); + offsets[n++] = i_block & (ptrs - 1); + } else { + mona_warning (inode->i_sb, "mona_block_to_path", "block > big"); + } + return n; +} + +/** +* mona_get_branch - read the chain of indirect blocks leading to data +* @inode: inode in question +* @depth: depth of the chain (1 - direct pointer, etc.) +* @offsets: offsets of pointers in inode/indirect blocks +* @chain: place to store the result +* @err: here we store the error value +* +* Function fills the array of triples and returns %NULL +* if everything went OK or the pointer to the last filled triple +* (incomplete one) otherwise. Upon the return chain[i].key contains +* the number of (i+1)-th block in the chain (as it is stored in memory, +* i.e. little-endian 32-bit), chain[i].p contains the address of that +* number (it points into struct inode for i==0 and into the bh->b_data +* for i>0) and chain[i].bh points to the buffer_head of i-th indirect +* block for i>0 and NULL for i==0. In other words, it holds the block +* numbers of the chain, addresses they were taken from (and where we can +* verify that chain did not change) and buffer_heads hosting these +* numbers. +* +* Function stops when it stumbles upon zero pointer (absent block) +* (pointer to last triple returned, *@err == 0) +* or when it gets an IO error reading an indirect block +* (ditto, *@err == -EIO) +* or when it notices that chain had been changed while it was reading +* (ditto, *@err == -EAGAIN) +* or when it reads all @depth-1 indirect blocks successfully and finds +* the whole chain, all way to the data (returns %NULL, *err == 0). +*/ +static inline Indirect *mona_get_branch(struct inode *inode, + int depth, + int *offsets, + Indirect chain[4], + int *err) +{ + kdev_t dev = inode->i_dev; + int size = inode->i_sb->s_blocksize; + Indirect *p = chain; + struct buffer_head *bh; + + *err = 0; + /* i_data is not going away, no lock needed */ + add_chain (chain, NULL, inode->u.mona_i.i_data + *offsets); + if (!p->key) + goto no_block; + while (--depth) { + bh = bread(dev, le32_to_cpu(p->key), size); + if (!bh) + goto failure; + /* Reader: pointers */ + if (!verify_chain(chain, p)) + goto changed; + add_chain(++p, bh, (u32*)bh->b_data + *++offsets); + /* Reader: end */ + if (!p->key) + goto no_block; + } + return NULL; + +changed: + *err = -EAGAIN; + goto no_block; +failure: + *err = -EIO; +no_block: + return p; +} + +/** +* mona_find_near - find a place for allocation with sufficient locality +* @inode: owner +* @ind: descriptor of indirect block. +* +* This function returns the prefered place for block allocation. +* It is used when heuristic for sequential allocation fails. +* Rules are: +* + if there is a block to the left of our position - allocate near it. +* + if pointer will live in indirect block - allocate near that block. +* + if pointer will live in inode - allocate in the same cylinder group. +* Caller must make sure that @ind is valid and will stay that way. +*/ + +static inline unsigned long mona_find_near(struct inode *inode, Indirect *ind) +{ + u32 *start = ind->bh ? (u32*) ind->bh->b_data : inode->u.mona_i.i_data; + u32 *p; + + /* Try to find previous block */ + for (p = ind->p - 1; p >= start; p--) + if (*p) + return le32_to_cpu(*p); + + /* No such thing, so let's try location of indirect block */ + if (ind->bh) + return ind->bh->b_blocknr; + + /* + * It is going to be refered from inode itself? OK, just put it into + * the same cylinder group then. + */ + return (inode->u.mona_i.i_block_group * + MONA_BLOCKS_PER_GROUP(inode->i_sb)) + + le32_to_cpu(inode->i_sb->u.mona_sb.s_ms->s_first_data_block); +} + +/** +* mona_find_goal - find a prefered place for allocation. +* @inode: owner +* @block: block we want +* @chain: chain of indirect blocks +* @partial: pointer to the last triple within a chain +* @goal: place to store the result. +* +* Normally this function find the prefered place for block allocation, +* stores it in *@goal and returns zero. If the branch had been changed +* under us we return -EAGAIN. +*/ + +static inline int mona_find_goal(struct inode *inode, + long block, + Indirect chain[4], + Indirect *partial, + unsigned long *goal) +{ + /* Writer: ->i_next_alloc* */ + if (block == inode->u.mona_i.i_next_alloc_block + 1) { + inode->u.mona_i.i_next_alloc_block++; + inode->u.mona_i.i_next_alloc_goal++; + } + /* Writer: end */ + /* Reader: pointers, ->i_next_alloc* */ + if (verify_chain(chain, partial)) { + /* + * try the heuristic for sequential allocation, + * failing that at least try to get decent locality. + */ + if (block == inode->u.mona_i.i_next_alloc_block) + *goal = inode->u.mona_i.i_next_alloc_goal; + if (!*goal) + *goal = mona_find_near(inode, partial); + return 0; + } + /* Reader: end */ + return -EAGAIN; +} + +/** +* mona_alloc_branch - allocate and set up a chain of blocks. +* @inode: owner +* @num: depth of the chain (number of blocks to allocate) +* @offsets: offsets (in the blocks) to store the pointers to next. +* @branch: place to store the chain in. +* +* This function allocates @num blocks, zeroes out all but the last one, +* links them into chain and (if we are synchronous) writes them to disk. +* In other words, it prepares a branch that can be spliced onto the +* inode. It stores the information about that chain in the branch[], in +* the same format as mona_get_branch() would do. We are calling it after +* we had read the existing part of chain and partial points to the last +* triple of that (one with zero ->key). Upon the exit we have the same +* picture as after the successful mona_get_block(), excpet that in one +* place chain is disconnected - *branch->p is still zero (we did not +* set the last link), but branch->key contains the number that should +* be placed into *branch->p to fill that gap. +* +* If allocation fails we free all blocks we've allocated (and forget +* ther buffer_heads) and return the error value the from failed +* mona_alloc_block() (normally -ENOSPC). Otherwise we set the chain +* as described above and return 0. +*/ + +static int mona_alloc_branch(struct inode *inode, + int num, + unsigned long goal, + int *offsets, + Indirect *branch) +{ + int blocksize = inode->i_sb->s_blocksize; + int n = 0; + int err; + int i; + int parent = mona_alloc_block(inode, goal, &err); + + branch[0].key = cpu_to_le32(parent); + if (parent) for (n = 1; n < num; n++) { + struct buffer_head *bh; + /* Allocate the next block */ + int nr = mona_alloc_block(inode, parent, &err); + if (!nr) + break; + branch[n].key = cpu_to_le32(nr); + /* + * Get buffer_head for parent block, zero it out and set + * the pointer to new one, then send parent to disk. + */ + bh = getblk(inode->i_dev, parent, blocksize); + if (!buffer_uptodate(bh)) + wait_on_buffer(bh); + memset(bh->b_data, 0, blocksize); + branch[n].bh = bh; + branch[n].p = (u32*) bh->b_data + offsets[n]; + *branch[n].p = branch[n].key; + mark_buffer_uptodate(bh, 1); + mark_buffer_dirty(bh); + if (IS_SYNC(inode) || inode->u.mona_i.i_osync) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + parent = nr; + } + if (n == num) + return 0; + + /* Allocation failed, free what we already allocated */ + for (i = 1; i < n; i++) + bforget(branch[i].bh); + for (i = 0; i < n; i++) + mona_free_blocks(inode, le32_to_cpu(branch[i].key), 1); + return err; +} + +/** +* mona_splice_branch - splice the allocated branch onto inode. +* @inode: owner +* @block: (logical) number of block we are adding +* @chain: chain of indirect blocks (with a missing link - see +* mona_alloc_branch) +* @where: location of missing link +* @num: number of blocks we are adding +* +* This function verifies that chain (up to the missing link) had not +* changed, fills the missing link and does all housekeeping needed in +* inode (->i_blocks, etc.). In case of success we end up with the full +* chain to new block and return 0. Otherwise (== chain had been changed) +* we free the new blocks (forgetting their buffer_heads, indeed) and +* return -EAGAIN. +*/ + +static inline int mona_splice_branch(struct inode *inode, + long block, + Indirect chain[4], + Indirect *where, + int num) +{ + int i; + + /* Verify that place we are splicing to is still there and vacant */ + + /* Writer: pointers, ->i_next_alloc*, ->i_blocks */ + if (!verify_chain(chain, where-1) || *where->p) + /* Writer: end */ + goto changed; + + /* That's it */ + + *where->p = where->key; + inode->u.mona_i.i_next_alloc_block = block; + inode->u.mona_i.i_next_alloc_goal = le32_to_cpu(where[num-1].key); + inode->i_blocks += num * inode->i_sb->s_blocksize/512; + + /* Writer: end */ + + /* We are done with atomic stuff, now do the rest of housekeeping */ + + inode->i_ctime = CURRENT_TIME; + + /* had we spliced it onto indirect block? */ + if (where->bh) { + mark_buffer_dirty(where->bh); + if (IS_SYNC(inode) || inode->u.mona_i.i_osync) { + ll_rw_block (WRITE, 1, &where->bh); + wait_on_buffer(where->bh); + } + } + + if (IS_SYNC(inode) || inode->u.mona_i.i_osync) + mona_sync_inode (inode); + else + mark_inode_dirty(inode); + return 0; + +changed: + for (i = 1; i < num; i++) + bforget(where[i].bh); + for (i = 0; i < num; i++) + mona_free_blocks(inode, le32_to_cpu(where[i].key), 1); + return -EAGAIN; +} + +/* +* Allocation strategy is simple: if we have to allocate something, we will +* have to go the whole way to leaf. So let's do it before attaching anything +* to tree, set linkage between the newborn blocks, write them if sync is +* required, recheck the path, free and repeat if check fails, otherwise +* set the last missing link (that will protect us from any truncate-generated +* removals - all blocks on the path are immune now) and possibly force the +* write on the parent block. +* That has a nice additional property: no special recovery from the failed +* allocations is needed - we simply release blocks and do not touch anything +* reachable from inode. +*/ + +static int mona_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create) +{ + int err = -EIO; + int offsets[4]; + Indirect chain[4]; + Indirect *partial; + unsigned long goal; + int left; + int depth = mona_block_to_path(inode, iblock, offsets); + + if (depth == 0) + goto out; + + lock_kernel(); +reread: + partial = mona_get_branch(inode, depth, offsets, chain, &err); + + /* Simplest case - block found, no allocation needed */ + if (!partial) { +got_it: + bh_result->b_dev = inode->i_dev; + bh_result->b_blocknr = le32_to_cpu(chain[depth-1].key); + bh_result->b_state |= (1UL << BH_Mapped); + /* Clean up and exit */ + partial = chain+depth-1; /* the whole chain */ + goto cleanup; + } + + /* Next simple case - plain lookup or failed read of indirect block */ + if (!create || err == -EIO) { +cleanup: + while (partial > chain) { + brelse(partial->bh); + partial--; + } + unlock_kernel(); +out: + return err; + } + + /* + * Indirect block might be removed by truncate while we were + * reading it. Handling of that case (forget what we've got and + * reread) is taken out of the main path. + */ + if (err == -EAGAIN) + goto changed; + + if (mona_find_goal(inode, iblock, chain, partial, &goal) < 0) + goto changed; + + left = (chain + depth) - partial; + err = mona_alloc_branch(inode, left, goal, + offsets+(partial-chain), partial); + if (err) + goto cleanup; + + if (mona_splice_branch(inode, iblock, chain, partial, left) < 0) + goto changed; + + bh_result->b_state |= (1UL << BH_New); + goto got_it; + +changed: + while (partial > chain) { + bforget(partial->bh); + partial--; + } + goto reread; +} + +struct buffer_head * mona_getblk(struct inode * inode, long block, int create, int * err) +{ + struct buffer_head dummy; + int error; + + dummy.b_state = 0; + dummy.b_blocknr = -1000; + error = mona_get_block(inode, block, &dummy, create); + *err = error; + if (!error && buffer_mapped(&dummy)) { + struct buffer_head *bh; + bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize); + if (buffer_new(&dummy)) { + if (!buffer_uptodate(bh)) + wait_on_buffer(bh); + memset(bh->b_data, 0, inode->i_sb->s_blocksize); + mark_buffer_uptodate(bh, 1); + mark_buffer_dirty(bh); + } + return bh; + } + return NULL; +} + +struct buffer_head * mona_bread (struct inode * inode, int block, + int create, int *err) +{ + struct buffer_head * bh; + int prev_blocks; + + prev_blocks = inode->i_blocks; + + bh = mona_getblk (inode, block, create, err); + if (!bh) + return bh; + + /* + * If the inode has grown, and this is a directory, then perform + * preallocation of a few more blocks to try to keep directory + * fragmentation down. + */ + if (create && + S_ISDIR(inode->i_mode) && + inode->i_blocks > prev_blocks && + MONA_HAS_COMPAT_FEATURE(inode->i_sb, + MONA_FEATURE_COMPAT_DIR_PREALLOC)) { + int i; + struct buffer_head *tmp_bh; + + for (i = 1; + i < MONA_SB(inode->i_sb)->s_ms->s_prealloc_dir_blocks; + i++) { + /* + * mona_getblk will zero out the contents of the + * directory for us + */ + tmp_bh = mona_getblk(inode, block+i, create, err); + if (!tmp_bh) { + brelse (bh); + return 0; + } + brelse (tmp_bh); + } + } + + if (buffer_uptodate(bh)) + return bh; + ll_rw_block (READ, 1, &bh); + wait_on_buffer (bh); + if (buffer_uptodate(bh)) + return bh; + brelse (bh); + *err = -EIO; + return NULL; +} + +static int mona_writepage(struct page *page) +{ + return block_write_full_page(page,mona_get_block); +} +static int mona_readpage(struct file *file, struct page *page) +{ + return block_read_full_page(page,mona_get_block); +} +static int mona_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) +{ + return block_prepare_write(page,from,to,mona_get_block); +} +static int mona_bmap(struct address_space *mapping, long block) +{ + return generic_block_bmap(mapping,block,mona_get_block); +} +struct address_space_operations mona_aops = { + readpage: mona_readpage, + writepage: mona_writepage, + sync_page: block_sync_page, + prepare_write: mona_prepare_write, + commit_write: generic_commit_write, + bmap: mona_bmap +}; + +/* +* Probably it should be a library function... search for first non-zero word +* or memcmp with zero_page, whatever is better for particular architecture. +* Linus? +*/ +static inline int all_zeroes(u32 *p, u32 *q) +{ + while (p < q) + if (*p++) + return 0; + return 1; +} + +/** +* mona_find_shared - find the indirect blocks for partial truncation. +* @inode: inode in question +* @depth: depth of the affected branch +* @offsets: offsets of pointers in that branch (see mona_block_to_path) +* @chain: place to store the pointers to partial indirect blocks +* @top: place to the (detached) top of branch +* +* This is a helper function used by mona_truncate(). +* +* When we do truncate() we may have to clean the ends of several indirect +* blocks but leave the blocks themselves alive. Block is partially +* truncated if some data below the new i_size is refered from it (and +* it is on the path to the first completely truncated data block, indeed). +* We have to free the top of that path along with everything to the right +* of the path. Since no allocation past the truncation point is possible +* until mona_truncate() finishes, we may safely do the latter, but top +* of branch may require special attention - pageout below the truncation +* point might try to populate it. +* +* We atomically detach the top of branch from the tree, store the block +* number of its root in *@top, pointers to buffer_heads of partially +* truncated blocks - in @chain[].bh and pointers to their last elements +* that should not be removed - in @chain[].p. Return value is the pointer +* to last filled element of @chain. +* +* The work left to caller to do the actual freeing of subtrees: +* a) free the subtree starting from *@top +* b) free the subtrees whose roots are stored in +* (@chain[i].p+1 .. end of @chain[i].bh->b_data) +* c) free the subtrees growing from the inode past the @chain[0].p +* (no partially truncated stuff there). +*/ + +static Indirect *mona_find_shared(struct inode *inode, + int depth, + int offsets[4], + Indirect chain[4], + u32 *top) +{ + Indirect *partial, *p; + int k, err; + + *top = 0; + for (k = depth; k > 1 && !offsets[k-1]; k--) + ; + partial = mona_get_branch(inode, k, offsets, chain, &err); + /* Writer: pointers */ + if (!partial) + partial = chain + k-1; + /* + * If the branch acquired continuation since we've looked at it - + * fine, it should all survive and (new) top doesn't belong to us. + */ + if (!partial->key && *partial->p) + /* Writer: end */ + goto no_top; + for (p=partial; p>chain && all_zeroes((u32*)p->bh->b_data,p->p); p--) + ; + /* + * OK, we've found the last block that must survive. The rest of our + * branch should be detached before unlocking. However, if that rest + * of branch is all ours and does not grow immediately from the inode + * it's easier to cheat and just decrement partial->p. + */ + if (p == chain + k - 1 && p > chain) { + p->p--; + } else { + *top = *p->p; + *p->p = 0; + } + /* Writer: end */ + + while(partial > p) + { + brelse(partial->bh); + partial--; + } +no_top: + return partial; +} + +/** +* mona_free_data - free a list of data blocks +* @inode: inode we are dealing with +* @p: array of block numbers +* @q: points immediately past the end of array +* +* We are freeing all blocks refered from that array (numbers are +* stored as little-endian 32-bit) and updating @inode->i_blocks +* appropriately. +*/ +static inline void mona_free_data(struct inode *inode, u32 *p, u32 *q) +{ + int blocks = inode->i_sb->s_blocksize / 512; + unsigned long block_to_free = 0, count = 0; + unsigned long nr; + + for ( ; p < q ; p++) { + nr = le32_to_cpu(*p); + if (nr) { + *p = 0; + /* accumulate blocks to free if they're contiguous */ + if (count == 0) + goto free_this; + else if (block_to_free == nr - count) + count++; + else { + /* Writer: ->i_blocks */ + inode->i_blocks -= blocks * count; + /* Writer: end */ + mona_free_blocks (inode, block_to_free, count); + mark_inode_dirty(inode); + free_this: + block_to_free = nr; + count = 1; + } + } + } + if (count > 0) { + /* Writer: ->i_blocks */ + inode->i_blocks -= blocks * count; + /* Writer: end */ + mona_free_blocks (inode, block_to_free, count); + mark_inode_dirty(inode); + } +} + +/** +* mona_free_branches - free an array of branches +* @inode: inode we are dealing with +* @p: array of block numbers +* @q: pointer immediately past the end of array +* @depth: depth of the branches to free +* +* We are freeing all blocks refered from these branches (numbers are +* stored as little-endian 32-bit) and updating @inode->i_blocks +* appropriately. +*/ +static void mona_free_branches(struct inode *inode, u32 *p, u32 *q, int depth) +{ + struct buffer_head * bh; + unsigned long nr; + + if (depth--) { + int addr_per_block = MONA_ADDR_PER_BLOCK(inode->i_sb); + for ( ; p < q ; p++) { + nr = le32_to_cpu(*p); + if (!nr) + continue; + *p = 0; + bh = bread (inode->i_dev, nr, inode->i_sb->s_blocksize); + /* + * A read failure? Report error and clear slot + * (should be rare). + */ + if (!bh) { + mona_error(inode->i_sb, "mona_free_branches", + "Read failure, inode=%ld, block=%ld", + inode->i_ino, nr); + continue; + } + mona_free_branches(inode, + (u32*)bh->b_data, + (u32*)bh->b_data + addr_per_block, + depth); + bforget(bh); + /* Writer: ->i_blocks */ + inode->i_blocks -= inode->i_sb->s_blocksize / 512; + /* Writer: end */ + mona_free_blocks(inode, nr, 1); + mark_inode_dirty(inode); + } + } else + mona_free_data(inode, p, q); +} + +void mona_truncate (struct inode * inode) +{ + u32 *i_data = inode->u.mona_i.i_data; + int addr_per_block = MONA_ADDR_PER_BLOCK(inode->i_sb); + int offsets[4]; + Indirect chain[4]; + Indirect *partial; + int nr = 0; + int n; + long iblock; + unsigned blocksize; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + return; + + mona_discard_prealloc(inode); + + blocksize = inode->i_sb->s_blocksize; + iblock = (inode->i_size + blocksize-1) + >> MONA_BLOCK_SIZE_BITS(inode->i_sb); + + block_truncate_page(inode->i_mapping, inode->i_size, mona_get_block); + + n = mona_block_to_path(inode, iblock, offsets); + if (n == 0) + return; + + if (n == 1) { + mona_free_data(inode, i_data+offsets[0], + i_data + MONA_NDIR_BLOCKS); + goto do_indirects; + } + + partial = mona_find_shared(inode, n, offsets, chain, &nr); + /* Kill the top of shared branch (already detached) */ + if (nr) { + if (partial == chain) + mark_inode_dirty(inode); + else + mark_buffer_dirty(partial->bh); + mona_free_branches(inode, &nr, &nr+1, (chain+n-1) - partial); + } + /* Clear the ends of indirect blocks on the shared branch */ + while (partial > chain) { + mona_free_branches(inode, + partial->p + 1, + (u32*)partial->bh->b_data + addr_per_block, + (chain+n-1) - partial); + mark_buffer_dirty(partial->bh); + if (IS_SYNC(inode)) { + ll_rw_block (WRITE, 1, &partial->bh); + wait_on_buffer (partial->bh); + } + brelse (partial->bh); + partial--; + } +do_indirects: + /* Kill the remaining (whole) subtrees */ + switch (offsets[0]) { + default: + nr = i_data[MONA_IND_BLOCK]; + if (nr) { + i_data[MONA_IND_BLOCK] = 0; + mark_inode_dirty(inode); + mona_free_branches(inode, &nr, &nr+1, 1); + } + case MONA_IND_BLOCK: + nr = i_data[MONA_DIND_BLOCK]; + if (nr) { + i_data[MONA_DIND_BLOCK] = 0; + mark_inode_dirty(inode); + mona_free_branches(inode, &nr, &nr+1, 2); + } + case MONA_DIND_BLOCK: + nr = i_data[MONA_TIND_BLOCK]; + if (nr) { + i_data[MONA_TIND_BLOCK] = 0; + mark_inode_dirty(inode); + mona_free_branches(inode, &nr, &nr+1, 3); + } + case MONA_TIND_BLOCK: + ; + } + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + if (IS_SYNC(inode)) + mona_sync_inode (inode); + else + mark_inode_dirty(inode); +} + +void mona_read_inode (struct inode * inode) +{ + struct buffer_head * bh; + struct mona_inode * raw_inode; + unsigned long block_group; + unsigned long group_desc; + unsigned long desc; + unsigned long block; + unsigned long offset; + struct mona_group_desc * gdp; + + if ((inode->i_ino != MONA_ROOT_INO && inode->i_ino != MONA_ACL_IDX_INO && + inode->i_ino != MONA_ACL_DATA_INO && + inode->i_ino < MONA_FIRST_INO(inode->i_sb)) || + inode->i_ino > le32_to_cpu(inode->i_sb->u.mona_sb.s_ms->s_inodes_count)) { + mona_error (inode->i_sb, "mona_read_inode", + "bad inode number: %lu", inode->i_ino); + goto bad_inode; + } + block_group = (inode->i_ino - 1) / MONA_INODES_PER_GROUP(inode->i_sb); + if (block_group >= inode->i_sb->u.mona_sb.s_groups_count) { + mona_error (inode->i_sb, "mona_read_inode", + "group >= groups count"); + goto bad_inode; + } + group_desc = block_group >> MONA_DESC_PER_BLOCK_BITS(inode->i_sb); + desc = block_group & (MONA_DESC_PER_BLOCK(inode->i_sb) - 1); + bh = inode->i_sb->u.mona_sb.s_group_desc[group_desc]; + if (!bh) { + mona_error (inode->i_sb, "mona_read_inode", + "Descriptor not loaded"); + goto bad_inode; + } + + gdp = (struct mona_group_desc *) bh->b_data; + /* + * Figure out the offset within the block group inode table + */ + offset = ((inode->i_ino - 1) % MONA_INODES_PER_GROUP(inode->i_sb)) * + MONA_INODE_SIZE(inode->i_sb); + block = le32_to_cpu(gdp[desc].bg_inode_table) + + (offset >> MONA_BLOCK_SIZE_BITS(inode->i_sb)); + if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) { + mona_error (inode->i_sb, "mona_read_inode", + "unable to read inode block - " + "inode=%lu, block=%lu", inode->i_ino, block); + goto bad_inode; + } + offset &= (MONA_BLOCK_SIZE(inode->i_sb) - 1); + raw_inode = (struct mona_inode *) (bh->b_data + offset); + + inode->i_mode = le16_to_cpu(raw_inode->i_mode); + inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); + inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); + if(!(test_opt (inode->i_sb, NO_UID32))) { + inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; + inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; + } + inode->i_nlink = le16_to_cpu(raw_inode->i_links_count); + inode->i_size = le32_to_cpu(raw_inode->i_size); + inode->i_atime = le32_to_cpu(raw_inode->i_atime); + inode->i_ctime = le32_to_cpu(raw_inode->i_ctime); + inode->i_mtime = le32_to_cpu(raw_inode->i_mtime); + inode->u.mona_i.i_dtime = le32_to_cpu(raw_inode->i_dtime); + /* We now have enough fields to check if the inode was active or not. + * This is needed because nfsd might try to access dead inodes + * the test is that same one that e2fsck uses + * NeilBrown 1999oct15 + */ + if (inode->i_nlink == 0 && (inode->i_mode == 0 || inode->u.mona_i.i_dtime)) { + /* this inode is deleted */ + brelse (bh); + goto bad_inode; + } + inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */ + inode->i_blocks = le32_to_cpu(raw_inode->i_blocks); + inode->i_version = ++event; + inode->u.mona_i.i_flags = le32_to_cpu(raw_inode->i_flags); + inode->u.mona_i.i_faddr = le32_to_cpu(raw_inode->i_faddr); + inode->u.mona_i.i_frag_no = raw_inode->i_frag; + inode->u.mona_i.i_frag_size = raw_inode->i_fsize; + inode->u.mona_i.i_file_acl = le32_to_cpu(raw_inode->i_file_acl); + if (S_ISDIR(inode->i_mode)) + inode->u.mona_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl); + else { + inode->u.mona_i.i_high_size = le32_to_cpu(raw_inode->i_size_high); + inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32; + } + inode->i_generation = le32_to_cpu(raw_inode->i_generation); + inode->u.mona_i.i_block_group = block_group; + + /* + * NOTE! The in-memory inode i_data array is in little-endian order + * even on big-endian machines: we do NOT byteswap the block numbers! + */ + for (block = 0; block < MONA_N_BLOCKS; block++) + inode->u.mona_i.i_data[block] = raw_inode->i_block[block]; + + if (inode->i_ino == MONA_ACL_IDX_INO || + inode->i_ino == MONA_ACL_DATA_INO) + /* Nothing to do */ ; + else if (S_ISREG(inode->i_mode)) { + inode->i_op = &mona_file_inode_operations; + inode->i_fop = &mona_file_operations; + inode->i_mapping->a_ops = &mona_aops; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &mona_dir_inode_operations; + inode->i_fop = &mona_dir_operations; + } else if (S_ISLNK(inode->i_mode)) { + if (!inode->i_blocks) + inode->i_op = &mona_fast_symlink_inode_operations; + else { + inode->i_op = &mona_symlink_inode_operations; + inode->i_mapping->a_ops = &mona_aops; + } + } else + init_special_inode(inode, inode->i_mode, + le32_to_cpu(raw_inode->i_block[0])); + brelse (bh); + inode->i_attr_flags = 0; + if (inode->u.mona_i.i_flags & MONA_SYNC_FL) { + inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS; + inode->i_flags |= S_SYNC; + } + if (inode->u.mona_i.i_flags & MONA_APPEND_FL) { + inode->i_attr_flags |= ATTR_FLAG_APPEND; + inode->i_flags |= S_APPEND; + } + if (inode->u.mona_i.i_flags & MONA_IMMUTABLE_FL) { + inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE; + inode->i_flags |= S_IMMUTABLE; + } + if (inode->u.mona_i.i_flags & MONA_NOATIME_FL) { + inode->i_attr_flags |= ATTR_FLAG_NOATIME; + inode->i_flags |= S_NOATIME; + } + return; + +bad_inode: + make_bad_inode(inode); + return; +} + +static int mona_update_inode(struct inode * inode, int do_sync) +{ + struct buffer_head * bh; + struct mona_inode * raw_inode; + unsigned long block_group; + unsigned long group_desc; + unsigned long desc; + unsigned long block; + unsigned long offset; + int err = 0; + struct mona_group_desc * gdp; + + if ((inode->i_ino != MONA_ROOT_INO && + inode->i_ino < MONA_FIRST_INO(inode->i_sb)) || + inode->i_ino > le32_to_cpu(inode->i_sb->u.mona_sb.s_ms->s_inodes_count)) { + mona_error (inode->i_sb, "mona_write_inode", + "bad inode number: %lu", inode->i_ino); + return -EIO; + } + block_group = (inode->i_ino - 1) / MONA_INODES_PER_GROUP(inode->i_sb); + if (block_group >= inode->i_sb->u.mona_sb.s_groups_count) { + mona_error (inode->i_sb, "mona_write_inode", + "group >= groups count"); + return -EIO; + } + group_desc = block_group >> MONA_DESC_PER_BLOCK_BITS(inode->i_sb); + desc = block_group & (MONA_DESC_PER_BLOCK(inode->i_sb) - 1); + bh = inode->i_sb->u.mona_sb.s_group_desc[group_desc]; + if (!bh) { + mona_error (inode->i_sb, "mona_write_inode", + "Descriptor not loaded"); + return -EIO; + } + gdp = (struct mona_group_desc *) bh->b_data; + /* + * Figure out the offset within the block group inode table + */ + offset = ((inode->i_ino - 1) % MONA_INODES_PER_GROUP(inode->i_sb)) * + MONA_INODE_SIZE(inode->i_sb); + block = le32_to_cpu(gdp[desc].bg_inode_table) + + (offset >> MONA_BLOCK_SIZE_BITS(inode->i_sb)); + if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) { + mona_error (inode->i_sb, "mona_write_inode", + "unable to read inode block - " + "inode=%lu, block=%lu", inode->i_ino, block); + return -EIO; + } + offset &= MONA_BLOCK_SIZE(inode->i_sb) - 1; + raw_inode = (struct mona_inode *) (bh->b_data + offset); + + raw_inode->i_mode = cpu_to_le16(inode->i_mode); + if(!(test_opt(inode->i_sb, NO_UID32))) { + raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid)); + raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid)); +/* +* Fix up interoperability with old kernels. Otherwise, old inodes get +* re-used with the upper 16 bits of the uid/gid intact +*/ + if(!inode->u.mona_i.i_dtime) { + raw_inode->i_uid_high = cpu_to_le16(high_16_bits(inode->i_uid)); + raw_inode->i_gid_high = cpu_to_le16(high_16_bits(inode->i_gid)); + } else { + raw_inode->i_uid_high = 0; + raw_inode->i_gid_high = 0; + } + } else { + raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(inode->i_uid)); + raw_inode->i_gid_low = cpu_to_le16(fs_high2lowgid(inode->i_gid)); + raw_inode->i_uid_high = 0; + raw_inode->i_gid_high = 0; + } + raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); + raw_inode->i_size = cpu_to_le32(inode->i_size); + raw_inode->i_atime = cpu_to_le32(inode->i_atime); + raw_inode->i_ctime = cpu_to_le32(inode->i_ctime); + raw_inode->i_mtime = cpu_to_le32(inode->i_mtime); + raw_inode->i_blocks = cpu_to_le32(inode->i_blocks); + raw_inode->i_dtime = cpu_to_le32(inode->u.mona_i.i_dtime); + raw_inode->i_flags = cpu_to_le32(inode->u.mona_i.i_flags); + raw_inode->i_faddr = cpu_to_le32(inode->u.mona_i.i_faddr); + raw_inode->i_frag = inode->u.mona_i.i_frag_no; + raw_inode->i_fsize = inode->u.mona_i.i_frag_size; + raw_inode->i_file_acl = cpu_to_le32(inode->u.mona_i.i_file_acl); + if (S_ISDIR(inode->i_mode)) + raw_inode->i_dir_acl = cpu_to_le32(inode->u.mona_i.i_dir_acl); + else { + raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32); + if (raw_inode->i_size_high) { + struct super_block *sb = inode->i_sb; + if (!MONA_HAS_RO_COMPAT_FEATURE(sb, + MONA_FEATURE_RO_COMPAT_LARGE_FILE) || + MONA_SB(sb)->s_ms->s_rev_level == + cpu_to_le32(MONA_GOOD_OLD_REV)) { + /* If this is the first large file + * created, add a flag to the superblock. + */ + lock_kernel(); + mona_update_dynamic_rev(sb); + MONA_SET_RO_COMPAT_FEATURE(sb, MONA_FEATURE_RO_COMPAT_LARGE_FILE); + unlock_kernel(); + mona_write_super(sb); + } + } + } + + raw_inode->i_generation = cpu_to_le32(inode->i_generation); + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + raw_inode->i_block[0] = cpu_to_le32(kdev_t_to_nr(inode->i_rdev)); + else for (block = 0; block < MONA_N_BLOCKS; block++) + raw_inode->i_block[block] = inode->u.mona_i.i_data[block]; + mark_buffer_dirty(bh); + if (do_sync) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + if (buffer_req(bh) && !buffer_uptodate(bh)) { + printk ("IO error syncing mona inode [" + "%s:%08lx]\n", + bdevname(inode->i_dev), inode->i_ino); + err = -EIO; + } + } + brelse (bh); + return err; +} + +void mona_write_inode (struct inode * inode, int wait) +{ + lock_kernel(); + mona_update_inode (inode, wait); + unlock_kernel(); +} + +int mona_sync_inode (struct inode *inode) +{ + return mona_update_inode (inode, 1); +} + +int mona_notify_change(struct dentry *dentry, struct iattr *iattr) +{ + struct inode *inode = dentry->d_inode; + int retval; + unsigned int flags; + + retval = -EPERM; + if (iattr->ia_valid & ATTR_ATTR_FLAG && + ((!(iattr->ia_attr_flags & ATTR_FLAG_APPEND) != + !(inode->u.mona_i.i_flags & MONA_APPEND_FL)) || + (!(iattr->ia_attr_flags & ATTR_FLAG_IMMUTABLE) != + !(inode->u.mona_i.i_flags & MONA_IMMUTABLE_FL)))) { + if (!capable(CAP_LINUX_IMMUTABLE)) + goto out; + } else if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + goto out; + + retval = inode_change_ok(inode, iattr); + if (retval != 0) + goto out; + + inode_setattr(inode, iattr); + + flags = iattr->ia_attr_flags; + if (flags & ATTR_FLAG_SYNCRONOUS) { + inode->i_flags |= S_SYNC; + inode->u.mona_i.i_flags |= MONA_SYNC_FL; + } else { + inode->i_flags &= ~S_SYNC; + inode->u.mona_i.i_flags &= ~MONA_SYNC_FL; + } + if (flags & ATTR_FLAG_NOATIME) { + inode->i_flags |= S_NOATIME; + inode->u.mona_i.i_flags |= MONA_NOATIME_FL; + } else { + inode->i_flags &= ~S_NOATIME; + inode->u.mona_i.i_flags &= ~MONA_NOATIME_FL; + } + if (flags & ATTR_FLAG_APPEND) { + inode->i_flags |= S_APPEND; + inode->u.mona_i.i_flags |= MONA_APPEND_FL; + } else { + inode->i_flags &= ~S_APPEND; + inode->u.mona_i.i_flags &= ~MONA_APPEND_FL; + } + if (flags & ATTR_FLAG_IMMUTABLE) { + inode->i_flags |= S_IMMUTABLE; + inode->u.mona_i.i_flags |= MONA_IMMUTABLE_FL; + } else { + inode->i_flags &= ~S_IMMUTABLE; + inode->u.mona_i.i_flags &= ~MONA_IMMUTABLE_FL; + } + mark_inode_dirty(inode); +out: + return retval; +} + + + diff -ruN linux/fs/mona/k2u.c linux-mona/fs/mona/k2u.c --- linux/fs/mona/k2u.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/k2u.c Wed Jun 27 01:11:02 2001 @@ -0,0 +1,393 @@ +/*\ + * k2u.c + * + * added to the mona beast by PWR on or around june 25, 2001 + * initially called pete.c, before it became big enough to become + * a real part of mona. a good chunk of this stuff was moved here + * from mioctl.c, since all the k2u ioctl stuff was transferred to + * work only on a special /proc file instead of on a hardcoded file + * in /mona through the regular mona ioctl call. + * + * the following is present in this file: + * + * - initialization of /proc/fs/mona/ + * - get_info function for /proc/fs/mona/kernel_xforms + * - ioctl function for /proc/fs/mona/k2u + * - k2u support functions for communicationg with monad + * + * PWR: a relatively unimportant thing that needs fixing: + * I was good and wrapped all the proc function calls + * around #ifdef CONFIG_PROC_FS checks. So if a kernel + * is compiled without /proc support (unlikely, I think) + * then mona's /proc directory won't be created. In this + * case kernel xforms will still work, but no user xforms, + * since the daemon won't be able to communicate with the + * kernel. I think this is acceptable, but it should be + * stated in a better manner in a more suitable location. + * +\*/ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef CONFIG_PROC_FS +struct proc_dir_entry* proc_fs_mona; +struct proc_dir_entry* proc_fs_mona_k2u; +#endif + +extern kernelXformPtr function_listing; + +/* defined in xforms.c */ +extern void display_ku_list(KUinfoPtr list); +extern KUinfoPtr add_k2u(void); +extern KUinfoPtr get_ku_info(int id, KUinfoPtr list); +extern int move_to_u2k(KUinfoPtr kuip); +extern int del_u2k(KUinfoPtr kuip); +extern KUinfoPtr k2u_list; +extern KUinfoPtr u2k_list; +extern wait_queue_head_t mona_k2u_wait; + + +/* local prototypes */ +static int u2k(unsigned long arg); +static int k2u_master(unsigned long arg); +static int k2u_slave(unsigned long arg); + + +/* get_info function for /proc/fs/mona/kernel_xforms */ +int +mona_kernel_xforms_get_info(char* buffer, char** start, off_t offset, + int length) +{ + int len = 0; + + kernelXformPtr xfp = function_listing; + while(xfp != NULL) { + if(xfp->function_name != NULL) + len += sprintf(buffer + len, "%s\n", xfp->function_name); + xfp = xfp->next; + } + + *start = buffer + offset; + + len -= offset; + if (len > length) + len = length; + if (len < 0) + len = 0; + + return len; +} + +/* wake up the process waiting on a particular user xform */ +int wake_xform(int id) +{ + KUinfoPtr kuip; + + kuip = get_ku_info(id, u2k_list); + + if(kuip == NULL) + return KU_INVALID_ID; + + wake_up(&kuip->u2k_wait); + + return 0; +} + +int daemon_fail(unsigned long arg) +{ + int err; + struct mona_u2k u2k_st; + KUinfoPtr kuip; + + if((err = verify_area(VERIFY_READ, + (struct mona_u2k *) arg, sizeof(struct mona_u2k)))) { + mona_debug("Mona: u2k: err = %d\n", err); + return err; + } + + /* get the structure of the user space message */ + copy_from_user(&u2k_st, (struct mona_u2k *) arg, sizeof(struct mona_u2k)); + kuip = get_ku_info(u2k_st.id, u2k_list); + if(kuip == NULL) + kuip = get_ku_info(u2k_st.id, k2u_list); + if (kuip == NULL) { + mona_debug("Mona: u2k: Error, invalid user space transformation id %d\n", + u2k_st.id); + return KU_INVALID_ID; + } + + kuip->u2k_size = 1; /* export_xform decrements this to 0 ... */ + wake_up(&kuip->u2k_wait); + + return KU_SUCCESS; +} + +int u2k(unsigned long arg) +{ + int err; + struct mona_u2k u2k_st; + KUinfoPtr kuip; + + if((err = verify_area(VERIFY_READ, + (struct mona_u2k *) arg, sizeof(struct mona_u2k)))) { + mona_debug("Mona: u2k: err = %d\n", err); + return err; + } + + /* get the structure of the user space message */ + copy_from_user(&u2k_st, (struct mona_u2k *) arg, sizeof(struct mona_u2k)); + kuip = get_ku_info(u2k_st.id, u2k_list); + if(kuip == NULL) { + mona_debug("Mona: u2k: Error, invalid user space transformation id %d\n", + u2k_st.id); + return KU_INVALID_ID; + } + + /* kuip points to a KUinfo structure in the u2k_list */ + if(kuip->u2k_buf == NULL) + return KU_NO_DATA; + + if((err = + verify_area(VERIFY_READ, (char *) (u2k_st.buffer + u2k_st.offset), + U_K_MESSAGE_SIZE - u2k_st.offset))) { + mona_debug("Mona: u2k: err = %d\n", err); + return err; + } + + copy_from_user(kuip->u2k_buf, (char *) (u2k_st.buffer + u2k_st.offset), + U_K_MESSAGE_SIZE - u2k_st.offset); + kuip->u2k_size = u2k_st.size; + mona_debug("Mona: u2k: In u2k case, before waking u2k wait queue, id = %d\n", u2k_st.id); + wake_up(&kuip->u2k_wait); + schedule(); /* PWR: gratuitous ... there's better ways to do this * + * note: the schedule() doesn't circumvent any bugs, + * it just makes things happen slightly quicker ... sometimes */ + mona_debug("Mona: u2k: After waking u2k wait queue\n"); + + /* state is set to 1 by the user xform when fresh data is ready */ + if (kuip->k2u_state == 0) + return KU_NO_DATA; /* no data is available */ + + if((err = verify_area(VERIFY_WRITE, (char *) u2k_st.buffer, + kuip->k2u_size))) { + mona_debug("Mona: k2u_slave: verify_area failed at (1): err = %d\n", err); + return err; + } + copy_to_user((char *) u2k_st.buffer, kuip->k2u_buf, kuip->k2u_size); + u2k_st.size = kuip->k2u_size; + if((err = verify_area(VERIFY_WRITE, (struct mona_u2k *)arg, + sizeof(struct mona_u2k)))) { + mona_debug("Mona: k2u_slave: verify_area failed at (2): err = %d\n", err); + return err; + } + copy_to_user((struct mona_u2k *) arg, &u2k_st, sizeof(struct mona_u2k)); + + kuip->k2u_state = 0; /* mark kuip as having been read */ + + mona_debug("ioctl merge success!\n"); + + return KU_SUCCESS; +} + + + +int k2u_slave(unsigned long arg) { + int err; + struct mona_u2k k2u_st; + KUinfoPtr kuip; + + /* read which id the slave is requesting information for */ + if((err = verify_area(VERIFY_READ, (struct mona_u2k *) arg, + sizeof(struct mona_u2k)))) { + mona_debug("Mona: k2u_slave: verify_area failed: err = %d\n", err); + return err; + } + copy_from_user(&k2u_st, (struct mona_u2k *) arg, + sizeof(struct mona_u2k)); + + // mona_debug("slave %d says yo\n", k2u_st.id); + kuip = get_ku_info(k2u_st.id, u2k_list); + if (kuip == NULL) { + mona_debug("Mona: k2u_slave: Invalid identification number: %d\n", k2u_st.id); + return KU_INVALID_ID; + } + + /* state is set to 1 by the user xform when fresh data is ready */ + if (kuip->k2u_state == 0) + return KU_NO_DATA; /* no data is available */ + + if((err = verify_area(VERIFY_WRITE, (char *) k2u_st.buffer, + kuip->k2u_size))) { + mona_debug("Mona: k2u_slave: verify_area failed at (1): err = %d\n", err); + return err; + } + copy_to_user((char *) k2u_st.buffer, kuip->k2u_buf, kuip->k2u_size); + k2u_st.size = kuip->k2u_size; + if((err = verify_area(VERIFY_WRITE, (struct mona_u2k *)arg, + sizeof(struct mona_u2k)))) { + mona_debug("Mona: k2u_slave: verify_area failed at (2): err = %d\n", err); + return err; + } + copy_to_user((struct mona_u2k *) arg, &k2u_st, sizeof(struct mona_u2k)); + + kuip->k2u_state = 0; /* mark kuip as having been read */ + + return KU_SUCCESS; +} + + + +int k2u_master(unsigned long arg) { + int err; + struct mona_u2k k2u_st; + KUinfoPtr kuip; + + mona_debug("Mona: k2u_master: In k2u_master, at beginning\n"); + + /* check if the caller is root and return with an error if it is not */ + if (current->uid != 0) { + mona_debug("Mona: k2u_master: Attempt to use master ioctl call by user %d\n", current->uid); + return KU_NOT_ROOT; + } + + /* if there are no messages for the master daemon, put it to sleep */ + mona_debug("Putting to Sleep\n"); + if (k2u_list == NULL) + interruptible_sleep_on(&mona_k2u_wait); + + if (k2u_list == NULL) + return KU_NO_DATA; + + mona_debug("Didn't pass sleep\n"); + if((err = verify_area(VERIFY_READ, (struct mona_u2k *) arg, + sizeof(struct mona_u2k)))) { + mona_debug("k2u 1: err = %d\n", err); + return err; + } + + copy_from_user(&k2u_st, (struct mona_u2k *) arg, + sizeof(struct mona_u2k)); + + mona_debug("Mona: k2u_master: In k2u case, looks like k2u_list has at least one entry:\n"); + display_ku_list(k2u_list); + move_to_u2k(k2u_list); /* move the first element to the u2k_list */ + kuip = u2k_list; + + /* state is set to 1 by the user xform when fresh data is ready */ + if (kuip->k2u_state == 0) + return KU_NO_DATA; + + /* copy the buffer from the kernel to user space */ + if((err = verify_area(VERIFY_WRITE, (char *) k2u_st.buffer, + kuip->k2u_size))) { + mona_debug("Mona: k2u_master: (1) err = %d\n", err); + return err; + } + + copy_to_user((char *) k2u_st.buffer, kuip->k2u_buf, kuip->k2u_size); + k2u_st.size = kuip->k2u_size; + + if((err = verify_area(VERIFY_WRITE, (struct mona_u2k *)arg, + sizeof(struct mona_u2k)))) { + mona_debug("Mona: k2u_master: (2) err = %d\n", err); + return err; + } + + copy_to_user((struct mona_u2k *) arg, &k2u_st, + sizeof(struct mona_u2k)); + + kuip->k2u_state = 0; /* mark kuip as having been read */ + + return KU_SUCCESS; +} + + + + + +static int +mona_k2u_ioctl(struct inode* inode, struct file* filp, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + + case MONA_IOC_U2K: + return u2k(arg); + case MONA_IOC_K2U_MASTER: + return k2u_master(arg); + case MONA_IOC_K2U_SLAVE: + return k2u_slave(arg); + case MONA_IOC_WAKE_XFORM: + return wake_xform(arg); + case MONA_IOC_DAEMON_FAIL: + return daemon_fail(arg); + + default: + return -ENOTTY; + } + + return 0; +} + +/* PWR: this is silly, but correct, I think. maybe. + * however, there may be a way to get /proc to take care of perms */ +int mona_k2u_permission(struct inode *ino, int m) +{ + return 0; +} + +static struct file_operations mona_k2u_fops = { + owner: THIS_MODULE, + ioctl: mona_k2u_ioctl +}; + + +static struct inode_operations mona_k2u_iops = { + permission: mona_k2u_permission /* check for permissions */ +}; + + +/* create the /proc/fs/mona/ directory and its contents */ +void +create_mona_proc_entry(void) +{ + +#ifdef CONFIG_PROC_FS + /* create /proc/fs/mona/ directory */ + proc_fs_mona = proc_mkdir("mona", proc_root_fs); + proc_fs_mona->owner = THIS_MODULE; + + /* create /proc/fs/mona/k2u file for monad use */ + proc_fs_mona_k2u = create_proc_entry("k2u", 0, proc_fs_mona); + mona_k2u_fops.owner = THIS_MODULE; + proc_fs_mona_k2u->proc_iops = &mona_k2u_iops; + proc_fs_mona_k2u->proc_fops = &mona_k2u_fops; + + /* create /proc/fs/mona/kernel_xforms */ + create_proc_info_entry("kernel_xforms", 0, proc_fs_mona, + mona_kernel_xforms_get_info); + +#endif + +} + +/* remove the /proc/fs/mona/ directory and its contents */ +void +remove_mona_proc_entry(void) +{ + +#if CONFIG_PROC_FS + remove_proc_entry("kernel_xforms", proc_fs_mona); + remove_proc_entry("k2u", proc_fs_mona); + remove_proc_entry("mona", proc_root_fs); +#endif + +} diff -ruN linux/fs/mona/mioctl.c linux-mona/fs/mona/mioctl.c --- linux/fs/mona/mioctl.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/mioctl.c Tue Jun 26 11:29:37 2001 @@ -0,0 +1,310 @@ +/* + * linux/fs/ext2/ioctl.c + * + * Copyright (C) 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + */ + +#include +#include +#include +#include +#include +#include + + +// external prototypes - in xforms.c +extern void *get_fn(char *); +extern long get_export_xform_id(void); + +// external variables - in xforms.c +extern fileListPtr mfd_list; +extern long mfd_index; +extern XformIOstreamPtr xform_stream_table[HASH_TABLE_SIZE]; +extern kernelXformPtr function_listing; + + +/* local prototypes */ +static int push_stream(struct inode * i, struct file * fp, + unsigned long arg, int stream); +static int pop_stream(struct inode * i, struct file * fp, + unsigned long arg, int stream); + +static int push_stream(struct inode * inodep, struct file * filp, + unsigned long arg, int stream) +{ + XformInfoPtr tempInfoPtr, prevInfoPtr = NULL; + XformIOstreamPtr tempStreamPtr; + long index; + long hashed_index; + + // find the file if it exists or get a free one if this is the first xform + + if((index = match_mfd(filp)) < 0) + index = mfd_index++; + + hashed_index = index % HASH_TABLE_SIZE; + + // find the corresponding hash table entry, or create one if needed + tempStreamPtr = xform_stream_table[hashed_index]; + + while(tempStreamPtr != NULL) { + if(tempStreamPtr->id == index) + break; + else + tempStreamPtr = tempStreamPtr->next; + } + + if(tempStreamPtr == NULL) { + tempStreamPtr = xform_stream_table[hashed_index]; + xform_stream_table[hashed_index] = + (XformIOstreamPtr) kmalloc(sizeof(XformIOstream), GFP_KERNEL); + xform_stream_table[hashed_index]->next = tempStreamPtr; + tempStreamPtr = xform_stream_table[hashed_index]; + tempStreamPtr->id = index; + tempStreamPtr->stream[INPUT] = NULL; + tempStreamPtr->stream[OUTPUT] = NULL; + tempStreamPtr->overflow[INPUT] = tempStreamPtr->overflow[OUTPUT] = 0; + tempStreamPtr->stream_state[INPUT] = + tempStreamPtr->stream_state[OUTPUT] = XF_READY; + } + + // find the end of the xform list + tempInfoPtr = tempStreamPtr->stream[stream]; + + while(tempInfoPtr != NULL) { + prevInfoPtr = tempInfoPtr; + tempInfoPtr = tempInfoPtr->next_xform; + } + + if(tempInfoPtr == prevInfoPtr) { + tempStreamPtr->stream[stream] = (XformInfoPtr) kmalloc(sizeof(XformInfo), GFP_KERNEL); + tempInfoPtr = tempStreamPtr->stream[stream]; + } + else { + tempInfoPtr = (XformInfoPtr) kmalloc(sizeof(XformInfo), GFP_KERNEL); + prevInfoPtr->next_xform = tempInfoPtr; + } + + tempInfoPtr->private_data = NULL; + tempInfoPtr->filp = filp; + tempInfoPtr->inodep = inodep; + tempInfoPtr->next_xform = NULL; + tempInfoPtr->id = -1; + tempInfoPtr->stream_dir = stream; + tempInfoPtr->state = XF_READY; + tempInfoPtr->argc = 0; + tempInfoPtr->argv = NULL; + + if((tempInfoPtr->xform = + (int (*)(XformInfoPtr, int, char*)) get_fn((char*) arg)) == NULL) + { + tempInfoPtr->xform = + (int (*)(XformInfoPtr, int, char*)) get_fn("export_xform"); + tempInfoPtr->private_data = + (char *) kmalloc(strlen((char*) arg), GFP_KERNEL); + strcpy(tempInfoPtr->private_data, (char*) arg); + tempInfoPtr->id = get_export_xform_id(); + } + + mfd_insert(filp, index); + return 0; +} + +/* pop_stream pops a transformation off the end of an input stream. + * This is the "programmatic" way of removing a transformation. + */ +static int pop_stream(struct inode *inodep, struct file *filp, + unsigned long arg, int stream) +{ + XformInfoPtr tempInfoPtr, prevInfoPtr = NULL; + XformIOstreamPtr tempStreamPtr, savedStreamPtr; + long index; + long hashed_index; + + if((index = match_mfd(filp)) < 0) + return -1; + + hashed_index = index % HASH_TABLE_SIZE; + + tempStreamPtr = xform_stream_table[hashed_index]; + + while(tempStreamPtr != NULL) { + if(tempStreamPtr->id == index) + break; + tempStreamPtr = tempStreamPtr->next; + } + + if(tempStreamPtr == NULL) + return -1; + + tempInfoPtr = tempStreamPtr->stream[stream]; + prevInfoPtr = tempStreamPtr->stream[stream]; + + if(tempInfoPtr == NULL) + return -1; + + while(tempInfoPtr != NULL) { + prevInfoPtr = tempInfoPtr; + tempInfoPtr = tempInfoPtr->next_xform; + } + + // this will never happen (hopefully) + if(tempInfoPtr == prevInfoPtr) { + kfree(tempInfoPtr); + tempInfoPtr = NULL; + } + else { + prevInfoPtr->next_xform = NULL; + if(tempInfoPtr->private_data != NULL) + kfree(tempInfoPtr->private_data); + if(tempInfoPtr->argv != NULL) + kfree(tempInfoPtr->argv); + kfree(tempInfoPtr); + } + + // if this was the last xform on this fd, release the mfd + // and deallocate the entry in the hash table + if(tempStreamPtr->stream[INPUT] == NULL && tempStreamPtr->stream[OUTPUT] == NULL) { + savedStreamPtr = tempStreamPtr; + tempStreamPtr = xform_stream_table[hashed_index]; + if(tempStreamPtr == savedStreamPtr) { + kfree(xform_stream_table[hashed_index]); + xform_stream_table[hashed_index] = NULL; + } + else { + while(tempStreamPtr->next != savedStreamPtr) + tempStreamPtr = tempStreamPtr->next; + tempStreamPtr->next = savedStreamPtr->next; + kfree(savedStreamPtr); + } + mfd_delete(index); + } + + return 0; +} + +/* num_xforms counts the number of xforms on the input stream +*/ + +static long num_xforms(struct file * filp, int stream) +{ + XformIOstreamPtr tempStreamPtr; + XformInfoPtr tempInfoPtr; + long index, cnt = 0; + long hashed_index; + + // find the file if it exists or return -1 (the index) if there is none + if ((index = match_mfd(filp)) < 0) + return -1; + + hashed_index = index % HASH_TABLE_SIZE; + tempStreamPtr = xform_stream_table[hashed_index]; + + while(tempStreamPtr != NULL) { + if(tempStreamPtr->id == index) + break; + tempStreamPtr = tempStreamPtr->next; + } + + if(tempStreamPtr == NULL) + return -1; + + tempInfoPtr = tempStreamPtr->stream[stream]; + + // count the number of xforms + while(tempInfoPtr != NULL) { + if(tempInfoPtr->stream_dir == stream) + ++cnt; + tempInfoPtr = tempInfoPtr->next_xform; + } + + return cnt; +} + + +/* mona_ioctl is the Mona implementation of the ioctl call. It is much the same + * as ext2's, but has additional functionality for adding/removing transformations + * and working with user transformations +*/ + +int mona_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg) +{ + unsigned int flags; + + switch (cmd) { + case MONA_IOC_GETFLAGS: + flags = inode->u.mona_i.i_flags & MONA_FL_USER_VISIBLE; + return put_user(inode->u.mona_i.i_flags, (int *) arg); + case MONA_IOC_SETFLAGS: + if (get_user(flags, (int *) arg)) + return -EFAULT; + flags = flags & MONA_FL_USER_MODIFIABLE; + /* + * The IMMUTABLE and APPEND_ONLY flags can only be changed by + * the super user when the security level is zero. + */ + if ((flags & (MONA_APPEND_FL | MONA_IMMUTABLE_FL)) ^ + (inode->u.mona_i.i_flags & + (MONA_APPEND_FL | MONA_IMMUTABLE_FL))) { + /* This test looks nicer. Thanks to Pauline Middelink */ + if (!capable(CAP_LINUX_IMMUTABLE)) + return -EPERM; + } else + if ((current->fsuid != inode->i_uid) && + !capable(CAP_FOWNER)) + return -EPERM; + if (IS_RDONLY(inode)) + return -EROFS; + inode->u.mona_i.i_flags = (inode->u.mona_i.i_flags & + ~MONA_FL_USER_MODIFIABLE) | flags; + if (flags & MONA_SYNC_FL) + inode->i_flags |= MS_SYNCHRONOUS; + else + inode->i_flags &= ~MS_SYNCHRONOUS; + if (flags & MONA_APPEND_FL) + inode->i_flags |= S_APPEND; + else + inode->i_flags &= ~S_APPEND; + if (flags & MONA_IMMUTABLE_FL) + inode->i_flags |= S_IMMUTABLE; + else + inode->i_flags &= ~S_IMMUTABLE; + if (flags & MONA_NOATIME_FL) + inode->i_flags |= MS_NOATIME; + else + inode->i_flags &= ~MS_NOATIME; + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + return 0; + case MONA_IOC_GETVERSION: + return put_user(inode->i_generation, (int *) arg); + case MONA_IOC_SETVERSION: + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EPERM; + if (IS_RDONLY(inode)) + return -EROFS; + if (get_user(inode->i_generation, (int *) arg)) + return -EFAULT; + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + return 0; + case MONA_IOC_PUSH_INPUT: + return push_stream(inode, filp, arg, INPUT); + case MONA_IOC_POP_INPUT: + return pop_stream(inode, filp, arg, INPUT); + case MONA_IOC_PUSH_OUTPUT: + return push_stream(inode, filp, arg, OUTPUT); + case MONA_IOC_POP_OUTPUT: + return pop_stream(inode, filp, arg, OUTPUT); + case MONA_IOC_NUM_IN_XFORMS: + return num_xforms(filp, INPUT); + case MONA_IOC_NUM_OUT_XFORMS: + return num_xforms(filp, OUTPUT); + default: + return -ENOTTY; + } + +} diff -ruN linux/fs/mona/mopen.c linux-mona/fs/mona/mopen.c --- linux/fs/mona/mopen.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/mopen.c Thu Jun 21 14:17:38 2001 @@ -0,0 +1,34 @@ +/* + * linux/fs/mona/......... + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include + +extern XformListPtr xform_data_list[3]; + +int mona_file_open (struct inode * inode, struct file * filp) +{ + if (!(filp->f_flags & O_LARGEFILE) && + inode->i_size > 0x7FFFFFFF) + return -EFBIG; + + /* See if we have any transformations to add, if not, return. */ + if(xform_data_list[INPUT] == NULL && xform_data_list[OUTPUT] == NULL) + return 0; + + /* Build the transformation tree from the transforms found by mona_follow_link */ + if(build_xform_tree(inode, filp) == EBADF) + return -EBADF; + + return 0; +} \ No newline at end of file diff -ruN linux/fs/mona/mread.c linux-mona/fs/mona/mread.c --- linux/fs/mona/mread.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/mread.c Wed Jun 27 00:27:39 2001 @@ -0,0 +1,368 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +extern XformIOstreamPtr xform_stream_table[HASH_TABLE_SIZE]; +extern task_queue tq_disk; + +unsigned int page_hash_bits; +struct page **page_hash_table; + +#define CLUSTER_PAGES (1 << page_cluster) +#define CLUSTER_OFFSET(x) (((x) >> page_cluster) << page_cluster) + +/* do_input_xforms executes the input transformations +*/ +static int do_input_xforms(char *buffer, int nr, long mfd, + XformIOstreamPtr StreamPtr) +{ + int total_bytes_sent = 0, nr_start = nr; + XformInfoPtr xf_ptr = StreamPtr->stream[INPUT]; + + if(StreamPtr->stream_state[INPUT] == XF_HAS_DATA) { + while(xf_ptr != NULL) { + if(xf_ptr->state == XF_HAS_DATA) + break; + xf_ptr = xf_ptr->next_xform; + } + } + + StreamPtr->stream_state[INPUT] = XF_READY; + + while(xf_ptr != NULL) { + total_bytes_sent = xf_ptr->xform(xf_ptr, nr, buffer); + if(xf_ptr->state == XF_HAS_DATA) { + if (total_bytes_sent < 0) + continue; + StreamPtr->stream_state[INPUT] = XF_HAS_DATA; + } + xf_ptr = xf_ptr->next_xform; + } + + if(StreamPtr->stream_state[INPUT] == XF_HAS_DATA && StreamPtr->overflow[INPUT] == 0) + StreamPtr->overflow[INPUT] = nr_start; + + return total_bytes_sent; +} + +/* +* This is based on the generic file read routine, and uses the +* inode->i_op->readpage() function for the actual low-level +* stuff. +* +* This is really ugly. But the goto's actually try to clarify some +* of the logic when it comes to error handling etc. +*/ +static void do_mona_file_read(struct file * filp, loff_t *ppos, + read_descriptor_t * desc, read_actor_m actor, + long mfd, XformIOstreamPtr StreamPtr) +{ + struct inode *inode = filp->f_dentry->d_inode; + struct address_space *mapping = inode->i_mapping; + unsigned long index, offset; + struct page *cached_page; + int reada_ok, error; + int max_readahead = get_max_readahead(inode); + char xform_buf[XFORM_PAGE_SIZE]; + int actual_bytes_sent = 0; + unsigned long nr; + + cached_page = NULL; + + index = *ppos >> PAGE_CACHE_SHIFT; + offset = *ppos & ~PAGE_CACHE_MASK; + + /* + * If the current position is outside the previous read-ahead window, + * we reset the current read-ahead context and set read ahead max to zero + * (will be set to just needed value later), + * otherwise, we assume that the file accesses are sequential enough to + * continue read-ahead. + */ + if (index > filp->f_raend || index + filp->f_rawin < filp->f_raend) { + reada_ok = 0; + filp->f_raend = 0; + filp->f_ralen = 0; + filp->f_ramax = 0; + filp->f_rawin = 0; + } else { + reada_ok = 1; + } + /* + * Adjust the current value of read-ahead max. + * If the read operation stay in the first half page, force no readahead. + * Otherwise try to increase read ahead max just enough to do the read request. + * Then, at least MIN_READAHEAD if read ahead is ok, + * and at most MAX_READAHEAD in all cases. + */ + if (!index && offset + desc->count <= (PAGE_CACHE_SIZE >> 1)) + filp->f_ramax = 0; + else { + unsigned long needed; + + needed = ((offset + desc->count) >> PAGE_CACHE_SHIFT) + 1; + + if (filp->f_ramax < needed) + filp->f_ramax = needed; + + if (reada_ok && filp->f_ramax < MIN_READAHEAD) + filp->f_ramax = MIN_READAHEAD; + if (filp->f_ramax > max_readahead) + filp->f_ramax = max_readahead; + } + + for (;;) { + struct page *page, **hash; + unsigned long end_index; + + end_index = inode->i_size >> PAGE_CACHE_SHIFT; + if (index > end_index) + break; + nr = PAGE_CACHE_SIZE; + if (index == end_index) { + nr = inode->i_size & ~PAGE_CACHE_MASK; + if (nr <= offset) + break; // we're all done + } + + nr = nr - offset; + + /* + * Try to find the data in the page cache.. + */ + hash = page_hash(mapping, index); + + spin_lock(&pagecache_lock); + page = __find_page_nolock(mapping, index, *hash); + if (!page) + goto no_cached_page; + found_page: + page_cache_get(page); + spin_unlock(&pagecache_lock); + + if (!Page_Uptodate(page)) + goto page_not_up_to_date; + generic_file_readahead(reada_ok, filp, inode, page); + + page_ok: + /* If users can be writing to this page using arbitrary + * virtual addresses, take care about potential aliasing + * before reading the page on the kernel side. + */ + if (page->mapping->i_mmap_shared != NULL) + flush_dcache_page(page); + + /* + * Ok, we have the page, and it's up-to-date, so + * now we can copy it to user space... + * + * The actor routine returns how many bytes were actually used.. + * NOTE! This may not be the same as how much of a user buffer + * we filled up (we may be padding etc), so we can only update + * "pos" here (the actor routine has to update the user buffer + * pointers and the remaining count). + */ + + memcpy(xform_buf, (void*) (page_address(page) + offset), nr); + + actual_bytes_sent = do_input_xforms(xform_buf, nr, mfd, StreamPtr); + + nr = actor(desc, xform_buf, actual_bytes_sent); + + offset += nr; + + if(StreamPtr->stream_state[INPUT] == XF_HAS_DATA) + offset -= nr; + else if(StreamPtr->overflow[INPUT] != 0) { + offset -= nr; + offset += StreamPtr->overflow[INPUT]; + StreamPtr->overflow[INPUT] = 0; + } + + index += offset >> PAGE_CACHE_SHIFT; + offset &= ~PAGE_CACHE_MASK; + + page_cache_release(page); + + if (nr && desc->count) + continue; + break; + + /* + * Ok, the page was not immediately readable, so let's try to read ahead while we're at it.. + */ + page_not_up_to_date: + generic_file_readahead(reada_ok, filp, inode, page); + + if (Page_Uptodate(page)) + goto page_ok; + + /* Get exclusive access to the page ... */ + lock_page(page); + if (Page_Uptodate(page)) { + UnlockPage(page); + goto page_ok; + } + + readpage: + /* ... and start the actual read. The read will unlock the page. */ + error = mapping->a_ops->readpage(filp, page); + + if (!error) { + if (Page_Uptodate(page)) + goto page_ok; + + /* Again, try some read-ahead while waiting for the page to finish.. */ + generic_file_readahead(reada_ok, filp, inode, page); + wait_on_page(page); + if (Page_Uptodate(page)) + goto page_ok; + error = -EIO; + } + + /* UHHUH! A synchronous read error occurred. Report it */ + desc->error = error; + page_cache_release(page); + break; + + no_cached_page: + /* + * Ok, it wasn't cached, so we need to create a new + * page.. + * + * We get here with the page cache lock held. + */ + if (!cached_page) { + spin_unlock(&pagecache_lock); + cached_page = page_cache_alloc(); + if (!cached_page) { + desc->error = -ENOMEM; + break; + } + + /* + * Somebody may have added the page while we + * dropped the page cache lock. Check for that. + */ + spin_lock(&pagecache_lock); + page = __find_page_nolock(mapping, index, *hash); + if (page) + goto found_page; + } + + /* + * Ok, add the new page to the hash-queues... + */ + page = cached_page; + __add_to_page_cache(page, mapping, index, hash); + spin_unlock(&pagecache_lock); + cached_page = NULL; + + goto readpage; + } + + *ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset; + filp->f_reada = 1; + if (cached_page) + page_cache_free(cached_page); + UPDATE_ATIME(inode); +} + + +static int mona_read_actor(read_descriptor_t *desc, char *buffer, unsigned long size) +{ + unsigned long left; + unsigned long count = desc->count; + + if(size > count) + size = count; + left = __copy_to_user(desc->buf, buffer, size); + if(left) { + size -= left; + desc->error = -EFAULT; + } + desc->count = count - size; + desc->written += size; + desc->buf += size; + + return size; +} + + +/* +* This is the "read()" routine for all filesystems +* that can use the page cache directly. +*/ +ssize_t mona_file_read(struct file * filp, char * buf, size_t count, + loff_t *ppos) +{ + ssize_t retval; + long mfd, hashed_index; + XformIOstreamPtr tempStreamPtr; + + retval = -EFAULT; + if (access_ok(VERIFY_WRITE, buf, count)) { + retval = 0; + if (count) { + read_descriptor_t desc; + + desc.written = 0; + desc.count = count; + desc.buf = buf; + desc.error = 0; + + // check if there are any transformations on this file + mfd = match_mfd(filp); + + if(mfd >= 0) { + hashed_index = mfd % HASH_TABLE_SIZE; + + tempStreamPtr = xform_stream_table[hashed_index]; + + while(tempStreamPtr != NULL) { + if(tempStreamPtr->id == mfd) + break; + tempStreamPtr = tempStreamPtr->next; + } + + if(tempStreamPtr == NULL) + return -1; + + if(tempStreamPtr->stream[INPUT] != NULL) + do_mona_file_read(filp, ppos, &desc, mona_read_actor, mfd, tempStreamPtr); + else + do_generic_file_read(filp, ppos, &desc, file_read_actor); + + } + else + do_generic_file_read(filp, ppos, &desc, file_read_actor); + + + retval = desc.written; + if (!retval) + retval = desc.error; + } + } + + return retval; +} diff -ruN linux/fs/mona/mrelease.c linux-mona/fs/mona/mrelease.c --- linux/fs/mona/mrelease.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/mrelease.c Wed Jun 27 01:16:25 2001 @@ -0,0 +1,124 @@ +/* + * linux/fs/mona/file.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/file.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * mona fs regular file handling primitives + * + * 64-bit file support on 64-bit platforms by Jakub Jelinek + * (jj@sunsite.ms.mff.cuni.cz) + */ + +#include +#include +#include +#include +#include + +extern XformIOstreamPtr xform_stream_table[HASH_TABLE_SIZE]; + +/* from xforms.c */ +extern KUinfoPtr u2k_list; +extern KUinfoPtr get_ku_info(int id, KUinfoPtr list); +extern int del_u2k(KUinfoPtr kuip); + + +/* recursively free all the xforms in a linked list */ +void free_xforms(XformInfoPtr xip) { + int i; + mona_debug("free_xforms\n"); + + if (xip != NULL) { + if(xip->next_xform != NULL) + free_xforms(xip->next_xform); + + /* free up KU info stuff if this is a export xform */ + if (xip->id >= 0) { + KUinfoPtr kuip = get_ku_info(xip->id, u2k_list); + if (kuip) + del_u2k(kuip); + } + + if(xip->private_data != NULL) + kfree(xip->private_data); + + if(xip->argv != NULL) { + for(i = 0; i < xip->argc; i++) + kfree(xip->argv[i]); + kfree(xip->argv); + } + + kfree(xip); + xip = NULL; + } +} + +void free_kernel_xforms(kernelXformPtr kPtr) { + if(kPtr != NULL) { + free_kernel_xforms(kPtr->next); + if(kPtr->function_name != NULL) + kfree(kPtr->function_name); + } +} + +/* + * Called when an inode is released. Note that this is different + * from mona_open: open gets called at every open, but release + * gets called only when /all/ the files are closed. + */ +int mona_release_file (struct inode * inode, struct file * filp) +{ + long mfd, hashed_index; + XformIOstreamPtr tempStreamPtr, prevStreamPtr; + + mfd = match_mfd(filp); + if(mfd >= 0) { + hashed_index = mfd % HASH_TABLE_SIZE; + tempStreamPtr = xform_stream_table[hashed_index]; + prevStreamPtr = NULL; + + while(tempStreamPtr != NULL) { + if(tempStreamPtr->id == mfd) { + break; + } + tempStreamPtr = tempStreamPtr->next; + prevStreamPtr = tempStreamPtr; + } + + if(tempStreamPtr == NULL) + return 0; + + if(prevStreamPtr != NULL) { + prevStreamPtr->next = tempStreamPtr->next; + if(tempStreamPtr->stream[INPUT] != NULL) + free_xforms(tempStreamPtr->stream[INPUT]); + if(tempStreamPtr->stream[OUTPUT] != NULL) + free_xforms(tempStreamPtr->stream[OUTPUT]); + } + else { + xform_stream_table[hashed_index] = tempStreamPtr->next; + if(tempStreamPtr->stream[INPUT] != NULL) + free_xforms(tempStreamPtr->stream[INPUT]); + if(tempStreamPtr->stream[OUTPUT] != NULL) + free_xforms(tempStreamPtr->stream[OUTPUT]); + } + + kfree(tempStreamPtr); + + mfd_delete(mfd); + } + + if(filp->f_mode & FMODE_WRITE) + mona_discard_prealloc (inode); + + return 0; +} diff -ruN linux/fs/mona/mwrite.c linux-mona/fs/mona/mwrite.c --- linux/fs/mona/mwrite.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/mwrite.c Thu Jun 21 14:17:38 2001 @@ -0,0 +1,274 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +extern XformIOstreamPtr xform_stream_table[HASH_TABLE_SIZE]; + +static inline int do_output_xforms(char *buffer, int nr, long mfd, + XformIOstreamPtr StreamPtr) +{ + int total_bytes_sent = 0, nr_start = nr; + XformInfoPtr xf_ptr = StreamPtr->stream[OUTPUT]; + + if(StreamPtr->stream_state[OUTPUT] == XF_HAS_DATA) { + while(xf_ptr != NULL) { + if(xf_ptr->state == XF_HAS_DATA) + break; + else + xf_ptr = xf_ptr->next_xform; + } + } + + StreamPtr->stream_state[OUTPUT] = XF_READY; + + while(xf_ptr != NULL) { + total_bytes_sent = xf_ptr->xform(xf_ptr, nr, buffer); + if(xf_ptr->state == XF_HAS_DATA) + StreamPtr->stream_state[OUTPUT] = XF_HAS_DATA; + + xf_ptr = xf_ptr->next_xform; + } + + if(StreamPtr->stream_state[OUTPUT] == XF_HAS_DATA && StreamPtr->overflow[OUTPUT] == 0) + StreamPtr->overflow[OUTPUT] = nr_start; + + return total_bytes_sent; +} + +static inline void cp_xform2mem(char *to, const char *from, unsigned long n) { + long i; + + for (i=0; if_dentry->d_inode; + struct address_space *mapping = inode->i_mapping; + unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur; + loff_t pos; + struct page *page, *cached_page = NULL; + unsigned long written; + long status; + int err; + int actual_bytes_sent = 0; + long mfd, hashed_index; + XformIOstreamPtr tempStreamPtr = NULL; + + down(&inode->i_sem); + + pos = *ppos; + err = -EINVAL; + if (pos < 0) + goto out; + + err = file->f_error; + if (err) { + file->f_error = 0; + goto out; + } + + written = 0; + + if (file->f_flags & O_APPEND) + pos = inode->i_size; + + /* + * Check whether we've reached the file size limit. + */ + err = -EFBIG; + if (limit != RLIM_INFINITY) { + if (pos >= limit) { + send_sig(SIGXFSZ, current, 0); + goto out; + } + if (count > limit - pos) { + send_sig(SIGXFSZ, current, 0); + count = limit - pos; + } + } + + status = 0; + if (count) { + remove_suid(inode); + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + mark_inode_dirty(inode); + } + + mfd = match_mfd(file); + + if(mfd >= 0) { + hashed_index = mfd % HASH_TABLE_SIZE; + + tempStreamPtr = xform_stream_table[hashed_index]; + + while(tempStreamPtr != NULL) { + if(tempStreamPtr->id == mfd) + break; + + tempStreamPtr = tempStreamPtr->next; + } + + if(tempStreamPtr == NULL) + return -1; + } + + while (count) { + unsigned long bytes, index, offset; + char *kaddr; + int deactivate = 1; + /* + * Try to find the page in the cache. If it isn't there, + * allocate a free page. + */ + offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */ + index = pos >> PAGE_CACHE_SHIFT; + bytes = PAGE_CACHE_SIZE - offset; + + if (bytes > count) { + bytes = count; + deactivate = 0; + } + + /* + * Bring in the user page that we will copy from _first_. + * Otherwise there's a nasty deadlock on copying from the + * same page as we're writing to, without it being marked + * up-to-date. + */ + { volatile unsigned char dummy; + __get_user(dummy, buf); + __get_user(dummy, buf+bytes-1); + } + + status = -ENOMEM; /* we'll assign it later anyway */ + page = __grab_cache_page(mapping, index, &cached_page); + if (!page) + break; + + /* We have exclusive IO access to the page.. */ + if (!PageLocked(page)) { + PAGE_BUG(page); + } + + status = mapping->a_ops->prepare_write(file, page, offset, offset+bytes); + if (status) + goto unlock; + + if(tempStreamPtr) + actual_bytes_sent = do_output_xforms(buf, bytes, mfd, tempStreamPtr); + + // copy the data to the page + kaddr = page_address(page); + status = copy_from_user(kaddr+offset, buf, bytes); + + flush_dcache_page(page); + if (status) + goto fail_write; + status = mapping->a_ops->commit_write(file, page, offset, offset+bytes); + if (!status) + status = bytes; + + if (status >= 0) { + written += status; + count -= status; + pos += status; + buf += status; + } + if(tempStreamPtr) { + if(tempStreamPtr->stream_state[OUTPUT] == XF_HAS_DATA) + count += status; + else if(tempStreamPtr->overflow[OUTPUT] != 0) { + count = 0; + written = tempStreamPtr->overflow[OUTPUT]; + tempStreamPtr->overflow[OUTPUT] = 0; + } + } +unlock: + /* Mark it unlocked again and drop the page.. */ + UnlockPage(page); + if(deactivate) + deactivate_page(page); + page_cache_release(page); + + if (status < 0) + break; + + + } + + *ppos = pos; + + if (cached_page) + page_cache_free(cached_page); + + /* For now, when the user asks for O_SYNC, we'll actually + * provide O_DSYNC. */ + //if ((status >= 0) && (file->f_flags & O_SYNC)) + //status = generic_osync_inode(inode, 1); + + err = written ? written : status; +out: + up(&inode->i_sem); + return err; +fail_write: + status = -EFAULT; + ClearPageUptodate(page); + kunmap(page); + goto unlock; +} \ No newline at end of file diff -ruN linux/fs/mona/namei.c linux-mona/fs/mona/namei.c --- linux/fs/mona/namei.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/namei.c Thu Jun 21 14:17:39 2001 @@ -0,0 +1,846 @@ +/* + * linux/fs/mona/namei.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/namei.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + * Directory entry file type support and forward compatibility hooks + * for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998 + */ + +#include +#include +#include +#include +#include + +/* + * define how far ahead to read directories while searching them. + */ +#define NAMEI_RA_CHUNKS 2 +#define NAMEI_RA_BLOCKS 4 +#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) +#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b)) + +/* + * NOTE! unlike strncmp, mona_match returns 1 for success, 0 for failure. + * + * `len <= MONA_NAME_LEN' is guaranteed by caller. + * `de != NULL' is guaranteed by caller. + */ +static inline int mona_match (int len, const char * const name, + struct mona_dir_entry_2 * de) +{ + if (len != de->name_len) + return 0; + if (!de->inode) + return 0; + return !memcmp(name, de->name, len); +} + +/* + * mona_find_entry() + * + * finds an entry in the specified directory with the wanted name. It + * returns the cache buffer in which the entry was found, and the entry + * itself (as a parameter - res_dir). It does NOT read the inode of the + * entry - you'll have to do that yourself if you want to. + */ +static struct buffer_head * mona_find_entry (struct inode * dir, + const char * const name, int namelen, + struct mona_dir_entry_2 ** res_dir) +{ + struct super_block * sb; + struct buffer_head * bh_use[NAMEI_RA_SIZE]; + struct buffer_head * bh_read[NAMEI_RA_SIZE]; + unsigned long offset; + int block, toread, i, err; + + *res_dir = NULL; + sb = dir->i_sb; + + if (namelen > MONA_NAME_LEN) + return NULL; + + memset (bh_use, 0, sizeof (bh_use)); + toread = 0; + for (block = 0; block < NAMEI_RA_SIZE; ++block) { + struct buffer_head * bh; + + if ((block << MONA_BLOCK_SIZE_BITS (sb)) >= dir->i_size) + break; + bh = mona_getblk (dir, block, 0, &err); + bh_use[block] = bh; + if (bh && !buffer_uptodate(bh)) + bh_read[toread++] = bh; + } + + for (block = 0, offset = 0; offset < dir->i_size; block++) { + struct buffer_head * bh; + struct mona_dir_entry_2 * de; + char * dlimit; + + if ((block % NAMEI_RA_BLOCKS) == 0 && toread) { + ll_rw_block (READ, toread, bh_read); + toread = 0; + } + bh = bh_use[block % NAMEI_RA_SIZE]; + if (!bh) { +#if 0 + mona_error (sb, "mona_find_entry", + "directory #%lu contains a hole at offset %lu", + dir->i_ino, offset); +#endif + offset += sb->s_blocksize; + continue; + } + wait_on_buffer (bh); + if (!buffer_uptodate(bh)) { + /* + * read error: all bets are off + */ + break; + } + + de = (struct mona_dir_entry_2 *) bh->b_data; + dlimit = bh->b_data + sb->s_blocksize; + while ((char *) de < dlimit) { + /* this code is executed quadratically often */ + /* do minimal checking `by hand' */ + int de_len; + + if ((char *) de + namelen <= dlimit && + mona_match (namelen, name, de)) { + /* found a match - + just to be sure, do a full check */ + if (!mona_check_dir_entry("mona_find_entry", + dir, de, bh, offset)) + goto failure; + for (i = 0; i < NAMEI_RA_SIZE; ++i) { + if (bh_use[i] != bh) + brelse (bh_use[i]); + } + *res_dir = de; + return bh; + } + /* prevent looping on a bad block */ + de_len = le16_to_cpu(de->rec_len); + if (de_len <= 0) + goto failure; + offset += de_len; + de = (struct mona_dir_entry_2 *) + ((char *) de + de_len); + } + + brelse (bh); + if (((block + NAMEI_RA_SIZE) << MONA_BLOCK_SIZE_BITS (sb)) >= + dir->i_size) + bh = NULL; + else + bh = mona_getblk (dir, block + NAMEI_RA_SIZE, 0, &err); + bh_use[block % NAMEI_RA_SIZE] = bh; + if (bh && !buffer_uptodate(bh)) + bh_read[toread++] = bh; + } + +failure: + for (i = 0; i < NAMEI_RA_SIZE; ++i) + brelse (bh_use[i]); + return NULL; +} + +static struct dentry *mona_lookup(struct inode * dir, struct dentry *dentry) +{ + struct inode * inode; + struct mona_dir_entry_2 * de; + struct buffer_head * bh; + + if (dentry->d_name.len > MONA_NAME_LEN) + return ERR_PTR(-ENAMETOOLONG); + + bh = mona_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de); + inode = NULL; + if (bh) { + unsigned long ino = le32_to_cpu(de->inode); + brelse (bh); + inode = iget(dir->i_sb, ino); + + if (!inode) + return ERR_PTR(-EACCES); + } + d_add(dentry, inode); + return NULL; +} + +#define S_SHIFT 12 +static unsigned char mona_type_by_mode[S_IFMT >> S_SHIFT] = { + [S_IFREG >> S_SHIFT] MONA_FT_REG_FILE, + [S_IFDIR >> S_SHIFT] MONA_FT_DIR, + [S_IFCHR >> S_SHIFT] MONA_FT_CHRDEV, + [S_IFBLK >> S_SHIFT] MONA_FT_BLKDEV, + [S_IFIFO >> S_SHIFT] MONA_FT_FIFO, + [S_IFSOCK >> S_SHIFT] MONA_FT_SOCK, + [S_IFLNK >> S_SHIFT] MONA_FT_SYMLINK, +}; + + +static inline void mona_set_de_type(struct super_block *sb, + struct mona_dir_entry_2 *de, + umode_t mode) { + if (MONA_HAS_INCOMPAT_FEATURE(sb, MONA_FEATURE_INCOMPAT_FILETYPE)) + de->file_type = mona_type_by_mode[(mode & S_IFMT)>>S_SHIFT]; +} + + +/* +* mona_add_entry() +* +* adds a file entry to the specified directory. +*/ +int mona_add_entry (struct inode * dir, const char * name, int namelen, + struct inode *inode) +{ + unsigned long offset; + unsigned short rec_len; + struct buffer_head * bh; + struct mona_dir_entry_2 * de, * de1; + struct super_block * sb; + int retval; + + sb = dir->i_sb; + + if (!namelen) + return -EINVAL; + bh = mona_bread (dir, 0, 0, &retval); + if (!bh) + return retval; + rec_len = MONA_DIR_REC_LEN(namelen); + offset = 0; + de = (struct mona_dir_entry_2 *) bh->b_data; + while (1) { + if ((char *)de >= sb->s_blocksize + bh->b_data) { + brelse (bh); + bh = NULL; + bh = mona_bread (dir, offset >> MONA_BLOCK_SIZE_BITS(sb), 1, &retval); + if (!bh) + return retval; + if (dir->i_size <= offset) { + if (dir->i_size == 0) { + return -ENOENT; + } + + de = (struct mona_dir_entry_2 *) bh->b_data; + de->inode = 0; + de->rec_len = le16_to_cpu(sb->s_blocksize); + dir->i_size = offset + sb->s_blocksize; + dir->u.mona_i.i_flags &= ~MONA_BTREE_FL; + mark_inode_dirty(dir); + } else + de = (struct mona_dir_entry_2 *) bh->b_data; + + } + if (!mona_check_dir_entry ("mona_add_entry", dir, de, bh, + offset)) { + brelse (bh); + return -ENOENT; + } + if (mona_match (namelen, name, de)) { + brelse (bh); + return -EEXIST; + } + if ((le32_to_cpu(de->inode) == 0 && le16_to_cpu(de->rec_len) >= rec_len) || + (le16_to_cpu(de->rec_len) >= MONA_DIR_REC_LEN(de->name_len) + rec_len)) { + offset += le16_to_cpu(de->rec_len); + if (le32_to_cpu(de->inode)) { + de1 = (struct mona_dir_entry_2 *) ((char *) de + + MONA_DIR_REC_LEN(de->name_len)); + de1->rec_len = cpu_to_le16(le16_to_cpu(de->rec_len) - + MONA_DIR_REC_LEN(de->name_len)); + de->rec_len = cpu_to_le16(MONA_DIR_REC_LEN(de->name_len)); + de = de1; + } + de->file_type = MONA_FT_UNKNOWN; + if (inode) { + de->inode = cpu_to_le32(inode->i_ino); + mona_set_de_type(dir->i_sb, de, inode->i_mode); + } else + de->inode = 0; + de->name_len = namelen; + memcpy (de->name, name, namelen); + /* + * XXX shouldn't update any times until successful + * completion of syscall, but too many callers depend + * on this. + * + * XXX similarly, too many callers depend on + * mona_new_inode() setting the times, but error + * recovery deletes the inode, so the worst that can + * happen is that the times are slightly out of date + * and/or different from the directory change time. + */ + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + dir->u.mona_i.i_flags &= ~MONA_BTREE_FL; + mark_inode_dirty(dir); + dir->i_version = ++event; + mark_buffer_dirty(bh); + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + brelse(bh); + return 0; + } + offset += le16_to_cpu(de->rec_len); + de = (struct mona_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); + } + brelse (bh); + return -ENOSPC; +} + +/* + * mona_delete_entry deletes a directory entry by merging it with the + * previous entry + */ +static int mona_delete_entry (struct inode * dir, + struct mona_dir_entry_2 * de_del, + struct buffer_head * bh) +{ + struct mona_dir_entry_2 * de, * pde; + int i; + + i = 0; + pde = NULL; + de = (struct mona_dir_entry_2 *) bh->b_data; + while (i < bh->b_size) { + if (!mona_check_dir_entry ("mona_delete_entry", NULL, + de, bh, i)) + return -EIO; + if (de == de_del) { + if (pde) + pde->rec_len = + cpu_to_le16(le16_to_cpu(pde->rec_len) + + le16_to_cpu(de->rec_len)); + else + de->inode = 0; + dir->i_version = ++event; + mark_buffer_dirty(bh); + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + return 0; + } + i += le16_to_cpu(de->rec_len); + pde = de; + de = (struct mona_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); + } + return -ENOENT; +} + +/* + * By the time this is called, we already have created + * the directory cache entry for the new file, but it + * is so far negative - it has no inode. + * + * If the create succeeds, we fill in the inode information + * with d_instantiate(). + */ +static int mona_create (struct inode * dir, struct dentry * dentry, int mode) +{ + struct inode * inode = mona_new_inode(dir, mode); + int err = PTR_ERR(inode); + if(IS_ERR(inode)) + return err; + + inode->i_op = &mona_file_inode_operations; + inode->i_fop = &mona_file_operations; + inode->i_mapping->a_ops = &mona_aops; + inode->i_mode = mode; + mark_inode_dirty(inode); + err = mona_add_entry (dir, dentry->d_name.name, dentry->d_name.len, + inode); + if (err) { + inode->i_nlink--; + mark_inode_dirty(inode); + iput (inode); + return err; + } + d_instantiate(dentry, inode); + return 0; +} + +static int mona_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev) +{ + struct inode * inode = mona_new_inode(dir, mode); + int err = PTR_ERR(inode); + + if(IS_ERR(inode)) + return err; + + inode->i_uid = current->fsuid; + init_special_inode(inode, mode, rdev); + err = mona_add_entry (dir, dentry->d_name.name, dentry->d_name.len, + inode); + if (err) + goto out_no_entry; + mark_inode_dirty(inode); + d_instantiate(dentry, inode); + return 0; + +out_no_entry: + inode->i_nlink--; + mark_inode_dirty(inode); + iput(inode); + return err; +} + +static int mona_mkdir(struct inode * dir, struct dentry * dentry, int mode) +{ + struct inode * inode; + struct buffer_head * dir_block; + struct mona_dir_entry_2 * de; + int err; + + if (dir->i_nlink >= MONA_LINK_MAX) + return -EMLINK; + + inode = mona_new_inode (dir, S_IFDIR); + if (!inode) + return err; + + inode->i_op = &mona_dir_inode_operations; + inode->i_fop = &mona_dir_operations; + inode->i_size = inode->i_sb->s_blocksize; + inode->i_blocks = 0; + dir_block = mona_bread (inode, 0, 1, &err); + if (!dir_block) { + inode->i_nlink--; /* is this nlink == 0? */ + mark_inode_dirty(inode); + iput (inode); + return -EIO; + } + de = (struct mona_dir_entry_2 *) dir_block->b_data; + de->inode = cpu_to_le32(inode->i_ino); + de->name_len = 1; + de->rec_len = cpu_to_le16(MONA_DIR_REC_LEN(de->name_len)); + strcpy (de->name, "."); + mona_set_de_type(dir->i_sb, de, S_IFDIR); + de = (struct mona_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); + de->inode = cpu_to_le32(dir->i_ino); + de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize - MONA_DIR_REC_LEN(1)); + de->name_len = 2; + strcpy (de->name, ".."); + mona_set_de_type(dir->i_sb, de, S_IFDIR); + inode->i_nlink = 2; + mark_buffer_dirty(dir_block); + brelse (dir_block); + inode->i_mode = S_IFDIR | mode; + if (dir->i_mode & S_ISGID) + inode->i_mode |= S_ISGID; + mark_inode_dirty(inode); + err = mona_add_entry (dir, dentry->d_name.name, dentry->d_name.len, + inode); + if (err) + goto out_no_entry; + dir->i_nlink++; + dir->u.mona_i.i_flags &= ~MONA_BTREE_FL; + mark_inode_dirty(dir); + d_instantiate(dentry, inode); + return 0; + +out_no_entry: + inode->i_nlink = 0; + mark_inode_dirty(inode); + iput (inode); + return err; +} + +/* + * routine to check that the specified directory is empty (for rmdir) + */ +static int empty_dir (struct inode * inode) +{ + unsigned long offset; + struct buffer_head * bh; + struct mona_dir_entry_2 * de, * de1; + struct super_block * sb; + int err; + + sb = inode->i_sb; + if (inode->i_size < MONA_DIR_REC_LEN(1) + MONA_DIR_REC_LEN(2) || + !(bh = mona_bread (inode, 0, 0, &err))) { + mona_warning (inode->i_sb, "empty_dir", + "bad directory (dir #%lu) - no data block", + inode->i_ino); + return 1; + } + de = (struct mona_dir_entry_2 *) bh->b_data; + de1 = (struct mona_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); + if (le32_to_cpu(de->inode) != inode->i_ino || !le32_to_cpu(de1->inode) || + strcmp (".", de->name) || strcmp ("..", de1->name)) { + mona_warning (inode->i_sb, "empty_dir", + "bad directory (dir #%lu) - no `.' or `..'", + inode->i_ino); + brelse (bh); + return 1; + } + offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len); + de = (struct mona_dir_entry_2 *) ((char *) de1 + le16_to_cpu(de1->rec_len)); + while (offset < inode->i_size ) { + if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) { + brelse (bh); + bh = mona_bread (inode, offset >> MONA_BLOCK_SIZE_BITS(sb), 0, &err); + if (!bh) { +#if 0 + mona_error (sb, "empty_dir", + "directory #%lu contains a hole at offset %lu", + inode->i_ino, offset); +#endif + offset += sb->s_blocksize; + continue; + } + de = (struct mona_dir_entry_2 *) bh->b_data; + } + if (!mona_check_dir_entry ("empty_dir", inode, de, bh, + offset)) { + brelse (bh); + return 1; + } + if (le32_to_cpu(de->inode)) { + brelse (bh); + return 0; + } + offset += le16_to_cpu(de->rec_len); + de = (struct mona_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); + } + brelse (bh); + return 1; +} + +static int mona_rmdir (struct inode * dir, struct dentry *dentry) +{ + int retval; + struct inode * inode; + struct buffer_head * bh; + struct mona_dir_entry_2 * de; + + retval = -ENOENT; + bh = mona_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de); + if (!bh) + goto end_rmdir; + + inode = dentry->d_inode; + DQUOT_INIT(inode); + + retval = -EIO; + if (le32_to_cpu(de->inode) != inode->i_ino) + goto end_rmdir; + + retval = -ENOTEMPTY; + if (!empty_dir (inode)) + goto end_rmdir; + + retval = mona_delete_entry(dir, de, bh); + if (retval) + goto end_rmdir; + if (inode->i_nlink != 2) + mona_warning (inode->i_sb, "mona_rmdir", + "empty directory has nlink!=2 (%d)", + inode->i_nlink); + inode->i_version = ++event; + inode->i_nlink = 0; + inode->i_size = 0; + mark_inode_dirty(inode); + dir->i_nlink--; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->u.mona_i.i_flags &= ~MONA_BTREE_FL; + mark_inode_dirty(dir); + +end_rmdir: + brelse (bh); + return retval; +} + +static int mona_unlink(struct inode * dir, struct dentry *dentry) +{ + int retval; + struct inode * inode; + struct buffer_head * bh; + struct mona_dir_entry_2 * de; + + retval = -ENOENT; + bh = mona_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de); + if (!bh) + goto end_unlink; + + inode = dentry->d_inode; + DQUOT_INIT(inode); + + retval = -EIO; + if (le32_to_cpu(de->inode) != inode->i_ino) + goto end_unlink; + + if (!inode->i_nlink) { + mona_warning (inode->i_sb, "mona_unlink", + "Deleting nonexistent file (%lu), %d", + inode->i_ino, inode->i_nlink); + inode->i_nlink = 1; + } + retval = mona_delete_entry(dir, de, bh); + if (retval) + goto end_unlink; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->u.mona_i.i_flags &= ~MONA_BTREE_FL; + mark_inode_dirty(dir); + inode->i_nlink--; + mark_inode_dirty(inode); + inode->i_ctime = dir->i_ctime; + retval = 0; + +end_unlink: + brelse (bh); + return retval; +} + +static int mona_symlink(struct inode * dir, struct dentry *dentry, const char *symname) +{ + struct inode *inode; + int l, err; + struct address_space *mapping; + struct page *page; + char *kaddr; + + // make sure filename is not too long + l = strlen(symname)+1; + if(l > dir->i_sb->s_blocksize) + return -ENAMETOOLONG; + + // fetch a new inode + inode = mona_new_inode(dir, S_IFLNK); + err = PTR_ERR(inode); + if(IS_ERR(inode)) + return err; + + inode->i_mode = S_IFLNK | S_IRWXUGO; + + if(l > sizeof(inode->u.mona_i.i_data)) { // slow symlink, cannot store link in inode + inode->i_op = &mona_symlink_inode_operations; + inode->i_mapping->a_ops = &mona_aops; + err = block_symlink(inode, symname, l); + mapping = inode->i_mapping; + page = grab_cache_page(mapping, 0); + if(!page) { + err = -ENOMEM; + goto out_no_entry; + } + err = mapping->a_ops->prepare_write(NULL, page, 0, l-1); + if(err) { + UnlockPage(page); + page_cache_release(page); + goto out_no_entry; + } + kaddr = page_address(page); + memcpy(kaddr, symname, l-1); + mapping->a_ops->commit_write(NULL, page, 0, l-1); + err = mapping->a_ops->readpage(NULL, page); + wait_on_page(page); + page_cache_release(page); + if(err < 0) + goto out_no_entry; + mark_inode_dirty(inode); + err = 0; + } else { // fast symlink, stores link in inode + inode->i_op = &mona_fast_symlink_inode_operations; + memcpy((char*)&inode->u.mona_i.i_data, symname, l); + inode->i_size = l-1; + } + + mark_inode_dirty(inode); + + err = mona_add_entry(dir, dentry->d_name.name, dentry->d_name.len, inode); + + if(err) + goto out_no_entry; + d_instantiate(dentry, inode); + + return 0; + +out_no_entry: + inode->i_nlink--; + mark_inode_dirty(inode); + iput(inode); + return err; +} + +static int mona_link (struct dentry * old_dentry, + struct inode * dir, struct dentry *dentry) +{ + struct inode *inode = old_dentry->d_inode; + int err; + + if (S_ISDIR(inode->i_mode)) + return -EPERM; + + if (inode->i_nlink >= MONA_LINK_MAX) + return -EMLINK; + + err = mona_add_entry (dir, dentry->d_name.name, dentry->d_name.len, + inode); + if (err) + return err; + + inode->i_nlink++; + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + atomic_inc(&inode->i_count); + d_instantiate(dentry, inode); + return 0; +} + +#define PARENT_INO(buffer) \ + ((struct mona_dir_entry_2 *) ((char *) buffer + \ + le16_to_cpu(((struct mona_dir_entry_2 *) buffer)->rec_len)))->inode + +/* + * Anybody can rename anything with this: the permission checks are left to the + * higher-level routines. + */ +static int mona_rename (struct inode * old_dir, struct dentry *old_dentry, + struct inode * new_dir,struct dentry *new_dentry) +{ + struct inode * old_inode, * new_inode; + struct buffer_head * old_bh, * new_bh, * dir_bh; + struct mona_dir_entry_2 * old_de, * new_de; + int retval; + + old_bh = new_bh = dir_bh = NULL; + + old_bh = mona_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de); + /* + * Check for inode number is _not_ due to possible IO errors. + * We might rmdir the source, keep it as pwd of some process + * and merrily kill the link to whatever was created under the + * same name. Goodbye sticky bit ;-< + */ + old_inode = old_dentry->d_inode; + retval = -ENOENT; + if (!old_bh || le32_to_cpu(old_de->inode) != old_inode->i_ino) + goto end_rename; + + new_inode = new_dentry->d_inode; + new_bh = mona_find_entry (new_dir, new_dentry->d_name.name, + new_dentry->d_name.len, &new_de); + if (new_bh) { + if (!new_inode) { + brelse (new_bh); + new_bh = NULL; + } else { + DQUOT_INIT(new_inode); + } + } + if (S_ISDIR(old_inode->i_mode)) { + if (new_inode) { + retval = -ENOTEMPTY; + if (!empty_dir (new_inode)) + goto end_rename; + } + retval = -EIO; + dir_bh = mona_bread (old_inode, 0, 0, &retval); + if (!dir_bh) + goto end_rename; + if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino) + goto end_rename; + retval = -EMLINK; + if (!new_inode && new_dir!=old_dir && + new_dir->i_nlink >= MONA_LINK_MAX) + goto end_rename; + } + if (!new_bh) { + retval = mona_add_entry (new_dir, new_dentry->d_name.name, + new_dentry->d_name.len, + old_inode); + if (retval) + goto end_rename; + } else { + new_de->inode = le32_to_cpu(old_inode->i_ino); + if (MONA_HAS_INCOMPAT_FEATURE(new_dir->i_sb, + MONA_FEATURE_INCOMPAT_FILETYPE)) + new_de->file_type = old_de->file_type; + new_dir->i_version = ++event; + mark_buffer_dirty(new_bh); + if (IS_SYNC(new_dir)) { + ll_rw_block (WRITE, 1, &new_bh); + wait_on_buffer (new_bh); + } + brelse(new_bh); + new_bh = NULL; + } + + /* + * Like most other Unix systems, set the ctime for inodes on a + * rename. + */ + old_inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(old_inode); + + /* + * ok, that's it + */ + mona_delete_entry(old_dir, old_de, old_bh); + + if (new_inode) { + new_inode->i_nlink--; + new_inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(new_inode); + } + old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; + old_dir->u.mona_i.i_flags &= ~MONA_BTREE_FL; + mark_inode_dirty(old_dir); + if (dir_bh) { + PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino); + mark_buffer_dirty(dir_bh); + old_dir->i_nlink--; + mark_inode_dirty(old_dir); + if (new_inode) { + new_inode->i_nlink--; + mark_inode_dirty(new_inode); + } else { + new_dir->i_nlink++; + new_dir->u.mona_i.i_flags &= ~MONA_BTREE_FL; + mark_inode_dirty(new_dir); + } + } + + retval = 0; + +end_rename: + brelse (dir_bh); + brelse (old_bh); + brelse (new_bh); + return retval; +} + +/* + * directories can handle most operations... + */ +struct inode_operations mona_dir_inode_operations = { + create: mona_create, + lookup: mona_lookup, + link: mona_link, + unlink: mona_unlink, + symlink: mona_symlink, + mkdir: mona_mkdir, + rmdir: mona_rmdir, + mknod: mona_mknod, + rename: mona_rename, +}; diff -ruN linux/fs/mona/super.c linux-mona/fs/mona/super.c --- linux/fs/mona/super.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/super.c Tue Jun 26 00:22:19 2001 @@ -0,0 +1,814 @@ +/* + * linux/fs/mona/super.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/inode.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Big-endian to little-endian byte-swapping/bitmaps by + * David S. Miller (davem@caip.rutgers.edu), 1995 + */ + +#include +#include +#include +#include +#include +#include /* for testopt declaration */ +#include +#include +#include +#include +#include + + +static char error_buf[1024]; + +extern void free_kernel_xforms(kernelXformPtr kPtr); +extern kernelXformPtr function_listing; + +extern void create_mona_proc_entry(void); +extern void remove_mona_proc_entry(void); + +void mona_error (struct super_block * sb, const char * function, + const char * fmt, ...) +{ + va_list args; + + if (!(sb->s_flags & MS_RDONLY)) { + sb->u.mona_sb.s_mount_state |= MONA_ERROR_FS; + sb->u.mona_sb.s_ms->s_state = + cpu_to_le16(le16_to_cpu(sb->u.mona_sb.s_ms->s_state) | MONA_ERROR_FS); + mark_buffer_dirty(sb->u.mona_sb.s_sbh); + sb->s_dirt = 1; + } + va_start (args, fmt); + vsprintf (error_buf, fmt, args); + va_end (args); + if (test_opt (sb, ERRORS_PANIC) || + (le16_to_cpu(sb->u.mona_sb.s_ms->s_errors) == MONA_ERRORS_PANIC && + !test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_RO))) + panic ("MONA-fs panic (device %s): %s: %s\n", + bdevname(sb->s_dev), function, error_buf); + printk (KERN_CRIT "MONA-fs error (device %s): %s: %s\n", + bdevname(sb->s_dev), function, error_buf); + if (test_opt (sb, ERRORS_RO) || + (le16_to_cpu(sb->u.mona_sb.s_ms->s_errors) == MONA_ERRORS_RO && + !test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_PANIC))) { + printk ("Remounting filesystem read-only\n"); + sb->s_flags |= MS_RDONLY; + } +} + +NORET_TYPE void mona_panic (struct super_block * sb, const char * function, + const char * fmt, ...) +{ + va_list args; + + if (!(sb->s_flags & MS_RDONLY)) { + sb->u.mona_sb.s_mount_state |= MONA_ERROR_FS; + sb->u.mona_sb.s_ms->s_state = + cpu_to_le16(le16_to_cpu(sb->u.mona_sb.s_ms->s_state) | MONA_ERROR_FS); + mark_buffer_dirty(sb->u.mona_sb.s_sbh); + sb->s_dirt = 1; + } + va_start (args, fmt); + vsprintf (error_buf, fmt, args); + va_end (args); + /* this is to prevent panic from syncing this filesystem */ + if (sb->s_lock) + sb->s_lock=0; + sb->s_flags |= MS_RDONLY; + panic ("MONA-fs panic (device %s): %s: %s\n", + bdevname(sb->s_dev), function, error_buf); +} + +void mona_warning (struct super_block * sb, const char * function, + const char * fmt, ...) +{ + va_list args; + + va_start (args, fmt); + vsprintf (error_buf, fmt, args); + va_end (args); + printk (KERN_WARNING "MONA-fs warning (device %s): %s: %s\n", + bdevname(sb->s_dev), function, error_buf); +} + +void mona_update_dynamic_rev(struct super_block *sb) +{ + struct mona_super_block *ms = MONA_SB(sb)->s_ms; + + if (le32_to_cpu(ms->s_rev_level) > MONA_GOOD_OLD_REV) + return; + + mona_warning(sb, __FUNCTION__, + "updating to rev %d because of new feature flag, " + "running e2fsck is recommended", + MONA_DYNAMIC_REV); + + ms->s_first_ino = cpu_to_le32(MONA_GOOD_OLD_FIRST_INO); + ms->s_inode_size = cpu_to_le16(MONA_GOOD_OLD_INODE_SIZE); + ms->s_rev_level = cpu_to_le32(MONA_DYNAMIC_REV); + /* leave es->s_feature_*compat flags alone */ + /* es->s_uuid will be set by e2fsck if empty */ + + /* + * The rest of the superblock fields should be zero, and if not it + * means they are likely already in use, so leave them alone. We + * can leave it up to e2fsck to clean up any inconsistencies there. + */ +} + +void mona_put_super (struct super_block * sb) +{ + int db_count; + int i; + + if(function_listing != NULL) + free_kernel_xforms(function_listing); // release the registered kernel functions + + if (!(sb->s_flags & MS_RDONLY)) { + sb->u.mona_sb.s_ms->s_state = le16_to_cpu(sb->u.mona_sb.s_mount_state); + mark_buffer_dirty(sb->u.mona_sb.s_sbh); + } + db_count = sb->u.mona_sb.s_gdb_count; + for (i = 0; i < db_count; i++) + if (sb->u.mona_sb.s_group_desc[i]) + brelse (sb->u.mona_sb.s_group_desc[i]); + kfree(sb->u.mona_sb.s_group_desc); + for (i = 0; i < MONA_MAX_GROUP_LOADED; i++) + if (sb->u.mona_sb.s_inode_bitmap[i]) + brelse (sb->u.mona_sb.s_inode_bitmap[i]); + for (i = 0; i < MONA_MAX_GROUP_LOADED; i++) + if (sb->u.mona_sb.s_block_bitmap[i]) + brelse (sb->u.mona_sb.s_block_bitmap[i]); + brelse (sb->u.mona_sb.s_sbh); + + return; +} + +static struct super_operations mona_sops = { + read_inode: mona_read_inode, + write_inode: mona_write_inode, + put_inode: mona_put_inode, + delete_inode: mona_delete_inode, + put_super: mona_put_super, + write_super: mona_write_super, + statfs: mona_statfs, + remount_fs: mona_remount, +}; + +/* + * This function has been shamelessly adapted from the msdos fs + */ +static int parse_options (char * options, unsigned long * sb_block, + unsigned short *resuid, unsigned short * resgid, + unsigned long * mount_options) +{ + char * this_char; + char * value; + + if (!options) + return 1; + for (this_char = strtok (options, ","); + this_char != NULL; + this_char = strtok (NULL, ",")) { + if ((value = strchr (this_char, '=')) != NULL) + *value++ = 0; + if (!strcmp (this_char, "bsddf")) + clear_opt (*mount_options, MINIX_DF); + else if (!strcmp (this_char, "nouid32")) { + set_opt (*mount_options, NO_UID32); + } + else if (!strcmp (this_char, "check")) { + if (!value || !*value || !strcmp (value, "none")) + clear_opt (*mount_options, CHECK); + else +#ifdef CONFIG_MONA_CHECK + set_opt (*mount_options, CHECK); +#else + printk("MONA Check option not supported\n"); +#endif + } + else if (!strcmp (this_char, "debug")) + set_opt (*mount_options, DEBUG); + else if (!strcmp (this_char, "errors")) { + if (!value || !*value) { + printk ("MONA-fs: the errors option requires " + "an argument\n"); + return 0; + } + if (!strcmp (value, "continue")) { + clear_opt (*mount_options, ERRORS_RO); + clear_opt (*mount_options, ERRORS_PANIC); + set_opt (*mount_options, ERRORS_CONT); + } + else if (!strcmp (value, "remount-ro")) { + clear_opt (*mount_options, ERRORS_CONT); + clear_opt (*mount_options, ERRORS_PANIC); + set_opt (*mount_options, ERRORS_RO); + } + else if (!strcmp (value, "panic")) { + clear_opt (*mount_options, ERRORS_CONT); + clear_opt (*mount_options, ERRORS_RO); + set_opt (*mount_options, ERRORS_PANIC); + } + else { + printk ("MONA-fs: Invalid errors option: %s\n", + value); + return 0; + } + } + else if (!strcmp (this_char, "grpid") || + !strcmp (this_char, "bsdgroups")) + set_opt (*mount_options, GRPID); + else if (!strcmp (this_char, "minixdf")) + set_opt (*mount_options, MINIX_DF); + else if (!strcmp (this_char, "nocheck")) + clear_opt (*mount_options, CHECK); + else if (!strcmp (this_char, "nogrpid") || + !strcmp (this_char, "sysvgroups")) + clear_opt (*mount_options, GRPID); + else if (!strcmp (this_char, "resgid")) { + if (!value || !*value) { + printk ("MONA-fs: the resgid option requires " + "an argument\n"); + return 0; + } + *resgid = simple_strtoul (value, &value, 0); + if (*value) { + printk ("MONA-fs: Invalid resgid option: %s\n", + value); + return 0; + } + } + else if (!strcmp (this_char, "resuid")) { + if (!value || !*value) { + printk ("MONA-fs: the resuid option requires " + "an argument"); + return 0; + } + *resuid = simple_strtoul (value, &value, 0); + if (*value) { + printk ("MONA-fs: Invalid resuid option: %s\n", + value); + return 0; + } + } + else if (!strcmp (this_char, "sb")) { + if (!value || !*value) { + printk ("MONA-fs: the sb option requires " + "an argument"); + return 0; + } + *sb_block = simple_strtoul (value, &value, 0); + if (*value) { + printk ("MONA-fs: Invalid sb option: %s\n", + value); + return 0; + } + } + /* Silently ignore the quota options */ + else if (!strcmp (this_char, "grpquota") + || !strcmp (this_char, "noquota") + || !strcmp (this_char, "quota") + || !strcmp (this_char, "usrquota")) + /* Don't do anything ;-) */ ; + else { + printk ("MONA-fs: Unrecognized mount option %s\n", this_char); + return 0; + } + } + return 1; +} + +static int mona_setup_super(struct super_block * sb, + struct mona_super_block * ms, + int read_only) +{ + int res = 0; + if (le32_to_cpu(ms->s_rev_level) > MONA_MAX_SUPP_REV) { + printk ("MONA-fs warning: revision level too high, " + "forcing read/only mode\n"); + res = MS_RDONLY; + } + if (read_only) + return res; + if (!(sb->u.mona_sb.s_mount_state & MONA_VALID_FS)) + printk ("MONA-fs warning: mounting unchecked fs, " + "running e2fsck is recommended\n"); + else if ((sb->u.mona_sb.s_mount_state & MONA_ERROR_FS)) + printk ("MONA-fs warning: mounting fs with errors, " + "running e2fsck is recommended\n"); + else if ((__s16) le16_to_cpu(ms->s_max_mnt_count) >= 0 && + le16_to_cpu(ms->s_mnt_count) >= + (unsigned short) (__s16) le16_to_cpu(ms->s_max_mnt_count)) + printk ("MONA-fs warning: maximal mount count reached, " + "running e2fsck is recommended\n"); + else if (le32_to_cpu(ms->s_checkinterval) && + (le32_to_cpu(ms->s_lastcheck) + le32_to_cpu(ms->s_checkinterval) <= CURRENT_TIME)) + printk ("MONA-fs warning: checktime reached, " + "running e2fsck is recommended\n"); + ms->s_state = cpu_to_le16(le16_to_cpu(ms->s_state) & ~MONA_VALID_FS); + if (!(__s16) le16_to_cpu(ms->s_max_mnt_count)) + ms->s_max_mnt_count = (__s16) cpu_to_le16(MONA_DFL_MAX_MNT_COUNT); + ms->s_mnt_count=cpu_to_le16(le16_to_cpu(ms->s_mnt_count) + 1); + ms->s_mtime = cpu_to_le32(CURRENT_TIME); + mark_buffer_dirty(sb->u.mona_sb.s_sbh); + sb->s_dirt = 1; + if (test_opt (sb, DEBUG)) + printk ("[MONA FS %s, %s, bs=%lu, fs=%lu, gc=%lu, " + "bpg=%lu, ipg=%lu, mo=%04lx]\n", + MONAFS_VERSION, MONAFS_DATE, sb->s_blocksize, + sb->u.mona_sb.s_frag_size, + sb->u.mona_sb.s_groups_count, + MONA_BLOCKS_PER_GROUP(sb), + MONA_INODES_PER_GROUP(sb), + sb->u.mona_sb.s_mount_opt); +#ifdef CONFIG_MONA_CHECK + if (test_opt (sb, CHECK)) { + mona_check_blocks_bitmap (sb); + mona_check_inodes_bitmap (sb); + } +#endif + return res; +} + +static int mona_check_descriptors (struct super_block * sb) +{ + int i; + int desc_block = 0; + unsigned long block = le32_to_cpu(sb->u.mona_sb.s_ms->s_first_data_block); + struct mona_group_desc * gdp = NULL; + + mona_debug ("Checking group descriptors"); + + for (i = 0; i < sb->u.mona_sb.s_groups_count; i++) + { + if ((i % MONA_DESC_PER_BLOCK(sb)) == 0) + gdp = (struct mona_group_desc *) sb->u.mona_sb.s_group_desc[desc_block++]->b_data; + if (le32_to_cpu(gdp->bg_block_bitmap) < block || + le32_to_cpu(gdp->bg_block_bitmap) >= block + MONA_BLOCKS_PER_GROUP(sb)) + { + mona_error (sb, "mona_check_descriptors", + "Block bitmap for group %d" + " not in group (block %lu)!", + i, (unsigned long) le32_to_cpu(gdp->bg_block_bitmap)); + return 0; + } + if (le32_to_cpu(gdp->bg_inode_bitmap) < block || + le32_to_cpu(gdp->bg_inode_bitmap) >= block + MONA_BLOCKS_PER_GROUP(sb)) + { + mona_error (sb, "mona_check_descriptors", + "Inode bitmap for group %d" + " not in group (block %lu)!", + i, (unsigned long) le32_to_cpu(gdp->bg_inode_bitmap)); + return 0; + } + if (le32_to_cpu(gdp->bg_inode_table) < block || + le32_to_cpu(gdp->bg_inode_table) + sb->u.mona_sb.s_itb_per_group >= + block + MONA_BLOCKS_PER_GROUP(sb)) + { + mona_error (sb, "mona_check_descriptors", + "Inode table for group %d" + " not in group (block %lu)!", + i, (unsigned long) le32_to_cpu(gdp->bg_inode_table)); + return 0; + } + block += MONA_BLOCKS_PER_GROUP(sb); + gdp++; + } + return 1; +} + +#define log2(n) ffz(~(n)) + +struct super_block * mona_read_super (struct super_block * sb, void * data, int silent) +{ + struct buffer_head *bh; + struct mona_super_block *ms; + unsigned long sb_block = 1; + unsigned short resuid = MONA_DEF_RESUID; + unsigned short resgid = MONA_DEF_RESGID; + unsigned long logic_sb_block = 1; + unsigned long offset = 0; + kdev_t dev = sb->s_dev; + int blocksize = BLOCK_SIZE; + int hblock; + int db_count; + int i, j; + + /* + * See what the current blocksize for the device is, and + * use that as the blocksize. Otherwise (or if the blocksize + * is smaller than the default) use the default. + * This is important for devices that have a hardware + * sectorsize that is larger than the default. + */ + blocksize = get_hardblocksize(dev); + if( blocksize == 0 || blocksize < BLOCK_SIZE ) { + blocksize = BLOCK_SIZE; + } + + sb->u.mona_sb.s_mount_opt = 0; + if (!parse_options ((char *) data, &sb_block, &resuid, &resgid, + &sb->u.mona_sb.s_mount_opt)) { + return NULL; + } + + set_blocksize (dev, blocksize); + + /* + * If the superblock doesn't start on a sector boundary, + * calculate the offset. FIXME(eric) this doesn't make sense + * that we would have to do this. + */ + if (blocksize != BLOCK_SIZE) { + logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize; + offset = (sb_block*BLOCK_SIZE) % blocksize; + } + + if (!(bh = bread (dev, logic_sb_block, blocksize))) { + printk ("MONA-fs: unable to read superblock\n"); + return NULL; + } + + ms = (struct mona_super_block *) (((char *)bh->b_data) + offset); + sb->u.mona_sb.s_ms = ms; + sb->s_magic = le16_to_cpu(ms->s_magic); + if(sb->s_magic != MONA_SUPER_MAGIC) { + if(!silent) + printk("VFS: Can't find a Mona filesystem on dev " + "%s.\n", bdevname(dev)); + failed_mount: + if(bh) + brelse(bh); + return NULL; + } + + if (le32_to_cpu(ms->s_rev_level) == MONA_GOOD_OLD_REV && + (MONA_HAS_COMPAT_FEATURE(sb, ~0U) || + MONA_HAS_RO_COMPAT_FEATURE(sb, ~0U) || + MONA_HAS_INCOMPAT_FEATURE(sb, ~0U))) + printk("EXT2-fs warning: feature flags set on rev 0 fs, " + "running e2fsck is recommended\n"); + + + if ((i = MONA_HAS_INCOMPAT_FEATURE(sb, ~MONA_FEATURE_INCOMPAT_SUPP))) { + printk("MONA-fs: %s: couldn't mount because of " + "unsupported optional features (%x).\n", + bdevname(dev), i); + goto failed_mount; + } + if (!(sb->s_flags & MS_RDONLY) && + (i = MONA_HAS_RO_COMPAT_FEATURE(sb, ~MONA_FEATURE_RO_COMPAT_SUPP))){ + printk("EXT2-fs: %s: couldn't mount RDWR because of " + "unsupported optional features (%x).\n", + bdevname(dev), i); + goto failed_mount; + } + sb->s_blocksize_bits = le32_to_cpu(sb->u.mona_sb.s_ms->s_log_block_size) + 10; + sb->s_blocksize = 1 << sb->s_blocksize_bits; + if (sb->s_blocksize != BLOCK_SIZE && + (sb->s_blocksize == 1024 || sb->s_blocksize == 2048 || + sb->s_blocksize == 4096)) { + /* + * Make sure the blocksize for the filesystem is larger + * than the hardware sectorsize for the machine. + */ + hblock = get_hardblocksize(dev); + if( (hblock != 0) + && (sb->s_blocksize < hblock) ) + { + printk("MONA-fs: blocksize too small for device.\n"); + goto failed_mount; + } + + brelse (bh); + set_blocksize (dev, sb->s_blocksize); + logic_sb_block = (sb_block*BLOCK_SIZE) / sb->s_blocksize; + offset = (sb_block*BLOCK_SIZE) % sb->s_blocksize; + bh = bread (dev, logic_sb_block, sb->s_blocksize); + if(!bh) { + printk("MONA-fs: Couldn't read superblock on " + "2nd try.\n"); + goto failed_mount; + } + ms = (struct mona_super_block *) (((char *)bh->b_data) + offset); + sb->u.mona_sb.s_ms = ms; + if (ms->s_magic != le16_to_cpu(MONA_SUPER_MAGIC)) { + printk ("MONA-fs: Magic mismatch, very weird !\n"); + goto failed_mount; + } + } + if (le32_to_cpu(ms->s_rev_level) == MONA_GOOD_OLD_REV) { + sb->u.mona_sb.s_inode_size = MONA_GOOD_OLD_INODE_SIZE; + sb->u.mona_sb.s_first_ino = MONA_GOOD_OLD_FIRST_INO; + } else { + sb->u.mona_sb.s_inode_size = le16_to_cpu(ms->s_inode_size); + sb->u.mona_sb.s_first_ino = le32_to_cpu(ms->s_first_ino); + if (sb->u.mona_sb.s_inode_size != MONA_GOOD_OLD_INODE_SIZE) { + printk ("MONA-fs: unsupported inode size: %d\n", + sb->u.mona_sb.s_inode_size); + goto failed_mount; + } + } + + sb->u.mona_sb.s_frag_size = MONA_MIN_FRAG_SIZE << + le32_to_cpu(ms->s_log_frag_size); + if (sb->u.ext2_sb.s_frag_size) + sb->u.ext2_sb.s_frags_per_block = sb->s_blocksize / + sb->u.ext2_sb.s_frag_size; + else + sb->s_magic = 0; + sb->u.mona_sb.s_feature_compat = le32_to_cpu(ms->s_feature_compat); + sb->u.mona_sb.s_feature_incompat = le32_to_cpu(ms->s_feature_incompat); + sb->u.mona_sb.s_feature_ro_compat = le32_to_cpu(ms->s_feature_ro_compat); + sb->u.mona_sb.s_frag_size = MONA_MIN_FRAG_SIZE << + le32_to_cpu(ms->s_log_frag_size); + if (sb->u.mona_sb.s_frag_size) + sb->u.mona_sb.s_frags_per_block = sb->s_blocksize / + sb->u.mona_sb.s_frag_size; + else + sb->s_magic = 0; + sb->u.mona_sb.s_blocks_per_group = le32_to_cpu(ms->s_blocks_per_group); + sb->u.mona_sb.s_frags_per_group = le32_to_cpu(ms->s_frags_per_group); + sb->u.mona_sb.s_inodes_per_group = le32_to_cpu(ms->s_inodes_per_group); + sb->u.mona_sb.s_inodes_per_block = sb->s_blocksize / + MONA_INODE_SIZE(sb); + sb->u.mona_sb.s_itb_per_group = sb->u.mona_sb.s_inodes_per_group / + sb->u.mona_sb.s_inodes_per_block; + sb->u.mona_sb.s_desc_per_block = sb->s_blocksize / + sizeof (struct mona_group_desc); + sb->u.mona_sb.s_sbh = bh; + if (resuid != MONA_DEF_RESUID) + sb->u.mona_sb.s_resuid = resuid; + else + sb->u.mona_sb.s_resuid = le16_to_cpu(ms->s_def_resuid); + if (resgid != MONA_DEF_RESGID) + sb->u.mona_sb.s_resgid = resgid; + else + sb->u.mona_sb.s_resgid = le16_to_cpu(ms->s_def_resgid); + sb->u.mona_sb.s_mount_state = le16_to_cpu(ms->s_state); + sb->u.mona_sb.s_addr_per_block_bits = + log2 (MONA_ADDR_PER_BLOCK(sb)); + sb->u.mona_sb.s_desc_per_block_bits = + log2 (MONA_DESC_PER_BLOCK(sb)); + if (sb->s_magic != MONA_SUPER_MAGIC) { + if (!silent) + printk ("VFS: Can't find an mona filesystem on dev " + "%s.\n", + bdevname(dev)); + goto failed_mount; + } + if (sb->s_blocksize != bh->b_size) { + if (!silent) + printk ("VFS: Unsupported blocksize on dev " + "%s.\n", bdevname(dev)); + goto failed_mount; + } + if (sb->s_blocksize != sb->u.mona_sb.s_frag_size) { + printk ("MONA-fs: fragsize %lu != blocksize %lu (not supported yet)\n", + sb->u.mona_sb.s_frag_size, sb->s_blocksize); + goto failed_mount; + } + + if (sb->u.mona_sb.s_blocks_per_group > sb->s_blocksize * 8) { + printk ("MONA-fs: #blocks per group too big: %lu\n", + sb->u.mona_sb.s_blocks_per_group); + goto failed_mount; + } + if (sb->u.mona_sb.s_frags_per_group > sb->s_blocksize * 8) { + printk ("MONA-fs: #fragments per group too big: %lu\n", + sb->u.mona_sb.s_frags_per_group); + goto failed_mount; + } + if (sb->u.mona_sb.s_inodes_per_group > sb->s_blocksize * 8) { + printk ("MONA-fs: #inodes per group too big: %lu\n", + sb->u.mona_sb.s_inodes_per_group); + goto failed_mount; + } + + sb->u.mona_sb.s_groups_count = (le32_to_cpu(ms->s_blocks_count) - + le32_to_cpu(ms->s_first_data_block) + + MONA_BLOCKS_PER_GROUP(sb) - 1) / + MONA_BLOCKS_PER_GROUP(sb); + db_count = (sb->u.mona_sb.s_groups_count + MONA_DESC_PER_BLOCK(sb) - 1) / + MONA_DESC_PER_BLOCK(sb); + sb->u.mona_sb.s_group_desc = kmalloc (db_count * sizeof (struct buffer_head *), GFP_KERNEL); + if (sb->u.mona_sb.s_group_desc == NULL) { + printk ("MONA-fs: not enough memory\n"); + goto failed_mount; + } + for (i = 0; i < db_count; i++) { + sb->u.mona_sb.s_group_desc[i] = bread (dev, logic_sb_block + i + 1, + sb->s_blocksize); + if (!sb->u.mona_sb.s_group_desc[i]) { + for (j = 0; j < i; j++) + brelse (sb->u.mona_sb.s_group_desc[j]); + kfree(sb->u.mona_sb.s_group_desc); + printk ("MONA-fs: unable to read group descriptors\n"); + goto failed_mount; + } + } + if (!mona_check_descriptors (sb)) { + for (j = 0; j < db_count; j++) + brelse (sb->u.mona_sb.s_group_desc[j]); + kfree(sb->u.mona_sb.s_group_desc); + printk ("MONA-fs: group descriptors corrupted !\n"); + goto failed_mount; + } + for (i = 0; i < MONA_MAX_GROUP_LOADED; i++) { + sb->u.mona_sb.s_inode_bitmap_number[i] = 0; + sb->u.mona_sb.s_inode_bitmap[i] = NULL; + sb->u.mona_sb.s_block_bitmap_number[i] = 0; + sb->u.mona_sb.s_block_bitmap[i] = NULL; + } + sb->u.mona_sb.s_loaded_inode_bitmaps = 0; + sb->u.mona_sb.s_loaded_block_bitmaps = 0; + sb->u.mona_sb.s_gdb_count = db_count; + /* + * set up enough so that it can read an inode + */ + sb->s_op = &mona_sops; + sb->s_root = d_alloc_root(iget(sb, MONA_ROOT_INO)); + if (!sb->s_root) { + for (i = 0; i < db_count; i++) + if (sb->u.mona_sb.s_group_desc[i]) + brelse (sb->u.mona_sb.s_group_desc[i]); + kfree(sb->u.mona_sb.s_group_desc); + brelse (bh); + printk ("MONA-fs: get root inode failed\n"); + return NULL; + } + mona_setup_super (sb, ms, sb->s_flags & MS_RDONLY); + return sb; +} + +static void mona_commit_super (struct super_block * sb, + struct mona_super_block * ms) +{ + ms->s_wtime = cpu_to_le32(CURRENT_TIME); + mark_buffer_dirty(sb->u.mona_sb.s_sbh); + sb->s_dirt = 0; +} + +/* + * In the Mona file system, it is not necessary to + * write the super block since we use a mapping of the + * disk super block in a buffer. + * + * However, this function is still used to set the fs valid + * flags to 0. We need to set this flag to 0 since the fs + * may have been checked while mounted and e2fsck may have + * set s_state to MONA_VALID_FS after some corrections. + */ + +void mona_write_super (struct super_block * sb) +{ + struct mona_super_block * ms; + + if (!(sb->s_flags & MS_RDONLY)) { + ms = sb->u.mona_sb.s_ms; + + if (le16_to_cpu(ms->s_state) & MONA_VALID_FS) { + ms->s_state = cpu_to_le16(le16_to_cpu(ms->s_state) & ~MONA_VALID_FS); + ms->s_mtime = cpu_to_le32(CURRENT_TIME); + } + mona_commit_super (sb, ms); + } + sb->s_dirt = 0; +} + +int mona_remount (struct super_block * sb, int * flags, char * data) +{ + struct mona_super_block * ms; + unsigned short resuid = sb->u.mona_sb.s_resuid; + unsigned short resgid = sb->u.mona_sb.s_resgid; + unsigned long new_mount_opt; + unsigned long tmp; + + /* + * Allow the "check" option to be passed as a remount option. + */ + new_mount_opt = sb->u.mona_sb.s_mount_opt; + if (!parse_options (data, &tmp, &resuid, &resgid, + &new_mount_opt)) + return -EINVAL; + + sb->u.mona_sb.s_mount_opt = new_mount_opt; + sb->u.mona_sb.s_resuid = resuid; + sb->u.mona_sb.s_resgid = resgid; + ms = sb->u.mona_sb.s_ms; + if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) + return 0; + if (*flags & MS_RDONLY) { + if (le16_to_cpu(ms->s_state) & MONA_VALID_FS || + !(sb->u.mona_sb.s_mount_state & MONA_VALID_FS)) + return 0; + /* + * OK, we are remounting a valid rw partition rdonly, so set + * the rdonly flag and then mark the partition as valid again. + */ + ms->s_state = cpu_to_le16(sb->u.mona_sb.s_mount_state); + ms->s_mtime = cpu_to_le32(CURRENT_TIME); + mark_buffer_dirty(sb->u.mona_sb.s_sbh); + sb->s_dirt = 1; + mona_commit_super (sb, ms); + } + else { + int ret; + if((ret = MONA_HAS_RO_COMPAT_FEATURE(sb, + ~MONA_FEATURE_RO_COMPAT_SUPP))) { + printk("MONA-fs: %s: couldn't remount RDWR because of " + "unsupported optional features (%x).\n", + bdevname(sb->s_dev), ret); + return -EROFS; + } + /* + * Mounting a RDONLY partition read-write, so reread and + * store the current valid flag. (It may have been changed + * by e2fsck since we originally mounted the partition.) + */ + sb->u.mona_sb.s_mount_state = le16_to_cpu(ms->s_state); + if (!mona_setup_super (sb, ms, 0)) + sb->s_flags &= ~MS_RDONLY; + } + return 0; +} + +int mona_statfs (struct super_block * sb, struct statfs * buf) +{ + unsigned long overhead; + int i; + + if (test_opt (sb, MINIX_DF)) + overhead = 0; + else { + /* + * Compute the overhead (FS structures) + */ + + /* + * All of the blocks before first_data_block are + * overhead + */ + overhead = le32_to_cpu(sb->u.mona_sb.s_ms->s_first_data_block); + + /* + * Add the overhead attributed to the superblock and + * block group descriptors. If the sparse superblocks + * feature is turned on, then not all groups have this. + */ + for (i = 0; i < MONA_SB(sb)->s_groups_count; i++) + overhead += mona_bg_has_super(sb, i) + + mona_bg_num_gdb(sb, i); + + /* + * Every block group has an inode bitmap, a block + * bitmap, and an inode table. + */ + overhead += (sb->u.mona_sb.s_groups_count * + (2 + sb->u.mona_sb.s_itb_per_group)); + } + + buf->f_type = MONA_SUPER_MAGIC; + buf->f_bsize = sb->s_blocksize; + buf->f_blocks = le32_to_cpu(sb->u.mona_sb.s_ms->s_blocks_count) - overhead; + buf->f_bfree = mona_count_free_blocks (sb); + buf->f_bavail = buf->f_bfree - le32_to_cpu(sb->u.mona_sb.s_ms->s_r_blocks_count); + if (buf->f_bfree < le32_to_cpu(sb->u.mona_sb.s_ms->s_r_blocks_count)) + buf->f_bavail = 0; + buf->f_files = le32_to_cpu(sb->u.mona_sb.s_ms->s_inodes_count); + buf->f_ffree = mona_count_free_inodes (sb); + buf->f_namelen = MONA_NAME_LEN; + return 0; +} + +static DECLARE_FSTYPE_DEV(mona_fs_type, "mona", mona_read_super); + +static int __init init_mona_fs(void) +{ + init_mona(); + create_mona_proc_entry(); + return register_filesystem(&mona_fs_type); +} + +static void __exit exit_mona_fs(void) +{ + remove_mona_proc_entry(); + unregister_filesystem(&mona_fs_type); +} + +EXPORT_NO_SYMBOLS; + +module_init(init_mona_fs) +module_exit(exit_mona_fs) diff -ruN linux/fs/mona/symlink.c linux-mona/fs/mona/symlink.c --- linux/fs/mona/symlink.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/symlink.c Tue Jun 26 23:28:49 2001 @@ -0,0 +1,570 @@ +/* + * linux/fs/mona/symlink.c + * + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/symlink.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * mona symlink handling code + */ + +#include +#include +#include +#include +#include + +/* added for mona xforms */ +extern void *get_fn(char *); +extern long get_export_xform_id(void); +extern void free_xforms(XformInfoPtr xip); + +XformListPtr xform_data_list[3]; +static int xform_index; + +static inline int atoi(const char *nptr) +{ + int i = 0, val = 0; + + if(nptr[0] == '-') + ++i; + + while(nptr[i]) + val = 10*val+(nptr[i++] - '0'); + + return val; +} + +int identify_type(char *xforms) { + while((xforms[xform_index] == ' ') || (xforms[xform_index] == '\t') || + (xforms[xform_index] == '\n')) + xform_index++; // eat white space + + if(xforms[xform_index] == '-') { + xform_index++; + + switch(xforms[xform_index++]) { + case 'o': + return OPEN; + case 'r': + return INPUT; + case 'w': + return OUTPUT; + default: + return EINVAL; + } + } + else if(xforms[xform_index] == '\0') + return DONE; + else + return EINVAL; +} + +int get_one_param(char *xforms, int type, int params) { + char to[255]; + int i = 0; + + while((xforms[xform_index] == ' ') || (xforms[xform_index] == '\t') || + (xforms[xform_index] == '\n')) + xform_index++; // eat white space + + while(1) { + switch(xforms[xform_index]) { + case ' ': + case '\t': + case '\n': + to[i++] = '\0'; + ++xform_index; + xform_data_list[type]->data[params] = (char *)kmalloc(i, GFP_KERNEL); + memcpy(xform_data_list[type]->data[params], to, i); + return 0; + case '\0': + to[i++] = '\0'; + if(to[0] == '\0') + return EINVAL; + // mona_debug("get_one_param (2), i = %d, params = %d\n", i, params); + xform_data_list[type]->data[params] = (char *)kmalloc(i, GFP_KERNEL); + memcpy(xform_data_list[type]->data[params], to, i); + return DONE; + default: + to[i++] = xforms[xform_index++]; + break; + } + } +} + +int get_word(char *xforms, int type) { + char to[255]; + int i = 0; + XformListPtr tempListPtr = NULL; + + while((xforms[xform_index] == ' ') || (xforms[xform_index] == '\t') || + (xforms[xform_index] == '\n')) + xform_index++; // eat white space + while(1) { + switch(xforms[xform_index]) { + case ' ': + case '\t': + case '\n': + to[i++] = '\0'; + ++xform_index; + tempListPtr = xform_data_list[type]; + xform_data_list[type] = (XformListPtr) kmalloc(sizeof(XformList), GFP_KERNEL); + xform_data_list[type]->xform_name = (char *)kmalloc(i, GFP_KERNEL); + memcpy(xform_data_list[type]->xform_name, to, i); + xform_data_list[type]->data = NULL; + xform_data_list[type]->argc_data = 0; + xform_data_list[type]->next = tempListPtr; + return 0; + case '\0': + to[i++] = '\0'; + + if(to[0] == '\0') + return EINVAL; // no word was parsed, just EOF + + // otherwise, we do the same as above + tempListPtr = xform_data_list[type]; + xform_data_list[type] = (XformListPtr) kmalloc(sizeof(XformList), GFP_KERNEL); + xform_data_list[type]->xform_name = (char *)kmalloc(i, GFP_KERNEL); + memcpy(xform_data_list[type]->xform_name, to, i); + xform_data_list[type]->data = NULL; + xform_data_list[type]->argc_data = 0; + xform_data_list[type]->next = tempListPtr; + return DONE; + default: + to[i++] = xforms[xform_index++]; + break; + } + } +} + +int get_number(char *xforms) { + char to[255]; + int i = 0; + + while((xforms[xform_index] == ' ') || (xforms[xform_index] == '\t') || + (xforms[xform_index] == '\n')) + xform_index++; // eat white space + + while(1) { + switch(xforms[xform_index]) { + case ' ': + case '\t': + case '\n': + to[i] = '\0'; + ++xform_index; + return atoi(to); // return the number of parameters + case '\0': + to[i] = '\0'; + if(to[0] == '\0') return EINVAL; // only EOF was input + return EINVAL; + default: + to[i++] = xforms[xform_index++]; + break; + } + } +} + +int get_params(char *xforms, int type) { + int params, ret; + + while((xforms[xform_index] == ' ') || (xforms[xform_index] == '\t') || + (xforms[xform_index] == '\n')) + xform_index++; // eat white space + + if(xforms[xform_index] == '-') { + xform_index++; + + switch(xforms[xform_index]) { + case 'o': + case 'r': + case 'w': + xform_index--; + xform_data_list[type]->argc_data = 0; // no params, another xform + return 0; + case 'p': + xform_index++; + break; // parameters exist + default: + return EINVAL; // parse error + } + } + else { + xform_data_list[type]->argc_data = 0; // no params + return 0; + } + + while((xforms[xform_index] == ' ') || (xforms[xform_index] == '\t') || + (xforms[xform_index] == '\n')) + xform_index++; // eat white space + + params = get_number(xforms); // get number of parameters + xform_data_list[type]->argc_data = params; + // allocate space for argv + xform_data_list[type]->data = (char **) kmalloc(params*sizeof(char*), GFP_KERNEL); + + while(params > 0) { + params--; // count down number of parameters given + ret = get_one_param(xforms, type, params); // pick of a paramter from input + switch(ret) { + case DONE: + if(!params) // end of input + return DONE; + else + return EINVAL; // parse error + case EINVAL: + return EINVAL; // parse error + default: + break; // parameter found + } + } + + return 0; +} + +void deallocate_xform_lists(void) { + XformListPtr tmp; + int i, j; + + // mona_debug("deallocating xforms\n"); + for(i = 0; i < 3; i++) { + while(xform_data_list[i] != NULL) { + // mona_debug("In while loop, i = %d\n", i); + tmp = xform_data_list[i]; // get front of list to deallocate + xform_data_list[i] = xform_data_list[i]->next; // new head + if(tmp->argc_data > 0 && tmp->data != NULL) { // if argc, deallocate argv + for(j = 0; j < tmp->argc_data; j++) { + if(tmp->data[j] != NULL) { + kfree(tmp->data[j]); + tmp->data[j] = NULL; + } + } + kfree(tmp->data); + tmp->data = NULL; + } + kfree(tmp->xform_name); // deallocate xform name + tmp->xform_name = NULL; + kfree(tmp); // deallocate structure + tmp = NULL; + } + } +} + +static int do_open_xforms(XformInfoPtr xformInfoPtr, int old_stream_state) { + int stream_state = XF_READY; + XformInfoPtr xf_ptr = xformInfoPtr; + + // locate the first xform that needs to be called again, if applicable + if(old_stream_state == XF_HAS_DATA) { + while(xf_ptr != NULL) { + if (xf_ptr->state == XF_HAS_DATA) + break; + else xf_ptr = xf_ptr->next_xform; + } + } + + while(xf_ptr != NULL) { + xf_ptr->xform(xf_ptr, 0, NULL); + if(xf_ptr->state == XF_HAS_DATA) + stream_state = XF_HAS_DATA; + xf_ptr = xf_ptr->next_xform; + } + + return stream_state; +} + +int append_xform(char *xforms) { + int ret, type, stream_state = XF_READY; + XformInfoPtr headInfoPtr = NULL, tempInfoPtr = NULL; + XformListPtr listPtr; + + deallocate_xform_lists(); + + xform_data_list[INPUT] = NULL; + xform_data_list[OUTPUT] = NULL; + xform_data_list[OPEN] = NULL; + xform_index = 0; + + while(1) { + // check the type of the transformation + type = ret = identify_type(xforms); + + switch(ret) { + case INPUT: + case OUTPUT: + case OPEN: + // It's a proper xform, get the transformation name + // mona_debug("getting_words\n"); + ret = get_word(xforms, type); + break; + case DONE: + // no more data to parse + goto exit; + default: + // parsing error, improper input + deallocate_xform_lists(); + return -EINVAL; + } + + switch(ret) { + case EINVAL: + deallocate_xform_lists(); + return -EINVAL; + case DONE: + goto exit; + default: + // mona_debug("getting params\n"); + // we have the transformation name, check for parameters + if((ret = get_params(xforms, type)) == EINVAL) { + deallocate_xform_lists(); + return -EINVAL; + } + else if(ret == DONE) { + goto exit; + } + break; + } + } + +exit: + if(xform_data_list[OPEN] != NULL) { + // set up the open xform network + listPtr = xform_data_list[OPEN]; + while(listPtr != NULL) { + tempInfoPtr = headInfoPtr; + headInfoPtr = (XformInfoPtr) kmalloc(sizeof(XformInfo), GFP_KERNEL); + headInfoPtr->id = -1; + headInfoPtr->state = XF_READY; + headInfoPtr->private_data = NULL; + headInfoPtr->filp = NULL; + headInfoPtr->inodep = NULL; + headInfoPtr->argc = listPtr->argc_data; + headInfoPtr->argv = listPtr->data; + headInfoPtr->stream_dir = OPEN; + listPtr->argc_data = 0; + + if((headInfoPtr->xform = (int (*)(XformInfoPtr, + int, char*)) get_fn(listPtr->xform_name)) == NULL) + { + headInfoPtr->xform = + (int (*)(XformInfoPtr, int, char*)) get_fn("open_export_xform"); + headInfoPtr->private_data = + (char *) kmalloc(strlen(listPtr->xform_name), GFP_KERNEL); + strcpy(headInfoPtr->private_data, listPtr->xform_name); + headInfoPtr->id = get_export_xform_id(); + } + + headInfoPtr->next_xform = tempInfoPtr; + listPtr = listPtr->next; + } + + stream_state = do_open_xforms(headInfoPtr, XF_READY); + + while(stream_state != XF_READY) + stream_state = do_open_xforms(headInfoPtr, stream_state); + + free_xforms(headInfoPtr); + } + + return 0; +} + +/* + * RJM - A race condition may occur here where during an open, mona_follow_link() + * creates an xform list for one file, is interrupted before mona_file_open() + * is executed, and mona_follow_link() is called for another file. Upon + * returning to the original, mona_file_open() now has another files + * transfomation list - this could be a problem. +*/ + +/* + * mona_follow_link and mona_slow_follow_link cut off transformation info + * from the file name and pass the path to vfs_follow_linkand let vfs handle + * the rest. + * + * If the link is a fastlink (i.e. under 60 bytes), then the symlink + * data is stored directly in the inode, and mona_follow_link will get + * called, otherwise, mona_slow_follow_link will be called. +*/ +static int mona_follow_link(struct dentry * dentry, struct nameidata *nd) +{ + int i, res, is_xform = 0; + char *link = (char *)dentry->d_inode->u.mona_i.i_data; + // The inode may contain up to 60 bytes of symlink data. + char *xform_data = (char *) kmalloc(60, GFP_KERNEL); + + // mona_debug("%s\n", link); + // check if it is a transformation link (name will contain a newline) + for(i = 0; link[i]; ++i) { + xform_data[i] = link[i]; // xform_data will contain the path *only* + if(link[i] == 10) { // new line, beginning of xforms + is_xform = 1; // we're dealing with an xform + xform_data[i] = 0; + if((res = append_xform(&link[++i])) < 0) // append the list of xforms + return res; + break; + } + } + + // If we're dealing with an xform here, we pass xform_data to vfs_follow_link, + // since it contains ONLY the symlink path (no xform stuff). Otherwise, + // we can just pass link since we're not dealing with an xform. + if(is_xform) + res = vfs_follow_link(nd, xform_data); + else + res = vfs_follow_link(nd, link); + + kfree(xform_data); + + return res; +} + +/* + * The symlink is larger than 60 bytes long +*/ + +static int mona_slow_follow_link(struct dentry * dentry, struct nameidata *nd) +{ + struct page *page = NULL; + int i, is_xform = 0, res; + char *xform_data = NULL; + char *link = page_getlink(dentry, &page); + + xform_data = (char *) kmalloc(1024, GFP_KERNEL); + + // check if it is a transformation link (name will contain a newline) + for(i = 0; link[i]; ++i) { + xform_data[i] = link[i]; // xform_data will contain the path *only* + if(link[i] == 10) { // new line, beginning of xforms + is_xform = 1; // we're dealing with an xform + xform_data[i] = 0; + append_xform(&link[++i]); // append the list of xforms to xform list + break; + } + } + + // If we're dealing with an xform here, we pass xform_data to vfs_follow_link, + // since it contains ONLY the symlink path (no xform stuff). Otherwise, + // we can just pass link since we're not dealing with an xform. + if(is_xform) + res = vfs_follow_link(nd, xform_data); + else + res = vfs_follow_link(nd, link); + + if (page) { + kunmap(page); + page_cache_release(page); + } + + kfree(xform_data); + + return res; +} + +/* + * mona_readlink and mona_slow_readlink strip away the transformation + * stuff that we added and pass the rest (the path) to vfs_readlink. + * + * If the link is a fastlink (i.e. under 60 bytes), then the symlink + * data is stored directly in the inode, and mona_readlink will get + * called, otherwise, mona_slow_readlink will be called. +*/ + +static int mona_readlink(struct dentry *dentry, char *buffer, int buflen) +{ + char *link = (char *)dentry->d_inode->u.mona_i.i_data; + char *xform_data = NULL; + int i, is_xform = 0, res; + + // The inode may contain up to 60 bytes of symlink data. + xform_data = (char *) kmalloc(60, GFP_KERNEL); + + // check if it is a transformation link (name will contain a newline) + for(i = 0; link[i]; ++i) { + xform_data[i] = link[i]; + if(link[i] == 10) { // newline + is_xform = 1; // therefore, we're dealing with a xform + xform_data[i] = 0; + break; + } + } + + // If we're dealing with an xform here, we pass xform_data to vfs_readlink, + // since it contains ONLY the symlink path (no xform stuff). Otherwise, + // we can just pass link since we're not dealing with an xform. + if(is_xform) + res = vfs_readlink(dentry, buffer, buflen, xform_data); + else + res = vfs_readlink(dentry, buffer, buflen, link); + + kfree(xform_data); + + return res; +} + +/* + * The symlink is larger than 60 bytes long. +*/ + +static int mona_slow_readlink(struct dentry *dentry, char *buffer, int buflen) +{ + struct page *page = NULL; + int i, is_xform = 0, res; + char *xform_data = NULL; + // We pass page_getlink the directory entry along with a page, which it + // fills in with the symlink data and returns the address of to us. + char *link = page_getlink(dentry, &page); + + // Allocate a buffer of buflen bytes for xform_data. This ensures + // that xform_data is large enough to hold the path, even though + // path will be fraction of what the total buffer size will be. + xform_data = (char *) kmalloc(buflen, GFP_KERNEL); + + // check if it is a transformation link (name will contain a newline) + for(i = 0; link[i]; ++i) { + xform_data[i] = link[i]; + if(link[i] == 10) { // newline + is_xform = 1; // therefore, we're dealing with an xform + xform_data[i] = 0; + break; + } + } + + // If we're dealing with an xform here, we pass xform_data to vfs_readlink, + // since it contains ONLY the symlink path (no xform stuff). Otherwise, + // we can just pass link since we're not dealing with an xform. + + if(is_xform) + res = vfs_readlink(dentry, buffer, buflen, xform_data); + else + res = vfs_readlink(dentry, buffer, buflen, link); + + if (page) { + kunmap(page); + page_cache_release(page); + } + + kfree(xform_data); + + return res; +} + + +struct inode_operations mona_fast_symlink_inode_operations = { + readlink: mona_readlink, + follow_link: mona_follow_link, +}; + +struct inode_operations mona_symlink_inode_operations = { + readlink: mona_slow_readlink, + follow_link: mona_slow_follow_link, +}; + diff -ruN linux/fs/mona/xforms.c linux-mona/fs/mona/xforms.c --- linux/fs/mona/xforms.c Wed Dec 31 19:00:00 1969 +++ linux-mona/fs/mona/xforms.c Wed Jun 27 01:13:22 2001 @@ -0,0 +1,601 @@ +/* File: xforms.c + * + * Author: Richard Kendall + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +fileListPtr mfd_list; +long mfd_index = 0; +kernelXformPtr function_listing; +XformIOstreamPtr xform_stream_table[HASH_TABLE_SIZE]; +extern XformListPtr xform_data_list[3]; + +DECLARE_WAIT_QUEUE_HEAD(u2k_wait_q); +DECLARE_WAIT_QUEUE_HEAD(mona_k2u_wait); + +KUinfoPtr k2u_list = NULL; +KUinfoPtr u2k_list = NULL; + +extern void deallocate_xform_lists(void); + +/************************************************************************** + * begin xform list * + **************************************************************************/ + +/* Simple non-size conserving transformation to demonstrate + * the use of the private_data pointer +*/ + +typedef struct Dbl { + int bytes; + char* data; +} dbl, *dblPtr; + +int doubling_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer) +{ + int i; + dblPtr ptr = (dblPtr) xf_ptr->private_data; + + if(ptr == NULL) { + xf_ptr->private_data = kmalloc(sizeof(dblPtr), GFP_KERNEL); + ptr = xf_ptr->private_data; + ptr->bytes = num_bytes; + ptr->data = (char*) kmalloc(num_bytes, GFP_KERNEL); + for(i = 0; i < num_bytes; i++) + ptr->data[i] = buffer[i]; + + xf_ptr->state = XF_HAS_DATA; + return num_bytes; + } + else { + for(i = 0; i < num_bytes; i++) + buffer[i] = ptr->data[i]; + kfree(ptr->data); + kfree(ptr); + xf_ptr->private_data = NULL; + xf_ptr->state = XF_READY; + return i; + } +} + +int upper2lower_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer) { + int i=0; + int total_bytes_sent = num_bytes; + + while (i < num_bytes) { + if ((buffer[i] <= 'Z') && (buffer[i] >= 'A')) + buffer[i] += ('a' - 'A'); + ++i; + } + + return total_bytes_sent; +} + +int lower2upper_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer) { + int i=0; + int total_bytes_sent = num_bytes; + + while(i < num_bytes) { + if ((buffer[i] <= 'z') && (buffer[i] >= 'a')) + buffer[i] -= ('a' - 'A'); + ++i; + } + + return total_bytes_sent; +} + + +int nop_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer) +{ + return num_bytes; +} + +int xor_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer) { + int total_bytes_sent = num_bytes; + int i; + + for (i=0; iid); + tmp = tmp->next; + } +#endif +} + + +KUinfoPtr add_k2u(void) { + KUinfoPtr kuip; + + if (k2u_list == NULL) { + k2u_list = (KUinfoPtr) kmalloc(sizeof(KUinfo), GFP_KERNEL); + k2u_list->next = NULL; + k2u_list->id = -1; + + init_waitqueue_head (&k2u_list->u2k_wait); + init_waitqueue_head (&k2u_list->k2u_wait); + return k2u_list; + } + + kuip = k2u_list; + + /* find end of linked list */ + while (kuip->next != NULL) + kuip = kuip->next; + + kuip->next = (KUinfoPtr) kmalloc(sizeof(KUinfo), GFP_KERNEL); + kuip->next->next = NULL; + kuip->next->id = -1; + + init_waitqueue_head (&k2u_list->u2k_wait); + init_waitqueue_head (&k2u_list->k2u_wait); + + return kuip->next; +} + + +KUinfoPtr get_ku_info(int id, KUinfoPtr list) { + KUinfoPtr tmp; + + tmp = list; + + while (tmp != NULL) { + if (tmp->id == id) + return tmp; + tmp = tmp->next; + } + + return NULL; +} + + +int move_to_u2k(KUinfoPtr kuip) { + KUinfoPtr tmp1, tmp2; + + tmp1 = tmp2 = k2u_list; + + /* find kuip in k2u_list and remove it */ + while(1) { + if (tmp1 == NULL) + return -1; /* kuip wasn't in the k2u_list */ + + if (tmp1 == kuip) { + if (k2u_list == tmp1) /* do a test for first node */ + k2u_list = tmp1->next; + else /* remove the node from k2u and reset it */ + tmp2->next = tmp1->next; + + break; + } + + tmp2 = tmp1; + tmp1 = tmp1->next; + } + + /* insert kuip at head of u2k_list */ + tmp2 = u2k_list; + u2k_list = kuip; + kuip->next = tmp2; + + return 0; +} + + +int del_u2k(KUinfoPtr kuip) { + KUinfoPtr tmp1, tmp2; + + tmp1 = tmp2 = u2k_list; + + while (1) { + if (tmp1 == NULL) + return -1; /* kuip wasn't in the u2k_list */ + + if (tmp1 == kuip) { + if (u2k_list == tmp1) + u2k_list = tmp1->next; + else + tmp2->next = tmp1->next; + + kfree(tmp1); + break; + } + + tmp2 = tmp1; + tmp1 = tmp1->next; + } + + return 0; +} + + +int export_xform(XformInfoPtr xf_ptr, int num_bytes, + char *buffer) { + char *msg, *msg2; + int total_bytes_sent = num_bytes; + int bytes; + int i; + + int total_len = 0; + KUinfoPtr k2u_ip, u2k_ip, kuip; + uid_t xuid; + gid_t xgid; + + if (num_bytes < 0) { + mona_debug("@@@###@@@ in export xform, num_bytes < 0\n"); + + // @@@ need to add code to pass this on down the chain + } + + /* xf_ptr->id specifies a unique identification number for each export + * space transformation. This id is used in the k2u_list and u2k_list + * as a security measure to prevent any process from posing as the mona + * daemon (it would need to know the id). Although the current + * implementation only uses a 32-bit integer, it can easily be expanded + * into a 128-bit encryption key. + */ + k2u_ip = get_ku_info(xf_ptr->id, k2u_list); + u2k_ip = get_ku_info(xf_ptr->id, u2k_list); + + if (k2u_ip != NULL) { + /* this is an error: the export_xform should not be called on the same + * xform until the daemon handles the previous access + */ + mona_debug("daemon did not handle previous access\n"); + kuip = k2u_ip; + } + else if (u2k_ip != NULL) { + /* use the KUinfo that is already instantiated */ + kuip = u2k_ip; + } + else { + /* neither k2u nor the u2k list had an instantiation so make one */ + kuip = add_k2u(); + kuip->id = xf_ptr->id; + } + + /* I can handle a 4 page message to/from user space, do I need more? */ + msg = (char *) kmalloc(sizeof(char) * U_K_MESSAGE_SIZE, GFP_KERNEL); + msg2 = (char *) kmalloc(sizeof(char) * U_K_MESSAGE_SIZE, GFP_KERNEL); + + kuip->u2k_buf = msg2; + + /* generate message to user space of the following form: + * + * int total size of message + * int export xform id number + * int uid + * int gid + * int state + * int stream_dir + * int size of buffer + * int argc + * string xform function name (terminating char on string) + * * argc parameter strings + * string buffer (no terminating char) + */ + + msg += sizeof(int); + + if (xf_ptr->inodep == NULL) { + xuid = current->uid; + xgid = current->gid; + } else { + xuid = xf_ptr->inodep->i_uid; + xgid = xf_ptr->inodep->i_gid; + } + + total_len = sprintf(msg, "%ld %d %d %d %d %d %d ", + xf_ptr->id, xuid, xgid, xf_ptr->state, + xf_ptr->stream_dir, num_bytes, xf_ptr->argc); + + if (xf_ptr->private_data != NULL) { + strcat(msg, xf_ptr->private_data); + total_len += strlen(xf_ptr->private_data) + 1; + msg[total_len-1] = ' '; + } else { + strcat(msg, "Transformation_not_found "); + total_len += 24; /* strlen("Trans... */ + } + + for (i = 0; i < xf_ptr->argc; ++i) { + mona_debug("appending !!!!!!!!!! %s\n", xf_ptr->argv[i]); + strcat(msg, xf_ptr->argv[i]); + strcat(msg, " "); + total_len += strlen(xf_ptr->argv[i]) + 1; + } + + total_len += num_bytes; + + /* PWR: if we were smart, we could get rid of this copy */ + if(num_bytes > 0) + memcpy(&msg[total_len - num_bytes], buffer, num_bytes); + + + kuip->k2u_size = total_len + sizeof(int); + + + msg -= sizeof(int); + *((int*) msg) = total_len + sizeof(int); + + /* write to the kernel-to-user buffer and then wait for a reply */ + kuip->k2u_buf = msg; + kuip->k2u_state = 1; /* tell ioctl that this struct has data */ + + wake_up(&mona_k2u_wait); + + /* sleep until the mona daemon accesses the user-to-kernel buffer */ + + interruptible_sleep_on(&kuip->u2k_wait); + + kfree(msg); + + /* read the reply from the mona daemon in user space */ + bytes = kuip->u2k_size; + + /* The first byte of the message is the state of the xform */ + + xf_ptr->state = (int) msg2[0]; + if (bytes > XFORM_PAGE_SIZE + 1) /* if the msg is too big, crop it */ + bytes = XFORM_PAGE_SIZE + 1; + --bytes; + if(bytes > 0) + memcpy(buffer, &msg2[1], bytes); + + total_bytes_sent = bytes; + kfree(msg2); + + mona_debug("user at end, returning %d bytes sent\n", total_bytes_sent); + return total_bytes_sent; +} + + +/************************************************************************** + * end xform list * + **************************************************************************/ + +void register_fn(int (*fn)(XformInfoPtr, int, char*), + char *fn_name) +{ + kernelXformPtr tmp = function_listing; + + function_listing = (kernelXformPtr) kmalloc(sizeof(kernelXform), GFP_KERNEL); + function_listing->function_name = (char *) kmalloc(strlen(fn_name), GFP_KERNEL); + strcpy(function_listing->function_name, fn_name); + function_listing->xform_function = fn; + function_listing->next = tmp; +} + +void register_kernel_functions(void) { + register_fn(nop_xform, "nop_xform"); + register_fn(upper2lower_xform, "upper2lower_xform"); + register_fn(lower2upper_xform, "lower2upper_xform"); + register_fn(xor_xform, "xor_xform"); + register_fn(xor100_xform, "xor100_xform"); + register_fn(inc_xform, "inc_xform"); + register_fn(op100_xform, "op100_xform"); + register_fn(doubling_xform, "doubling_xform"); + register_fn(export_xform, "export_xform"); + /* register_fn(open_export_xform, "open_export_xform");*/ +} + +void init_mona(void) { + int i; + + mfd_list = NULL; + function_listing = NULL; + + for (i=0; i < HASH_TABLE_SIZE; ++i) + xform_stream_table[i] = NULL; + + register_kernel_functions(); +} + +int mfd_insert(struct file *filp, long index) { + fileListPtr tempListPtr; + + if(index < 0) + return EBADF; + + tempListPtr = mfd_list; + mfd_list = (fileListPtr) kmalloc(sizeof(fileList), GFP_KERNEL); + mfd_list->file = filp; + mfd_list->id = index; + mfd_list->next = tempListPtr; + + return 0; +} + +void mfd_delete(long id) { + fileListPtr tmp, prev; + + tmp = mfd_list; + prev = NULL; + + while(tmp != NULL) { // traverse the list + if(tmp->id == id) + break; + prev = tmp; + tmp = tmp->next; // prev is tmp's predecessor + } + + if(tmp == NULL) // no id found + return; + + if(prev != NULL) + prev->next = tmp->next; + else + mfd_list = tmp->next; + + kfree(tmp); +} + +long match_mfd(struct file *filp) { + fileListPtr tmp; + + tmp = mfd_list; + while(tmp != NULL) { + if((tmp->file) && tmp->file == filp) + return tmp->id; + tmp = tmp->next; + } + + return -1; +} + +// returns a pointer to the function named in the parameter +// or NULL if it does not exist +void* get_fn(char *fn_name) { + kernelXformPtr tmp; + + tmp = function_listing; + while(tmp != NULL) { + if(tmp->function_name != NULL) + if(strcmp(tmp->function_name, fn_name) == 0) { + return tmp->xform_function; + } + tmp = tmp->next; + } + + return NULL; +} + +int build_xform_tree(struct inode *i_node, struct file *filp) { + XformListPtr tempListPtr; + XformIOstreamPtr tempStreamPtr; + XformInfoPtr tempInfoPtr, tempInfoPtr2; + long index, hashed_index; + short stream; + + index = mfd_index++; + hashed_index = index % HASH_TABLE_SIZE; + + if(xform_data_list[INPUT] || xform_data_list[OUTPUT]) { + tempStreamPtr = xform_stream_table[hashed_index]; + xform_stream_table[hashed_index] = + (XformIOstreamPtr) kmalloc(sizeof(XformIOstream), GFP_KERNEL); + xform_stream_table[hashed_index]->stream[INPUT] = NULL; + xform_stream_table[hashed_index]->stream[OUTPUT] = NULL; + + for(stream = INPUT; stream < OPEN; stream++) { + tempListPtr = xform_data_list[stream]; + + // if xforms exist, locate empty slot in hash table + while(tempListPtr != NULL) { // add the XformList info to the IOstream + tempInfoPtr = xform_stream_table[hashed_index]->stream[stream]; + xform_stream_table[hashed_index]->stream[stream] = + (XformInfoPtr) kmalloc(sizeof(XformInfo), GFP_KERNEL); + tempInfoPtr2 = xform_stream_table[hashed_index]->stream[stream]; + tempInfoPtr2->private_data = NULL; + tempInfoPtr2->filp = filp; + tempInfoPtr2->state = XF_READY; + tempInfoPtr2->id = -1; + tempInfoPtr2->inodep = i_node; + tempInfoPtr2->id = index; + tempInfoPtr2->argc = tempListPtr->argc_data; + tempListPtr->argc_data = 0; + tempInfoPtr2->argv = tempListPtr->data; + tempInfoPtr2->stream_dir = stream; + // check for the function name in kernel and user space + if((tempInfoPtr2->xform = (int (*)(XformInfoPtr, + int, char*)) get_fn(tempListPtr->xform_name)) == NULL) + { + tempInfoPtr2->xform = + (int (*)(XformInfoPtr, int, char*)) get_fn("export_xform"); + tempInfoPtr2->private_data = + (char *) kmalloc(strlen(tempListPtr->xform_name), GFP_KERNEL); + strcpy(tempInfoPtr2->private_data, tempListPtr->xform_name); + tempInfoPtr2->id = get_export_xform_id(); + } + + tempInfoPtr2->next_xform = tempInfoPtr; + tempListPtr = tempListPtr->next; + } + xform_stream_table[hashed_index]->overflow[stream] = 0; + xform_stream_table[hashed_index]->stream_state[stream] = XF_READY; + } + xform_stream_table[hashed_index]->id = index; + xform_stream_table[hashed_index]->next = tempStreamPtr; + } + + deallocate_xform_lists(); + + if(mfd_insert(filp, index) == EBADF) + return EBADF; + + return 0; +} diff -ruN linux/fs/namei.c linux-mona/fs/namei.c --- linux/fs/namei.c Fri Dec 29 17:07:23 2000 +++ linux-mona/fs/namei.c Fri Jun 22 20:42:02 2001 @@ -1945,7 +1945,7 @@ } /* get the link contents into pagecache */ -static char *page_getlink(struct dentry * dentry, struct page **ppage) +char *page_getlink(struct dentry * dentry, struct page **ppage) { struct page * page; struct address_space *mapping = dentry->d_inode->i_mapping; diff -ruN linux/include/linux/fs.h linux-mona/include/linux/fs.h --- linux/include/linux/fs.h Tue Jan 30 02:24:56 2001 +++ linux-mona/include/linux/fs.h Fri Jun 22 21:00:44 2001 @@ -271,6 +271,7 @@ #include #include #include +#include #include #include #include @@ -434,6 +435,7 @@ union { struct minix_inode_info minix_i; struct ext2_inode_info ext2_i; + struct mona_inode_info mona_i; struct hpfs_inode_info hpfs_i; struct ntfs_inode_info ntfs_i; struct msdos_inode_info msdos_i; @@ -613,6 +615,7 @@ #include #include +#include #include #include #include @@ -661,6 +664,7 @@ union { struct minix_sb_info minix_sb; struct ext2_sb_info ext2_sb; + struct mona_sb_info mona_sb; struct hpfs_sb_info hpfs_sb; struct ntfs_sb_info ntfs_sb; struct msdos_sb_info msdos_sb; @@ -1175,7 +1179,7 @@ } read_descriptor_t; typedef int (*read_actor_t)(read_descriptor_t *, struct page *, unsigned long, unsigned long); - +typedef int (*read_actor_m)(read_descriptor_t *desc, char *buffer, unsigned long size); /* needed for stackable file system support */ extern loff_t default_llseek(struct file *file, loff_t offset, int origin); diff -ruN linux/include/linux/mona_fs.h linux-mona/include/linux/mona_fs.h --- linux/include/linux/mona_fs.h Wed Dec 31 19:00:00 1969 +++ linux-mona/include/linux/mona_fs.h Wed Jun 27 01:12:38 2001 @@ -0,0 +1,810 @@ +/* + * linux/include/linux/mona_fs.h + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/include/linux/minix_fs.h + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#ifndef _LINUX_MONA_FS_H +#define _LINUX_MONA_FS_H + +#include +#include +#include +#include + +/* + * Define MONAFS_DEBUG to produce debug messages +*/ +/* #define MONAFS_DEBUG */ + +/* The following are defined for ext2 in /include/asm/bitops.h + * I really don't understand the architecture dependent stuff so + * I'm just assuming that ext2 knows what it's doing. Mona hasn't + * changed any inode structure so we should still be equivalent to + * ext2. +*/ + +#define mona_find_first_zero_bit ext2_find_first_zero_bit +#define mona_find_next_zero_bit ext2_find_next_zero_bit +#define mona_test_bit ext2_test_bit +#define mona_clear_bit ext2_clear_bit +#define mona_set_bit ext2_set_bit + +/* + * The Mona filesystem constants/structures +*/ + +/* + * Define MONA_PREALLOCATE to preallocate data blocks for expanding files +*/ +#define MONA_PREALLOCATE +#define MONA_DEFAULT_PREALLOC_BLOCKS 0 + +/* + * Define size of blocks that are passed by default through a transformation +*/ +#define XFORM_PAGE_SIZE 4096 +#define U_K_MESSAGE_SIZE 4 * XFORM_PAGE_SIZE + +/* + * Define the size of the hash table which holds the transformation streams +*/ +#define HASH_TABLE_SIZE 11 + + +/* + * Define the maximum length in characters that a filename is allowed (this + * is originally defined in limits.h) + */ +#define MAX_FILENAME_LEN NAME_MAX + +/* + * The Mona filesystem version + */ + +#define MONAFS_DATE "01/06/27" +#define MONAFS_VERSION "0.8.0" + +/* + * Debug code +*/ + +#ifdef MONAFS_DEBUG +#define mona_debug(f, a...) { \ + printk ("MONA-fs DEBUG (%s, %d): %s:", \ + __FILE__, __LINE__, __FUNCTION__); \ + printk (f, ## a); \ + } +#else +#define mona_debug(f, a...) +#endif + +/* + * Special inodes numbers +*/ +#define MONA_BAD_INO 1 +#define MONA_ROOT_INO 2 +#define MONA_ACL_IDX_INO 3 +#define MONA_ACL_DATA_INO 4 +#define MONA_BOOT_LOADER_INO 5 +#define MONA_UNDEL_DIR_INO 6 + +/* + * First non-reserved inode for old mona filesystems +*/ +#define MONA_GOOD_OLD_FIRST_INO 11 + +/* + * The mona file system magic number +*/ +#define MONA_SUPER_MAGIC 0xEF53 + +/* + * Maximal count of links to a file +*/ +#define MONA_LINK_MAX 32000 + +/* + * Macro-instructions used to manage several block sizes +*/ +#define MONA_MIN_BLOCK_SIZE 1024 +#define MONA_MAX_BLOCK_SIZE 4096 +#define MONA_MIN_BLOCK_LOG_SIZE 10 +#ifdef __KERNEL__ +#define MONA_BLOCK_SIZE(s) ((s)->s_blocksize) +#else +#define MONA_BLOCK_SIZE(s) (MONA_MIN_BLOCK_SIZE << (s)->s_log_block_size) +#endif +#define MONA_ACLE_PER_BLOCK(s) (MONA_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry)) +#define MONA_ADDR_PER_BLOCK(s) (MONA_BLOCK_SIZE(s) / sizeof (__u32)) +#ifdef __KERNEL__ +#define MONA_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) +#else +#define MONA_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) +#endif +#ifdef __KERNEL__ +#define MONA_ADDR_PER_BLOCK_BITS(s) ((s)->u.mona_sb.s_addr_per_block_bits) +#define MONA_INODE_SIZE(s) ((s)->u.mona_sb.s_inode_size) +#define MONA_FIRST_INO(s) ((s)->u.mona_sb.s_first_ino) +#else +#define MONA_INODE_SIZE(s) (((s)->s_rev_level == MONA_GOOD_OLD_REV) ? \ + MONA_GOOD_OLD_INODE_SIZE : \ + (s)->s_inode_size) +#define MONA_FIRST_INO(s) (((s)->s_rev_level == MONA_GOOD_OLD_REV) ? \ + MONA_GOOD_OLD_FIRST_INO : \ + (s)->s_first_ino) +#endif + +/* + * Macro-instructions used to manage fragments +*/ + +#define MONA_MIN_FRAG_SIZE 1024 +#define MONA_MAX_FRAG_SIZE 4096 +#define MONA_MIN_FRAG_LOG_SIZE 10 +#ifdef __KERNEL__ +# define MONA_FRAG_SIZE(s) ((s)->u.mona_sb.s_frag_size) +# define MONA_FRAGS_PER_BLOCK(s) ((s)->u.mona_sb.s_frags_per_block) +#else +# define MONA_FRAG_SIZE(s) (MONA_MIN_FRAG_SIZE << (s)->s_log_frag_size) +# define MONA_FRAGS_PER_BLOCK(s) (MONA_BLOCK_SIZE(s) / MONA_FRAG_SIZE(s)) +#endif + +enum ku_return_val { KU_SUCCESS, KU_INVALID_ID, KU_NOT_ROOT, KU_NO_DATA }; + +/* + * Location of user-to-kernel and kernel-to-user files +*/ + +#define MONA_K2U "/proc/fs/mona/k2u" + +#define INPUT 0 +#define OUTPUT 1 +#define OPEN 2 +#define DONE 3 + +/* + * Structures for passing data through transformations +*/ + +typedef struct xform_info { + struct xform_info *next_xform; + int (*xform) (struct xform_info *, int, char *); + long id; /* PWR: change to 64 bit id */ + int state; + int stream_dir; + int argc; + char **argv; + void *private_data; + struct file *filp; + struct inode *inodep; +} XformInfo, *XformInfoPtr; + +typedef struct xform_iostream { + long id; + XformInfoPtr stream[2]; + int stream_state[2]; + long overflow[2]; + struct xform_iostream *next; +} XformIOstream, *XformIOstreamPtr; + + +typedef struct xform_list { + char *xform_name; + int argc_data; + char **data; + struct xform_list *next; +} XformList, *XformListPtr; + +typedef struct file_list {\ + long id; + struct file *file; + struct file_list *next; +} fileList, *fileListPtr; + +typedef struct function_list { + char* function_name; + int (*xform_function)(XformInfoPtr, int, char*); + struct function_list *next; +} kernelXform, *kernelXformPtr; + +#define XF_EXIT_NOW -2 + +enum xform_states { + XF_READY, XF_HAS_DATA +}; + +/* + * kernel to user communication structure +*/ + +struct mona_u2k { + int size; + int id; + int offset; + char *buffer; +}; + +#define BLOCK 4096 + +/* + * ACL structures +*/ +struct mona_acl_header /* Header of Access Control Lists */ +{ + __u32 aclh_size; + __u32 aclh_file_count; + __u32 aclh_acle_count; + __u32 aclh_first_acle; +}; + +struct mona_acl_entry /* Access Control List Entry */ +{ + __u32 acle_size; + __u16 acle_perms; /* Access permissions */ + __u16 acle_type; /* Type of entry */ + __u16 acle_tag; /* User or group identity */ + __u16 acle_pad1; + __u32 acle_next; /* Pointer on next entry for the */ + /* same inode or on next free entry */ +}; + +/* + * Structure of a blocks group descriptor + */ +struct mona_group_desc +{ + __u32 bg_block_bitmap; /* Blocks bitmap block */ + __u32 bg_inode_bitmap; /* Inodes bitmap block */ + __u32 bg_inode_table; /* Inodes table block */ + __u16 bg_free_blocks_count; /* Free blocks count */ + __u16 bg_free_inodes_count; /* Free inodes count */ + __u16 bg_used_dirs_count; /* Directories count */ + __u16 bg_pad; + __u32 bg_reserved[3]; +}; + +/* + * Macro-instructions used to manage group descriptors + */ +#ifdef __KERNEL__ +# define MONA_BLOCKS_PER_GROUP(s) ((s)->u.mona_sb.s_blocks_per_group) +# define MONA_DESC_PER_BLOCK(s) ((s)->u.mona_sb.s_desc_per_block) +# define MONA_INODES_PER_GROUP(s) ((s)->u.mona_sb.s_inodes_per_group) +# define MONA_DESC_PER_BLOCK_BITS(s) ((s)->u.mona_sb.s_desc_per_block_bits) +#else +# define MONA_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) +# define MONA_DESC_PER_BLOCK(s) (MONA_BLOCK_SIZE(s) / sizeof (struct mona_group_desc)) +# define MONA_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) +#endif + +/* + * Constants relative to the data blocks + */ +#define MONA_NDIR_BLOCKS 12 +#define MONA_IND_BLOCK MONA_NDIR_BLOCKS +#define MONA_DIND_BLOCK (MONA_IND_BLOCK + 1) +#define MONA_TIND_BLOCK (MONA_DIND_BLOCK + 1) +#define MONA_N_BLOCKS (MONA_TIND_BLOCK + 1) + +/* + * Inode flags + */ +#define MONA_SECRM_FL 0x00000001 /* Secure deletion */ +#define MONA_UNRM_FL 0x00000002 /* Undelete */ +#define MONA_COMPR_FL 0x00000004 /* Compress file */ +#define MONA_SYNC_FL 0x00000008 /* Synchronous updates */ +#define MONA_IMMUTABLE_FL 0x00000010 /* Immutable file */ +#define MONA_APPEND_FL 0x00000020 /* writes to file may only append */ +#define MONA_NODUMP_FL 0x00000040 /* do not dump file */ +#define MONA_NOATIME_FL 0x00000080 /* do not update atime */ +/* Reserved for compression usage... */ +#define MONA_DIRTY_FL 0x00000100 +#define MONA_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ +#define MONA_NOCOMP_FL 0x00000400 /* Don't compress */ +#define MONA_ECOMPR_FL 0x00000800 /* Compression error */ +/* End compression flags --- maybe not all used */ +#define MONA_BTREE_FL 0x00001000 /* btree format dir */ +#define MONA_RESERVED_FL 0x80000000 /* reserved for mona lib */ + +#define MONA_FL_USER_VISIBLE 0x00001FFF /* User visible flags */ +#define MONA_FL_USER_MODIFIABLE 0x000000FF /* User modifiable flags */ + +/* + * ioctl commands +*/ +#define MONA_IOC_GETFLAGS _IOR('f', 1, long) +#define MONA_IOC_SETFLAGS _IOW('f', 2, long) +#define MONA_IOC_GETVERSION _IOR('v', 3, long) +#define MONA_IOC_SETVERSION _IOW('v', 4, long) +#define MONA_IOC_PUSH_INPUT 42 +#define MONA_IOC_POP_INPUT 43 +#define MONA_IOC_PUSH_OUTPUT 44 +#define MONA_IOC_POP_OUTPUT 45 +#define MONA_IOC_NUM_IN_XFORMS 46 +#define MONA_IOC_NUM_OUT_XFORMS 47 +#define MONA_IOC_WAKE_XFORM 48 +#define MONA_IOC_K2U_SIZE 49 +#define MONA_IOC_U2K_SIZE 50 +#define MONA_IOC_U2K 51 +#define MONA_IOC_K2U_MASTER 52 +#define MONA_IOC_K2U_SLAVE 53 +#define MONA_IOC_WAKE_MASTER 54 +#define MONA_IOC_INIT_KU 55 +#define MONA_IOC_DAEMON_FAIL 56 + +/* + * Structure of an inode on the disk + */ +struct mona_inode { + __u16 i_mode; /* File mode */ + __u16 i_uid; /* Low 16 bits of Owner Uid */ + __u32 i_size; /* Size in bytes */ + __u32 i_atime; /* Access time */ + __u32 i_ctime; /* Creation time */ + __u32 i_mtime; /* Modification time */ + __u32 i_dtime; /* Deletion Time */ + __u16 i_gid; /* Low 16 bits of Group Id */ + __u16 i_links_count; /* Links count */ + __u32 i_blocks; /* Blocks count */ + __u32 i_flags; /* File flags */ + union { + struct { + __u32 l_i_reserved1; + } linux1; + struct { + __u32 h_i_translator; + } hurd1; + struct { + __u32 m_i_reserved1; + } masix1; + } osd1; /* OS dependent 1 */ + __u32 i_block[MONA_N_BLOCKS];/* Pointers to blocks */ + __u32 i_generation; /* File version (for NFS) */ + __u32 i_file_acl; /* File ACL */ + __u32 i_dir_acl; /* Directory ACL */ + __u32 i_faddr; /* Fragment address */ + union { + struct { + __u8 l_i_frag; /* Fragment number */ + __u8 l_i_fsize; /* Fragment size */ + __u16 i_pad1; + __u16 l_i_uid_high; /* these 2 fields */ + __u16 l_i_gid_high; /* were reserved2[0] */ + __u32 l_i_reserved2; + } linux2; + struct { + __u8 h_i_frag; /* Fragment number */ + __u8 h_i_fsize; /* Fragment size */ + __u16 h_i_mode_high; + __u16 h_i_uid_high; + __u16 h_i_gid_high; + __u32 h_i_author; + } hurd2; + struct { + __u8 m_i_frag; /* Fragment number */ + __u8 m_i_fsize; /* Fragment size */ + __u16 m_pad1; + __u32 m_i_reserved2[2]; + } masix2; + } osd2; /* OS dependent 2 */ +}; + +#define i_size_high i_dir_acl + +#if defined(__KERNEL__) || defined(__linux__) +#define i_reserved1 osd1.linux1.l_i_reserved1 +#define i_frag osd2.linux2.l_i_frag +#define i_fsize osd2.linux2.l_i_fsize +#define i_uid_low i_uid +#define i_gid_low i_gid +#define i_uid_high osd2.linux2.l_i_uid_high +#define i_gid_high osd2.linux2.l_i_gid_high +#define i_reserved2 osd2.linux2.l_i_reserved2 +#endif + +#ifdef __hurd__ +#define i_translator osd1.hurd1.h_i_translator +#define i_frag osd2.hurd2.h_i_frag; +#define i_fsize osd2.hurd2.h_i_fsize; +#define i_uid_high osd2.hurd2.h_i_uid_high +#define i_gid_high osd2.hurd2.h_i_gid_high +#define i_author osd2.hurd2.h_i_author +#endif + +#ifdef __masix__ +#define i_reserved1 osd1.masix1.m_i_reserved1 +#define i_frag osd2.masix2.m_i_frag +#define i_fsize osd2.masix2.m_i_fsize +#define i_reserved2 osd2.masix2.m_i_reserved2 +#endif + +/* + * File system states + */ +#define MONA_VALID_FS 0x0001 /* Unmounted cleanly */ +#define MONA_ERROR_FS 0x0002 /* Errors detected */ + +/* + * Mount flags + */ +#define MONA_MOUNT_CHECK 0x0001 /* Do mount-time checks */ +#define MONA_MOUNT_GRPID 0x0004 /* Create files with directory's group */ +#define MONA_MOUNT_DEBUG 0x0008 /* Some debugging messages */ +#define MONA_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */ +#define MONA_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */ +#define MONA_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */ +#define MONA_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */ +#define MONA_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */ + +/* These should be the same as EXT2's */ +/* +#define clear_opt(o, opt) o &= ~MONA_MOUNT_##opt +#define set_opt(o, opt) o |= MONA_MOUNT_##opt +#define test_opt(sb, opt) ((sb)->u.mona_sb.s_mount_opt & \ + MONA_MOUNT_##opt) +*/ + +/* + * Maximal mount counts between two filesystem checks + */ +#define MONA_DFL_MAX_MNT_COUNT 1000 /* Allow 1000 mounts, should be 20 @@@ */ +#define MONA_DFL_CHECKINTERVAL 0 /* Don't use interval check */ + +/* + * Behaviour when detecting errors + */ +#define MONA_ERRORS_CONTINUE 1 /* Continue execution */ +#define MONA_ERRORS_RO 2 /* Remount fs read-only */ +#define MONA_ERRORS_PANIC 3 /* Panic */ +#define MONA_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE + +/* + * Structure of the super block + */ +struct mona_super_block { + __u32 s_inodes_count; /* Inodes count */ + __u32 s_blocks_count; /* Blocks count */ + __u32 s_r_blocks_count; /* Reserved blocks count */ + __u32 s_free_blocks_count; /* Free blocks count */ + __u32 s_free_inodes_count; /* Free inodes count */ + __u32 s_first_data_block; /* First Data Block */ + __u32 s_log_block_size; /* Block size */ + __s32 s_log_frag_size; /* Fragment size */ + __u32 s_blocks_per_group; /* # Blocks per group */ + __u32 s_frags_per_group; /* # Fragments per group */ + __u32 s_inodes_per_group; /* # Inodes per group */ + __u32 s_mtime; /* Mount time */ + __u32 s_wtime; /* Write time */ + __u16 s_mnt_count; /* Mount count */ + __s16 s_max_mnt_count; /* Maximal mount count */ + __u16 s_magic; /* Magic signature */ + __u16 s_state; /* File system state */ + __u16 s_errors; /* Behaviour when detecting errors */ + __u16 s_minor_rev_level; /* minor revision level */ + __u32 s_lastcheck; /* time of last check */ + __u32 s_checkinterval; /* max. time between checks */ + __u32 s_creator_os; /* OS */ + __u32 s_rev_level; /* Revision level */ + __u16 s_def_resuid; /* Default uid for reserved blocks */ + __u16 s_def_resgid; /* Default gid for reserved blocks */ + /* + * These fields are for MONA_DYNAMIC_REV superblocks only. + * + * Note: the difference between the compatible feature set and + * the incompatible feature set is that if there is a bit set + * in the incompatible feature set that the kernel doesn't + * know about, it should refuse to mount the filesystem. + * + * e2fsck's requirements are more strict; if it doesn't know + * about a feature in either the compatible or incompatible + * feature set, it must abort and not try to meddle with + * things it doesn't understand... + */ + __u32 s_first_ino; /* First non-reserved inode */ + __u16 s_inode_size; /* size of inode structure */ + __u16 s_block_group_nr; /* block group # of this superblock */ + __u32 s_feature_compat; /* compatible feature set */ + __u32 s_feature_incompat; /* incompatible feature set */ + __u32 s_feature_ro_compat; /* readonly-compatible feature set */ + __u8 s_uuid[16]; /* 128-bit uuid for volume */ + char s_volume_name[16]; /* volume name */ + char s_last_mounted[64]; /* directory where last mounted */ + __u32 s_algorithm_usage_bitmap; /* For compression */ + /* + * Performance hints. Directory preallocation should only + * happen if the MONA_COMPAT_PREALLOC flag is on. + */ + __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ + __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ + __u16 s_padding1; + __u32 s_reserved[204]; /* Padding to the end of the block */ +}; + +#ifdef __KERNEL__ +#define MONA_SB(sb) (&((sb)->u.mona_sb)) +#else +/* Assume that user mode programs are passing in an monafs superblock, not + * a kernel struct super_block. This will allow us to call the feature-test + * macros from user land. */ +#define MONA_SB(sb) (sb) +#endif + +/* + * Codes for operating systems + */ +#define MONA_OS_LINUX 0 +#define MONA_OS_HURD 1 +#define MONA_OS_MASIX 2 +#define MONA_OS_FREEBSD 3 +#define MONA_OS_LITES 4 + +/* + * Revision levels + */ +#define MONA_GOOD_OLD_REV 0 /* The good old (original) format */ +#define MONA_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ + +#define MONA_CURRENT_REV MONA_GOOD_OLD_REV +#define MONA_MAX_SUPP_REV MONA_DYNAMIC_REV + +#define MONA_GOOD_OLD_INODE_SIZE 128 + +#define MONA_HAS_COMPAT_FEATURE(sb,mask) \ + ( MONA_SB(sb)->s_ms->s_feature_compat & cpu_to_le32(mask) ) +#define MONA_HAS_RO_COMPAT_FEATURE(sb,mask) \ + ( MONA_SB(sb)->s_ms->s_feature_ro_compat & cpu_to_le32(mask) ) +#define MONA_HAS_INCOMPAT_FEATURE(sb,mask) \ + ( MONA_SB(sb)->s_ms->s_feature_incompat & cpu_to_le32(mask) ) +#define MONA_SET_COMPAT_FEATURE(sb,mask) \ + MONA_SB(sb)->s_ms->s_feature_compat |= cpu_to_le32(mask) +#define MONA_SET_RO_COMPAT_FEATURE(sb,mask) \ + MONA_SB(sb)->s_ms->s_feature_ro_compat |= cpu_to_le32(mask) +#define MONA_SET_INCOMPAT_FEATURE(sb,mask) \ + MONA_SB(sb)->s_ms->s_feature_incompat |= cpu_to_le32(mask) +#define MONA_CLEAR_COMPAT_FEATURE(sb,mask) \ + MONA_SB(sb)->s_ms->s_feature_compat &= ~cpu_to_le32(mask) +#define MONA_CLEAR_RO_COMPAT_FEATURE(sb,mask) \ + MONA_SB(sb)->s_ms->s_feature_ro_compat &= ~cpu_to_le32(mask) +#define MONA_CLEAR_INCOMPAT_FEATURE(sb,mask) \ + MONA_SB(sb)->s_ms->s_feature_incompat &= ~cpu_to_le32(mask) + + +#define MONA_FEATURE_COMPAT_DIR_PREALLOC 0x0001 + +#define MONA_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 +#define MONA_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 +#define MONA_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 + +#define MONA_FEATURE_INCOMPAT_COMPRESSION 0x0001 +#define MONA_FEATURE_INCOMPAT_FILETYPE 0x0002 + +#define MONA_FEATURE_COMPAT_SUPP 0 +#define MONA_FEATURE_INCOMPAT_SUPP MONA_FEATURE_INCOMPAT_FILETYPE +#define MONA_FEATURE_RO_COMPAT_SUPP (MONA_FEATURE_RO_COMPAT_SPARSE_SUPER| \ + MONA_FEATURE_RO_COMPAT_LARGE_FILE| \ + MONA_FEATURE_RO_COMPAT_BTREE_DIR) + +/* + * Default values for user and/or group using reserved blocks + */ +#define MONA_DEF_RESUID 0 +#define MONA_DEF_RESGID 0 + +/* + * Structure of a directory entry + */ +#define MONA_NAME_LEN 255 + +struct mona_dir_entry { + __u32 inode; /* Inode number */ + __u16 rec_len; /* Directory entry length */ + __u16 name_len; /* Name length */ + char name[MONA_NAME_LEN]; /* File name */ +}; + +/* + * The new version of the directory entry. Since Mona structures are + * stored in intel byte order, and the name_len field could never be + * bigger than 255 chars, it's safe to reclaim the extra byte for the + * file_type field. + */ +struct mona_dir_entry_2 { + __u32 inode; /* Inode number */ + __u16 rec_len; /* Directory entry length */ + __u8 name_len; /* Name length */ + __u8 file_type; + char name[MONA_NAME_LEN]; /* File name */ +}; + +/* + * Mona directory file types. Only the low 3 bits are used. The + * other bits are reserved for now. + */ +#define MONA_FT_UNKNOWN 0 +#define MONA_FT_REG_FILE 1 +#define MONA_FT_DIR 2 +#define MONA_FT_CHRDEV 3 +#define MONA_FT_BLKDEV 4 +#define MONA_FT_FIFO 5 +#define MONA_FT_SOCK 6 +#define MONA_FT_SYMLINK 7 + +#define MONA_FT_MAX 8 + +/* + * MONA_DIR_PAD defines the directory entries boundaries + * + * NOTE: It must be a multiple of 4 + */ +#define MONA_DIR_PAD 4 +#define MONA_DIR_ROUND (MONA_DIR_PAD - 1) +#define MONA_DIR_REC_LEN(name_len) (((name_len) + 8 + MONA_DIR_ROUND) & \ + ~MONA_DIR_ROUND) + +#ifdef __KERNEL__ +/* + * Function prototypes + */ + +/* + * Ok, these declarations are also in but none of the + * mona source programs needs to include it so they are duplicated here. + */ +# define NORET_TYPE /**/ +# define ATTRIB_NORET __attribute__((noreturn)) +# define NORET_AND noreturn, + +/* need these exported from mm/filemap.c */ +extern void add_page_to_hash_queue(struct page * page, struct page **p); +extern inline int get_max_readahead(struct inode * inode); +extern inline struct page * __find_page_nolock(struct address_space *mapping, unsigned + long offset, struct page *page); +extern inline void __add_to_page_cache(struct page * page, struct address_space *mapping, + unsigned long offset, struct page **hash); +extern int add_to_page_cache_unique(struct page * page, struct address_space *mapping, + unsigned long offset, struct page **hash); +extern inline int page_cache_read(struct file * file, unsigned long offset); +extern void drop_behind(struct file * file, unsigned long index); +extern void generic_file_readahead(int reada_ok, struct file * filp, struct inode * inode, + struct page * page); +extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, + unsigned long size); +extern inline void remove_suid(struct inode *inode); +extern inline struct page * __grab_cache_page(struct address_space *mapping, + unsigned long index, struct page **cached_page); + +extern int generic_osync_inode(struct inode *inode, int datasync); + +/* need these exported from fs/namei.c */ +char *page_getlink(struct dentry * dentry, struct page **ppage); + +/* acl.c */ +extern int mona_permission (struct inode *, int); + +/* balloc.c */ +extern int mona_bg_has_super(struct super_block *sb, int group); +extern unsigned long mona_bg_num_gdb(struct super_block *sb, int group); +extern int mona_new_block (const struct inode *, unsigned long, + __u32 *, __u32 *, int *); +extern void mona_free_blocks (const struct inode *, unsigned long, + unsigned long); +extern unsigned long mona_count_free_blocks (struct super_block *); +extern void mona_check_blocks_bitmap (struct super_block *); +extern struct mona_group_desc * mona_get_group_desc(struct super_block * sb, + unsigned int block_group, + struct buffer_head ** bh); + +/* bitmap.c */ +extern unsigned long mona_count_free (struct buffer_head *, unsigned); + +/* dir.c */ +extern int mona_check_dir_entry (const char *, struct inode *, + struct mona_dir_entry_2 *, struct buffer_head *, + unsigned long); + +/* file.c */ +extern int mona_read (struct inode *, struct file *, char *, int); +extern int mona_write (struct inode *, struct file *, char *, int); + +/* fsync.c */ +extern int mona_sync_file (struct file *, struct dentry *, int datasync); +extern int mona_fsync_inode (struct inode *, int); + +/* ialloc.c */ +extern struct inode * mona_new_inode (const struct inode *, int); +extern void mona_free_inode (struct inode *); +extern unsigned long mona_count_free_inodes (struct super_block *); +extern void mona_check_inodes_bitmap (struct super_block *); + +/* inode.c */ + +extern struct buffer_head * mona_getblk (struct inode *, long, int, int *); +extern struct buffer_head * mona_bread (struct inode *, int, int, int *); + +extern void mona_read_inode (struct inode *); +extern void mona_write_inode (struct inode *, int); +extern void mona_put_inode (struct inode *); +extern void mona_delete_inode (struct inode *); +extern int mona_sync_inode (struct inode *); +extern void mona_discard_prealloc (struct inode *); +extern void mona_update_dynamic_rev(struct super_block *sb); + +/* ioctl.c */ +extern int mona_ioctl (struct inode *, struct file *, unsigned int, + unsigned long); + +/* namei.c */ +extern struct inode_operations mona_dir_inode_operations; + +/* super.c */ +extern void mona_error (struct super_block *, const char *, const char *, ...) + __attribute__ ((format (printf, 3, 4))); +extern NORET_TYPE void mona_panic (struct super_block *, const char *, + const char *, ...) + __attribute__ ((NORET_AND format (printf, 3, 4))); +extern void mona_warning (struct super_block *, const char *, const char *, ...) + __attribute__ ((format (printf, 3, 4))); +extern void mona_put_super (struct super_block *); +extern void mona_write_super (struct super_block *); +extern int mona_remount (struct super_block *, int *, char *); +extern struct super_block * mona_read_super (struct super_block *,void *,int); +extern int mona_statfs (struct super_block *, struct statfs *); + +/* truncate.c */ +extern void mona_truncate (struct inode *); + + +/* file.c */ +extern int mona_file_open (struct inode *, struct file *); + +/* mread.c */ +extern ssize_t mona_file_read(struct file *, char *, size_t, loff_t *); + +/* mwrite.c */ +inline void __add_to_page_cache(struct page * page, + struct address_space *mapping, unsigned long offset, + struct page **hash); + +inline void add_page_to_inode_queue(struct address_space *mapping, struct page * page); + +/* xforms.c */ +void mfd_delete(long); +int mfd_insert(struct file *, long); +int build_xform_tree(struct inode *, struct file *); +long match_mfd(struct file *); +void release_xforms(void); +void init_mona(void); + +/* mrelease.c */ +int mona_release_file (struct inode * inode, struct file * filp); +int mona_flush_file (struct file * filp); + +/* + * Inodes and files operations + */ + +/* dir.c */ +extern struct file_operations mona_dir_operations; + +/* file.c */ +extern struct inode_operations mona_file_inode_operations; +extern struct file_operations mona_file_operations; + +/* symlink.c */ +extern struct inode_operations mona_fast_symlink_inode_operations; +extern struct inode_operations mona_symlink_inode_operations; +extern struct address_space_operations mona_aops; + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_MONA_FS_H */ diff -ruN linux/include/linux/mona_fs_i.h linux-mona/include/linux/mona_fs_i.h --- linux/include/linux/mona_fs_i.h Wed Dec 31 19:00:00 1969 +++ linux-mona/include/linux/mona_fs_i.h Thu Jan 11 15:36:15 2001 @@ -0,0 +1,42 @@ +/* + * linux/include/linux/mona_fs_i.h + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/include/linux/minix_fs_i.h + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#ifndef _LINUX_MONA_FS_I +#define _LINUX_MONA_FS_I + +/* + * Mona file system inode data in memory + */ +struct mona_inode_info { + __u32 i_data[15]; + __u32 i_flags; + __u32 i_faddr; + __u8 i_frag_no; + __u8 i_frag_size; + __u16 i_osync; + __u32 i_file_acl; + __u32 i_dir_acl; + __u32 i_dtime; + __u32 not_used_1; /* FIX: not used/ 2.2 placeholder */ + __u32 i_block_group; + __u32 i_next_alloc_block; + __u32 i_next_alloc_goal; + __u32 i_prealloc_block; + __u32 i_prealloc_count; + __u32 i_high_size; + int i_new_inode:1; /* Is a freshly allocated inode */ +}; + +#endif /* _LINUX_MONA_FS_I */ \ No newline at end of file diff -ruN linux/include/linux/mona_fs_k.h linux-mona/include/linux/mona_fs_k.h --- linux/include/linux/mona_fs_k.h Wed Dec 31 19:00:00 1969 +++ linux-mona/include/linux/mona_fs_k.h Wed Jun 27 01:01:31 2001 @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include + +/* PWR: this structure seems excessively bloated ... */ +typedef struct mona_ku_info { + char *k2u_buf, *u2k_buf; /* may only need one of these @@@ */ + int k2u_size, u2k_size; + int k2u_state; + int id; + struct mona_ku_info *next; + wait_queue_head_t k2u_wait; + wait_queue_head_t u2k_wait; + //DECLARE_WAIT_QUEUE_HEAD(u2k_wait); + //struct wait_queue *k2u_wait; + //struct wait_queue *u2k_wait; +} KUinfo, *KUinfoPtr; diff -ruN linux/include/linux/mona_fs_sb.h linux-mona/include/linux/mona_fs_sb.h --- linux/include/linux/mona_fs_sb.h Wed Dec 31 19:00:00 1969 +++ linux-mona/include/linux/mona_fs_sb.h Mon Feb 19 23:23:00 2001 @@ -0,0 +1,64 @@ +/* + * linux/include/linux/mona_fs_sb.h + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/include/linux/minix_fs_sb.h + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#ifndef _LINUX_MONA_FS_SB +#define _LINUX_MONA_FS_SB + +/* + * The following is not needed anymore since the descriptors buffer + * heads are now dynamically allocated + */ +/* #define MONA_MAX_GROUP_DESC 8 */ + +#define MONA_MAX_GROUP_LOADED 8 + +/* + * second extended-fs super-block data in memory + */ +struct mona_sb_info { + unsigned long s_frag_size; /* Size of a fragment in bytes */ + unsigned long s_frags_per_block;/* Number of fragments per block */ + unsigned long s_inodes_per_block;/* Number of inodes per block */ + unsigned long s_frags_per_group;/* Number of fragments in a group */ + unsigned long s_blocks_per_group;/* Number of blocks in a group */ + unsigned long s_inodes_per_group;/* Number of inodes in a group */ + unsigned long s_itb_per_group; /* Number of inode table blocks per group */ + unsigned long s_gdb_count; /* Number of descriptor blocks per group */ + unsigned long s_desc_per_block; /* Number of group descriptors per block */ + unsigned long s_groups_count; /* Number of groups in the fs */ + struct buffer_head * s_sbh; /* Buffer containing the super block */ + struct mona_super_block * s_ms; /* Pointer to the super block in the buffer */ + struct buffer_head ** s_group_desc; + unsigned short s_loaded_inode_bitmaps; + unsigned short s_loaded_block_bitmaps; + unsigned long s_inode_bitmap_number[EXT2_MAX_GROUP_LOADED]; + struct buffer_head * s_inode_bitmap[EXT2_MAX_GROUP_LOADED]; + unsigned long s_block_bitmap_number[EXT2_MAX_GROUP_LOADED]; + struct buffer_head * s_block_bitmap[EXT2_MAX_GROUP_LOADED]; + unsigned long s_mount_opt; + uid_t s_resuid; + gid_t s_resgid; + unsigned short s_mount_state; + unsigned short s_pad; + int s_addr_per_block_bits; + int s_desc_per_block_bits; + int s_inode_size; + int s_first_ino; + int s_feature_compat; + int s_feature_incompat; + int s_feature_ro_compat; +}; + +#endif /* _LINUX_MONA_FS_SB */ diff -ruN linux/kernel/ksyms.c linux-mona/kernel/ksyms.c --- linux/kernel/ksyms.c Sun Jan 28 19:11:20 2001 +++ linux-mona/kernel/ksyms.c Fri Jun 22 20:41:45 2001 @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -59,6 +61,7 @@ extern int sys_tz; extern int request_dma(unsigned int dmanr, char * deviceID); +extern void xmon_enter(void); extern void free_dma(unsigned int dmanr); extern spinlock_t dma_spin_lock; @@ -115,7 +118,7 @@ EXPORT_SYMBOL(find_vma); EXPORT_SYMBOL(get_unmapped_area); EXPORT_SYMBOL(init_mm); -EXPORT_SYMBOL(deactivate_page); +//EXPORT_SYMBOL(deactivate_page); #ifdef CONFIG_HIGHMEM EXPORT_SYMBOL(kmap_high); EXPORT_SYMBOL(kunmap_high); @@ -538,3 +541,28 @@ EXPORT_SYMBOL(tasklist_lock); EXPORT_SYMBOL(pidhash); + +/* extra Mona symbols we need for now */ +EXPORT_SYMBOL(deactivate_page); +EXPORT_SYMBOL(open_namei); +EXPORT_SYMBOL(pagecache_lock); +EXPORT_SYMBOL(wakeup_kswapd); +EXPORT_SYMBOL(free_shortage); +EXPORT_SYMBOL(memory_pressure); +EXPORT_SYMBOL(lru_cache_add); +EXPORT_SYMBOL(age_page_up); +EXPORT_SYMBOL(inactive_shortage); +EXPORT_SYMBOL(file_read_actor); +EXPORT_SYMBOL(add_page_to_hash_queue); +EXPORT_SYMBOL(get_max_readahead); +EXPORT_SYMBOL(__find_page_nolock); +EXPORT_SYMBOL(__add_to_page_cache); +EXPORT_SYMBOL(add_to_page_cache_unique); +EXPORT_SYMBOL(page_cache_read); +EXPORT_SYMBOL(drop_behind); +EXPORT_SYMBOL(generic_file_readahead); +EXPORT_SYMBOL(add_page_to_inode_queue); +EXPORT_SYMBOL(remove_suid); +EXPORT_SYMBOL(__grab_cache_page); +EXPORT_SYMBOL(page_getlink); +EXPORT_SYMBOL(generic_osync_inode); diff -ruN linux/mm/filemap.c linux-mona/mm/filemap.c --- linux/mm/filemap.c Mon Jan 15 20:14:41 2001 +++ linux-mona/mm/filemap.c Fri Jun 22 20:41:56 2001 @@ -55,7 +55,7 @@ #define CLUSTER_PAGES (1 << page_cluster) #define CLUSTER_OFFSET(x) (((x) >> page_cluster) << page_cluster) -static void add_page_to_hash_queue(struct page * page, struct page **p) +void add_page_to_hash_queue(struct page * page, struct page **p) { struct page *next = *p; @@ -69,7 +69,7 @@ atomic_inc(&page_cache_size); } -static inline void add_page_to_inode_queue(struct address_space *mapping, struct page * page) +inline void add_page_to_inode_queue(struct address_space *mapping, struct page * page) { struct list_head *head = &mapping->clean_pages; @@ -286,7 +286,7 @@ spin_unlock(&pagecache_lock); } -static inline struct page * __find_page_nolock(struct address_space *mapping, unsigned long offset, struct page *page) +inline struct page * __find_page_nolock(struct address_space *mapping, unsigned long offset, struct page *page) { goto inside; @@ -498,7 +498,7 @@ * This adds a page to the page cache, starting out as locked, * owned by us, but unreferenced, not uptodate and with no errors. */ -static inline void __add_to_page_cache(struct page * page, +inline void __add_to_page_cache(struct page * page, struct address_space *mapping, unsigned long offset, struct page **hash) { @@ -523,7 +523,7 @@ spin_unlock(&pagecache_lock); } -static int add_to_page_cache_unique(struct page * page, +int add_to_page_cache_unique(struct page * page, struct address_space *mapping, unsigned long offset, struct page **hash) { @@ -547,7 +547,7 @@ * This adds the requested page to the page cache if it isn't already there, * and schedules an I/O to read in its contents from disk. */ -static inline int page_cache_read(struct file * file, unsigned long offset) +inline int page_cache_read(struct file * file, unsigned long offset) { struct inode *inode = file->f_dentry->d_inode; struct address_space *mapping = inode->i_mapping; @@ -731,7 +731,7 @@ * * Rik van Riel, 2000 */ -static void drop_behind(struct file * file, unsigned long index) +void drop_behind(struct file * file, unsigned long index) { struct inode *inode = file->f_dentry->d_inode; struct address_space *mapping = inode->i_mapping; @@ -883,14 +883,14 @@ * 64k if defined (4K page size assumed). */ -static inline int get_max_readahead(struct inode * inode) +inline int get_max_readahead(struct inode * inode) { if (!inode->i_dev || !max_readahead[MAJOR(inode->i_dev)]) return MAX_READAHEAD; return max_readahead[MAJOR(inode->i_dev)][MINOR(inode->i_dev)]; } -static void generic_file_readahead(int reada_ok, +void generic_file_readahead(int reada_ok, struct file * filp, struct inode * inode, struct page * page) { @@ -1209,7 +1209,7 @@ UPDATE_ATIME(inode); } -static int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size) +int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size) { char *kaddr; unsigned long left, count = desc->count; @@ -2375,7 +2375,7 @@ return page; } -static inline struct page * __grab_cache_page(struct address_space *mapping, +inline struct page * __grab_cache_page(struct address_space *mapping, unsigned long index, struct page **cached_page) { struct page *page, **hash = page_hash(mapping, index); @@ -2408,7 +2408,7 @@ return page; } -static inline void remove_suid(struct inode *inode) +inline void remove_suid(struct inode *inode) { unsigned int mode;