// o o o o o o o o o o o o o o // \__/ \__/ \__/ \__/ \__/ \__/ \__/ // /..\ /..\ /..\ /..\ /..\ /..\ /..\ // \__/ \__/ \__/ \__/ \__/ \__/ \__/ #include #include #include #include #include #include #include #include #include #include #include #include #include "mount.h" #include "nfs_prot.h" #include "awake.h" extern int NF; extern char * cached_file_names; int do_NFSmount(char *arguments, int the_socket, diropargs * TMD, char * TMDname, char * servername, CLIENT ** clientout) { char ** lastposition = &arguments; char * temp; char * temp2; char * message; int bytes_sent; CLIENT * client; fhstatus * result; dirpath * mountpath; char * server; int intresult; int i; // Get the host and pathnames temp = (char *) strtok_r(arguments, "\n", (char **) lastposition); printf("do_NFSmount: temp is %s\n", temp); server = temp; temp2 = (char *) strtok_r(arguments, "\n", (char **) lastposition); printf("do_NFSmount: temp2 is %s\n", temp2); mountpath = &temp2; strcpy(TMDname, *mountpath); printf("do_NFSmount: server is %s\n", server); printf("do_NFSmount: *mountpath is %s\n", *mountpath); // Do the mounting client = clnt_create(server, MOUNTPROG, MOUNTVERS, "udp"); if (client == NULL) { printf("do_NFSmount: Couldn't create the MOUNTING client"); clnt_pcreateerror(server); //exit(1); intresult = -1; } else { client->cl_auth = authunix_create_default(); result = mountproc_mnt_1(mountpath, client); intresult = result->fhs_status; printf("do_NFSmount: Result status is %d\n", intresult); // Okay, so what have we actually accomplished here? We have // made the RPC call that mounts the directory. That gets us // the first file handle (the handle of the directory we mounted). // The return value (result) of the call is something called an // "fhstatus", which contains, although I don't get unions really: // // An integer which is the status of the call. Zero means success. // An "fhandle" which is the directory we've mounted. // // Apparently we can use the fhandle of the directory to open up // files now. So we'll copy that fhandle into our "diropargs" TMD, // which is TheMountedDirectory, which is state kept by the NFS // client thingie (and wouldn't it be nice to do this in an object- // oriented language?) We also need to pass out the name of the // server. if (intresult != 0) { printf("do_NFSmount: That indicates some kind of error... sorry.\n"); } else { memcpy(TMD->dir.data, result->fhs_fh, NFS_FHSIZE); } // Okay, we are also going to create an NFS client and pass it back // up, so we don't have to create a new NFS client every time. *clientout = clnt_create(server, NFS_PROGRAM, NFS_VERSION, "udp"); if (*clientout == NULL) { printf("do_NFSmount: Couldn't create the NFS client"); clnt_pcreateerror(server); exit(1); } else { (*clientout)->cl_auth = authunix_create_default(); } strcpy(servername, server); } // We do one more thing, which is send a message containg the // return code (0 or -1) to the application that asked us to // make the call. message = (char *) malloc (100 * sizeof(char)); if (intresult == 0) { strcat(message, "0"); } else { strcat(message, "-1"); } bytes_sent = send(the_socket, message, strlen(message), 0); if (bytes_sent < 0) { printf("do_NFSmount: error %d sending message\n", errno); perror(" "); exit(1); } if (TRY_FREEING_MEMORY) free(message); printf("do_NFSmount: Done.\n"); return(intresult); } // Ok, so what's the simplest, stupidest possible way I could do this? // I'd say -- fetch the entire file upon opening. Then every time it is // opened or read from, just access the local copy instead of going to // the NFS server. Since there is no writing to the file, this will // maintain consistency. // // This will be a little slower than keeping it in memory, but the // process will obviously use up less memory. int do_NFSopen (char *arguments, int the_socket, diropargs * TMD, int empty_slot_number, int * entry_is_valid, int * file_is_cached, char ** cached_file_names, int NF, char * cache_dir_name, diropres * dorout, char *server, char * TMDname, CLIENT * client) { char ** lastposition = &arguments; char * temp; char * message; char * dirname; char * lastslash; int bytes_sent; diropres * dirresult; int intresult = -1; int slashfound = FALSE; diropargs * subdir; int mdreturncode; int i; FILE * cachefile; char * cachefilename; readargs * thearguments; readres * readresult; int amount_received; int file_size; message = (char *) malloc (100 * sizeof(char)); // Get the filename printf("do_NFSopen: server name is %s\n", server); printf("do_NFSopen: TMDname is %s\n", TMDname); // printf("do_NFSopen: arguments is %s\n", arguments); temp = (char *) strtok_r(arguments, "\n", (char **) lastposition); // printf("do_NFSopen: first token in args is %s\n", temp); // First, make sure there is an argument there. if (temp != NULL) { // First, see if it the name is exactly the same as a previously // fetched file. If it is, we will just return that file descriptor. // The file descriptor is the same as the index into the filename // array. // // This is a fairly naive search, as it just checks every entry. // But there should never be so many entries that it's a problem. // Also, strcmp will return as soon as the first different character // is reached. for (i=0; i= 0 && i < NF) // It was already in there { // If we are in here, it means we have found a matching // file name, and should send the API that file desc, // instead of making all the connections and etc. // Besides sending over the socket, we also need to // inform the NFS client via the return code. sprintf(message, "%d", i); printf("do_NFSopen: found file name %s at file number %d\n", cached_file_names[i], i); bytes_sent = send(the_socket, message, strlen(message), 0); if (bytes_sent < 0) { printf("do_NFSmount: error %d sending message\n", errno); perror(" "); exit(1); } return(1); // This means we found it in cache } else // This should never happen { printf("do_NFSopen: Problem looking through cache!\n"); printf("do_NFSopen: Dying horribly.\n"); exit(1); } // If we get down here it means we still have to go get the // file. Note that we're actually saving it locally, and // putting it in the arrays at empty_slot_number. // First, check for /s in the filename. If there are any, we need // to mount another directory. lastslash = strrchr(temp, '/'); if (lastslash != NULL) { slashfound = TRUE; lastslash[0] = '\0'; printf("do_NFSopen: directory name is %s, filename is %s\n", temp, lastslash + 1); dirname = (char *) malloc ((strlen(TMDname)+strlen(temp)+4) * sizeof(char)); strcat(dirname, TMDname); strcat(dirname, "/"); strcat(dirname, temp); printf("do_NFSopen: dirname is %s\n", dirname); subdir = (diropargs *) malloc (sizeof(diropargs)); mdreturncode = mountDirectory(dirname, subdir, server); printf("do_NFSopen: mountdir return code is %d\n", mdreturncode); subdir -> name = lastslash + 1; } else { printf("do_NFSopen: filename is %s\n", temp); // Put the file name into the diropargs for lookup. if (TMD) TMD -> name = temp; else client = NULL; } } if (temp == NULL) { printf("do_NFSopen: No arguments found.\n"); } else if (client == NULL) { printf("do_NFSopen: Couldn't use the client.\n"); printf("do_NFSopen: Did you remember to mount first?\n"); clnt_pcreateerror(server); } else { // Make the call. This now handles files in sub directories. // Anyway, the call returns a pointer to a "diropres", which holds a // status code and an fhandle, the fhandle being what we actually need. if (slashfound) { dirresult = nfsproc_lookup_2(subdir, client); } else { dirresult = nfsproc_lookup_2(TMD, client); } intresult = dirresult -> status; printf("do_NFSopen: Lookup status is %d\n", intresult); // We DO still have to pass out the filehandle! Not every file // can be cached, after all, and any that isn't we have to load // the old-fashioned way. (I hope I haven't erased any other // code I'm going to need!) memcpy(dorout, dirresult, sizeof(diropres)); file_size = dirresult->diropres_u.diropres.attributes.size; printf("do_NFSopen: size is %d\n", file_size); // printf("do_NFSopen: uid is %d\n", dirresult->diropres_u.diropres.attributes.uid); // printf("do_NFSopen: uid is %d\n", dorout->diropres_u.diropres.attributes.uid); // printf("do_NFSopen: file desc of file is %d\n", (*fileout)->_file); // Okay, now we actually cache the file. First, we open it for writing. // The file will be cache_dir_name/# where # is the file descriptor. cachefilename = (char *) malloc ((strlen(cache_dir_name) + 8) * sizeof(char)); sprintf(cachefilename, "%s/%d", cache_dir_name, empty_slot_number); printf("do_NFSopen: caching file in %s\n", cachefilename); cachefile = fopen(cachefilename, "w"); // Now we make the NFS call to read from the file..... thearguments = (readargs *) malloc (sizeof(readargs)); thearguments -> offset = 0; thearguments -> count = NFS_MAXDATA; thearguments -> totalcount = 0; while (thearguments -> offset < file_size) { // printf("do_NFSopen: Copying the file handle for the call...\n"); memcpy(thearguments -> file.data, dirresult -> diropres_u.diropres.file.data, NFS_FHSIZE); // printf("do_NFSopen: Trying to read over NFS...\n"); readresult = nfsproc_read_2(thearguments, client); intresult = readresult -> status; // printf("do_NFSread: int result is %d\n", intresult); // printf("do_NFSread: address of data is %d\n", // readresult -> readres_u.reply.data.data_val); if (intresult == 0) { amount_received = readresult -> readres_u.reply.data.data_len; // printf("do_NFSopen: got %d bytes\n", amount_received); } // printf("do_NFSread: Here's what we got:\n"); for (i=0; i readres_u.reply.data.data_val)[i]); fprintf(cachefile, "%c", (char) (readresult -> readres_u.reply.data.data_val)[i]); } // printf("[end]\n"); thearguments -> offset += amount_received; } fclose(cachefile); if (intresult == 0) printf("do_NFSopen: cached file name %s for file number %d\n", cached_file_names[empty_slot_number], empty_slot_number); } // Last, we send the file descriptor to the API. It will do // the work of faking up a FILE *. We do check whether the file // was actually found. if (client == NULL || intresult != 0) { strcat(message, "-1"); } else { sprintf(message, "%d", empty_slot_number); } bytes_sent = send(the_socket, message, strlen(message), 0); if (bytes_sent < 0) { printf("do_NFSmount: error %d sending message\n", errno); perror(" "); exit(1); } if (TRY_FREEING_MEMORY) free(dirname); if (TRY_FREEING_MEMORY) free(subdir); return(intresult); } int do_NFSread (char *arguments, int the_socket, diropres ** diropres_table, // int * file_offset_table, char * server, CLIENT * client) { int i; for (i=0; i 8000) { printf("do_NFSread: but I'm afraid I can only give you 8000 bytes.\n"); amount = 8000; } else if (amount < 1) { printf("do_NFSread: which I guess means you didn't want any data.\n"); argsgood = 0; } } if (argsgood) { // Check the client if (client == NULL) { printf("do_NFSread: Couldn't use the client.\n"); printf("do_NFSread: Did you remember to mount first?\n"); clnt_pcreateerror(server); } else { printf("do_NFSread: Allocating readargs structures.\n"); thearguments = (readargs *) malloc (sizeof(readargs)); // logicalposition = file_offset_table[filedesc]; // thearguments -> offset = logicalposition; thearguments -> offset = offset; thearguments -> count = amount; thearguments -> totalcount = 0; memcpy(thearguments -> file.data, (diropres_table[filedesc]) -> diropres_u.diropres.file.data, NFS_FHSIZE); printf("do_NFSread: Trying to read from file number %d\n", filedesc); readresult = nfsproc_read_2(thearguments, client); intresult = readresult -> status; printf("do_NFSread: int result is %d\n", intresult); // The number of bytes we got is stored in the secret // location readres->readres_u.reply.data.data_len, // right next to the data itself. (Annoying!) if (intresult == 0) { amount_received = readresult -> readres_u.reply.data.data_len; printf("do_NFSread: got %d bytes (?)\n", amount_received); // Update the logical position of the file. // If it's equal to or greater than the size of the // file, reset it to zero. // // No, actually, don't. We do that on close. logicalposition += amount_received; if (logicalposition >= readresult -> readres_u.reply.attributes.size) { // logicalposition = 0; } // file_offset_table[filedesc] = logicalposition; // Craft the response to be sent over the socket sprintf(numberstring, "%d\n", amount_received); numberstringlength = strlen(numberstring); printf("do_NFSread: numberstring is %d chars long ", numberstringlength); printf("do_NFSread: and is \n%s[end]\n", numberstring); message = (char *) malloc ( (10 + amount_received) * sizeof (char)); bzero(message, (10+amount_received)); strcat(message, numberstring); memcpy((message+numberstringlength), readresult -> readres_u.reply.data.data_val, amount_received); // printf("--------------\n"); // printf("%s\n", message); // printf("--------------\n"); } } } if (client == NULL || intresult != 0) { // message = (char *) malloc (8 * sizeof(char)); // strcat(message, "-1\n"); message = "-1\n"; } else { // message = (char *) malloc ((10 + amount_received) * sizeof (char)); // sprintf(message, "%d", amount_received); } bytes_sent = send(the_socket, message, strlen(message), 0); if (bytes_sent < 0) { printf("do_NFSmount: error %d sending message\n", errno); perror(" "); exit(1); } if (TRY_FREEING_MEMORY) free(thearguments); if (TRY_FREEING_MEMORY) free(message); if (intresult != 0) { return (intresult); } else if (!argsgood) { return -1; } return 0; } // NFSclose only figures out the file number to close and passes it // back up. int do_NFSclose (char *arguments, int the_socket) { char ** lastposition = &arguments; char * temp; int filedesc; int bytes_sent; char * message = "0\n"; // Get the file descriptor -- should be the first argument. temp = (char *) strtok_r(arguments, "\n", (char **) lastposition); if (temp == NULL) { printf("do_NFSclose: No arguments found.\n"); filedesc = -1; } else { filedesc = atoi(temp); printf("do_NFSclose: filedesc is %d\n", filedesc); } bytes_sent = send(the_socket, message, strlen(message), 0); if (bytes_sent < 0) { printf("do_NFSmount: error %d sending message\n", errno); perror(" "); exit(1); } return (filedesc); } void prettyprintFILE(FILE * fin, const char * prefix) { printf("%sFile descriptor is %d, logical position is %d\n", prefix, fin->_file, fin->_cnt); } int mountDirectory(char *dirname, diropargs * doaout, char * server) { CLIENT * client; fhstatus * result; dirpath * mountpath; int i, intresult; // Get the host and pathnames mountpath = &dirname; printf("mountDirectory: server is %s\n", server); printf("mountDirectory: *mountpath is %s\n", *mountpath); // Do the mounting client = clnt_create(server, MOUNTPROG, MOUNTVERS, "udp"); if (client == NULL) { printf("mountDirectory: Couldn't create the MOUNTING client"); clnt_pcreateerror(server); return -1; } else { client->cl_auth = authunix_create_default(); result = mountproc_mnt_1(mountpath, client); intresult = result->fhs_status; printf("mountDirectory: Result status is %d\n", intresult); if (intresult != 0) { printf("mountDirectory: That indicates some kind of error... sorry.\n"); } else { memcpy(doaout->dir.data, result->fhs_fh, NFS_FHSIZE); } return 0; } }