/* -------------------------------- * PQfnumber - Return the field index of a given * field name within a tuple. * -------------------------------- */ int PQfnumber(PortalBuffer *portal, int tuple_index, char *field_name) { GroupBuffer *gbp; if (!valid_pointer("PQfnumber: invalid portal pointer", portal) || !valid_pointer("PQfnumber: invalid field name pointer", field_name) || !in_range("PQfnumber: tuple index", tuple_index, 0, portal->no_tuples)) return(-1); gbp = PQgroup(portal, tuple_index); if (gbp) return(pbuf_findFnumber(gbp, field_name)); return(-1); }
/* * syscall_stat * * Implementation of the stat system call, which obtains information about a * particular file or directory. You should use this as a guideline for how to * implement the other system calls in assignment 3. */ int syscall_stat(const char *path, struct stat *buf) { /* * Ensure the supplied path name and buffer are valid pointers */ if (!valid_string(path)) return -EFAULT; if (!valid_pointer(buf, sizeof(struct stat))) return -EFAULT; /* * Get the directory_entry object for this path from the filesystem */ directory_entry *entry; int r; char abs[PATH_MAX]; relative_to_absolute(abs, current_process->cwd, path, PATH_MAX); if (0 != (r = get_directory_entry(filesystem, abs, &entry))) return r; /* * Set all fields of the stat buffer */ buf->st_mode = entry->mode; buf->st_uid = 0; buf->st_gid = 0; buf->st_size = entry->size; buf->st_mtime = entry->mtime; return 0; }
char *syscall_getcwd(char *buf, size_t size) { if (!valid_pointer(buf, size)) return NULL; snprintf(buf, size, "%s", current_process->cwd); return buf; }
/* ---------------- * PQclear - free storage claimed by named portal * ---------------- */ void PQclear(char *pname) { if (!valid_pointer("PQclear: invalid portal name pointer", pname)) return; pbuf_close(pname); }
int syscall_getdent(int fd, struct dirent *entry) { if (!valid_pointer(entry, sizeof(struct dirent))) return -EFAULT; if ((0 > fd) || (MAX_FDS <= fd) || (NULL == current_process->filedesc[fd])) return -EBADF; filehandle *fh = current_process->filedesc[fd]; if (FH_DIR == fh->type) { directory *dir = (directory *) (filesystem + fh->entry->location); if (fh->entryno >= dir->count) return 0; entry->d_ino = 0; snprintf(entry->d_name, NAME_MAX + 1, dir->entries[fh->entryno].name); fh->entryno++; return 1; } else { return -ENOTDIR; } return 0; }
/* -------------------------------- * PQfnumberGroup - Return the field number (index) given * the group index and the field name * -------------------------------- */ int PQfnumberGroup(PortalBuffer *portal, int group_index, char *field_name) { GroupBuffer *gbp; if (!valid_pointer("PQfnumberGroup: invalid portal pointer", portal) || !valid_pointer("PQfnumberGroup: invalid field name pointer", field_name) || !in_range("PQfnumberGroup: group index", group_index, 0, portal->no_groups)) return(-1); gbp = pbuf_findGroup(portal, group_index); if (gbp) return(pbuf_findFnumber(gbp, field_name)); return(-1); }
/* -------------------------------- * PQntuples - Return the number of tuples in a portal buffer * -------------------------------- */ int PQntuples(PortalBuffer *portal) { if (!valid_pointer("PQntuples: invalid portal pointer", portal)) return(-1); return(portal->no_tuples); }
/* -------------------------------- * PQngroups - Return the number of tuple groups in a portal buffer * -------------------------------- */ int PQngroups(PortalBuffer *portal) { if (!valid_pointer("PQngroups: invalid portal pointer", portal)) return(-1); return(portal->no_groups); }
/* -------------------------------- * PQrulep - Return 1 if an asynchronous portal * -------------------------------- */ int PQrulep(PortalBuffer *portal) { if (!valid_pointer("PQrulep: invalid portal pointer", portal)) return(-1); return(portal->rule_p); }
/* -------------------------------- * PQparray - Return the portal buffer given a portal name * -------------------------------- */ PortalBuffer * PQparray(char *pname) { int i; if (!valid_pointer("PQparray: invalid name buffer", pname)) return NULL; if ((i = pbuf_getIndex(pname)) < 0) return((PortalBuffer *) NULL); return(portals[i]->portal); }
/* * syscall_pipe * * Implements the pipe system call. This creates a pipe, as well as two file * handles. The first file handle can be used for reading from the pipe, and the * second for writing to it. Both handles are then associated with file descriptors * in the current process's file descriptor table. * * The most common use of this function is when a process is about to fork. A pipe * is created to allow the parent and child process to communicate. When the fork * occurs, the child inherits references to the pipe, and both sides release either * the reading or writing file descriptor, depending on the direction in which the * data is to flow. The pipe can then be used to transfer data from the parent to * the child, or vice-versa. */ int syscall_pipe(int filedes[2]) { /* * Ensure the supplied array is within the process's address space */ if (!valid_pointer(filedes, 2 * sizeof(int))) return -EFAULT; /* * Find two unused file descriptors */ int readfd = -1; int writefd = -1; int i; for (i = 0; (i < MAX_FDS) && (-1 == writefd); i++) { if (NULL == current_process->filedesc[i]) { if (-1 == readfd) readfd = i; else if (-1 == writefd) writefd = i; } } /* * If we were unable to allocate the file descriptors, the call cannot * complete successfully. Return an error to the process indicating that there * aren't enough file descriptors available. */ if ((-1 == readfd) || (-1 == writefd)) return -EMFILE; /* * Create a new pipe */ pipe_buffer *b = new_pipe(); /* * Create the file handles and place references to them in the process's * file descriptor table */ current_process->filedesc[readfd] = new_pipe_reader(b); current_process->filedesc[writefd] = new_pipe_writer(b); /* * Store the file descriptors in the output array, so the process knows which * ones to use for reading and writing to the pipe */ filedes[0] = readfd; filedes[1] = writefd; return 0; }
static TupleBlock * PQGetTupleBlock(PortalBuffer *portal, int tuple_index, int *tuple_offset) { GroupBuffer *gbp; TupleBlock *tbp; int tuple_count = 0; if (!valid_pointer("PQGetTupleBlock: invalid portal pointer", portal) || !valid_pointer("PQGetTupleBlock: invalid offset pointer", tuple_offset) || !in_range("PQGetTupleBlock: tuple index", tuple_index, 0, portal->no_tuples)) return((TupleBlock *) NULL); for (gbp = portal->groups; gbp && tuple_index >= (tuple_count += gbp->no_tuples); gbp = gbp->next) ; if (!gbp || !in_range("PQGetTupleBlock: tuple not found: tuple index", tuple_index, 0, tuple_count)) return((TupleBlock *) NULL); tuple_count -= gbp->no_tuples; for (tbp = gbp->tuples; tbp && tuple_index >= (tuple_count += TupleBlockSize); tbp = tbp->next) ; if (!tbp || !in_range("PQGetTupleBlock: tuple not found: tuple index", tuple_index, 0, tuple_count)) return((TupleBlock *) NULL); tuple_count -= TupleBlockSize; *tuple_offset = tuple_index - tuple_count; return(tbp); }
/* -------------------------------- * PQnfields - Return the number of fields in a tuple * -------------------------------- */ int PQnfields(PortalBuffer *portal, int tuple_index) { GroupBuffer *gbp; if (!valid_pointer("PQnfields: invalid portal pointer", portal) || !in_range("PQnfields: tuple index", tuple_index, 0, portal->no_tuples)) return(-1); gbp = PQgroup(portal, tuple_index); if (gbp) return(gbp->no_fields); return(-1); }
/* -------------------------------- * PQnfieldsGroup - Return the number of fields in a tuple group * -------------------------------- */ int PQnfieldsGroup(PortalBuffer *portal, int group_index) { GroupBuffer *gbp; if (!valid_pointer("PQnfieldsGroup: invalid portal pointer", portal) || !in_range("PQnfieldsGroup: group index", group_index, 0, portal->no_groups)) return(-1); gbp = pbuf_findGroup(portal, group_index); if (gbp) return(gbp->no_fields); return(-1); }
/* -------------------------------- * PQfsize - Return the size of a field * -------------------------------- */ int PQfsize(PortalBuffer *portal, int tuple_index, int field_number) { GroupBuffer *gbp; if (!valid_pointer("PQfsize: invalid portal pointer", portal) || !in_range("PQfsize: tuple index", tuple_index, 0, portal->no_tuples)) return(-1); if ((gbp = PQgroup(portal, tuple_index)) && in_range("PQfsize: field number", field_number, 0, gbp->no_fields)) return(gbp->types[field_number].adtsize); return(-1); }
/* -------------------------------- * PQfsizeGroup - Return the size of a field given * the group index and field index * -------------------------------- */ int PQfsizeGroup(PortalBuffer *portal, int group_index, int field_number) { GroupBuffer *gbp; if (!valid_pointer("PQfsizeGroup: invalid portal pointer", portal) || !in_range("PQfsizeGroup: tuple index", group_index, 0, portal->no_groups)) return(-1); if ((gbp = pbuf_findGroup(portal, group_index)) && in_range("PQfsizeGroup: field number", field_number, 0, gbp->no_fields)) return(gbp->types[field_number].adtsize); return(-1); }
/* -------------------------------- * PQfnameGroup - Return the field (attribute) name given * the group index and field index. * -------------------------------- */ char * PQfnameGroup(PortalBuffer *portal, int group_index, int field_number) { GroupBuffer *gbp; if (!valid_pointer("PQfnameGroup: invalid portal pointer", portal) || !in_range("PQfnameGroup: group index", group_index, 0, portal->no_groups)) return((char *) NULL); if ((gbp = pbuf_findGroup(portal, group_index)) && in_range("PQfnameGroup: field number", field_number, 0, gbp->no_fields)) return(pbuf_findFname(gbp, field_number)); return((char *) NULL); }
/* -------------------------------- * PQfname - Return the name of a field * -------------------------------- */ char * PQfname(PortalBuffer *portal, int tuple_index, int field_number) { GroupBuffer *gbp; if (!valid_pointer("PQfname: invalid portal pointer", portal) || !in_range("PQfname: tuple index", tuple_index, 0, portal->no_tuples)) return((char *) NULL); if ((gbp = PQgroup(portal, tuple_index)) && in_range("PQfname: field number", field_number, 0, gbp->no_fields)) return(pbuf_findFname(gbp, field_number)); return((char *) NULL); }
/* -------------------------------- * PQpnames - Return all the portal names * If rule_p, only return asynchronous portals. * * the caller must have allocated sufficient memory for char** pnames * (an array of PQnportals strings of length PortalNameLength). * * notice that this assumes that the user is calling PQnportals and * PQpnames with the same rule_p argument, and with no intervening * portal closures. if not, you can get in heap big trouble.. * -------------------------------- */ void PQpnames(char **pnames, int rule_p) { int i, cur_pname = 0; if (!valid_pointer("PQpnames: invalid name buffer", pnames)) return; for (i = 0; i < portals_array_size; ++i) { if (portals[i] && portals[i]->portal) { if (!rule_p || portals[i]->portal->rule_p) { (void) strncpy(pnames[cur_pname], portals[i]->name, PortalNameLength); ++cur_pname; } } } }
/* -------------------------------- * PQsametype - Return 1 if the two tuples have the same type * (in the same group) * -------------------------------- */ int PQsametype(PortalBuffer *portal, int tuple_index1, int tuple_index2) { GroupBuffer *gbp1, *gbp2; if (!valid_pointer("PQsametype: invalid portal pointer", portal) || !in_range("PQsametype: tuple index 1", tuple_index1, 0, portal->no_tuples) || !in_range("PQsametype: tuple index 2", tuple_index2, 0, portal->no_tuples)) return(-1); gbp1 = PQgroup(portal, tuple_index1); gbp2 = PQgroup(portal, tuple_index2); if (gbp1 && gbp2) return(gbp1 == gbp2); return(-1); }
/* -------------------------------- * PQgetgroup - Return the index of the group that a * particular tuple is in * -------------------------------- */ int PQgetgroup(PortalBuffer *portal, int tuple_index) { GroupBuffer *gbp; int tuple_count = 0, group_count = 0; if (!valid_pointer("PQgetgroup: invalid portal pointer", portal) || !in_range("PQgetgroup: tuple index", tuple_index, 0, portal->no_tuples)) return(-1); for (gbp = portal->groups; gbp && tuple_index >= (tuple_count += gbp->no_tuples); gbp = gbp->next) ++group_count; if (!gbp || !in_range("PQgetgroup: tuple not found: tuple index", tuple_index, 0, tuple_count)) return(-1); return(group_count); }
/* * syscall_execve * * Implements the execve system call. This effectively does a "brain transplant" * on a process by arranging for it to run a different program to what it was * previously. This is achieved by loading the new program from the file system, * placing a copy in the process's text segment, and changing the instruction * pointer of the process to point to the first instruction of the loaded * executable file. * * In addition to loading a new program, this call is also responsible for passing * command line arguments to the new program. This is done by using the memory * at the bottom of the stack (actually the highest address, since the stack grows * downwards), in which the array of strings corresponding to argv is placed. The * argv and argc values are placed at the top of the stack, so that the main * function will be able to access them as arguments. */ int syscall_execve(const char *filename, char *const argv[], char *const envp[], regs * r) { process *proc = current_process; /* * Verify that the filename and all of the pointers within argc arg valid * (i.e. completely reside in the process's address space) */ if (!valid_string(filename)) return -EFAULT; unsigned int argno = 0; if (NULL != argv) { while (1) { if (!valid_pointer(argv, (argno + 1) * sizeof(char *))) return -EFAULT; if (NULL == argv[argno]) break; if (!valid_string(argv[argno])) return -EFAULT; argno++; } } /* * Check that the specified executable file actually exists, and find out its * location within the file system */ directory_entry *entry; int res; if (0 > (res = get_directory_entry(filesystem, filename, &entry))) return res; if (TYPE_DIR == entry->type) return -EISDIR; /* * Calculate number of arguments and amount of space needed to store them */ unsigned int argc = 0; unsigned int argslen = 0; for (argc = 0; argv && argv[argc]; argc++) argslen += strlen(argv[argc]) + 1; /* * Allocate a temporary buffer in which to store the argument data. This will * later be copied to the process's stack. The reason we can't do this * in-place is that doing so would risk overwriting some of the data we are * copying from. */ unsigned int argdata_size = argslen + argc * sizeof(char *) + 2 * sizeof(int); char *argdata = kmalloc(argdata_size); char **newargv = (char **)(argdata + 8); /* * Work backwards through the allocated buffer, copying in the strings one- * by-one */ unsigned int pos = argdata_size; for (argno = 0; argno < argc; argno++) { unsigned int nbytes = strlen(argv[argno]) + 1; pos -= nbytes; memmove(&argdata[pos], argv[argno], nbytes); newargv[argno] = (char *)(PROCESS_STACK_BASE - argdata_size + pos); } /* * Set argc and argv as the top two words on the stack. These are the values * that main will see passed in as its parameters. */ *(unsigned int *)(argdata + 0) = argc; *(unsigned int *)(argdata + 4) = PROCESS_STACK_BASE - argdata_size + 8; /* * Unmap the existing text segment */ disable_paging(); unsigned int addr; for (addr = proc->text_start; addr < proc->text_end; addr += PAGE_SIZE) unmap_and_free_page(proc->pdir, addr); for (addr = proc->data_start; addr < proc->data_end; addr += PAGE_SIZE) unmap_and_free_page(proc->pdir, addr); /* * Resize text and data segments to 0 bytes each */ proc->text_start = PROCESS_TEXT_BASE; proc->text_end = PROCESS_TEXT_BASE; proc->data_start = PROCESS_DATA_BASE; proc->data_end = PROCESS_DATA_BASE; /* * Load in the text segment from the executable file */ char *data = filesystem + entry->location; for (pos = 0; pos < entry->size; pos += PAGE_SIZE) { proc->text_end = proc->text_start + pos; void *page = alloc_page(); if (PAGE_SIZE <= entry->size - pos) memmove(page, &data[pos], PAGE_SIZE); else memmove(page, &data[pos], entry->size - pos); map_page(proc->pdir, proc->text_end, (unsigned int)page, PAGE_USER, PAGE_READ_WRITE); } proc->text_end = proc->text_start + pos; enable_paging(current_process->pdir); /* * Copy the command line argument data we set up above to the process's * stack */ memmove((void *)(PROCESS_STACK_BASE - argdata_size), argdata, argdata_size); kfree(argdata); /* * Set up the process's saved register state so that when it resumes * execution, it will start from the beginning of the loaded code. */ init_regs(r, PROCESS_STACK_BASE - argdata_size, (void *)current_process->text_start); return 0; }