Back to index

avfs  1.0.1
child.c
Go to the documentation of this file.
00001 /*
00002     AVFS: A Virtual File System Library
00003     Copyright (C) 1998-2001  Miklos Szeredi <miklos@szeredi.hu>
00004 
00005     This program can be distributed under the terms of the GNU GPL.
00006     See the file COPYING.
00007 */
00008 
00009 #include "virtual.h"
00010 #include "avfscoda.h"
00011 
00012 #include <stdio.h>
00013 #include <stdlib.h>
00014 #include <string.h>
00015 #include <unistd.h>
00016 #include <errno.h>
00017 #include <fcntl.h>
00018 #include <pthread.h>
00019 
00020 #include <sys/stat.h>
00021 
00022 /* #include "KERNINCLUDE/linux/coda.h" */
00023 #include CODAINCLUDE
00024 
00025 #define MULTITHREADED 1
00026 
00027 #define MAXPMSGLEN 8192
00028 #define MAXMSGLEN 1045
00029 
00030 /* #define HAVE_FIFO_BUG */
00031 
00032 static int child_outfd;
00033 
00034 static int st2type(struct stat *s)
00035 {
00036     if (S_ISDIR(s->st_mode))
00037         return C_VDIR;
00038 
00039     if (S_ISREG(s->st_mode))
00040         return C_VREG;
00041 
00042     if (S_ISBLK(s->st_mode))
00043         return C_VBLK;
00044 
00045     if (S_ISCHR(s->st_mode))
00046         return C_VCHR;
00047 
00048     if (S_ISLNK(s->st_mode))
00049         return C_VLNK;
00050 
00051     if (S_ISSOCK(s->st_mode))
00052         return C_VSOCK;
00053 
00054     if (S_ISFIFO(s->st_mode))
00055         return C_VFIFO;
00056 
00057     fprintf(stderr, "Unknown type\n");
00058     return C_VNON;
00059 }
00060 
00061 
00062 static void st2attr(struct stat *s, struct coda_vattr *a, ViceFid *id)
00063 {
00064     memset(a, 0, sizeof(struct coda_vattr));
00065     a->va_type = st2type(s);
00066        
00067     a->va_mode = s->st_mode & 07777;
00068        
00069     /* File type handling in linux-coda is a mess */
00070     a->va_mode |= (s->st_mode  & S_IFMT);
00071        
00072     a->va_nlink = s->st_nlink;
00073     a->va_uid = s->st_uid;
00074     a->va_gid = s->st_gid;
00075     a->va_fileid = coda_f2i(id);
00076     a->va_size = s->st_size;
00077     a->va_blocksize = 1024; /* s->st_blksize */
00078     a->va_atime.tv_nsec = a->va_ctime.tv_nsec = a->va_mtime.tv_nsec = 0;
00079     a->va_atime.tv_sec = s->st_atime;
00080     a->va_mtime.tv_sec = s->st_mtime;
00081     a->va_ctime.tv_sec = s->st_ctime;
00082     a->va_gen = 0;
00083     a->va_flags = 0;
00084     a->va_rdev = s->st_rdev;
00085        
00086     a->va_bytes = s->st_blocks * s->st_blksize;
00087     a->va_filerev = 0;
00088        
00089 #ifdef HAVE_FIFO_BUG
00090     /* Make a char device (255/255) out of pipes */
00091     if(S_ISFIFO(s->st_mode)) {
00092         a->va_mode = (s->st_mode & 07777) | S_IFCHR;
00093         a->va_type = C_VCHR;
00094         a->va_rdev = ~0;
00095     }
00096 #endif
00097 }
00098 
00099 
00100 static int set_attr(const char *path, struct coda_vattr *a)
00101 {
00102     
00103     if(a->va_mode != (u_short) -1) {
00104         if(virt_chmod(path, a->va_mode & 07777) == -1)
00105             return -1;
00106     }
00107     
00108     if(a->va_uid != (vuid_t) -1 || a->va_gid != (vuid_t) -1) {
00109         if(virt_lchown(path, a->va_uid, a->va_gid) == -1)
00110             return -1;
00111     }
00112 
00113     if(a->va_size != (u_quad_t) -1) {
00114         if(virt_truncate(path, a->va_size) == -1)
00115             return -1;
00116     }
00117 
00118     if(a->va_atime.tv_sec != (time_t) -1 ||
00119        a->va_mtime.tv_sec != (time_t) -1) {
00120         struct utimbuf utbuf;
00121 
00122         utbuf.actime = a->va_atime.tv_sec;
00123         utbuf.modtime = a->va_mtime.tv_sec;
00124 
00125         if(virt_utime(path, &utbuf) == -1)
00126             return -1;
00127     }
00128 
00129     return 0;
00130 }
00131 
00132 static int create_empty_dir(const char *tmpname)
00133 {
00134     int outfd;
00135 
00136     outfd = open(tmpname, O_WRONLY | O_TRUNC);
00137     if(outfd == -1) {
00138         fprintf(stderr, "open(%s, O_WRONLY | O_TRUNC) failed (%s)\n", tmpname, 
00139                 strerror(errno));
00140         return -EIO;
00141     }
00142 
00143     close(outfd);
00144     return 0;
00145 }
00146 
00147 static int copy_dir(const char *path, const char *tmpname)
00148 {
00149     struct venus_dirent vd;
00150     int res;
00151     DIR *dirp;
00152     int outfd;
00153     struct dirent *ent;
00154        
00155     dirp = virt_opendir(path);
00156     if(dirp == NULL)
00157         return -errno;
00158        
00159     outfd = open(tmpname, O_WRONLY | O_TRUNC);
00160     if(outfd == -1) {
00161         fprintf(stderr, "open(%s, O_WRONLY | O_TRUNC) failed (%s)\n", tmpname, 
00162                 strerror(errno));
00163         virt_closedir(dirp);
00164         return -EIO;
00165     }
00166 
00167     while(1) {
00168         errno = 0;
00169         ent = virt_readdir(dirp);
00170         if(ent == NULL) {
00171             if(errno != 0)
00172                 res = -errno;
00173             else
00174                 res = 0;
00175             break;
00176         }
00177 
00178         vd.d_fileno = 1; /* We don't know the inode number */
00179         vd.d_type   = CDT_UNKNOWN;
00180         strncpy(vd.d_name, ent->d_name, CODA_MAXNAMLEN);
00181         vd.d_name[CODA_MAXNAMLEN] = '\0';
00182         vd.d_namlen = strlen(vd.d_name);
00183         vd.d_reclen = DIRSIZ(&vd);
00184         
00185         res = write(outfd, &vd, vd.d_reclen);
00186         if(res == -1) {
00187             fprintf(stderr, "write failed (%s)\n", strerror(errno));
00188             res = -EIO;
00189             break;
00190         }
00191     } while(ent != NULL);
00192        
00193     close(outfd);
00194     if(res == 0) {
00195         res = virt_closedir(dirp);
00196         if(res == -1)
00197             return -errno;
00198     }
00199     else
00200         virt_closedir(dirp);
00201 
00202     return res;
00203 }
00204 
00205 #define COPYBUF 16384
00206 
00207 static int copy_file(const char *name, const char *tmpname)
00208 {
00209     char buf[COPYBUF];
00210     int infd;
00211     int outfd;
00212     int res;
00213        
00214     infd = virt_open(name, O_RDONLY, 0);
00215     if(infd == -1)
00216         return -errno;
00217        
00218     outfd = open(tmpname, O_WRONLY | O_TRUNC);
00219     if(outfd == -1) {
00220         fprintf(stderr, "open(%s) failed (%s)\n", tmpname, strerror(errno));
00221         virt_close(infd);
00222         return -EIO;
00223     }
00224        
00225     do {
00226         res = virt_read(infd, buf, COPYBUF);
00227         if(res == -1) {
00228             res = -errno;
00229             break;
00230         }
00231         if (res > 0) {
00232             res = write(outfd, buf, res);
00233             if(res == -1) {
00234                 fprintf(stderr, "write failed (%s)\n", strerror(errno));
00235                 res = -EIO;
00236                 break;
00237             }
00238         }
00239     } while(res > 0);
00240 
00241     close(outfd);
00242     if(res == 0) {
00243         res = virt_close(infd);
00244         if(res == -1)
00245             return -errno;
00246     }
00247     else
00248         virt_close(infd);
00249 
00250     return res;
00251 }
00252 
00253 static int write_file(const char *tmpname, const char *name)
00254 {
00255     char buf[COPYBUF];
00256     int infd;
00257     int outfd;
00258     int res;
00259        
00260     outfd = virt_open(name, O_WRONLY | O_TRUNC, 0);
00261     if(outfd == -1)
00262         return -errno;
00263        
00264     infd = open(tmpname, O_RDONLY, 0);
00265     if(infd == -1) {
00266         fprintf(stderr, "open(%s) failed (%s)\n", tmpname, strerror(errno));
00267         virt_close(outfd);
00268         return -EIO;
00269     }
00270        
00271     do {
00272         res = read(infd, buf, COPYBUF);
00273         if(res == -1) {
00274             fprintf(stderr, "read failed (%s)\n", strerror(errno));
00275             res = -EIO;
00276             break;
00277         }
00278         if (res > 0) {
00279             res = virt_write(outfd, buf, res);
00280             if(res == -1) {
00281                 res = -errno;
00282                 break;
00283             }
00284         }
00285     } while(res > 0);
00286 
00287     close(infd);
00288     if(res == 0) {
00289         res = virt_close(outfd);
00290         if(res == -1)
00291             return -errno;
00292     }
00293     
00294     return res;
00295 }
00296 
00297 static int create_empty_file(const char *tmpname)
00298 {
00299     int fd;
00300 
00301     fprintf(stderr, "create_empty_file: %s\n", tmpname);
00302 
00303     fd = open(tmpname, O_WRONLY | O_TRUNC);
00304     if(fd == -1) {
00305         fprintf(stderr, "open(%s, O_WRONLY | O_TRUNC) failed (%s)\n", tmpname,
00306                 strerror(errno));
00307         
00308         return -EIO;
00309     }
00310 
00311     close(fd);
00312     return 0;
00313 }
00314 
00315 
00316 void *process_request(void *arg)
00317 {
00318     char *ibuf = (char *) arg;
00319     int ret;
00320     struct child_message *msg = (struct child_message *) ibuf;
00321     union inputArgs *req;
00322     char obuf[MAXMSGLEN + sizeof(int)];
00323     union outputArgs *rep = (union outputArgs *) (obuf + sizeof(int));
00324     int size, noff;
00325     char *path1;
00326     char *path2;
00327     int offset = sizeof(struct child_message);
00328     struct stat stbuf;
00329     int outfd = child_outfd;
00330 
00331     req = (union inputArgs *)  (ibuf + offset);
00332 
00333     if(msg->path1size != 0)
00334        path1 = ibuf + offset + msg->reqsize;
00335     else
00336        path1 = NULL;
00337     
00338     if(msg->path2size != 0)
00339        path2 = ibuf + offset + msg->reqsize + msg->path1size;
00340     else
00341        path2 = NULL;
00342     
00343     
00344 #if 0
00345     fprintf(stderr, 
00346            "- %i/%i [%i] ---------------------------------------------------\n", 
00347            uid, gid, pid);
00348     fprintf(stderr, 
00349            "%i (%i (%i)) bytes: opcode: %li, unique: %li\n", 
00350            msg->reqsize, numread, insize, req->ih.opcode, 
00351            req->ih.unique);
00352     fprintf(stderr, "ibuf: %p, req: %p msg: %p\n", ibuf, req, msg);
00353 #endif
00354     
00355     size = sizeof(rep->oh);
00356     rep->oh.opcode = req->ih.opcode;
00357     rep->oh.unique = req->ih.unique;
00358     rep->oh.result = 0;
00359     
00360     switch (req->ih.opcode) {
00361     case CODA_GETATTR:
00362        size = sizeof(rep->coda_getattr);
00363        
00364        ret = virt_lstat(path1, &stbuf);
00365        if(ret == -1) 
00366            rep->oh.result = errno;
00367        else 
00368            st2attr(&stbuf, &rep->coda_getattr.attr, 
00369                   &req->coda_getattr.VFid);
00370        break;
00371                      
00372     case CODA_ACCESS:
00373        size = sizeof(rep->oh);
00374                      
00375        ret = virt_access(path1, req->coda_access.flags & 0x7);
00376        if(ret == -1) 
00377            rep->oh.result = errno;
00378        break;
00379                      
00380 #ifdef CODA_OPEN_BY_FD
00381     case CODA_OPEN_BY_FD:
00382 #endif
00383     case CODA_OPEN:
00384        size = sizeof(rep->oh);
00385        if(strcmp(path1, "/") == 0)
00386            ret = create_empty_dir(path2);
00387        else {
00388            if((req->coda_open.flags & C_O_TRUNC) != 0)
00389               ret = create_empty_file(path2);
00390            else {
00391               ret = virt_stat(path1, &stbuf);
00392               if(ret == -1)
00393                     ret = -errno;
00394               else {
00395                   if(S_ISDIR(stbuf.st_mode))
00396                      ret = copy_dir(path1, path2);
00397                   else 
00398                      ret = copy_file(path1, path2);
00399               }
00400            }
00401         }
00402         if(ret < 0)
00403             rep->oh.result = -ret;
00404        break;
00405 
00406     case CODA_CREATE:
00407        size = sizeof(rep->coda_create);
00408        if((req->coda_create.mode & S_IFMT) == S_IFREG) {
00409            ret = virt_open(path1, O_WRONLY | O_CREAT | O_TRUNC, 
00410                          req->coda_create.mode & 07777);
00411            if(ret != -1) 
00412               ret = virt_close(ret);
00413        }
00414        else {
00415            ret = virt_mknod(path1, req->coda_create.mode,
00416                           req->coda_create.attr.va_rdev);
00417        }
00418        if(ret == -1)
00419            rep->oh.result = errno;
00420        break;
00421 
00422 
00423     case CODA_CLOSE:
00424        size = sizeof(rep->oh);
00425        ret = write_file(path2, path1);
00426        if(ret < 0)
00427            rep->oh.result = -ret;
00428        break;
00429                      
00430     case CODA_LOOKUP:
00431        size = sizeof(rep->coda_lookup);
00432                      
00433        ret = virt_lstat(path1, &stbuf);
00434        if(ret == -1) 
00435            rep->oh.result = errno;
00436        else {
00437            /* We don't know these */
00438            rep->coda_lookup.VFid.Volume = 0;
00439            rep->coda_lookup.VFid.Vnode  = 0;
00440            rep->coda_lookup.VFid.Unique = 0; 
00441            rep->coda_lookup.vtype = st2type(&stbuf);
00442        }
00443        break;
00444                      
00445     case CODA_READLINK:
00446        size = sizeof(rep->coda_readlink);
00447        noff = size;
00448                      
00449        ret = virt_readlink(path1, (char *) rep + noff,
00450                          MAXMSGLEN - noff);
00451        if(ret == -1) 
00452            rep->oh.result = errno;
00453        else {
00454            rep->coda_readlink.data = (void *) noff;
00455            rep->coda_readlink.count = ret;
00456            size += ret;
00457        }
00458        break;
00459 
00460     case CODA_SETATTR:
00461        size = sizeof(rep->oh);
00462        ret = set_attr(path1, &req->coda_setattr.attr);
00463        if(ret == -1)
00464            rep->oh.result = errno;
00465        break;
00466 
00467     case CODA_REMOVE:
00468        size = sizeof(rep->oh);
00469        ret = virt_unlink(path1);
00470        if(ret == -1)
00471            rep->oh.result = errno;
00472        break;
00473 
00474     case CODA_RMDIR:
00475        size = sizeof(rep->oh);
00476        ret = virt_rmdir(path1);
00477        if(ret == -1)
00478            rep->oh.result = errno;
00479        break;
00480 
00481     case CODA_MKDIR:
00482        size = sizeof(rep->coda_mkdir);
00483        ret = virt_mkdir(path1, req->coda_mkdir.attr.va_mode & 07777);
00484        if(ret == -1)
00485            rep->oh.result = errno;
00486        break;
00487 
00488     case CODA_RENAME:
00489        size = sizeof(rep->oh);
00490        ret = virt_rename(path1, path2);
00491        if(ret == -1)
00492            rep->oh.result = errno;
00493        break;
00494 
00495     case CODA_SYMLINK:
00496        size = sizeof(rep->oh);
00497        ret = virt_symlink(path2, path1);
00498        if(ret == -1)
00499            rep->oh.result = errno;
00500        break;
00501 
00502     case CODA_LINK:
00503        size = sizeof(rep->oh);
00504        ret = virt_link(path2, path1);
00505        if(ret == -1)
00506            rep->oh.result = errno;
00507        break;
00508 
00509     default:
00510        rep->oh.result = EOPNOTSUPP;
00511     }
00512               
00513     *(int *) obuf = size;
00514     size += sizeof(int);
00515     ret = write(outfd, obuf, size);
00516     if(ret == -1 || ret != size) {
00517        fprintf(stderr, "Error writing to parent: %s\n", strerror(errno));
00518        exit(1);
00519     }
00520     
00521     free(ibuf);
00522 
00523     return NULL;
00524 }
00525 
00526 void child_process(int infd, int outfd)
00527 {
00528     int res;
00529     int insize;
00530     int numread;
00531     char ibuf[MAXPMSGLEN];
00532     char *bufcpy;
00533     pthread_attr_t attr;
00534     pthread_t thrid;
00535 
00536     pthread_attr_init(&attr);
00537     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00538 
00539     child_outfd = outfd;
00540 
00541 #if 0
00542     pid_t pid = getpid();
00543     uid_t uid = getuid();
00544     gid_t gid = getgid();
00545        
00546 
00547     fprintf(stderr, "My pid: %i\n", pid);
00548     sleep(15);
00549 #endif
00550     
00551     while(1) {
00552         numread = read(infd, &insize, sizeof(insize));
00553         if(numread == -1) {
00554             fprintf(stderr, "Error reading from device: %s\n",
00555                     strerror(errno));
00556             exit(1);
00557         }
00558         if(insize > MAXPMSGLEN || insize <= 0) {
00559             fprintf(stderr, "Error: illegal size");
00560             exit(1);
00561         }
00562               
00563         numread = read(infd, ibuf, insize);
00564         if(numread == -1) {
00565             fprintf(stderr, "Error reading from device: %s\n", 
00566                     strerror(errno));
00567             exit(1);
00568         }
00569        
00570        bufcpy = malloc(numread);
00571        if(bufcpy == NULL) {
00572            fprintf(stderr, "Out of memory\n");
00573            exit(1);
00574        }
00575        
00576        memcpy(bufcpy, ibuf, numread);
00577 
00578 
00579 #if MULTITHREADED
00580        res = pthread_create(&thrid, &attr, process_request, bufcpy);
00581        if(res != 0) {
00582            fprintf(stderr, "Error creating thread: %s\n", strerror(errno));
00583            exit(1);
00584        }
00585 #else
00586         process_request(bufcpy);
00587 #endif
00588        
00589     }
00590 }
00591