diff --git a/checkin_notes b/checkin_notes index 54088cab20..1396aae923 100755 --- a/checkin_notes +++ b/checkin_notes @@ -27165,3 +27165,21 @@ David 13 April 2005 cs_apps.C cs_scheduler.C gui_rpc_server.C + +Bruce 14 April 2005 + - file_upload_handler: when responding to a request for the + file length, check first that the file is not already + in open (locked) by another file_upload_handler. If the + file IS open (locked), then do NOT hand back the file length. + Instead return a transient error. This will prevent + transmission of upload data starting at the wrong offset. + - To help understand when/why multiple file_upload_handlers + are trying to write to the same file, set default log level + to DEBUG. Also log messages at level CRITICAL if there is + an attempt to write to a locked file. We may want to change + this level to DEBUG in the future, if this turns out to be + 'normal' TCP buffering of data between host and server. + + sched/ + file_upload_handler.C + diff --git a/sched/file_upload_handler.C b/sched/file_upload_handler.C index 480aa062f9..ac4793cfa0 100644 --- a/sched/file_upload_handler.C +++ b/sched/file_upload_handler.C @@ -47,7 +47,7 @@ SCHED_CONFIG config; #define ERR_TRANSIENT true #define ERR_PERMANENT false -#define DEBUG_LEVEL SCHED_MSG_LOG::NORMAL +#define DEBUG_LEVEL SCHED_MSG_LOG::DEBUG char this_filename[256]; @@ -342,7 +342,8 @@ int handle_file_upload(FILE* in, R_RSA_PUBLIC_KEY& key) { int handle_get_file_size(char* file_name) { struct stat sbuf; char path[256], buf[256]; - int retval; + int retval,fd; + FILE *fp; // TODO: check to ensure path doesn't point somewhere bad // Use 64-bit variant @@ -350,12 +351,54 @@ int handle_get_file_size(char* file_name) { dir_hier_path(file_name, config.upload_dir, config.uldl_dir_fanout, true, path); retval = stat( path, &sbuf ); if (retval && errno != ENOENT) { - log_messages.printf(SCHED_MSG_LOG::DEBUG, "handle_get_file_size(): [%s] returning error\n", file_name); + // file DOES perhaps exit, but can't stat it:try again later + // + log_messages.printf(SCHED_MSG_LOG::CRITICAL, "handle_get_file_size(): [%s] returning error\n", file_name); return return_error(ERR_TRANSIENT, "cannot open file" ); } else if (retval) { + // file does not exist: return zero length + // log_messages.printf(SCHED_MSG_LOG::DEBUG, "handle_get_file_size(): [%s] returning zero\n", file_name); return return_success("0"); + } else if (!(fp=fopen(path, "ab"))) { + // file exists, but can't be written to: try again later + // + /* Opening a file with append mode (a as the first character in + the mode argument) causes all subsequent writes to the file + to be forced to the then current end-of-file, regardless of + intervening calls to fseek(3C). If two separate processes + open the same file for append, each process may write freely + to the file without fear of destroying output being written + by the other. The output from the two processes will be + intermixed in the file in the order in which it is written. + */ + log_messages.printf(SCHED_MSG_LOG::CRITICAL, + "handle_get_file_size(): [%s] %d bytes long returning error\n", + file_name, (int)sbuf.st_size + ); + return return_error(ERR_TRANSIENT, "can't open file for writing" ); + } else if ((fd=fileno(fp))<0) { + // file exists and is writable, but can't get file descriptor: try again later + // + fclose(fp); + log_messages.printf(SCHED_MSG_LOG::CRITICAL, + "handle_get_file_size(): [%s] %d bytes long returning error\n", + file_name, (int)sbuf.st_size + ); + return return_error(ERR_TRANSIENT, "can't get file descriptor" ); + } else if (lockf(fd, F_TEST, 0)) { + // file locked by another file_upload_handler: try again later + // + fclose(fp); + log_messages.printf(SCHED_MSG_LOG::CRITICAL, + "handle_get_file_size(): [%s] %d bytes long returning error\n", + file_name, (int)sbuf.st_size + ); + return return_error(ERR_TRANSIENT, "file locked by another file_upload_handler" ); } else { + // file exists, writable, not locked, so return length. + // + fclose(fp); log_messages.printf( SCHED_MSG_LOG::DEBUG, "handle_get_file_size(): [%s] returning %d\n", file_name, (int)sbuf.st_size @@ -408,6 +451,8 @@ int handle_request(FILE* in, R_RSA_PUBLIC_KEY& key) { } did_something = true; break; + } else if (match_tag(buf, "")) { + // DO NOTHING } else { log_messages.printf(SCHED_MSG_LOG::DEBUG, "handle_request: unrecognized %s\n", buf); }