/** * Read a request from the input stream. */ static req_t* read_request(int fd) { req_t *req = req_create(); ssize_t nbytes, nused; while (!req_is_complete(req)) { nbytes = read(fd, input_buffer, BUFFER_SIZE); if (nbytes < 0) { if (errno == EINTR) { // interrupted, try again continue; } else { goto abort; } } else if (nbytes == 0) { // no data - end of file, but request is incomplete return NULL; } // we have data! nused = req_parse(req, input_buffer, nbytes); } /* if we are here, then two things are true: * - the request is complete * - nused has the number of bytes of input_buffer that have been used */ input_buf_pos = nused; return req; abort: req_destroy(req); return NULL; }
/*===========================================================================* * new_node * *===========================================================================*/ static struct vnode *new_node(mode_t bits) { struct vnode *dirp, *vp; int r; struct node_details res; struct vnode *rest; /* See if the path can be opened down to the last directory. */ if ((dirp = last_dir()) == NIL_VNODE) return(NIL_VNODE); /* The final directory is accessible. Get final component of the path. */ vp = advance(dirp, 0); if (vp == NIL_VNODE && err_code == -ENOENT) { /* Last path component does not exist. Make a new directory entry. */ if ((vp = get_free_vnode()) == NIL_VNODE) { /* Can't create new vnode: out of vnodes. */ put_vnode(dirp); return(NIL_VNODE); } if ((r = forbidden(dirp, W_BIT|X_BIT)) != 0 || (r = req_create(dirp->v_fs_e, dirp->v_inode_nr,bits, fp->fp_effuid, fp->fp_effgid, user_fullpath, &res)) != 0 ) { /* Can't create new directory entry: either no permission or something else is wrong. */ put_vnode(dirp); err_code = r; return(NIL_VNODE); } /* Store results and mark vnode in use */ vp->v_fs_e = res.fs_e; vp->v_inode_nr = res.inode_nr; vp->v_mode = res.fmode; vp->v_size = res.fsize; vp->v_uid = res.uid; vp->v_gid = res.gid; vp->v_sdev = res.dev; vp->v_vmnt = dirp->v_vmnt; vp->v_dev = vp->v_vmnt->m_dev; vp->v_fs_count = 1; vp->v_ref_count = 1; } else { /* Either last component exists, or there is some other problem. */ if (vp != NIL_VNODE) r = -EEXIST; else r = err_code; } err_code = r; put_vnode(dirp); return(vp); }
void server_task_queue(int accept_fd) { //5! Work here! int i; pthread_t *threads = malloc(sizeof(pthread_t) * MAX_CONCURRENCY); for (i = 0 ; i < MAX_CONCURRENCY ; i++) pthread_create(&threads[i], NULL, (void *)&pthread_handle, NULL); printf("ALL THREADS CREATED\n"); for(;;) { int fd = server_accept(accept_fd); put_request(req_create((void*)fd)); printf("ADDING STUFF!\n"); } return; }
/*===========================================================================* * new_node * *===========================================================================*/ static struct vnode *new_node(struct lookup *resolve, int oflags, mode_t bits) { /* Try to create a new inode and return a pointer to it. If the inode already exists, return a pointer to it as well, but set err_code accordingly. NULL is returned if the path cannot be resolved up to the last directory, or when the inode cannot be created due to permissions or otherwise. */ struct vnode *dirp, *vp; struct vmnt *dir_vmp, *vp_vmp; int r; struct node_details res; struct lookup findnode; char *path; path = resolve->l_path; /* For easy access */ lookup_init(&findnode, path, resolve->l_flags, &dir_vmp, &dirp); findnode.l_vmnt_lock = VMNT_WRITE; findnode.l_vnode_lock = VNODE_WRITE; /* dir node */ /* When O_CREAT and O_EXCL flags are set, the path may not be named by a * symbolic link. */ if (oflags & O_EXCL) findnode.l_flags |= PATH_RET_SYMLINK; /* See if the path can be opened down to the last directory. */ if ((dirp = last_dir(&findnode, fp)) == NULL) return(NULL); /* The final directory is accessible. Get final component of the path. */ lookup_init(&findnode, findnode.l_path, findnode.l_flags, &vp_vmp, &vp); findnode.l_vmnt_lock = VMNT_WRITE; findnode.l_vnode_lock = (oflags & O_TRUNC) ? VNODE_WRITE : VNODE_OPCL; vp = advance(dirp, &findnode, fp); assert(vp_vmp == NULL); /* Lookup to last dir should have yielded lock * on vmp or final component does not exist. * Either way, vp_vmp ought to be not set. */ /* The combination of a symlink with absolute path followed by a danglink * symlink results in a new path that needs to be re-resolved entirely. */ if (path[0] == '/') { unlock_vnode(dirp); unlock_vmnt(dir_vmp); put_vnode(dirp); if (vp != NULL) { unlock_vnode(vp); put_vnode(vp); } return new_node(resolve, oflags, bits); } if (vp == NULL && err_code == ENOENT) { /* Last path component does not exist. Make a new directory entry. */ if ((vp = get_free_vnode()) == NULL) { /* Can't create new entry: out of vnodes. */ unlock_vnode(dirp); unlock_vmnt(dir_vmp); put_vnode(dirp); return(NULL); } lock_vnode(vp, VNODE_OPCL); if ((r = forbidden(fp, dirp, W_BIT|X_BIT)) != OK || (r = req_create(dirp->v_fs_e, dirp->v_inode_nr,bits, fp->fp_effuid, fp->fp_effgid, path, &res)) != OK ) { /* Can't create inode either due to permissions or some other * problem. In case r is EEXIST, we might be dealing with a * dangling symlink.*/ if (r == EEXIST) { struct vnode *slp, *old_wd; /* Resolve path up to symlink */ findnode.l_flags = PATH_RET_SYMLINK; findnode.l_vnode_lock = VNODE_READ; findnode.l_vnode = &slp; slp = advance(dirp, &findnode, fp); if (slp != NULL) { if (S_ISLNK(slp->v_mode)) { /* Get contents of link */ r = req_rdlink(slp->v_fs_e, slp->v_inode_nr, VFS_PROC_NR, (vir_bytes) path, PATH_MAX - 1, 0); if (r < 0) { /* Failed to read link */ unlock_vnode(slp); unlock_vnode(dirp); unlock_vmnt(dir_vmp); put_vnode(slp); put_vnode(dirp); err_code = r; return(NULL); } path[r] = '\0'; /* Terminate path */ } unlock_vnode(slp); put_vnode(slp); } /* Try to create the inode the dangling symlink was * pointing to. We have to use dirp as starting point * as there might be multiple successive symlinks * crossing multiple mountpoints. * Unlock vnodes and vmnts as we're going to recurse. */ unlock_vnode(dirp); unlock_vnode(vp); unlock_vmnt(dir_vmp); old_wd = fp->fp_wd; /* Save orig. working dirp */ fp->fp_wd = dirp; vp = new_node(resolve, oflags, bits); fp->fp_wd = old_wd; /* Restore */ if (vp != NULL) { put_vnode(dirp); *(resolve->l_vnode) = vp; return(vp); } r = err_code; } if (r == EEXIST) err_code = EIO; /* Impossible, we have verified that * the last component doesn't exist and * is not a dangling symlink. */ else err_code = r; unlock_vnode(dirp); unlock_vnode(vp); unlock_vmnt(dir_vmp); put_vnode(dirp); return(NULL); } /* Store results and mark vnode in use */ vp->v_fs_e = res.fs_e; vp->v_inode_nr = res.inode_nr; vp->v_mode = res.fmode; vp->v_size = res.fsize; vp->v_uid = res.uid; vp->v_gid = res.gid; vp->v_sdev = res.dev; vp->v_vmnt = dirp->v_vmnt; vp->v_dev = vp->v_vmnt->m_dev; vp->v_fs_count = 1; vp->v_ref_count = 1; } else { /* Either last component exists, or there is some other problem. */ if (vp != NULL) { r = EEXIST; /* File exists or a symlink names a file while * O_EXCL is set. */ } else r = err_code; /* Other problem. */ } err_code = r; /* When dirp equals vp, we shouldn't release the lock as a vp is locked only * once. Releasing the lock would cause the resulting vp not be locked and * cause mayhem later on. */ if (dirp != vp) { unlock_vnode(dirp); } unlock_vmnt(dir_vmp); put_vnode(dirp); *(resolve->l_vnode) = vp; return(vp); }
/*===========================================================================* * new_node * *===========================================================================*/ PRIVATE struct vnode *new_node(int oflags, mode_t bits) { /* Try to create a new inode and return a pointer to it. If the inode already exists, return a pointer to it as well, but set err_code accordingly. NULL is returned if the path cannot be resolved up to the last directory, or when the inode cannot be created due to permissions or otherwise. */ struct vnode *dirp, *vp; int r, flags; struct node_details res; /* When O_CREAT and O_EXCL flags are set, the path may not be named by a * symbolic link. */ flags = PATH_NOFLAGS; if (oflags & O_EXCL) flags |= PATH_RET_SYMLINK; /* See if the path can be opened down to the last directory. */ if ((dirp = last_dir(fp)) == NULL) return(NULL); /* The final directory is accessible. Get final component of the path. */ vp = advance(dirp, flags, fp); /* The combination of a symlink with absolute path followed by a danglink * symlink results in a new path that needs to be re-resolved entirely. */ if (user_fullpath[0] == '/') return new_node(oflags, bits); if (vp == NULL && err_code == ENOENT) { /* Last path component does not exist. Make a new directory entry. */ if ((vp = get_free_vnode()) == NULL) { /* Can't create new vnode: out of vnodes. */ put_vnode(dirp); return(NULL); } if ((r = forbidden(dirp, W_BIT|X_BIT)) != OK || (r = req_create(dirp->v_fs_e, dirp->v_inode_nr,bits, fp->fp_effuid, fp->fp_effgid, user_fullpath, &res)) != OK ) { /* Can't create inode either due to permissions or some other * problem. In case r is EEXIST, we might be dealing with a * dangling symlink.*/ if (r == EEXIST) { struct vnode *slp, *old_wd; /* Resolve path up to symlink */ slp = advance(dirp, PATH_RET_SYMLINK, fp); if (slp != NULL) { if (S_ISLNK(slp->v_mode)) { /* Get contents of link */ int max_linklen; max_linklen = sizeof(user_fullpath)-1; r = req_rdlink(slp->v_fs_e, slp->v_inode_nr, VFS_PROC_NR, user_fullpath, max_linklen, 0); if (r < 0) { /* Failed to read link */ put_vnode(slp); put_vnode(dirp); err_code = r; return(NULL); } user_fullpath[r] = '\0';/* Term. path*/ } put_vnode(slp); } /* Try to create the inode the dangling symlink was * pointing to. We have to use dirp as starting point * as there might be multiple successive symlinks * crossing multiple mountpoints. */ old_wd = fp->fp_wd; /* Save orig. working dirp */ fp->fp_wd = dirp; vp = new_node(oflags, bits); fp->fp_wd = old_wd; /* Restore */ if (vp != NULL) { put_vnode(dirp); return(vp); } r = err_code; } if (r == EEXIST) err_code = EIO; /* Impossible, we have verified that * the last component doesn't exist and * is not a dangling symlink. */ else err_code = r; put_vnode(dirp); return(NULL); } /* Store results and mark vnode in use */ vp->v_fs_e = res.fs_e; vp->v_inode_nr = res.inode_nr; vp->v_mode = res.fmode; vp->v_size = res.fsize; vp->v_uid = res.uid; vp->v_gid = res.gid; vp->v_sdev = res.dev; vp->v_vmnt = dirp->v_vmnt; vp->v_dev = vp->v_vmnt->m_dev; vp->v_fs_count = 1; vp->v_ref_count = 1; } else { /* Either last component exists, or there is some other problem. */ if (vp != NULL) r = EEXIST; /* File exists or a symlink names a file while * O_EXCL is set. */ else r = err_code; /* Other problem. */ } err_code = r; put_vnode(dirp); return(vp); }