Sfoglia il codice sorgente

WebDAV for Windows Explorer (Step 3/?)

bel2125 3 anni fa
parent
commit
5dbd955f15
1 ha cambiato i file con 76 aggiunte e 74 eliminazioni
  1. 76 74
      src/civetweb.c

+ 76 - 74
src/civetweb.c

@@ -12535,13 +12535,14 @@ print_dav_dir_entry(struct de *de, void *data)
 
 
 #define NUM_WEBDAV_LOCKS 10
-uint64_t dav_lock_counter = 0;
 struct tdav_lock {
-	uint64_t counter;
+	uint64_t locktime;
 	char token[33];
 	char path[UTF8_PATH_MAX * 2];
 	char user[UTF8_PATH_MAX * 2];
-} dav_lock[NUM_WEBDAV_LOCKS];
+};
+static uint32_t LOCK_DURATION_S = 60;
+static struct tdav_lock dav_lock[NUM_WEBDAV_LOCKS];
 
 
 static void
@@ -12605,12 +12606,13 @@ handle_propfind(struct mg_connection *conn,
 				          "<d:lockscope><d:exclusive/></d:lockscope>"
 				          "<d:depth>0</d:depth>"
 				          "<d:owner>%s</d:owner>"
-				          "<d:timeout>Second-60</d:timeout>"
+				          "<d:timeout>Second-%u</d:timeout>"
 				          "<d:locktoken>"
 				          "<d:href>%s</d:href>"
 				          "</d:locktoken>"
 				          "</d:activelock>\n",
 				          dav_lock[i].user,
+				          LOCK_DURATION_S,
 				          dav_lock[i].token);
 			}
 		}
