MDL-49399 core: Allow creation of a new per-request basedir
authorAndrew Nicols <andrew@nicols.co.uk>
Wed, 5 Dec 2018 07:20:20 +0000 (15:20 +0800)
committerAndrew Nicols <andrew@nicols.co.uk>
Wed, 16 Jan 2019 04:14:25 +0000 (12:14 +0800)
Shutdown handlers are processed in order. If something in a shutdown
handler uses a file which is stored in a per-request directory, and
another, unrelated, per-request directory was created before the handler
started. then a fresh per-request directory will be required.

lib/classes/task/logmanager.php
lib/setuplib.php

index fe89d25..8b812e1 100644 (file)
@@ -89,8 +89,7 @@ class logmanager {
         }
 
         // We register a shutdown handler to ensure that logs causing any failures are correctly disposed of.
         }
 
         // We register a shutdown handler to ensure that logs causing any failures are correctly disposed of.
-        // Note: This must happen before the per-request directory is requested because the shutdown handler may delete
-        // the logfile.
+        // Note: This must happen before the per-request directory is requested because the shutdown handler deletes the logfile.
         if (!self::$tasklogregistered) {
             \core_shutdown_manager::register_function(function() {
                 // These will only actually do anything if capturing is current active when the thread ended, which
         if (!self::$tasklogregistered) {
             \core_shutdown_manager::register_function(function() {
                 // These will only actually do anything if capturing is current active when the thread ended, which
@@ -98,6 +97,9 @@ class logmanager {
                 \core\task\logmanager::finalise_log(true);
             });
 
                 \core\task\logmanager::finalise_log(true);
             });
 
+            // Create a brand new per-request directory basedir.
+            get_request_storage_directory(true, true);
+
             self::$tasklogregistered = true;
         }
 
             self::$tasklogregistered = true;
         }
 
index 2550a14..68c283a 100644 (file)
@@ -1633,15 +1633,22 @@ function make_upload_directory($directory, $exceptiononerror = true) {
  *
  * The directory is automatically cleaned up during the shutdown handler.
  *
  *
  * The directory is automatically cleaned up during the shutdown handler.
  *
- * @param bool $exceptiononerror throw exception if error encountered
- * @return string|false Returns full path to directory if successful, false if not; may throw exception
+ * @param   bool    $exceptiononerror throw exception if error encountered
+ * @param   bool    $forcecreate Force creation of a new parent directory
+ * @return  string  Returns full path to directory if successful, false if not; may throw exception
  */
  */
-function get_request_storage_directory($exceptiononerror = true) {
+function get_request_storage_directory($exceptiononerror = true, bool $forcecreate = false) {
     global $CFG;
 
     static $requestdir = null;
 
     global $CFG;
 
     static $requestdir = null;
 
-    if (!$requestdir || !file_exists($requestdir) || !is_dir($requestdir) || !is_writable($requestdir)) {
+    $writabledirectoryexists = (null !== $requestdir);
+    $writabledirectoryexists = $writabledirectoryexists && file_exists($requestdir);
+    $writabledirectoryexists = $writabledirectoryexists && is_dir($requestdir);
+    $writabledirectoryexists = $writabledirectoryexists && is_writable($requestdir);
+    $createnewdirectory = $forcecreate || !$writabledirectoryexists;
+
+    if ($createnewdirectory) {
         if ($CFG->localcachedir !== "$CFG->dataroot/localcache") {
             check_dir_exists($CFG->localcachedir, true, true);
             protect_directory($CFG->localcachedir);
         if ($CFG->localcachedir !== "$CFG->dataroot/localcache") {
             check_dir_exists($CFG->localcachedir, true, true);
             protect_directory($CFG->localcachedir);
@@ -1649,10 +1656,12 @@ function get_request_storage_directory($exceptiononerror = true) {
             protect_directory($CFG->dataroot);
         }
 
             protect_directory($CFG->dataroot);
         }
 
-        if ($requestdir = make_unique_writable_directory($CFG->localcachedir, $exceptiononerror)) {
+        if ($dir = make_unique_writable_directory($CFG->localcachedir, $exceptiononerror)) {
             // Register a shutdown handler to remove the directory.
             // Register a shutdown handler to remove the directory.
-            \core_shutdown_manager::register_function('remove_dir', array($requestdir));
+            \core_shutdown_manager::register_function('remove_dir', [$dir]);
         }
         }
+
+        $requestdir = $dir;
     }
 
     return $requestdir;
     }
 
     return $requestdir;
@@ -1663,13 +1672,18 @@ function get_request_storage_directory($exceptiononerror = true) {
  * This can only be used during the current request and will be tidied away
  * automatically afterwards.
  *
  * This can only be used during the current request and will be tidied away
  * automatically afterwards.
  *
- * A new, unique directory is always created within the current request directory.
+ * A new, unique directory is always created within a shared base request directory.
  *
  *
- * @param bool $exceptiononerror throw exception if error encountered
- * @return string full path to directory if successful, false if not; may throw exception
+ * In some exceptional cases an alternative base directory may be required. This can be accomplished using the
+ * $forcecreate parameter. Typically this will only be requried where the file may be required during a shutdown handler
+ * which may or may not be registered after a previous request directory has been created.
+ *
+ * @param   bool    $exceptiononerror throw exception if error encountered
+ * @param   bool    $forcecreate Force creation of a new parent directory
+ * @return  string  The full path to directory if successful, false if not; may throw exception
  */
  */
-function make_request_directory($exceptiononerror = true) {
-    $basedir = get_request_storage_directory($exceptiononerror);
+function make_request_directory($exceptiononerror = true, bool $forcecreate = false) {
+    $basedir = get_request_storage_directory($exceptiononerror, $forcecreate);
     return make_unique_writable_directory($basedir, $exceptiononerror);
 }
 
     return make_unique_writable_directory($basedir, $exceptiononerror);
 }