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);
}