/** * This is used by the client application program to unmount a previously mounted file system * @param localFolderName local name of the folder given to the mounted files * @return 0 on success and -1 otherwise */ int fsUnmount(const char *localFolderName) { // the counterpart of fsMount() // to unmount a remote filesystem that is referred to locally by localFolderName. // Returns 0 on success, −1 on failure with errno set appropriately remote_folder_server *serverToUnmount = findServerByFolderName(localFolderName); // printf("serverName: %s, serverPort: %i, clientID: %i\n", serverToUnmount->srvIpOrDomName, serverToUnmount->srvPort, *serverToUnmount->clientId); return_type ans = make_remote_call( serverToUnmount->srvIpOrDomName, serverToUnmount->srvPort, "fsUnmount", 2, strlen(localFolderName), (void *)(localFolderName), sizeof(int), (void *)(serverToUnmount->clientId)); int result = *(int*)(ans.return_val); if (result != 0) { errno = result; return -1; } if (removeServerByFolderName(localFolderName) == -1) { return -1; } return result; }
/** * Opens the folder folder_name that is presumably the local name of * a folder that has been mounted previously. Returns a NULL if an error occurs. * * @param folder_name name of the directory * @return struct containing details about the directory, NULL if failure */ FSDIR* fsOpenDir(const char *folder_name) { struct mount_info *info = mount_info_list_find(folder_name, false); if (info == NULL) { errno = ENOENT; return NULL; } char *relpath = relative_path_from_mount_path(folder_name, info->local_folder_name); if (relpath == NULL) { errno = ENOENT; return NULL; } return_type ans = make_remote_call(info->ip_or_domain, info->port_no, "fsOpenDir", 1, strlen(relpath) + 1, (void *) relpath); fs_response *response = (fs_response *)ans.return_val; FSDIR *fsdirp = NULL; if (!handle_possible_error(response)) { fsdirp = (FSDIR *)malloc(sizeof(FSDIR)); fsdirp->dirp = *(DIR **)response->retval; fsdirp->mount_info = info; } free(relpath); free(response); return fsdirp; }
/** * Removes (i.e., deletes) this file or folder from the server. * * @param name of file or folder to be removed * @return 0 on success, −1 on failure */ int fsRemove(const char *name) { struct mount_info *info = mount_info_list_find(name, false); if (info == NULL) { errno = ENOENT; return -1; } char * relpath = relative_path_from_mount_path(name, info->local_folder_name); if (strcmp(relpath, "/") == 0) { free(relpath); errno = EBUSY; return -1; } return_type ans = make_remote_call(info->ip_or_domain, info->port_no, "fsRemove", 1, strlen(relpath) + 1, (void *)relpath); fs_response *response = (fs_response *)ans.return_val; int retval = *(int *)response->retval; handle_possible_error(response); free(relpath); free(response); return retval; }
/** * Reads up to "count" bytes in to the supplied buffer buf from the file referred * to by the file descriptor fd, which was presumably the return from a call to * fsOpen() in read-mode. * * @param fd file descriptor of file to be read * @param buf buffer for data to be written to * @param count number of bytes to be read * @return 0 on success, −1 on failure */ int fsRead(int fd, void *buf, const unsigned int count) { struct fd_entry *current = fd_entry_list_find(fd); if (current == NULL) { errno = EBADF; return -1; } return_type ans = make_remote_call(current->mount_info->ip_or_domain, current->mount_info->port_no, "fsRead", 2, sizeof(int), (void *) &fd, sizeof(int), (void *) &count); int inerror = *(int *)ans.return_val; if (inerror) { int _errno = *(int *)(ans.return_val + sizeof(int)); errno = _errno; free(ans.return_val); return -1; } int bytesread = *(int *)(ans.return_val + (2 * sizeof(int))); memcpy(buf, ans.return_val + (3 * sizeof(int)), bytesread); free(ans.return_val); return bytesread; }
/** * This is used by the client application program to open a remote file * @param fname Name of the remote file to open * @param mode Mode in which to open the remote file, * 1 for write permission and 0 for read permissions * @return File descriptor number, positive integer, -1 on error */ int fsOpen(const char *fname, int mode) { #ifdef _DEBUG_CLI_ printf("in fsOpen\n"); #endif remote_folder_server *server; if ((server = findServerByFolderName(fname)) == NULL) { errno = ENOENT; return -1; } while(1) { return_type ans = make_remote_call( server->srvIpOrDomName, server->srvPort, "fsOpen", 3, sizeof(int), (void *)(server->clientId), strlen(fname), (void *)(fname), sizeof(int), (void *)(&mode)); if (ans.return_size == 0) { //error set errno #ifdef _DEBUG_CLI_ printf("return_size zero: %d\n", ans.return_size); #endif errno = EBADMSG; return -1; } else { int *status = (int*)malloc(sizeof(int)); memcpy( status, ans.return_val, sizeof(int)); char * index = (char*)(ans.return_val); index += sizeof(int); // printf("status: %d\n", *status); int *val = (int*)malloc(sizeof(int)); memcpy( val, index, sizeof(int)); if (*status == 0){ #ifdef _DEBUG_CLI_ printf("positive val: %d\n", *val); #endif int clientFd = createClientFd(fname, *val); return clientFd; } else if(*status == -2) { // printf("fsOpen client will start to sleep\n"); usleep(100000); } else { errno = *val; #ifdef _DEBUG_CLI_ printf("negative val: %d, errno: %s\n", *val, strerror(errno)); #endif return -1; } } } }
/** * This is used by the client application program to mount a remote server. * @param srvIpOrDomName the name or the IP address of the server to mount * @param srvPort port number in the server to mount * @param localFolderName local name of the folder given to the mounted files * @return 0 on success and -1 otherwise */ int fsMount(const char *srvIpOrDomName, const unsigned int srvPort, const char *localFolderName) { // do similar stuff as ass1 client app // save ip address and port number for subsequent remote calls #ifdef _DEBUG_CLI_ printf("Calling fsMount to server\n"); #endif remote_folder_server *newServer; if ((newServer = findServerByFolderName(localFolderName)) != NULL) { // printf("Server %s already exists as %s\n", localFolderName, newServer->localFolderName); errno = EEXIST; return -1; } return_type ans = make_remote_call( srvIpOrDomName, (int)srvPort, "fsMount", 1, strlen(localFolderName), (void *)(localFolderName)); int containsError; int returnedValue; memcpy(&containsError, ans.return_val, sizeof(int)); memcpy(&returnedValue, ans.return_val+sizeof(int), sizeof(int)); if (containsError == 0) { //save id #ifdef _DEBUG_CLI_ printf("Successfully returned, given clientID: %d\n", returnedValue); #endif newServer = (remote_folder_server*)malloc(sizeof(remote_folder_server)); newServer->localFolderName = (char*)malloc(strlen(localFolderName)); newServer->srvIpOrDomName = (char*)malloc(strlen(srvIpOrDomName)); newServer->clientId = (int*) malloc(sizeof(int)); *newServer->clientId = returnedValue; newServer->srvPort = srvPort; newServer->next = NULL; strcpy(newServer->localFolderName, localFolderName); strcpy(newServer->srvIpOrDomName, srvIpOrDomName); addNewServer(newServer); return 0; } errno = returnedValue; return -1; }
/** * This is used by the client application program to close a remote file * @param fd File descriptor of the file to close * @return 0 on success, -1 otherwise */ int fsClose(int fd) { #ifdef _DEBUG_CLI_ printf("in fsClose\n"); #endif client_fd *clientFdNode; if ((clientFdNode = getNodeFromClientFd(fd)) == NULL) { errno = EBADF; return -1; } remote_folder_server *server; if ((server = findServerByFolderName(clientFdNode->localFolderName)) == NULL) { errno = ENOENT; return -1; } return_type ans = make_remote_call( server->srvIpOrDomName, server->srvPort, "fsClose", 2, sizeof(int), (void *)(server->clientId), sizeof(int), (void *)(&clientFdNode->serverFd)); if (ans.return_size == 0) { //error set errno #ifdef _DEBUG_CLI_ printf("return_size zero: %d\n", ans.return_size); #endif errno = EBADMSG; return -1; } else if (*(int*)(ans.return_val) != 0) { #ifdef _DEBUG_CLI_ printf("return_val not zero: %s\n", strerror(*(int*)(ans.return_val))); #endif errno = *(int*)(ans.return_val); //set errno before returning using return_val as errno return -1; } else { #ifdef _DEBUG_CLI_ printf("return_val should be zero: %d\n", *(int*)(ans.return_val)); #endif if (removeClientFd(clientFdNode->clientFd) == 0) { return 0; } else { #ifdef _DEBUG_CLI_ printf("did not removeClientFd, return_size zero: %d\n", ans.return_size); #endif errno = EBADMSG; return -1; } } }
int main() { int a = -10, b = 25, c = 50; return_type ans = make_remote_call("129.97.56.15", 10000, "addtwo", 3, sizeof(int), (void *)(&a), sizeof(int), (void *)(&b), sizeof(int), (void *)(&c)); int i = *(int *)(ans.return_val); printf("client, got result: %d\n", i); return 0; }
/** * Closes a directory. * * @param fsdirp details of the directory to be closed * @return 0 on success, −1 on failure */ int fsCloseDir(FSDIR *fsdirp) { const return_type ans = make_remote_call(fsdirp->mount_info->ip_or_domain, fsdirp->mount_info->port_no, "fsCloseDir", 1, sizeof(DIR *), (void *) &fsdirp->dirp); fs_response *response = (fs_response *)ans.return_val; int retval = *(int *)response->retval; if (!handle_possible_error(response)) { free(fsdirp); } free(response); return retval; }
/** * Reads a directory. Returns NULL of an error occured. * * @param fsdirp details of the directory to be read * @return fsDirent of the directory to be read. */ struct fsDirent *fsReadDir(FSDIR *fsdirp) { return_type ans = make_remote_call(fsdirp->mount_info->ip_or_domain, fsdirp->mount_info->port_no, "fsReadDir", 1, sizeof(DIR *), (void *) &fsdirp->dirp); fs_response *response = (fs_response *)ans.return_val; struct fsDirent *retval = NULL; if (!handle_possible_error(response)) { dent = *(struct fsDirent *)response->retval; retval = &dent; } free(response); return retval; }
/** * This is used by the client application program to close * a directory in the remote file system * @param folder Pointer to the remote folder to close * @return 0 on success -1 otherwise */ int fsCloseDir(FSDIR *folder) { remote_folder_server *server = findServerByFolderName(folder->folderName); // printf("in fsCloseDir, clientId: %d\n", *server->clientId); return_type ans = make_remote_call( server->srvIpOrDomName, server->srvPort , "fsCloseDir", 1, sizeof(int), (void *)(server->clientId)); // printf("return_size: %d\n", ans.return_size); // printf("return_val: %d\n", *(int*)(ans.return_val)); if (ans.return_size == 0) { #ifdef _DEBUG_CLI_ printf("return_size zero: %d\n", ans.return_size); #endif //set errno before returning using a generic error errno = EBADMSG; return -1; } else if (*(int*)(ans.return_val) != 0) { #ifdef _DEBUG_CLI_ printf("return_val not zero: %s\n", strerror(*(int*)(ans.return_val))); #endif errno = *(int*)(ans.return_val); //set errno before returning using return_val as errno return -1; } else { #ifdef _DEBUG_CLI_ printf("return_val should be zero: %d\n", *(int*)(ans.return_val)); #endif free(folder); folder = NULL; return 0; } }
/** * This is used by the client application program to open * a directory in the remote file system * @param folderName Local name of the mounted folder * @return Pointer to the file system directory */ FSDIR* fsOpenDir(const char *folderName) { remote_folder_server *server; if ((server = findServerByFolderName(folderName)) == NULL) { errno = ENOENT; return NULL; } // printf("in fsOpenDir, clientId: %d, folderName: %s\n", *server->clientId, folderName); return_type ans = make_remote_call( server->srvIpOrDomName, server->srvPort, "fsOpenDir", 2, sizeof(int), (void *)(server->clientId), strlen(folderName), (void *)(folderName)); // printf("return_size: %d\n", ans.return_size); // printf("return_val: %d\n", *(int*)(ans.return_val)); if (ans.return_size == 0) { #ifdef _DEBUG_CLI_ // printf("return_size zero: %d\n", ans.return_size); #endif FSDIR *nice = NULL; //set errno before returning using a generic error errno = EBADMSG; return nice; } else if (*(int*)(ans.return_val) != 0) { #ifdef _DEBUG_CLI_ // printf("return_val not zero: %s\n", strerror(*(int*)(ans.return_val))); #endif //set errno before returning using return_val as errno FSDIR *nice = NULL; errno = *(int*)(ans.return_val); return nice; } else { FSDIR* result = malloc(sizeof(FSDIR)); result->folderName = (char*)malloc(strlen(folderName)); strcpy(result->folderName, folderName); result->id = *server->clientId; result->status = *(int*)(ans.return_val); return result; } }
/** * Writes up to "count" bytes from buf into the file referred to with the file * descriptor fd that was presumably the return from an earlier fsOpen() call * in write-mode. * * @param fd file descriptor of file to be written to * @param buf buffer of data to be written * @param count number of bytes to be written * @return 0 on success, −1 on failure */ int fsWrite(int fd, const void *buf, const unsigned int count) { struct fd_entry *current = fd_entry_list_find(fd); if (current == NULL) { errno = EBADF; return -1; } return_type ans = make_remote_call(current->mount_info->ip_or_domain, current->mount_info->port_no, "fsWrite", 2, sizeof(int), (void *) &fd, count, (void *) buf); fs_response *response = (fs_response *)ans.return_val; int retval = *(int *)response->retval; handle_possible_error(response); free(response); return retval; }
/** * Closes an open file. * * @param fd file descriptor of file to be closed * @return 0 on success, −1 on failure */ int fsClose(int fd) { struct fd_entry *current = fd_entry_list_find(fd); if (current == NULL) { errno = EBADF; return -1; } return_type ans = make_remote_call(current->mount_info->ip_or_domain, current->mount_info->port_no, "fsClose", 1, sizeof(int), (void *) &fd); fs_response *response = (fs_response *)ans.return_val; if (!handle_possible_error(response)) { fd_entry_list_delete(current); } int retval = *(int *)response->retval; free(response); return retval; }
/** * Opens a file whose path is fname. The mode is one of two values: 0 for read, * and 1 for write. Returns a file descriptor that can be used in future calls for * operations on this file. * * @param fname path of file to be opened * @param mode read mode. 0 for read, and 1 for write * @return a file descriptor of the file. -1 if failure */ int fsOpen(const char *fname, int mode) { struct mount_info *info = mount_info_list_find(fname, false); if (info == NULL) { errno = ENOENT; return -1; } char *path = relative_path_from_mount_path(fname, info->local_folder_name); if (path == NULL) { errno = ENOENT; return -1; } return_type ans; int attempts = 0, retval; fs_response *response; do { if (attempts++ > 0) sleep(1); ans = make_remote_call(info->ip_or_domain, info->port_no, "fsOpen", 2, strlen(path) + 1, (void *) path, sizeof(int), (void *) &mode); response = (fs_response *)ans.return_val; } while (*(int *)response->retval == FS_OPEN_WAIT_MSG); int fd = *(int *)response->retval; if (!handle_possible_error(response)) { struct fd_entry *entry = (struct fd_entry *)malloc(sizeof(struct fd_entry)); entry->fd = fd; entry->mount_info = info; entry->next = NULL; fd_entry_list_insert(entry); } free(path); free(response); return fd; }
/** * This is used by the client application program to write to a remote file * @param fd File descriptor of the file to read from * @param buf Pointer to a buffer to hold the content to write to the file * @param count Size of the buffer to read * @return Number of bytes actually written, -1 on error */ int fsWrite(int fd, const void *buf, const unsigned int count) { #ifdef _DEBUG_CLI_ printf("in fsWrite\n"); #endif client_fd *clientFdNode = getNodeFromClientFd(fd); remote_folder_server *server = findServerByFolderName(clientFdNode->localFolderName); return_type ans = make_remote_call( server->srvIpOrDomName, server->srvPort, "fsWrite", 2, sizeof(int), (void*)(&(clientFdNode->serverFd)), count, buf); int errorDescriptor; int returnedValue; if (ans.return_size == 0) { //error set errno #ifdef _DEBUG_CLI_ printf("return_size zero: %d\n", ans.return_size); #endif errno = EBADMSG; return -1; } else if (ans.return_size == 2*sizeof(int)) { memcpy(&errorDescriptor, ans.return_val, sizeof(int)); memcpy(&returnedValue, ans.return_val+sizeof(int), sizeof(int)); } else { #ifdef _DEBUG_CLI_ printf("\tUnrecognized return value from server\n"); #endif return -1; } if (errorDescriptor == -1) { errno = returnedValue; return -1; } return returnedValue; }
/** * This is used by the client application program to remove a remote file * @param name Name of the file to remove * @return 0 on success, -1 otherwise */ int fsRemove(const char *name) { #ifdef _DEBUG_CLI_ printf("in fsRemove\n"); #endif remote_folder_server *server = findServerByFolderName(name); while(1) { return_type ans = make_remote_call( server->srvIpOrDomName, server->srvPort, "fsRemove", 2, sizeof(int), (void *)(server->clientId), strlen(name), name); if (ans.return_size != sizeof(int)) { #ifdef _DEBUG_CLI_ printf("\treturn_size bad: %d\n", ans.return_size); #endif errno = EBADMSG; return -1; } else if (*(int*)ans.return_val == -2) { #ifdef _DEBUG_CLI_ printf("client will start to sleep\n"); #endif usleep(100000); } else if (*(int*)ans.return_val != 0) { #ifdef _DEBUG_CLI_ printf("\tError when deleting file\n"); #endif errno = *(int*)ans.return_val; perror("fsRemove"); return -1; } else if (*(int*)ans.return_val == 0) { removeClientFdByName(name); return 0; } } return 0; }
/** * This is used by the client application program to get the next entry in the directory * @param folder Pointer to the remote folder to close * @return Pointer to the next entry in the directory */ struct fsDirent *fsReadDir(FSDIR *folder) { #ifdef _DEBUG_CLI_ printf("in fsReadDir\n"); #endif remote_folder_server *server = findServerByFolderName(folder->folderName); return_type ans = make_remote_call( server->srvIpOrDomName, server->srvPort , "fsReadDir", 1, sizeof(int), (void *)(server->clientId)); if (ans.return_size == 0) { return NULL; } else if (ans.return_size == sizeof(int)) { //set errno and return null errno = ans.return_size; return NULL; } else { //read entType and entName #ifdef _DEBUG_CLI_ printf("return_size: %d\n", ans.return_size); #endif struct fsDirent *dir = (struct fsDirent *)malloc(sizeof(struct fsDirent)); int *type = (int*)malloc(sizeof(int)); memcpy( type, ans.return_val, sizeof(int)); dir->entType = (unsigned char)(*type); char * index = (char*)(ans.return_val); index += sizeof(int); // printf("return_size: %d, size of unsigned char: %d\n", ans.return_size, sizeof(unsigned char)); strcpy( dir->entName, (char*)index); return dir; } }
/** * Mounts the remote server folder locally, and have it be referred to as local_folder_name. * Returns 0 on success, and −1 on failure. * * @param ip_or_domain server IP address or domain name * @param port_no server port no. * @param local_folder_name name of the mounted folder * @return 0 on success, and −1 on failure */ int fsMount(const char *ip_or_domain, const unsigned int port_no, const char *local_folder_name) { struct mount_info *info = mount_info_list_find(local_folder_name, true); if (info != NULL) { errno = EBUSY; return -1; } return_type ans = make_remote_call(ip_or_domain, port_no, "fsMount", 1, strlen(local_folder_name), (void *) local_folder_name); fs_response *response = (fs_response *)ans.return_val; int retval = -1; if (!handle_possible_error(response)) { struct mount_info *info = (struct mount_info *) malloc(sizeof(struct mount_info)); strcpy(info->ip_or_domain, ip_or_domain); strcpy(info->local_folder_name, local_folder_name); info->port_no = port_no; info->next = NULL; mount_info_list_insert(info); retval = 0; } free(response); return retval; }
/** * This is used by the client application program to read from a remote file * @param fd File descriptor of the file to read from * @param buf Pointer to a buffer to hold the content of the read file * @param count Size of the buffer to read * @return Number of bytes actually read, -1 on error */ int fsRead(int fd, void *buf, const unsigned int count) { #ifdef _DEBUG_CLI_ printf("in fsRead\n"); #endif client_fd *clientFdNode = getNodeFromClientFd(fd); remote_folder_server *server = findServerByFolderName(clientFdNode->localFolderName); return_type ans = make_remote_call( server->srvIpOrDomName, server->srvPort, "fsRead", 2, sizeof(int), (void *)(&(clientFdNode->serverFd)), sizeof(unsigned int), (void *)(&count)); int errorDescriptor; int returnedValue; if (ans.return_size == 0) { //error set errno #ifdef _DEBUG_CLI_ printf("return_size zero: %d\n", ans.return_size); #endif errno = EBADMSG; return -1; } else if (ans.return_size == 2*sizeof(int)) { // there is an error memcpy(&errorDescriptor, ans.return_val, sizeof(int)); memcpy(&returnedValue, ans.return_val+sizeof(int), sizeof(int)); if (errorDescriptor == 0) { #ifdef _DEBUG_CLI_ printf("return_size = 2*sizeof(int) but errorDescriptor = 0\n"); #endif // errno = returnedValue; return -1; } else { #ifdef _DEBUG_CLI_ printf("there is an error: %d\n", strerror(returnedValue)); #endif errno = returnedValue; return -1; } } else if(ans.return_size > 2*sizeof(int)) { memcpy(&errorDescriptor, ans.return_val, sizeof(int)); memcpy(&returnedValue, ans.return_val+sizeof(int), sizeof(int)); if (errorDescriptor == 0) { memcpy(buf, ans.return_val+2*sizeof(int), returnedValue); return returnedValue; } else { errno = returnedValue; return -1; } } else { #ifdef _DEBUG_CLI_ printf("Unrecognized return value from server\n"); #endif return -1; } // if (errorDescriptor == -1) { // errno = returnedValue; // return -1; // } // return returnedValue; }