@@ -12631,8 +12633,11 @@ static void
 dav_lock_file(struct mg_connection *conn, const char *path)
 {
 	char link_buf[UTF8_PATH_MAX * 2]; /* Path + server root */
+	uint64_t new_locktime;
 	int lock_index = -1;
 	int i;
+	uint64_t LOCK_DURATION_NS = LOCK_DURATION_S * (int64_t)1000000000;
+
 	if (!conn || !path || !conn->dom_ctx || !conn->request_info.remote_user) {
 		return;
 	}
@@ -12645,77 +12650,70 @@ dav_lock_file(struct mg_connection *conn, const char *path)
 	 */
 
 	mg_lock_context(conn->phys_ctx);
-	/* find existing lock */
-	for (i = 0; i < NUM_WEBDAV_LOCKS; i++) {
-		if (!strcmp(dav_lock[i].path, link_buf)) {
-			if (!strcmp(conn->request_info.remote_user, dav_lock[i].user)) {
-				/* locked by the same user */
-				dav_lock_counter++;
-				dav_lock[i].counter = dav_lock_counter;
-				lock_index = i;
-				break;
-			} else {
-				/* already locked by someone else */
-				mg_unlock_context(conn->phys_ctx);
-				mg_send_http_error(conn, 423, "%s", "Already locked");
-				return;
+	new_locktime = mg_get_current_time_ns();
+
+	/* Find a slot for a lock */
+	while (lock_index < 0) {
+		/* find existing lock */
+		for (i = 0; i < NUM_WEBDAV_LOCKS; i++) {
+			if (!strcmp(dav_lock[i].path, link_buf)) {
+				if (!strcmp(conn->request_info.remote_user, dav_lock[i].user)) {
+					/* locked by the same user */
+					dav_lock[i].locktime = new_locktime;
+					lock_index = i;
+					break;
+				} else {
+					/* already locked by someone else */
+					if (new_locktime
+					    > (dav_lock[i].locktime + LOCK_DURATION_NS)) {
+						/* Lock expired */
+						dav_lock[i].path[0] = 0;
+					} else {
+						/* Lock still valid */
+						mg_unlock_context(conn->phys_ctx);
+						mg_send_http_error(conn, 423, "%s", "Already locked");
+						return;
+					}
+				}
 			}
 		}
-	}
 
-	/* create new lock token */
-	for (i = 0; i < NUM_WEBDAV_LOCKS; i++) {
-		if (dav_lock[i].path[0] == 0) {
-			char s[32];
-			dav_lock_counter++;
-			dav_lock[i].counter = dav_lock_counter;
-			sprintf(s, "%" UINT64_FMT, (uint64_t)dav_lock_counter);
-			mg_md5(dav_lock[i].token,
-			       link_buf,
-			       "\x01",
-			       s,
-			       "\x01",
-			       conn->request_info.remote_user,
-			       NULL);
-			strncpy(dav_lock[i].path, link_buf, sizeof(dav_lock[i].path) - 1);
-			strncpy(dav_lock[i].user,
-			        conn->request_info.remote_user,
-			        sizeof(dav_lock[i].user) - 1);
-			lock_index = i;
-			break;
-		}
-	}
-	if (lock_index < 0) {
-		char s[32];
-		/* too many locks. Find oldest lock */
-		uint64_t oldest_counter = dav_lock[0].counter;
-		lock_index = 0;
-		for (i = 1; i < NUM_WEBDAV_LOCKS; i++) {
-			if (dav_lock[i].counter < oldest_counter) {
-				oldest_counter = dav_lock[i].counter;
+		/* create new lock token */
+		for (i = 0; i < NUM_WEBDAV_LOCKS; i++) {
+			if (dav_lock[i].path[0] == 0) {
+				char s[32];
+				dav_lock[i].locktime = mg_get_current_time_ns();
+				sprintf(s, "%" UINT64_FMT, (uint64_t)dav_lock[i].locktime);
+				mg_md5(dav_lock[i].token,
+				       link_buf,
+				       "\x01",
+				       s,
+				       "\x01",
+				       conn->request_info.remote_user,
+				       NULL);
+				strncpy(dav_lock[i].path,
+				        link_buf,
+				        sizeof(dav_lock[i].path) - 1);
+				strncpy(dav_lock[i].user,
+				        conn->request_info.remote_user,
+				        sizeof(dav_lock[i].user) - 1);
 				lock_index = i;
+				break;
+			}
+		}
+		if (lock_index < 0) {
+			/* too many locks. Find oldest lock */
+			uint64_t oldest_locktime = dav_lock[0].locktime;
+			lock_index = 0;
+			for (i = 1; i < NUM_WEBDAV_LOCKS; i++) {
+				if (dav_lock[i].locktime < oldest_locktime) {
+					oldest_locktime = dav_lock[i].locktime;
+					lock_index = i;
+				}
 			}
+			/* invalidate oldest lock */
+			dav_lock[lock_index].path[0] = 0;
 		}
-		/* invalidate oldest lock */
-		dav_lock[lock_index].path[0] = 0;
-
-		/* Reuse it (TODO: remove code duplication) */
-		dav_lock_counter++;
-		dav_lock[lock_index].counter = dav_lock_counter;
-		sprintf(s, "%" UINT64_FMT, (uint64_t)dav_lock_counter);
-		mg_md5(dav_lock[lock_index].token,
-		       link_buf,
-		       "\x01",
-		       s,
-		       "\x01",
-		       conn->request_info.remote_user,
-		       NULL);
-		strncpy(dav_lock[lock_index].path,
-		        link_buf,
-		        sizeof(dav_lock[lock_index].path) - 1);
-		strncpy(dav_lock[lock_index].user,
-		        conn->request_info.remote_user,
-		        sizeof(dav_lock[lock_index].user) - 1);
 	}
 	mg_unlock_context(conn->phys_ctx);
 
@@ -12740,9 +12738,9 @@ dav_lock_file(struct mg_connection *conn, const char *path)
 	          "         <d:lockscope><d:exclusive/></d:lockscope>\n"
 	          "         <d:locktype><d:write/></d:locktype>\n"
 	          "         <d:owner>\n"
-	          "           <d:href>user</d:href>\n"
+	          "           <d:href>%s</d:href>\n"
 	          "         </d:owner>\n"
-	          "         <d:timeout>Second-60</d:timeout>\n"
+	          "         <d:timeout>Second-%u</d:timeout>\n"
 	          "         <d:locktoken><d:href>%s</d:href></d:locktoken>\n"
 	          "         <d:lockroot>\n"
 	          "           <d:href>%s</d:href>\n"
@@ -12750,6 +12748,8 @@ dav_lock_file(struct mg_connection *conn, const char *path)
 	          "       </d:activelock>\n"
 	          "     </d:lockdiscovery>\n"
 	          "   </d:prop>\n",
+	          dav_lock[lock_index].user,
+	          LOCK_DURATION_S,
 	          dav_lock[lock_index].token,
 	          dav_lock[lock_index].path);
 }
@@ -12818,10 +12818,9 @@ dav_proppatch(struct mg_connection *conn, const char *path)
 	          "Forbidden</d:status></d:propstat>\n");
 	mg_printf(conn, "%s\n", "</d:response></d:multistatus>");
 }
-
-
 #endif
 
+
 void
 mg_lock_connection(struct mg_connection *conn)
 {
@@ -12830,6 +12829,7 @@ mg_lock_connection(struct mg_connection *conn)
 	}
 }
 
+
 void
 mg_unlock_connection(struct mg_connection *conn)
 {
@@ -12838,6 +12838,7 @@ mg_unlock_connection(struct mg_connection *conn)
 	}
 }
 
+
 void
 mg_lock_context(struct mg_context *ctx)
 {
@@ -12846,6 +12847,7 @@ mg_lock_context(struct mg_context *ctx)
 	}
 }
 
+
 void
 mg_unlock_context(struct mg_context *ctx)
 {
@@ -14998,7 +15000,7 @@ handle_request(struct mg_connection *conn)
 	}
 
 	/* 12. Directory uris should end with a slash */
-	if (file.stat.is_directory && ((uri_len = (int) strlen(ri->local_uri)) > 0)
+	if (file.stat.is_directory && ((uri_len = (int)strlen(ri->local_uri)) > 0)
 	    && (ri->local_uri[uri_len - 1] != '/')) {
 
 		size_t len = strlen(ri->request_uri);