? 690828-block-ahah_0.patch
? 732542-system-goto-action-D7.patch
? 735528-states-or.patch
? 823428-entity-uri-34.patch
? 846296-file-download.patch
? file_download_access6.patch
? test.patch
? modules/file/file.api.php
? sites/default/files
? sites/default/private
Index: modules/comment/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v
retrieving revision 1.891
diff -u -p -r1.891 comment.module
--- modules/comment/comment.module	22 Aug 2010 10:01:06 -0000	1.891
+++ modules/comment/comment.module	23 Aug 2010 09:39:50 -0000
@@ -2615,3 +2615,12 @@ function comment_rdf_mapping() {
     ),
   );
 }
+
+/**
+ * Implements hook_file_download_access().
+ */
+function comment_file_download_access($field, $entity_type, $entity) {
+  if ($entity_type == 'comment') {
+    return user_access('access comments') && $entity->status == COMMENT_PUBLISHED || user_access('administer comments');
+  }
+}
Index: modules/file/file.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/file/file.module,v
retrieving revision 1.35
diff -u -p -r1.35 file.module
--- modules/file/file.module	22 Aug 2010 13:52:58 -0000	1.35
+++ modules/file/file.module	23 Aug 2010 09:39:50 -0000
@@ -141,46 +141,69 @@ function file_file_download($uri, $field
   // Find out which (if any) file fields contain this file.
   $references = file_get_file_references($file, NULL, FIELD_LOAD_REVISION, $field_type);
 
-  // TODO: Check field-level access if available here.
-
-  $denied = $file->status ? NULL : FALSE;
-  // Check access to content containing the file fields. If access is allowed
-  // to any of this content, allow the download.
+  // Default to allow access.
+  $denied = FALSE;
+  // Loop through all references of this file. If a reference explicitly allows
+  // access to the field to which this file belongs, no further checks are done
+  // and download access is granted. If a reference denies access, eventually
+  // existing additional references are checked. If all references were checked
+  // and no reference denied access, access is granted as well. If at least one
+  // reference denied access, access is denied.
   foreach ($references as $field_name => $field_references) {
     foreach ($field_references as $entity_type => $type_references) {
-      foreach ($type_references as $reference) {
-        // If access is allowed to any object, immediately stop and grant
-        // access. If access is denied, continue through in case another object
-        // grants access.
-        // TODO: Switch this to a universal access check mechanism if available.
-        if ($entity_type == 'node' && ($node = node_load($reference->nid))) {
-          if (node_access('view', $node)) {
-            $denied = FALSE;
-            break 3;
-          }
-          else {
-            $denied = TRUE;
+      foreach ($type_references as $id => $reference) {
+        // Try to load $entity and $field.
+        $entity = reset(entity_load($entity_type, array($id)));
+        $field = NULL;
+        if ($entity) {
+          // Load all fields for that entity.
+          $field_items = field_get_items($entity_type, $entity, $field_name);
+
+          // Find the field item with the matching URI.
+          foreach ($field_items as $field_item) {
+            if ($field_item['uri'] == $uri) {
+              $field = $field_item;
+              break;
+            }
           }
         }
-        if ($entity_type == 'user') {
-          if (user_access('access user profiles') || $user->uid == $reference->uid) {
-            $denied = FALSE;
-            break 3;
-          }
-          else {
-            $denied = TRUE;
-          }
+
+        // Check that $entity and $field were loaded successfully and check if
+        // access to that field is not disallowed. If any of these checks fail,
+        // stop checking access for this reference.
+        if (empty($entity) || empty($field) || !field_access('view', $field, $entity_type, $entity)) {
+          $denied = TRUE;
+          break;
+        }
+
+        // Invoke hook and collect grants/denies for download access.
+        // Default to FALSE and let entities overrule this ruling.
+        $grants = array('system' => FALSE);
+        foreach (module_implements('file_download_access') as $module) {
+          $grants = array_merge($grants, array($module => module_invoke($module, 'file_download_access', $field, $entity_type, $entity)));
+        }
+        // Allow other modules to alter the returned grants/denies.
+        drupal_alter('file_download_access', $grants, $field, $entity_type, $entity);
+
+        if (in_array(TRUE, $grants)) {
+          // If TRUE is returned, access is granted and no further checks are
+          // necessary.
+          $denied = FALSE;
+          break 3;
+        }
+
+        if (in_array(FALSE, $grants)) {
+          // If an implementation returns FALSE, access to this entity is denied
+          // but the file could belong to another entity to which the user might
+          // have access. Continue with these.
+          $denied = TRUE;
         }
       }
     }
   }
 
-  // No access was denied or granted.
-  if (!isset($denied)) {
-    return;
-  }
-  // Access specifically denied and not granted elsewhere.
-  elseif ($denied == TRUE) {
+  // Access specifically denied.
+  if ($denied) {
     return -1;
   }
 
Index: modules/file/tests/file.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/file/tests/file.test,v
retrieving revision 1.22
diff -u -p -r1.22 file.test
--- modules/file/tests/file.test	22 Aug 2010 13:52:58 -0000	1.22
+++ modules/file/tests/file.test	23 Aug 2010 09:39:50 -0000
@@ -14,7 +14,7 @@ class FileFieldTestCase extends DrupalWe
 
   function setUp() {
     parent::setUp('file');
-    $this->admin_user = $this->drupalCreateUser(array('access content', 'access administration pages', 'administer site configuration', 'administer users', 'administer content types', 'administer nodes', 'bypass node access'));
+    $this->admin_user = $this->drupalCreateUser(array('access content', 'access administration pages', 'administer site configuration', 'administer users', 'administer permissions', 'administer content types', 'administer nodes', 'bypass node access'));
     $this->drupalLogin($this->admin_user);
   }
 
@@ -301,6 +301,68 @@ class FileFieldWidgetTestCase extends Fi
     $this->drupalGet("admin/structure/types/manage/$type_name/fields/$field_name");
     $this->assertFieldByXpath('//input[@id="edit-field-settings-uri-scheme-public" and not(@disabled)]', 'public', t('Upload destination setting enabled.'));
   }
+
+  /**
+   * Tests that download restrictions on private files work on comments.
+   */
+  function testPrivateFileComment() {
+    $user = $this->drupalCreateUser(array('access comments'));
+
+    // Remove access comments permission from anon user.
+    $edit = array(
+      '1[access comments]' => FALSE,
+    );
+    $this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
+
+    // Create a new field.
+    $edit = array(
+      '_add_new_field[label]' => $label = $this->randomName(),
+      '_add_new_field[field_name]' => $name = strtolower($this->randomName()),
+      '_add_new_field[type]' => 'file',
+      '_add_new_field[widget_type]' => 'file_generic',
+    );
+    $this->drupalPost('admin/structure/types/manage/article/comment/fields', $edit, t('Save'));
+    $edit = array('field[settings][uri_scheme]' => 'private');
+    $this->drupalPost(NULL, $edit, t('Save field settings'));
+    $this->drupalPost(NULL, array(), t('Save settings'));
+
+    // Create node.
+    $text_file = $this->getTestFile('text');
+    $edit = array(
+      'title' => $this->randomName(),
+    );
+    $this->drupalPost('node/add/article', $edit, t('Save'));
+
+    // Add a comment with a file.
+    $text_file = $this->getTestFile('text');
+    $edit = array(
+      'files[field_' . $name . '_' . LANGUAGE_NONE . '_' . 0 . ']' => realpath($text_file->uri),
+      'comment_body[' . LANGUAGE_NONE . '][0][value]' => $comment_body = $this->randomName(),
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    // Get the comment ID.
+    preg_match('/comment-([0-9]+)/', $this->getUrl(), $matches);
+    $cid = $matches[1];
+
+    // Log in as normal user.
+    $this->drupalLogin($user);
+   
+    $comment = comment_load($cid);
+    $comment_file = (object) $comment->{'field_' . $name}[LANGUAGE_NONE][0];
+    $this->assertFileExists($comment_file, t('New file saved to disk on node creation.'));
+    // Test authenticated file download.
+    $url = file_create_url($comment_file->uri);
+    $this->assertNotEqual($url, NULL, t('Confirmed that the URL is valid'));
+    $this->drupalGet(file_create_url($comment_file->uri));
+    $this->assertResponse(200, t('Confirmed that the generated URL is correct by downloading the shipped file.'));
+ 
+    // Test anonymous file download.
+    $this->drupalLogout();
+    $this->drupalGet(file_create_url($comment_file->uri));
+    $this->assertResponse(403, t('Confirmed that acces is denied for the file without the needed permission.'));
+  }
+
 }
 
 /**
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.1291
diff -u -p -r1.1291 node.module
--- modules/node/node.module	22 Aug 2010 16:11:12 -0000	1.1291
+++ modules/node/node.module	23 Aug 2010 09:39:51 -0000
@@ -3763,3 +3763,13 @@ class NodeController extends DrupalDefau
     return $query;
   }
 }
+
+/**
+ * Implements hook_file_download_access().
+ */
+function node_file_download_access($field, $entity_type, $entity) {
+dsm($field);
+  if ($entity_type == 'node') {
+    return node_access('view', $entity);
+  }
+}
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.1194
diff -u -p -r1.1194 user.module
--- modules/user/user.module	22 Aug 2010 13:52:59 -0000	1.1194
+++ modules/user/user.module	23 Aug 2010 09:39:51 -0000
@@ -3684,3 +3684,12 @@ function user_rdf_mapping() {
     ),
   );
 }
+
+/**
+ * Implements hook_file_download_access().
+ */
+function user_file_download_access($field, $entity_type, $entity) {
+  if ($entity_type == 'user') {
+    return user_view_access($entity);
+  }
+}
