diff --git a/file_entity.module b/file_entity.module
index 484882b..f343f2f 100644
--- a/file_entity.module
+++ b/file_entity.module
@@ -117,8 +117,8 @@ function file_entity_menu() {
     // the menu router's title is overridden by a menu link.
     'page callback' => 'file_entity_view_page',
     'page arguments' => array(1),
-    'access callback' => 'file_entity_access',
-    'access arguments' => array('view'),
+    'access callback' => 'file_access',
+    'access arguments' => array('view', 1),
     'file' => 'file_entity.pages.inc',
   );
   $items['file/%file/view'] = array(
@@ -130,8 +130,8 @@ function file_entity_menu() {
     'title' => 'Edit',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('file_entity_edit', 1),
-    'access callback' => 'file_entity_access',
-    'access arguments' => array('edit'),
+    'access callback' => 'file_access',
+    'access arguments' => array('update', 1),
     'weight' => 0,
     'type' => MENU_LOCAL_TASK,
     'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
@@ -141,8 +141,8 @@ function file_entity_menu() {
     'title' => 'Delete',
     'page callback' => 'drupal_get_form',
     'page arguments'  => array('file_delete_form', 1),
-    'access callback' => 'file_entity_access',
-    'access arguments' => array('edit'),
+    'access callback' => 'file_access',
+    'access arguments' => array('delete', 1),
     'weight' => 1,
     'type' => MENU_LOCAL_TASK,
     'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
@@ -820,6 +820,199 @@ function file_entity_get_hidden_stream_wrappers() {
 }
 
 /**
+ * Return a specific stream wrapper's registry information.
+ * 
+ * @param $scheme
+ * A URI scheme, a stream is referenced as "scheme://target".
+ * 
+ * @see file_get_stream_wrappers()
+ */
+function file_get_stream_wrapper($scheme) {
+  $wrappers = file_get_stream_wrappers();
+  return isset($wrappers[$scheme]) ? $wrappers[$scheme] : FALSE;
+}
+
+/**
+ * Implements hook_stream_wrappers_alter().
+ */
+function file_entity_stream_wrappers_alter(&$wrappers) {
+  if (isset($wrappers['private'])) {
+    $wrappers['private']['private'] = TRUE;
+    }
+  if (isset($wrappers['temporary'])) {
+    $wrappers['temporary']['private'] = TRUE;
+    }
+}
+
+/**
+ * @defgroup file_access File access rights
+ * @{
+ * The file access system determines who can do what to which files.
+ * 
+ * In determining access rights for a file, file_access() first checks
+ * whether the user has the "bypass file access" permission. Such users have
+ * unrestricted access to all files. user 1 will always pass this check.
+ * 
+ * Next, all implementations of hook_file_access() will be called. Each
+ * implementation may explicitly allow, explicitly deny, or ignore the access
+ * request. If at least one module says to deny the request, it will be rejected.
+ * If no modules deny the request and at least one says to allow it, the request
+ * will be permitted.
+ * 
+ * There is no access grant system for files.
+ * 
+ * In file listings, the process above is followed except that
+ * hook_file_access() is not called on each file for performance reasons and for
+ * proper functioning of the pager system. When adding a filelisting to your
+ * module, be sure to use a dynamic query created by db_select() and add a tag
+ * of "file_access". This will allow modules dealing with file access to ensure
+ * only files to which the user has access are retrieved, through the use of
+ * hook_query_TAG_alter().
+ * 
+ * Note: Even a single module returning FILE_ACCESS_DENY from hook_file_access()
+ * will block access to the file. Therefore, implementers should take care to
+ * not deny access unless they really intend to. Unless a module wishes to
+ * actively deny access it should return FILE_ACCESS_IGNORE (or simply return
+ * nothing) to allow other modules to control access.
+ * 
+ * Stream wrappers that are considered private should implement a 'private'
+ * flag equal to TRUE in hook_stream_wrappers().
+ * 
+ * @todo Unify core's hook_file_download() as a 'download' op of file_access().
+ */
+
+/**
+ * Determine if a user may perform the given operation on the specified file.
+ * 
+ * @param $op
+ *  The operation to be performed on the file. Possible values are:
+ *  - "view"
+ *  - "update"
+ *  - "delete"
+ *  - "create"
+ * @param $file
+ *  The file object on which the operation is to be performed, or file type
+ *  (e.g. 'image') for "create" operation.
+ * @param $account
+ *  Optional, a user object representing the user for whom the operation is to
+ *  be performed. Determines access for a user other than the current user.
+ * 
+ * @return
+ *  TRUE if the operation may be performed, FALSE otherwise.
+ */
+function file_access($op, $file, $account = NULL) {
+  $rights = &drupal_static(__FUNCTION__, array());
+  if (!$file || !in_array($op, array('view', 'update', 'delete', 'create'), TRUE)) {
+    // If there was no file to check against, or the $op was not one of the
+    // supported ones, we return access denied.
+    return FALSE;
+    }
+
+    // If no user object is supplied, the access check is for the current user.
+  if (empty($account)) {
+    $account = $GLOBALS['user'];
+    }
+
+    // $file may be either an object or a file type. Since file types cannot be
+    // an integer, use either fid or type as the static cache id.
+    $cid = is_object($file) ? $file->fid : $file;
+
+    // If we've already checked access for this file, user and op, return from
+    // cache.
+    if (isset($rights[$account->uid][$cid][$op])) {
+      return $rights[$account->uid][$cid][$op];
+      }
+    if (user_access('bypass file access', $account)) {
+      return $rights[$account->uid][$cid][$op] = TRUE;
+      }
+
+    // We grant access to the file if both of the following conditions are met:
+    // - No modules say to deny access.
+    // - At least one module says to grant access.
+    $access = module_invoke_all('file_access', $op, $file, $account);
+    if (in_array(FILE_ACCESS_DENY, $access, TRUE)) {
+      return $rights[$account->uid][$cid][$op] = FALSE;
+      }
+      elseif (in_array(FILE_ACCESS_ALLOW, $access, TRUE)) {
+        return $rights[$account->uid][$cid][$op] = TRUE;
+        }
+
+    // Fall back to default behaviors on view.
+    if ($op == 'view' && is_object($file)) {
+      $scheme = file_uri_scheme($file->uri);
+      $wrapper = file_get_stream_wrapper($scheme);
+
+      if (!empty($wrapper['private'])) {
+        // For private files, users can view their own private files if the
+        // user is not anonymous, and has the 'view own private files' permission.
+
+        if (!empty($account->uid) && $file->uid == $account->uid && user_access('view own private files', $account)) {
+          return $rights[$account->uid][$cid][$op] = TRUE;
+        }
+      }
+      elseif ($file->status == FILE_STATUS_PERMANENT && user_access('view files')) {
+        // For non-private files, users can view if they have the 'view files'
+        // permission.
+        return $rights[$account->uid][$cid][$op] = TRUE;
+      }
+    }
+
+    return FALSE;
+}
+
+/**
+ * Implements hook_file_access().
+ */
+function file_entity_file_access($op, $file, $account) {
+  $type = is_string($file) ? $file : $file->type;
+  
+  // If the file URI is invalid, deny access.
+  if (is_object($file) && !file_valid_uri($file->uri)) {
+    return FILE_ACCESS_DENY;
+  }
+  if ($op == 'create') {
+    if (user_access('create files')) {
+      return FILE_ACCESS_ALLOW;
+    }
+  }
+  if ($op == 'update') {
+    if (user_access('edit any files', $account) || (user_access('edit own files', $account) && ($account->uid == $file->uid))) {
+      return FILE_ACCESS_ALLOW;
+    }
+  }
+  if ($op == 'delete') {
+    if (user_access('delete any files', $account) || (user_access('delete own files', $account) && ($account->uid == $file->uid))) {
+      return FILE_ACCESS_ALLOW;
+    }
+  }
+  
+  return FILE_ACCESS_IGNORE;
+}
+
+/**
+ * Implements hook_file_access() on behalf of system.module and private files.
+ */
+function system_file_access($op, $file, $account) {
+  if ($op == 'view' && file_uri_scheme($file->uri) == 'private') {
+    // When viewing private files, we can only invoke hook_file_download()
+    // if the $account user objet matches the current user.
+    if ($GLOBALS['user']->uid == $account->uid) {
+      foreach (module_implements('file_download') as $module) {
+        if (module_invoke($module, 'file_download', $file->uri) === -1) {
+          return FILE_ACCESS_DENY;
+        }
+      }
+    }
+  }
+
+return FILE_ACCESS_IGNORE;
+}
+
+/**
+ * @} End of "defgroup file_access".
+ */
+
+/**
  * Clear the field cache for any entities referencing a specific file.
  *
  * @param object $file
