OX Drive API

From Open-Xchange
Revision as of 15:35, 15 July 2015 by Jan.bauerdick (talk | contribs) (Drive API change)
OX Drive API

Introduction

The module drive is used to synchronize files and folders between server and client, using a server-centric approach to allow an easy implementation on the client-side.

The synchronization is based on checksums for files and folders, differences between the server- and client-side are determined using a three-way comparison of server, client and previously acknowledged file- and directory-versions. The synchronization logic is performed by the server, who instructs the client with a set of actions that should be executed in order to come to a synchronized state.

Therefore, the client takes a snapshot of it's local files and directories, calculates their checksums, and sends them as a list to the server, along with a list of previously acknowledged checksums. The server takes a similar snapshot of the files and directories on the underlying file storages and evaluates which further actions are necessary for synchronization. After executing the server-side actions, the client receives a list of actions that should be executed on the client-side. These steps are repeated until the server-state matches the client-state.

Key concept is that the synchronization works stateless, i.e. it can be interrupted and restarted at any time, following the eventual consistency model.

Entry point for the synchronization is the syncfolders request, where the directories are compared, and further actions are determined by the server, amongst others actions to synchronize the files in a specific directory using the syncfiles request. After executing the actions, the client should send another syncfolders request to the server and execute the returned actions (if present), or finish the synchronization if there are no more actions to execute. In pseudo-code, the synchronization routine could be implemented as follows:

WHILE TRUE
{
  response = SYNCFOLDERS()
  IF 0 == response.actions.length
    BREAK
  ELSE
    EXECUTE(response.actions)
}

Basically, it's up to the client how often such a synchronization cycle is initiated. For example, he could start a new synchronization cycle after a fixed interval, if he recognizes that the client directories have changed, or if he is informed that something has changed on the server by an event. It's also up to the client to interrupt the synchronization cycle at any time during execution of the actions and continue later on, however, it's recommended to start a new synchronization cycle each time to avoid possibly outdated actions.

API

As part of the HTTP API, the basic conventions for exchanging messages that described there are also valid for this case, especially the low level protocol and error handling. Each request against the Drive API assumes a valid server session that is uniquely identified by the session id and the corresponding cookies and are sent with each request. A new session can be created via the login module.

The root folder plays another important role for the message exchange. The root folder has a unique identifier. It is the parent server folder for the synchronization. All path details for directories and files are relative to this folder. This folder's id is sent with each request. To select the root folder during initial client configuration, the client may get a list of synchronizable folders with the subfolders action.

Subsequently all transferred objects and all possible actions are listed.

File Version

A file in a directory is uniquely identified by its filename and the checksum of its content.

File Version
Name Type Value
name String The name of the file, including its extension, e.g. test.doc.
checksum String The MD5 hash of the file, expressed as a lowercase hexadecimal number string, 32 characters long, e.g. f8cacac95379527cd4fa15f0cb782a09.

Directory Version

A directory is uniquely identified by its full path, relative to the root folder, and the checksum of its content.

Directory Version
Name Type Value
path String The path of the directory, including the directory's name, relative to the root folder, e.g. /sub/test/letters.
checksum String The MD5 hash of the directory, expressed as a lowercase hexadecimal number string, 32 characters long, e.g. f8cacac95379527cd4fa15f0cb782a09.

Note: the checksum of a directory is calculated based on its contents in the following algorithm:

  • Build a list containing each file in the directory (not including subfolders or files in subfolders)
  • Ensure a lexicographically order in the following way:
    • Normalize the filename using the NFC normalization form (canonical decomposition, followed by canonical composition) - see http://www.unicode.org/reports/tr15/tr15-23.html for details
    • Encode the filename to an array of UTF-8 unsigned bytes (array of codepoints)
    • Compare the filename (encoded as byte array "fn1") to another one "fn2" using the following comparator algorithm:
min_length = MIN(LENGTH(fn1), LENGTH(fn2))
FOR i = 0; i < min_length; i++ 
{
  result = fn1[i] - fn2[i]
  IF 0 != result RETURN result
}
RETURN LENGTH(fn1) - LENGTH(fn2)
  • Calculate the aggregated MD5 checksum for the directory based on each file in the ordered list:
    • Append the file's NFC-normalized (see above) name, encoded as UTF-8 bytes
    • Append the file's MD5 checksum string, encoded as UTF-8 bytes

Actions

All actions are encoded in the following format. Depending on the action type, not all properties may be present.

Actions
Name Type Value
action String The type of action to execute, currently one of acknowledge, edit, download, upload, remove, sync, error.
version Object The (original) file- or directory-version referenced by the action.
newVersion Object The (new) file- or directory-version referenced by the action.
path String The path to the synchronized folder, relative to the root folder.
offset Number The requested start offset in bytes for file uploads.
totalLength Number The total length in bytes for file downloads.
contentType String The file's content type for downloads.
created Timestamp The file's creation time (always UTC, not translated into user time).
modified Timestamp The file's last modification time (always UTC, not translated into user time).
error Object The error object in case of synchronization errors.
quarantine Boolean The flag to indicate whether versions need to be excluded from synchronization.
reset Boolean The flag to indicate whether locally stored checksums should be invalidated.
stop Boolean The flag to signal that the client should stop the current synchronizsation cycle.
acknowledge Boolean The flag to signal if the client should not update it's stored checksums when performing an EDIT action.
thumbnailLink String A direct link to a small thumbnail image of the file if available (deprecated, available until API version 2).
previewLink String A direct link to a medium-sized preview image of the file if available (deprecated, available until API version 2).
directLink String A direct link to the detail view of the file in the web interface (deprecated, available until API version 2).
directLinkFragments String The fragments part of the direct link (deprecated, available until API version 2).

The following list gives an overview about the used action types:

acknowledge

Acknowledges the successful synchronization of a file- or directory version, i.e., the client should treat the version as synchronized by updating the corresponding entry in its metadata store and including this updated information in all following originalVersions arrays of the syncfiles / syncfolders actions. Depending on the version and newVersion parameters of the action, the following acknowledge operations should be executed (exemplarily for directory versions, file versions are acknowledged in the same way):

  • Example 1: Acknowledge a first time synchronized directory
    The server sends an acknowledge action where the newly synchronized directory version is encoded in the newVersion parameter. The client should store the version in his local checksum store and send this version in the originalVersions array in upcoming syncfolders requests.
{
  "action" : "acknowledge",
  "newVersion" : {
     "path" : "/",
     "checksum" : "d41d8cd98f00b204e9800998ecf8427e"
  }
}
  • Example 2: Acknowledge a synchronized directory after updates
    The server sends an acknowledge action where the previous directory version is encoded in the version, and the newly synchronized directory in the newVersion parameter. The client should replace any previously stored entries of the directory version in his local checksum store with the updated version, and send this version in the originalVersions array in upcoming syncfolders requests.
{
  "action" : "acknowledge",
  "newVersion" : {
    "path" : "/",
    "checksum" : "7bb1f1a550e9b9ab4be8a12246f9d5fb"
  },
  "version" : {
    "path" : "/",
    "checksum" : "d41d8cd98f00b204e9800998ecf8427e"
  }
}
  • Example 3: Acknowledge the deletion of a previously synchronized directory
    The server sends an acknowledge where the newVersion parameter is set to null to acknowledge the deletion of the previously synchronized directory version as found in the version parameter. The client should remove any stored entries for this directory from his local checksum store, and no longer send this version in the originalVersions array in upcoming syncfolders requests.
    Note that an acknowledged deletion of a directory implicitly acknowledges the deletion of all contained files and subfolders, too, so the client should also remove those originalVersions from his local checksum store.
{
  "action" : "acknowledge",
  "version" : {
    "path" : "/test",
    "checksum" : "3525d6f28eb8cb30eb61ab7932367c35"
  }
}

edit

Instructs the client to edit a file- or directory version. This is used for move/rename operations. The version parameter is set to the version as sent in the clientVersions array of the preceding syncfiles/syncfolders action. The newVersion contains the new name/path the client should use. Unless the optional boolean parameter acknowledge is set to false an edit action implies that the client updates its known versions store accordingly, i.e. removes the previous entry for version and adds a new entry for newVersion. When editing a directory version, the client should implicitly take care to create any not exisiting subdirectories in the path of the newVersion parameter. A concurrent client-side modification of the file/directory version can be detected by the client by comparing the current checksum against the one in the passed newVersion parameter.

  • Example 1: Rename a file
    The server sends an edit action where the source file is encoded in the version, and the target file in the newVersion parameter. The client should rename the file identified by the version parameter to the name found in the newVersion parameter. Doing so, the stored checksum entry for the file in version should be updated, too, to reflect the changes.
{
  "path" : "/",
  "action" : "edit",
  "newVersion" : {
    "name" : "test_1.txt",
    "checksum" : "03395a94b57eef069d248d90a9410650"
  },
  "version" : {
    "name" : "test.txt",
    "checksum" : "03395a94b57eef069d248d90a9410650"
  }
}
  • Example 2: Move a directory
    The server sends an edit action where the source directory is encoded in the version, and the target directory in the newVersion parameter. The client should move the directory identified by the version parameter to the path found in the newVersion parameter. Doing so, the stored checksum entry for the directory in version should be updated, too, to reflect the changes.
{
  "action" : "edit",
  "newVersion" : {
    "path" : "/test2",
    "checksum" : "3addd6de801f4a8650c5e089769bdb62"
  },
  "version" : {
    "path" : "/test1/test2",
    "checksum" : "3addd6de801f4a8650c5e089769bdb62"
  }
}
  • Example 3: Rename a conflicting file
    The server sends an edit action where the original client file is encoded in the version, and the target filename in the newVersion parameter. The client should rename the file identified by the version parameter to the new filename found in the newVersion parameter. If the acknowledge parameter is set to true or is not set, the stored checksum entry for the file in version should be updated, too, to reflect the changes, otherwise, as in this example, no changes should be done to the stored checksums.
{
  "action" : "edit",
  "version" : {
    "checksum" : "fade32203220752f1fa0e168889cf289",
    "name" : "test.txt"
  },
  "newVersion" : {
    "checksum" : "fade32203220752f1fa0e168889cf289",
    "name" : "test (TestDrive).txt"
  },
  "acknowledge" : false,
  "path" : "/"
}

download

Contains information about a file version the client should download. For updates of existing files, the previous client version is supplied in the version parameter. For new files, the version parameter is omitted. The newVersion holds the target file version, i.e. filename and checksum, and should be used for the following download request. The totalLength parameter is set to the file size in bytes, allowing the client to recognize when a download is finished. Given the supplied checksum, the client may decide on its own if the target file needs to be downloaded from the server, or can be created by copying a file with the same checksum to the target location, e.g. from a trash folder. The file's content type can be retrieved from the contentType parameter, similar to the file's creation and modification times that are availble in the created and modified parameters.

  • Example 1: Download a new file
    The server sends a download action where the file version to download is encoded in the newVersion paramter. The client should download and save the file as indicated by the name property of the newVersion in the directory identified by the supplied path. After downloading, the newVersion should be added to the client's known file versions database.
{
  "totalLength" : 536453,
  "path" : "/",
  "action" : "download",
  "newVersion" : {
    "name" : "test.pdf",
    "checksum" : "3e0d7541b37d332c42a9c3adbe34aca2"
  },
  "contentType" : "application/pdf",
  "created" : 1375276738232,
  "modified" : 1375343720985
}
  • Example 2: Download an updated file
    The server sends a download action where the previous file version is encoded in the version, and the file version to download in the newVersion parameter. The client should download and save the file as indicated by the name property of the newVersion in the directory identified by the supplied path, replacing the previous file. After downloading, the newVersion should be added to the client's known file versions database, replacing an existing entry for the previous version.
{
  "totalLength" : 1599431,
  "path" : "/",
  "action" : "download",
  "newVersion" : {
    "name" : "test.pdf",
    "checksum" : "bb198790904f5a1785d7402b0d8c390e"
  },
  "contentType" : "application/pdf",
  "version" : {
    "name" : "test.pdf",
    "checksum" : "3e0d7541b37d332c42a9c3adbe34aca2"
  },
  "created" : 1375276738232,
  "modified" : 1375343720985
}

upload

Instructs the client to upload a file to the server. For updates of existing files, the previous server version is supplied in the version parameter, and should be used for the following upload request. For new files, the version parameter is omitted. The newVersion holds the target file version, i.e. filename and checksum, and should be used for the following upload request. When resuming a previously partly completed upload, the offset parameter contains the offset in bytes from which the file version should be uploaded by the client. If possible, the client should set the contentType parameter for the uploaded file, otherwise, the content type falls back to application/octet-stream.

remove

Instructs the client to delete a file or directory version. The version parameter contains the version to delete. A deletion also implies a removal of the corresponding entry in the client's known versions store. A concurrent client-side modification of the file/directory version can be detected by comparing the current checksum against the one in the passed version parameter.

  • Example 1: Remove a file
    The server sends a remove action where the file to be removed is encoded as version parameter. The newVersion parameter is not set in the action. The client should delete the file identified by the version parameter. A stored checksum entry for the file in version should be removed, too, to reflect the changes. The newVersion parameter is not set in the action.
{
  "path" : "/test2",
  "action" : "remove",
  "version" : {
    "name" : "test.txt",
    "checksum" : "03395a94b57eef069d248d90a9410650"
  }
}
  • Example 2: Remove a directory
    The server sends a remove action where the directory to be removed is encoded as version parameter. The newVersion parameter is not set in the action. The client should delete the directory identified by the version parameter. A stored checksum entry for the directory in version should be removed, too, to reflect the changes.
{
  "action" : "remove",
  "version" : {
    "path" : "/test1",
    "checksum" : "d41d8cd98f00b204e9800998ecf8427e"
  }
}

sync

The client should trigger a synchronization of the files in the directory supplied in the version parameter using the syncfiles request. A sync action implies the client-side creation of the referenced directory if it not yet exists, in case of a new directory on the server. \\ If the version parameter is not specified, a synchronization of all folders using the syncfolders request should be initiated by the client. \\ If the reset flag in the SYNC action is set to true, the client should reset his local state before synchronizing the files in the directory. This may happen when the server detects a synchronization cycle, or believes something else is going wrong. Reset means that the client should invalidate any stored original checksums for the directory itself and any contained files, so that they get re-calculated upon the next synchronization. If the reset flag is set in a SYNC action without a apecific directory version, the client should invalidate any stored checksums, so that all file- and directory-versions get re-calculated during the following synchronizations.

  • Example 1: Synchronize folder
    The server sends a sync action with a version. The client should trigger a syncfiles request for the specified folder.
{
  "action": "sync",
  "version": {
    "path": "<folder>",
    "checksum": "<md5>"
  }
}
  • Example 2: Synchronize all folders
    The server sends a sync action without version (or version is //null//). The client should trigger a syncfolder request, i.e. the client should synchronize all folders.
{
  "action": "sync",
  "version": null
}

error

With the error action, file- or directory versions causing a synchronization problem can be identified. The root cause of the error is encoded in the error parameter as described at the HTTP API.

Basically, there are two scenarios where either the errorneous version affects the synchronization state or not. For example, a file that was deleted at the client without sufficient permissions on the server can just be downloaded again by the client, and afterwards, client and server are in-sync again. On the other hand, e.g. when creating a new file at the client and this file can't be uploaded to the server due to missing permissions, the client is out of sync as long as the file is present. Therefore, the boolean parameter quarantine instructs the client whether the file or directory version must be excluded from the synchronization or not. If it is set to true, the client should exclude the version from the clientVersions array, and indicate the issue to the enduser. However, if the synchronization itself is not affected and the quarantine flag is set to false, the client may still indicate the issue once to the user in the background, e.g. as a balloontip notification.

The client may reset it's quarantined versions on it's own, e.g. if the user decides to "try again", or automatically after a configurable interval.

The server may also decide that further synchronization should be suspended, e.g. in case of repeated synchronization problems. Such a situation is indicated with the parameter stop set to true. In this case, the client should at least cancel the current synchronization cycle. If appropriate, the client should also be put into a 'paused' mode, and the user should be informed accordingly.

There may also be situations where a error or warning is sent to the client, independently of a file- or directory version, e.g. when the client version is outdated and a newer version is available for download.

The most common examples for errors are insufficient permissions or exceeded quota restrictions, see examples below.

  • Example 1: Create a file in a read-only folder
    The server sends an error action where the errorneous file is encoded in the newVersion parameter and the quarantine flag is set to true. The client should exclude the version from the clientVersions array in upcoming syncFiles requests so that it doesn't affect the synchronization algorithm. The error message and further details are encoded in the error object of the action.
{
  "error" : {
    "category" : 3,
    "error_params" : ["/test"],
    "error" : "You are not allowed to create files at \"/test\"",
    "error_id" : "1358320776-69",
    "categories" : "PERMISSION_DENIED",
    "code" : "DRV-0012"
  },
  "path" : "/test",
  "quarantine" : true,
  "action" : "error",
  "newVersion" : {
    "name" : "test.txt",
    "checksum" : "3f978a5a54cef77fa3a4d3fe9a7047d2"
  }
}
  • Example 2: Delete a file without sufficient permissions
    Besides a new download action to restore the locally deleted file again, the server sends an error action where the errorneous file is encoded in the version parameter and the quarantine flag is set to false. Further synchronizations are not affected, but the client may still inform the user about the rejected operation. The error message and further details are encoded in the error object of the action.
{
  "error" : {
    "category" : 3,
    "error_params" : ["test.png", "/test"],
    "error" : "You are not allowed to delete the file \"test.png\" at \"/test\"",
    "error_id" : "1358320776-74",
    "categories" : "PERMISSION_DENIED",
    "code" : "DRV-0011"
  },
  "path" : "/test",
  "quarantine" : false,
  "action" : "error",
  "newVersion" : {
    "name" : "test.png",
    "checksum" : "438f06398ce968afdbb7f4db425aff09"
  }
}
  • Example 3: Upload a file that exceeds the quota
    The server sends an error action where the errorneous file is encoded in the newVersion parameter and the quarantine flag is set to true. The client should exclude the version from the clientVersions array in upcoming syncFiles requests so that it doesn't affect the synchronization algorithm. The error message and further details are encoded in the error object of the action.
{
  "error" : {
    "category" : 3,
    "error_params" : [],
    "error" : "The allowed Quota is reached",
    "error_id" : "-485491844-918",
    "categories" : "PERMISSION_DENIED",
    "code" : "DRV-0016"
  },
  "path" : "/",
  "quarantine" : true,
  "action" : "error",
  "newVersion" : {
    "name" : "test.txt",
    "checksum" : "0ca6033e2a9c2bea1586a2984bf111e6"
  }
}
  • Example 4: Synchronize with a client where the version is no longer supported.
    The server sends an error action with code DRV-0028 and an appropriate error message. The stop flag is set to true to interrupt the synchronization cycle.
{
  "stop" : true,
  "error" : {
    "category" : 13,
    "error_params" : [],
    "error" : "The client application you're using is outdated and no longer supported - please upgrade to a newer version.",
    "error_id" : "103394512-13",
    "categories" : "WARNING",
    "code" : "DRV-0028",
    "error_desc" : "Client outdated - current: \"0.9.2\", required: \"0.9.10\""
  },
  "quarantine" : false,
  "action" : "error"
}
  • Example 5: Synchronize with a client where a new version of the client application is available.
    The server sends an error action with code DRV-0029 and an appropriate error message. The stop flag is set to false to indicate that the synchronization can continue.
{
  "stop" : false,
  "error" : {
    "category" : 13,
    "error_params" : [],
    "error" : "A newer version of your client application is available for download.",
    "error_id" : "103394512-29",
    "categories" : "WARNING",
    "code" : "DRV-0029",
    "error_desc" : "Client update available - current: \"0.9.10\", available: \"0.9.12\""
  },
  "quarantine" : false,
  "action" : "error"
}

Synchronize folders

This request performs the synchronization of all folders, resulting in different actions that should be executed on the client afterwards. This operation typically serves as an entry point for a synchronization cycle.

PUT /ajax/drive?action=syncfolders

Parameters:

  • session - A session ID previously obtained from the login module.
  • root - The ID of the referenced root folder on the server.
  • version - The current client version (matching the pattern ^[0-9]+(\\.[0-9]+)*$). If not set, the initial version 0 is assumed.
  • apiVersion - The API version that the client is using. If not set, the initial version 0 is assumed.
  • diagnostics (optional) - If set to true, an additional diagnostics trace is supplied in the response.
  • pushToken (optional) - The client's push registration token to associate it to generated events.

Request Body:
A JSON object containing two JSON arrays named clientVersions and originalVersions. The client versions array lists all current directories below the root directory as a flat list, encoded as Directory Versions. The original versions array contains all previously known directories, i.e. all previously synchronized and acknowledged directories, also encoded as Directory Versions. \\ Optionally, available since API version 2, the JSON object may also contain two arrays named fileExclusions and directoryExclusions to define client-side exclusion filters, with each element encoded as File patterns and Directory patterns accordingly. See #Client_side_filtering for details.

Response:
A JSON array containing all actions the client should execute for synchronization. Each array element is an action as described in Actions.
If the diagnostics flag was set (either to true or false), this array is wrapped into an additional JSON object in the actions parameter, and the diagnostics trace is provided at diagnostics.

Example:

==> PUT http://192.168.32.191/ajax/drive?action=syncfolders&root=56&session=5d0c1e8eb0964a3095438b450ff6810f
  > Content:
    {
      "clientVersions" : [{
          "path" : "/",
          "checksum" : "7b744b13df4b41006495e1a15327368a"
        }, {
          "path" : "/test1",
          "checksum" : "3ecc97334d7f6bf2b795988092b8137e"
        }, {
          "path" : "/test2",
          "checksum" : "56534fc2ddcb3b7310d3ef889bc5ae18"
        }, {
          "path" : "/test2/test3",
          "checksum" : "c193fae995d9f9431986dcdc3621cd98"
        }
      ],
      "originalVersions" : [{
          "path" : "/",
          "checksum" : "7b744b13df4b41006495e1a15327368a"
        }, {
          "path" : "/test2/test3",
          "checksum" : "c193fae995d9f9431986dcdc3621cd98"
        }, {
          "path" : "/test2",
          "checksum" : "35d1b51fdefbee5bf81d7ae8167719b8"
        }, {
          "path" : "/test1",
          "checksum" : "3ecc97334d7f6bf2b795988092b8137e"
        }
      ]
    }
  
<== HTTP 200 OK (8.0004 ms elapsed, 102 bytes received)
<   Content: 
    {
      "data" : [{
          "action" : "sync",
          "version" : {
            "path" : "/test2",
            "checksum" : "56534fc2ddcb3b7310d3ef889bc5ae18"
          }
        }
      ]
    }

Example 2:

==> PUT http://192.168.32.191/ajax/drive?action=syncfolders&root=56&session=5d0c1e8eb0964a3095438b450ff6810f
  > Content:
    {
      "clientVersions" : [{
          "path" : "/",
          "checksum" : "7b744b13df4b41006495e1a15327368a"
        }, {
          "path" : "/test1",
          "checksum" : "3ecc97334d7f6bf2b795988092b8137e"
        }, {
          "path" : "/test2",
          "checksum" : "56534fc2ddcb3b7310d3ef889bc5ae18"
        }, {
          "path" : "/test2/test3",
          "checksum" : "c193fae995d9f9431986dcdc3621cd98"
        }
      ],
      "originalVersions" : [{
          "path" : "/",
          "checksum" : "7b744b13df4b41006495e1a15327368a"
        }, {
          "path" : "/test2/test3",
          "checksum" : "c193fae995d9f9431986dcdc3621cd98"
        }, {
          "path" : "/test2",
          "checksum" : "35d1b51fdefbee5bf81d7ae8167719b8"
        }, {
          "path" : "/test1",
          "checksum" : "3ecc97334d7f6bf2b795988092b8137e"
        }
      ]
      "fileExclusions" : [{
          "path" : "/",
          "name" : "excluded.txt",
          "type" : "exact"
        }
      ], "directoryExclusions" : [{
          "path" : "/temp",
          "type" : "exact"
        }, {
          "path" : "/temp/*",
          "type" : "glob"
        }
      ]
    }
  
<== HTTP 200 OK (8.0004 ms elapsed, 102 bytes received)
<   Content: 
    {
      "data" : [{
          "action" : "sync",
          "version" : {
            "path" : "/test2",
            "checksum" : "56534fc2ddcb3b7310d3ef889bc5ae18"
          }
        }
      ]
    }


Synchronize files in a folder

This request performs the synchronization of a single folder, resulting in different actions that should be executed on the client afterwards. This action is typically executed as result of a syncfolders action.

PUT /ajax/drive?action=syncfiles

Parameters:

  • session - A session ID previously obtained from the login module.
  • root - The ID of the referenced root folder on the server.
  • path - The path to the synchronized folder, relative to the root folder.
  • device (optional) - A friendly name identifying the client device from a user's point of view, e.g. "My Tablet PC".
  • apiVersion - The API version that the client is using. If not set, the initial version 0 is assumed.
  • diagnostics (optional) - If set to true, an additional diagnostics trace is supplied in the response.
  • columns (optional) - A comma-separated list of columns representing additional metadata that is relevant for the client. Each column is specified by a numeric column identifier. Column identifiers for file metadata are defined in #File Metadata. If available, the requested metadata of files is included in the corresponsing DOWNLOAD and ACKNOWLEDGE actions (deprecated, available until API version 2).
  • pushToken (optional) - The client's push registration token to associate it to generated events.

Request Body:
A JSON object containing two JSON arrays named clientVersions and originalVersions. The client versions array lists all current files in the client directory, encoded as File Versions. The original versions array contains all previously known files, i.e. all previously synchronized and acknowledged files, also encoded as File Versions. \\ Optionally, available since API version 2, the JSON object may also contain an array named fileExclusions to define client-side exclusion filters, with each element encoded as File patterns. See #Client side filtering for details.

Response:
A JSON array containing all actions the client should execute for synchronization. Each array element is an action as described in Actions.
If the diagnostics flag was set (either to true or false), this array is wrapped into an additional JSON object in the actions parameter, and the diagnostics trace is provided at diagnostics.

Example:

==> PUT http://192.168.32.191/ajax/drive?action=syncfiles&root=56&path=/test2&device=Laptop&session=5d0c1e8eb0964a3095438b450ff6810f
  > Content: 
    {
      "clientVersions" : [{
          "name" : "Jellyfish.jpg",
          "checksum" : "5a44c7ba5bbe4ec867233d67e4806848"
        }, {
          "name" : "Penguins.jpg",
          "checksum" : "9d377b10ce778c4938b3c7e2c63a229a"
        }
      ],
      "originalVersions" : [{
          "name" : "Jellyfish.jpg",
          "checksum" : "5a44c7ba5bbe4ec867233d67e4806848"
        }
      ]
    }

<== HTTP 200 OK (6.0004 ms elapsed, 140 bytes received)
<   Content:
    {
      "data" : [{
          "path" : "/test2",
          "action" : "upload",
          "newVersion" : {
            "name" : "Penguins.jpg",
            "checksum" : "9d377b10ce778c4938b3c7e2c63a229a"
          },
          "offset" : 0
        }
      ]
    }

Example 2:

==> PUT http://192.168.32.191/ajax/drive?action=syncfiles&root=56&path=/test2&device=Laptop&session=5d0c1e8eb0964a3095438b450ff6810f
  > Content: 
    {
      "clientVersions" : [{
          "name" : "Jellyfish.jpg",
          "checksum" : "5a44c7ba5bbe4ec867233d67e4806848"
        }, {
          "name" : "Penguins.jpg",
          "checksum" : "9d377b10ce778c4938b3c7e2c63a229a"
        }
      ],
      "originalVersions" : [{
          "name" : "Jellyfish.jpg",
          "checksum" : "5a44c7ba5bbe4ec867233d67e4806848"
        }
      ]
      "fileExclusions" : [{
          "path" : "*",
          "name" : "*.tmp",
          "type" : "glob"
        }
      ]
    }

<== HTTP 200 OK (6.0004 ms elapsed, 140 bytes received)
<   Content:
    {
      "data" : [{
          "path" : "/test2",
          "action" : "upload",
          "newVersion" : {
            "name" : "Penguins.jpg",
            "checksum" : "9d377b10ce778c4938b3c7e2c63a229a"
          },
          "offset" : 0
        }
      ]
    }

Download a file

Downloads a file from the server.

GET /ajax/drive?action=download

or

PUT /ajax/drive?action=download

Parameters:

  • session - A session ID previously obtained from the login module.
  • root - The ID of the referenced root folder on the server.
  • path - The path to the synchronized folder, relative to the root folder.
  • name - The name of the file version to download.
  • checksum - The checksum of the file version to download.
  • apiVersion - The API version that the client is using. If not set, the initial version 0 is assumed.
  • offset (optional) - The start offset in bytes for the download. If not defined, an offset of 0 is assumed.
  • length (optional) - The number of bytes to include in the download stream. If not defined, the file is read until the end.

Request Body:
Optionally, available since API version 3, if client-side file- and/or directory exclusion filters are active, a PUT request can be used. The request body then holds a JSON object containing two arrays named fileExclusions and directoryExclusions to define client-side exclusion filters, with each element encoded as File patterns and Directory patterns accordingly. See Client side filtering for details.

Response:
The binary content of the requested file version. Note that in case of errors, an exception is not encoded in the default JSON error format here. Instead, an appropriate HTTP error with a status code != 200 is returned. For example, in case of the requested file being deleted or modified in the meantime, a response with HTTP status code 404 (not found) is sent.

Example:

==> GET http://192.168.32.191/ajax/drive?action=download&root=56&path=/test2&name=Jellyfish.jpg&checksum=5a44c7ba5bbe4ec867233d67e4806848&offset=0&length=-1&session=5d0c1e8eb0964a3095438b450ff6810f

<== HTTP 200 OK (20.0011 ms elapsed, 775702 bytes received)

Upload a file

Uploads a file to the server.

PUT /ajax/drive?action=upload

Parameters:

  • session - A session ID previously obtained from the login module.
  • root - The ID of the referenced root folder on the server.
  • path - The path to the synchronized folder, relative to the root folder.
  • newName - The target name of the file version to upload.
  • newChecksum - The target checksum of the file version to upload.
  • name (optional) - The previous name of the file version being uploaded. Only set when uploading an updated version of an existing file to the server.
  • checksum - The previous checksum of the file version to upload. Only set when uploading an updated version of an existing file to the server.
  • apiVersion - The API version that the client is using. If not set, the initial version 0 is assumed.
  • contentType (optional) - The content type of the file. If not defined, application/octet-stream is assumed.
  • offset (optional) - The start offset in bytes for the upload when resuming a previous partial upload. If not defined, an offset of 0 is assumed.
  • totalLength (optional) - The total expected length of the file (required to support resume of uploads). If not defined, the upload is assumed completed after the operation.
  • created (optional) - The creation time of the file as timestamp.
  • modified (optional) - The last modification time of the file as timestamp. Defaults to the current server time if no value or a value larger than the current time is supplied.
  • binary - Expected to be set to true to indicate the binary content.
  • device (optional) - A friendly name identifying the client device from a user's point of view, e.g. "My Tablet PC".
  • diagnostics (optional) - If set to true, an additional diagnostics trace is supplied in the response.
  • pushToken (optional) - The client's push registration token to associate it to generated events.

Request body:
The binary content of the uploaded file version.

Response:
A JSON array containing all actions the client should execute for synchronization. Each array element is an action as described in Actions.
If the diagnostics flag was set (either to true or false), this array is wrapped into an additional JSON object in the actions parameter, and the diagnostics trace is provided at diagnostics.

Example:

==> PUT http://192.168.32.191/ajax/drive?action=upload&root=56&path=/test2&newName=Penguins.jpg&newChecksum=9d377b10ce778c4938b3c7e2c63a229a&contentType=image/jpeg&offset=0&totalLength=777835&binary=true&device=Laptop&created=1375343426999&modified=1375343427001&session=5d0c1e8eb0964a3095438b450ff6810f
  > Content: 
    [application/octet-stream;, 777835 bytes]

<== HTTP 200 OK (108.0062 ms elapsed, 118 bytes received)
<   Content: 
    {
      "data" : [{
          "action" : "acknowledge",
          "newVersion" : {
            "name" : "Penguins.jpg",
            "checksum" : "9d377b10ce778c4938b3c7e2c63a229a"
          }
        }
      ]
    }

Listen for changes (long polling)

Listens for server-side changes. The request blocks until new actions for the client are available, or the specified waiting time elapses. May return immediately if previously received but not yet processed actions are available for this client.

GET /ajax/drive?action=listen

Parameters:

  • session - A session ID previously obtained from the login module.
  • root - The ID of the referenced root folder on the server.
  • timeout (optional) - The maximum timeout in milliseconds to wait.
  • pushToken (optional) - The client's push registration token to associate it to generated events.

Response:
A JSON array containing all actions the client should execute for synchronization. Each array element is an action as described in Actions. If there no changes were detected, an empty array is returned. Typically, the client will continue with the next listen request after the response was processed.

Example:

==> GET http://192.168.32.191/ajax/drive?action=listen&root=65841&session=51378e29f82042b4afe4af1c034c6d68

<== HTTP 200 OK (63409.6268 ms elapsed, 28 bytes received)
<   Content: 
    {
      "data" : [{
          "action" : "sync",
        }
      ]
    }

Get quota

Gets the quota limits and current usage for the storage the supplied root folder belongs to. Depending on the filestore configuration, this may include both restrictions on the number of allowed files and the total size of all contained files in bytes. If there's no limit, -1 is returned.

GET /ajax/drive?action=quota

Parameters:

  • session - A session ID previously obtained from the login module.
  • root - The ID of the referenced root folder on the server.

Response:
A JSON object containing the quota restrictions inside a JSON array with the property name quota. The JSON array contains zero, one or two quota objects as described below, depending on the filestore configuration. If one or more quota types are missing in the array, the client can expect that there are no limitations for that type. Besides the array, the JSON object also contains a hyperlink behind the manageLink parameter, pointing to an URL where the user could manage his quota restrictions.

Quota
Name Type Value
limit Number The allowed limit (either number of files or sum of filesizes in bytes).
use Number The current usage (again either number of files or sum of filesizes in bytes).
type String The kind of quota restriction, currently either storage (size of contained files in bytes) or file (number of files).

Example:

==> GET http://192.168.32.191/ajax/drive?action=quota&root=56&session=35cb8c2d1423480692f0d5053d14ba52
  
<== HTTP 200 OK (9.6854 ms elapsed, 113 bytes received)
<   Content: 
    {
      "data" : {
        "quota" : [{
            "limit" : 107374182400,
            "use" : 1109974882,
            "type" : "storage"
          }, {
            "limit" : 800000000000,
            "use" : 1577,
            "type" : "file"
          }
        ],
        "manageLink" : "https://www.example.com/manageQuota"
      }
    }

Get Settings

Gets various settings applicable for the drive clients.

GET /ajax/drive?action=settings

Parameters:

  • session - A session ID previously obtained from the login module.
  • root - The ID of the referenced root folder on the server.
  • language (optional) - The locale to use for language-sensitive settings (in the format <2-letter-language>_<2-letter-region>, e.g. de_CH or en_GB). Defaults to the user's configured locale on the server.

Response:
A JSON object holding the settings as described below. This also includes a JSON array with the property name quota that contains zero, one or two quota objects as described below, depending on the filestore configuration. If one or more quota types are missing in the array, the client can expect that there are no limitations for that type.

Quota
Name Type Value
limit Number The allowed limit (either number of files or sum of filesizes in bytes).
use Number The current usage (again either number of files or sum of filesizes in bytes).
type String The kind of quota restriction, currently either storage (size of contained files in bytes) or file (number of files).
Settings
Name Type Value
helpLink String A hyperlink to the online help.
quotaManageLink String A hyperlink to an URL where the user could manage his quota restrictions.
quota Array A JSON array containing the quota restrictions as described above.
serverVersion String The server version string.
supportedApiVersion String The API version supported by the server.
minApiVersion String The API version required to synchronize with the server.

Example:

==> GET http://192.168.32.191/ajax/drive?action=settings&root=56&session=35cb8c2d1423480692f0d5053d14ba52
  
<== HTTP 200 OK (11.3530 ms elapsed, 318 bytes received)
<   Content: 
    {
      "data" : {
        "quota" : [{
            "limit" : 107374182400,
            "use" : 8828427,
            "type" : "storage"
          }, {
            "limit" : 800000000000,
            "use" : 1559,
            "type" : "file"
          }
        ],
        "helpLink" : "http://192.168.32.191/ajax/help/en_US/index.html",
        "quotaManageLink" : "https://192.168.32.191/manageQuota",
        "serverVersion" : "7.4.2-Rev1",
        "supportedApiVersion" : "2",
        "minApiVersion" : "1"
      }
    }

Subscribe to Push-Events

Registers a client device to receive push notifications from the server. The subscription is performed based on the configured root folder ID of the client application that identifies itself with it's device token. Supported services currently include the Apple Push Notification Service (APN) and Google Cloud Messaging (GCM). Trying to perform an identical subscription (same root, service and token) from the same user account again is treated as a no-op.

GET /ajax/drive?action=subscribe

Parameters:

  • session - A session ID previously obtained from the login module.
  • root - The ID of the referenced root folder on the server.
  • service - The name of the underlying push service to use, currently one of gcm, apn or apn.macos.
  • token - The device's registration token as assigned by the service.

Response:
An empty JSON result.

Example:

==> GET http://192.168.32.191/ajax/drive?action=subscribe&root=65841&session=51378e29f82042b4afe4af1c034c6d68&service=apn&token=28919862989a1b5ba59c11d5f7cb7ba2b9678be9dd18b033184d04f682013677

<== HTTP 200 OK (13.6268 ms elapsed, 11 bytes received)
<   Content: 
    {
      "data" : {
      }
    }


Unsubscribe from Push-Events

Unregisters a previously registered client device to stop receiving push notifications from the server. The same parameters that were used to perform the subscription need to be passed again, which includes the root folder ID, the device token and the service name.

GET /ajax/drive?action=unsubscribe

Parameters:

  • session - A session ID previously obtained from the login module.
  • root - The ID of the referenced root folder on the server.
  • service - The name of the underlying push service to use, currently one of gcm, apn or apn.macos.
  • token - The device's registration token as assigned by the service.

Response:
An empty JSON result.

Example:

==> GET http://192.168.32.191/ajax/drive?action=unsubscribe&root=65841&session=51378e29f82042b4afe4af1c034c6d68&service=apn&token=28919862989a1b5ba59c11d5f7cb7ba2b9678be9dd18b033184d04f682013677

<== HTTP 200 OK (26.0015 ms elapsed, 11 bytes received)
<   Content: 
    {
      "data" : {
      }
    }

Update the subscription token

Updates a device's registration token in case a new one was assigned by the service.

GET /ajax/drive?action=updateToken

Parameters:

  • session - A session ID previously obtained from the login module.
  • service - The name of the underlying push service to use, currently one of gcm, apn or apn.macos.
  • token - The previous registration token as assigned by the service.
  • newToken - The new registration token as assigned by the service.

Response:
An empty JSON result.

Example:

==> GET http://192.168.32.191/ajax/drive?action=updateToken&service=apn&session=51378e29f82042b4afe4af1c034c6d68&token=28919862989a1b5ba59c11d5f7cb7ba2b9678be9dd18b033184d04f682013677&newToken=38919862989a1b5ba59c11d5f7cb7ba2b9678be9dd18b033184d04f682013677

<== HTTP 200 OK (15.6653 ms elapsed, 11 bytes received)
<   Content: 
    {
      "data" : {
      }
    }

Get file metadata

Deprecated, available until API version 2.
Additional metadata of synchronized files is made available via the fileMetadata request.

PUT /ajax/drive?action=fileMetata

Parameters:

  • session - A session ID previously obtained from the login module.
  • root - The ID of the referenced root folder on the server.
  • path - The path to the synchronized folder, relative to the root folder.
  • columns - A comma-separated list of columns to return. Each column is specified by a numeric column identifier. Column identifiers for file metadata are defined in #File Metadata.

Request Body:
A JSON array containing the file versions to get the metadata for. Each object in the array should be sent as File Versions, and needs to be present in the referenced path.

Response:
A JSON array containing the file metadata in the order of the requested file versions. Each array element describes one file metadata and is itself an array. The elements of each array contain the information specified by the corresponding identifiers in the columns parameter.

File Metadata (deprecated)
ID Name Type Value
name String The name of the file version.
4 created Timestamp The file's last modification time (always UTC, not translated into user time).
5 modified Timestamp The file's last modification time (always UTC, not translated into user time).
702 name String The name of the file, including it's extension, e.g. test.doc.
703 contentType String The file's content type, e.g. "image/png".
708 checksum String The MD5 hash of the file, expressed as a lowercase hexadecimal number string, 32 characters long, e.g. f8cacac95379527cd4fa15f0cb782a09.
750 previewLink String A direct link to a medium-sized preview image of the file if available.
751 directLinkFragments The fragments part of the direct link that can be used in combination with the [|token login] method to jump directly to the detail view of the file in the web interface, bypassing the need to login manually.
752 directLink String A direct link to the detail view of the file in the web interface.
753 thumbnailLink String A direct link to a small thumbnail image of the file if available.

Example:

==> PUT http://192.168.32.191/ajax/drive?action=fileMetadata&root=97974&path=%2f&columns=702%2c708%2c752%2c750%2c753&session=43aca91a80de42559ff0c2493dd973d0
  > Content:
    [
      {
        "name" : "image.jpg",
        "checksum" : "2b04df3ecc1d94afddff082d139c6f15"
      }, {
        "name" : "song.mp3",
        "checksum" : "5a9a91184e611dae3fed162b8787ce5f"
      }, {
        "name" : "test1.txt",
        "checksum" : "7e36f409a042f06ecb88606a97a88c8f"
      }, {
        "name" : "test3.txt",
        "checksum" : "703bc9aabff33faf07cf121dcda12ec8"
      }
    ]  

<== HTTP 200 OK (6.0004 ms elapsed, 140 bytes received)
<   Content:
    [
      ["image.jpg", "2b04df3ecc1d94afddff082d139c6f15", "https://192.168.32.191/ox6/index.html#m=infostore&f=97974&i=179629", "https://192.168.32.191/ajax/files?action=document&folder=97974&id=179629&version=1&delivery=download&scaleType=contain&width=128&height=90", "m=infostore&f=97974&i=179629"], 
      ["song.mp3", "5a9a91184e611dae3fed162b8787ce5f", "https://192.168.32.191/ox6/index.html#m=infostore&f=97974&i=179630", "https://192.168.32.191/ajax/image/file/mp3Cover?folder=97974&id=179630&version=1&delivery=download&scaleType=contain&width=128&height=90", "m=infostore&f=97974&i=179630"], 
      ["test1.txt", "7e36f409a042f06ecb88606a97a88c8f", "https://192.168.32.191/ox6/index.html#m=infostore&f=97974&i=179626", null, "m=infostore&f=97974&i=179626"], 
      ["test3.txt", "703bc9aabff33faf07cf121dcda12ec8", "https://192.168.32.191/ox6/index.html#m=infostore&f=97974&i=179624", null, "m=infostore&f=97974&i=179624"]
    ]

Get a direct link for a folder/a file into appsuite

Available since API version 4.

Generate a direct link into appsuite UI for a synchronized file/a synchronized folder and a token for token-based login.

POST /ajax/drive?action=jump

Parameters:

  • session - A session ID previously obtained from the login module.
  • root - The ID of the referenced root folder on the server.
  • path - The path to the synchronized folder, relative to the root folder.
  • name - The name of the file in the synchronized folder given in path-parameter. Optional
  • method - Methods
  • authId - Identifier for tracing every single login request passed between different systems in a cluster. The value should be some token that is unique for every login request. This parameter must be given as URL parameter and not inside the body of the POST request.
  • clientToken - Client side identifier for accessing the session later. The value should be some token that is unique for every login request.

Methods:

  • edit: Open the file in appsuite editor or in text/spreadsheet (if available).
  • permissions: Open the file's/folder's change-permission dialog.
  • version_history: Open the file's version history summary.
  • preview: Open the file's/folder's preview.

Response:
A JSON array containing the direct link to the file/folder including a server token for token based login.

Example:

==> POST http://localhost/ajax/drive?action=jump&session=48a289898ad949faaa46c04e7fb422f5&root=9547&path=/path/to/file&name=file_to_edit.txt&method=edit&authId=41763584-8460-11e4-b116-123b93f75dba
  > Content: clientToken=47d74b1c-81df-11e4-b116-123b93f75cba

<== HTTP 200 OK
<   Content: 
    {
      "data": {
        "redirectUrl": "http://localhost/appsuite#app=io.ox/editor&folder=273264&id=273264/307438&serverToken=7b90972628e34e89bb9a3946d1372c68"
      }
    }

Use direct link and token with token-based login

Available since API version 4.

Login to appsuite UI with token-based login via the link created with Get a direct link for a folder/a file into appsuite.

GET [direct link]

Parameters:

Example:

==> GET http://localhost/appsuite#app=io.ox/editor&folder=273264&id=273264/307438&serverToken=7b90972628e34e89bb9a3946d1372c68&clientToken=47d74b1c-81df-11e4-b116-123b93f75cba

<== HTTP 200 OK

Get synchronizable Folders

Available since API version 4.

Allows getting a list of folders that are available on the server for synchronization. This request should be used to build up a folder tree and let the user select the root synchronization folder(s).

GET /ajax/drive?action=subfolders

Parameters:

  • session - A session ID previously obtained from the login module.
  • parent - The ID of the parent folder to get the subfolders for as read from a previously fetched directory metadata object. Optional; if not set, the root available root folders are returned.

Response:
A JSON array holding metadata information for all subfolders as defined in Directory Metadata, with the files array being left out.

Example:

==> GET http://192.168.32.191/ajax/drive?action=subfolders&session=35cb8c2d1423480692f0d5053d14ba52
  
<== HTTP 200 OK (241.0252 ms elapsed, 966 bytes received)
<   Content: 
    {
      "data": [{
        "id": "com.openexchange.file.storage.googledrive://1/",
        "name": "Google Drive",
        "path": "/Google Drive",
        "has_subfolders": true,
        "own_rights": 403710016,
        "permissions": [{
          "bits": 403710016,
          "group": false,
          "entity": 182,
          "display_name": "Mander, Jens",
          "email_address": "jens.mander@example.com",
          "guest": false
        }],
        "jump": ["permissions"]
      },
      {
        "id": "10",
        "name": "Freigegebene Dateien",
        "path": "/Freigegebene Dateien",
        "created": 1224493261628,
        "modified": 1417164170136,
        "has_subfolders": true,
        "own_rights": 1,
        "permissions": [{
          "bits": 1,
          "group": true,
          "entity": 0,
          "display_name": "All users",
          "guest": false
        },
        {
          "bits": 1,
          "group": true,
          "entity": 2147483647,
          "display_name": "Guests",
          "guest": false
        }],
        "jump": ["permissions"],
        "shared": true
      },
      {
        "id": "15",
        "name": "Öffentliche Dateien",
        "path": "/Öffentliche Dateien",
        "created": 1224493261628,
        "modified": 1418383637250,
        "has_subfolders": true,
        "own_rights": 403709956,
        "permissions": [{
          "bits": 403709956,
          "group": true,
          "entity": 0,
          "display_name": "All users",
          "guest": false
        },
        {
          "bits": 1,
          "group": true,
          "entity": 2147483647,
          "display_name": "Guests",
          "guest": false
        }],
        "jump": ["permissions"],
        "shared": true
      },
      {
        "id": "com.openexchange.file.storage.dropbox://1/",
        "name": "Dropbox",
        "path": "/Dropbox",
        "has_subfolders": true,
        "own_rights": 403710016,
        "permissions": [{
          "bits": 403710016,
          "group": false,
          "entity": 182,
          "display_name": "Mander, Jens",
          "email_address": "jens.mander@example.com",
          "guest": false
        }],
        "jump": ["permissions"]
      },
      {
        "id": "9542",
        "name": "Meine Dateien",
        "path": "/Meine Dateien",
        "created": 1320230546147,
        "modified": 1426764458823,
        "default_folder": true,
        "has_subfolders": true,
        "own_rights": 403710016,
        "permissions": [{
          "bits": 403710016,
          "group": false,
          "entity": 182,
          "display_name": "Mander, Jens",
          "email_address": "jens.mander@example.com",
          "guest": false
        }],
        "jump": ["permissions"]
      }]
    }

Sharing (since API version 4)

File Version with path

A file in a directory is uniquely identified by its filename and the checksum of its content.

File Version with Path
Name Type Value
name String The name of the file, including its extension, e.g. test.doc.
path String The path of the file, relative to the root folder.
checksum String The MD5 hash of the file, expressed as a lowercase hexadecimal number string, 32 characters long, e.g. f8cacac95379527cd4fa15f0cb782a09.

Share Recipient

A Person who can receive a share.

Share Recipient
Name Type Value
type One of (user, group, anonymous, guest) The type of the recipient.
entity Integer The identifier. Mandatory for type user or group.
password String The password. Mandatory for type anonymous.
email_address String The Email Address. Mandatory for type guest.
display_name String The display Name. Optional for type guest.

Share

Detailed share information.

Share
Name Type Value
share_url String The url pointing to the share.
recipient Share Recipient The recipient.
fileVersion File Version with path The shared file. One of fileVersion or directoryVersion must be present.
directoryVersion Directory Versions The shared directory. One of fileVersion or directoryVersion must be present.

Get a share link (since API version 4)

Creates a link for a file or folder which can be accessed from an external person with the specified password.

PUT /ajax/drive?action=getLink

Parameters:

  • session - A session ID previously obtained from the login module.
  • root - The ID of the referenced root folder on the server.

Request body: A JSON object describing the shares to be created as described in Get a link. It contains an array with File Versions with path and an array with Directory Versions, as well as some properties of the guest user to be created.

Response:
A JSON object containing the Link URL.

Example:

==> PUT http://192.168.32.191/ajax/drive?action=getLink&root=12345&session=43aca91a80de42559ff0c2493dd973d0
 > Content:
  {
   "password":"5321a46c95ed49f29f42a75f106980d7",
   "directoryVersions":[],
   "fileVersions":
    [
      {
        "path":"/b29b040b7ceb4a198b761428815dcd29",
        "name":"GetLinkTest_1427962453371",
        "checksum":"fb24cd885db597953a0b96c6e19cf35b"
      }
    ]
   }

<== HTTP 200 OK
 > Content:
  {
   "data":
    {
     "url":"http://127.0.0.1/ajax/share/1d6f102c0dde47664267dc1dde6e4cfcb6514a2949cd7e66/a81f3549",
     "password":"5321a46c95ed49f29f42a75f106980d7"
    },
   "timestamp":1427962736135
  }

Invite (since API version 4)

Creates shares for multiple targets and multiple recipients.

PUT /ajax/drive?action=invite

Parameters:

  • session - A session ID previously obtained from the login module.
  • root - The ID of the referenced root folder on the server.

Request Body:
A JSON object containing an array with File Versions with Path, an array with Directory Versions and an array with Share Recipients.

Response:
A JSON array with a share token for each Share Recipient. The token will be NULL if the recipient is an internal user.

Example:

==> PUT http://192.168.32.191/ajax/drive?action=invite&root=12345&session=43aca91a80de42559ff0c2493dd973d0
 > Content:
  {"directoryVersions":
   [
    {
     "path":"/483dc76483324877b5383ab7427717c1",
     "checksum":"d41d8cd98f00b204e9800998ecf8427e"
    }
   ],
   "fileVersions":
    [
     {
      "path":"/f5ec455ce617473186e4f3da1d06facd",
      "name":"InviteTest_1427966187114",
      "checksum":"fb24cd885db597953a0b96c6e19cf35b"
     }
    ],
    "recipients":
     [
      {
       "type":"anonymous",
       "bits":257,
       "password":"password123"
      },{
       "type":"user",
       "bits":257,
       "entity":4
      }
     ]
    }

<== HTTP 200 OK
 > Content:
  {
   "data":
    [
     "12f1e4100f57ff62bb889fdf57d64cf890fe3928e74b07a4",
     null
    ],
   "timestamp":1427966205983
  }

Update a share link (since API version 4)

Upates a single share, identified by the share token.

PUT /ajax/drive?action=updateLink

Parameters:

  • session - A session ID previously obtained from the login module.
  • root - The ID of the referenced root folder on the server.
  • timestamp - The timestamp.

Request Body:
A JSON object containing the drive share target and the fields to be updated.

Response:
An empty JSON object.

Example:

==> PUT http://192.168.32.191/ajax/drive?action=updateLink&root=12345&timestamp=1427966205983&session=43aca91a80de42559ff0c2493dd973d0
 > Content:
  {
   "directoryVersions":[],
   "fileVersions":
    [
      {
        "path":"/b29b040b7ceb4a198b761428815dcd29",
        "name":"GetLinkTest_1427962453371",
        "checksum":"fb24cd885db597953a0b96c6e19cf35b"
      }
    ]
   }
   "expiry_date":1428053078298,
   "bits":4227332,
   "password":"2e1d9e7c09ba4c31a6da0654c2ebc375"
  }

<== HTTP 200 OK
 > Content:
  {
   "data":{},
   "timestamp":1427966721942
  }

Delete a share link (since API version 4)

Deletes share, identified by the share token.

PUT /ajax/drive?action=deleteLink

Parameters:

  • session - A session ID previously obtained from the login module.
  • root - The ID of the referenced root folder on the server.

Request Body:
A JSON object containing the drive share target to be deleted.

Response:
An empty JSON object.

Example:

==> PUT http://192.168.32.191/ajax/drive?action=deleteLink&root=12345&session=43aca91a80de42559ff0c2493dd973d0
 > Content:
  {
   "directoryVersions":[],
   "fileVersions":
    [
      {
        "path":"/b29b040b7ceb4a198b761428815dcd29",
        "name":"GetLinkTest_1427962453371",
        "checksum":"fb24cd885db597953a0b96c6e19cf35b"
      }
    ]
  }

<== HTTP 200 OK
 > Content:
  {
   "data":{},
   "timestamp":1427962612446
  }

Show all shares (since API version 4)

Shows all shares.

GET /ajax/drive?action=shares

Parameters:

  • session - A session ID previously obtained from the login module.
  • root - The ID of the referenced root folder on the server.

Response:
A JSON array of Shares.

Example:

==> GET http://192.168.32.191/ajax/drive?action=deleteLink&root=12345&session=43aca91a80de42559ff0c2493dd973d0

<== HTTP 200 OK
 > Content:
  {
   "data":
    [
     {
      "share_url":"http://127.0.0.1/ajax/share/191e221a003df8640574ff703dd14b2d97fcf8e592ff6f38/702e23ae",
      "token":"191e221a003df8640574ff703dd14b2d97fcf8e592ff6f38/702e23ae",
      "directoryVersion":
       {
        "path":"/faac75b0d7a34d0bad05254ee9af689d",
        "checksum":"d41d8cd98f00b204e9800998ecf8427e"
       },
      "recipient":
       {
        "type":"anonymous",
        "base_token":"191e221a003df8640574ff703dd14b2d97fcf8e592ff6f38",
        "password":"password123",
        "entity":"10543"
       }
     },{
      "share_url":"http://127.0.0.1/ajax/share/191e221a003df8640574ff703dd14b2d97fcf8e592ff6f38/e1c4ced0",
      "token":"191e221a003df8640574ff703dd14b2d97fcf8e592ff6f38/e1c4ced0",
      "fileVersion":
       {
        "path":"/4e2bda1eca3246d4ab782ff87d356c9d",
        "name":"GetLinkTest_1427966365278",
        "checksum":"fb24cd885db597953a0b96c6e19cf35b"
       },
      "recipient":
       {
        "type":"anonymous",
        "base_token":"191e221a003df8640574ff703dd14b2d97fcf8e592ff6f38",
        "password":"password123",
        "entity":"10543"
       }
     }
    ]
  }

File- and Directory Name Restrictions

Regarding the case sensitivity of file and directory names, OX Drive works in a case-insensitive, but case-preserving way. That means that there cannot be two files with an equal name ignoring case in the same directory, but it's still possible to synchronize the names in a case-sensitive manner, as well as it's possible to change only the case of file- and directory names.

The same applies to equally named files and directories on the same level in the folder hierarchy, i.e. it's not possible to create a new file in a directory where an equally (ignoring case) named subdirectory already exists and vice versa.

There is a similar restriction regarding file and directory names in the same directory having different unicode normalization forms, yet the same textual representation. OX Drive requires uniqueness regarding this textual representaion of potentially different encoded unicode strings. So, in case the client tries to synchronize two textually equal files or directories, he is instructed to put one of them into quarantine. Internally the server performs an equals-check of the "NFC" normalization forms of the strings, i.e. an unicode string is normalized using full canonical decomposition, followed by the replacement of sequences with their primary composites, if possible. Details regarding unicode normalization can be found at http://www.unicode.org/reports/tr15/tr15-23.html .

Invalid and ignored Filenames

There are some filenames that are invalid or ignored and therefore not synchronized. This means that files with these names should not be taken into account when sending the directory contents to the server, or when calculating the directory checksum (see below). The following list describes when a filename is considered invalid:

  • If it contains one or of the following reserved characters:
    • < (less than),
    • > (greater than)
    • : (colon)
    • " (double quote)
    • / (forward slash)
    • \ (backslash)
    • | (vertical bar or pipe)
    • ? (question mark)
    • * (asterisk)
    • Characters whose integer representations are in the range from 0 through 31
  • The last character is a . (dot) or ' ' (space)
  • It's case-invariant name without an optional extension matches one of the reserved names CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, or LPT9
  • It consists solely of whitespace characters

The following list gives an overview about the ignored filenames:

  • desktop.ini
  • Thumbs.db
  • .DS_Store
  • icon\r
  • Any filename ending with .drivepart
  • Any filename starting with .msngr_hstr_data_ and ending with .log

Nevertheless, if the client still insists to send a file version with an invalid or ignored filename, the file creation on the server is refused with a corresponding error action (see below).

Invalid and ignored Directory Names

There are also similar restrictions regarding invalid directory names. Any try to include them in the list of directory versions will be responded with a corresponding error action for the directory version. The following list describes when a path is considered invalid:

  • If it contains one or of the following reserved characters:
    • < (less than),
    • > (greater than)
    • : (colon)
    • " (double quote)
    • \ (backslash)
    • | (vertical bar or pipe)
    • ? (question mark)
    • * (asterisk)
    • Characters whose integer representations are in the range from 0 through 31
  • The last character of any subpath (i.e. the last part of the whole path or the part preceding the spearator character /) is a . (dot) or ' ' (space)
  • It consists solely of whitespace characters
  • It not equals the root path /, but ends with a / (forward slash) character
  • It contains two or more consecutive / (forward slash) characters

The following list gives an overview about the ignored directory names:

  • /.drive
  • Any directory whose path ends with /.msngr_hstr_data

Length Restrictions

The maximum allowed length for path segments, i.e. the parts between forawrd slashes (/) in directory and filenames, is restricted to 255 characters. Synchronizing a file or directory version that contains path segments longer than this limit leads to those versions being put into quarantine.

Client side filtering

Client-side filtering is available since API version 2.

OX Drive clients may define a user- and/or application-defined list of file- and directory name exclusions. Those exclusion filters are then taken into account during synchronization, i.e. files and directories matching a defined exclusion pattern are ignored when comparing the list of server-, client- and original versions. Also, the file exclusion lists are considered for the calculation of aggergated directory checksums.

The exclusion filters may be set, changed or unset at any time during synchronization, there are no additional requests needed to set them up. Instead, the list of excluded files and directories is simply sent along with each syncFolders, syncFiles and download request. The following tables show the JSON representation of file- and directory patterns that are used to build up the exlcusion lists:

Directory pattern

A directory pattern is defined by a pattern string and further attributes.

Directory Pattern
Name Type Value
type String The pattern type, currently one of exact or glob.
path String The path pattern, in a format depending on the pattern type.
caseSensitive Optional flag to enable case-sensitive matching, defaults to false

File pattern

A file pattern is defined by pattern strings for the filename and path, as well as further attributes.

File Pattern
Name Type Value
type String The pattern type, currently one of exact or glob.
path String The path pattern, in a format depending on the pattern type.
name String The filename pattern, in a format depending on the pattern type.
caseSensitive Optional flag to enable case-sensitive matching, defaults to false

Pattern types

A pattern currently may be defined in two formats: exact or glob.

  • exact
    An exact pattern, matching the file- or directory version literally. For example, to exclude the file Backup.pst in the subfolder Mail below the root synchronization folder, an exact file pattern would look like: {"path":"/Mail","name":"Backup.pst","type":"exact"}, or, an exact directory pattern for the directory /Archive would be represented as {"path":"/Archive","type":"exact"}.
  • glob
    A simple pattern allowing to use the common wildcards * and ? to match file- and directory versions. For example, to exclude all files ending with .tmp across all directories, the glob file pattern could be defined as {"path":"*","name":"*.tmp","type":"glob"}, or, to exclude the directory /Project/.git and all its subdirectories recursively, this would be expressed using a combination of the following two directory patterns: [{"path":"/Project/.git","type":"exact"},{"path":"/Project/.git*","type":"glob"}].

Further considerations

  • It's possible to exclude a (parent) directory with an appropriate pattern, while still subfolders below that directory being synchronized. This usually results in the excluded directory being created ob both client- and server side, but no file contents within the excluded directory being exchanged. If subfolders should be excluded, too, a wildcard should be used in the pattern to match any subdirectories.
  • If the client tries to synchronize a file- or directory version that is ignored, i.e. a version that would match any of the provided exclusion filters, the server behaves similarly to the handling of invalid and ignored file- and directory names (see above), i.e. the client would be instructed to put those versions into quarantine.
  • For the calculation of directory checksums, it's important that the server and client perform exactly the same matching for ignored filenames: A * character matches zero or more characters, a ? character matches exactly one character. All other characters are matched literally. Advanced glob flavors like braces to define subpattern alternatives or square brackets for character sets are not used.
  • Client-side filtering is available with API version 2. The API version that is supported by the server is included in the response of the Settings request.
  • Whenever there are active exclusion filters, the syncFolders request should contain all of both directory and file exclusion filter lists. For the syncFiles request, it's sufficient to include the list of file exclusions.


Metadata Synchronization

The synchronization of metadata is available since API version 3.

Introduction

Previously, only the "raw" folders and files were synchronized between server and clients. While this is sufficient for basic synchronization, there are cases where the clients could benefit from additional data - "metadata" - that is already available on the server. For example, clients could display directories that have been shared or published to other people in a different way. Or, clients could consider folder permissions directly in case the user is performing a local change that would be rejected by the server in the next synchronization cycle anyway.

To supply the clients with those additional information without any influence on the existing synchronization protocol (!), .drive-meta files are introduced for each synchronized directory. Regarding synchronization, such files are treated like any other ordinary file. Especially, those files are taken into account when it comes to directory checksum calculation. Doing so, metadata updates result in a changed .drive-meta file, which in turn causes the parent directory checksum to change, hence synchronization is triggered.

However, some special handling applies for those files:

  • Clients are not allowed to change metadata, so modifications of metadata files or the deletion of them is rejected. Recovery is done via the protocol here, i.e. the client is instructed to re-download the file.
  • .drive-meta files are actually not stored physically on the file storage backend, but created on the fly based on the actual metadata of the directory.
  • Client applications may either store such files on the client file system, or evaluate and store the contained metadata information in a local database for later retrieval. If the file is not saved physically on the client (which is actually recommended), the client is responsible to consider the metadata file in a virtual way and include it's checksum for the directory checksum calculation - similar to the server's internal handling.

Metadata format

The metadata in .drive-meta files is serialized in JSON format to allow easy processing at the clients. The following shows an example of the contents:

{
  "path": "/",
  "created": 1418024049629,
  "modified": 1418024189166,
  "own_rights": 403710016,
  "permissions": [{
    "bits": 403710016,
    "group": false,
    "entity": 182,
    "display_name": "Mander, Jens",
    "email_address": "jens.mander@example.com",
    "guest": false
  }],
  "jump": ["permissions"],
  "files": [{
    "name": "Koala.jpg",
    "created": 1418024190565,
    "modified": 1418026995663,
    "created_by": {
      "group": false,
      "entity": 182,
      "display_name": "Mander, Jens",
      "email_address": "jens.mander@example.com",
      "guest": false
    },
    "modified_by": {
      "group": false,
      "entity": 182,
      "display_name": "Mander, Jens",
      "email_address": "jens.mander@example.com",
      "guest": false
    },
    "preview": "http://192.168.32.191/ajax/files?action=document&folder=268931&id=268931/297620&version=1&delivery=download&scaleType=contain&width=800&height=800&rotate=true",
    "thumbnail": "http://192.168.32.191/ajax/files?action=document&folder=268931&id=268931/297620&version=1&delivery=download&scaleType=contain&width=100&height=100&rotate=true",
    "object_permissions": [{
      "bits": 1,
      "group": false,
      "entity": 10,
      "display_name": "Jan Ot/to Finsel",
      "email_address": "jan.finsel@premium",
      "guest": false
    },
    {
      "bits": 1,
      "group": false,
      "entity": 8338,
      "email_address": "horst@example.com",
      "guest": true
    }],
    "shared": true,
    "number_of_versions": 1,
    "version": "1",
    "jump": ["preview",
    "permissions",
    "version_history"]
  },
  {
    "name": "test.txt",
    "created": 1418024198520,
    "modified": 1418027394897,
    "created_by": {
      "group": false,
      "entity": 182,
      "display_name": "Mander, Jens",
      "email_address": "jens.mander@example.com",
      "guest": false
    },
    "modified_by": {
      "group": false,
      "entity": 182,
      "display_name": "Mander, Jens",
      "email_address": "jens.mander@example.com",
      "guest": false
    },
    "preview": "http://192.168.32.191/ajax/files?action=document&format=preview_image&folder=268931&id=268931/297621&version=6&delivery=download&scaleType=contain&width=800&height=800",
    "thumbnail": "http://192.168.32.191/ajax/files?action=document&format=preview_image&folder=268931&id=268931/297621&version=6&delivery=download&scaleType=contain&width=100&height=100",
    "locked": true,
    "number_of_versions": 4,
    "version": "6",
    "version_comment": "Uploaded with OX Drive (TestDrive)",
    "versions": [{
      "name": "test.txt",
      "file_size": 23,
      "created": 1418024198520,
      "modified": 1418024202878,
      "created_by": {
        "group": false,
        "entity": 182,
        "display_name": "Mander, Jens",
        "email_address": "jens.mander@example.com",
        "guest": false
      },
      "modified_by": {
        "group": false,
        "entity": 182,
        "display_name": "Mander, Jens",
        "email_address": "jens.mander@example.com",
        "guest": false
      },
      "version": "1",
      "version_comment": "Uploaded with OX Drive (TestDrive)"
    },
    {
      "name": "test.txt",
      "file_size": 54,
      "created": 1418024234782,
      "modified": 1418024231522,
      "created_by": {
        "group": false,
        "entity": 182,
        "display_name": "Mander, Jens",
        "email_address": "jens.mander@example.com",
        "guest": false
      },
      "modified_by": {
        "group": false,
        "entity": 182,
        "display_name": "Mander, Jens",
        "email_address": "jens.mander@example.com",
        "guest": false
      },
      "version": "2",
      "version_comment": "Uploaded with OX Drive (TestDrive)"
    },
    {
      "name": "test.txt",
      "file_size": 120,
      "created": 1418027349026,
      "modified": 1418027355957,
      "created_by": {
        "group": false,
        "entity": 182,
        "display_name": "Mander, Jens",
        "email_address": "jens.mander@example.com",
        "guest": false
      },
      "modified_by": {
        "group": false,
        "entity": 182,
        "display_name": "Mander, Jens",
        "email_address": "jens.mander@example.com",
        "guest": false
      },
      "version": "5"
    },
    {
      "name": "test.txt",
      "file_size": 127,
      "created": 1418027370051,
      "modified": 1418027366945,
      "created_by": {
        "group": false,
        "entity": 182,
        "display_name": "Mander, Jens",
        "email_address": "jens.mander@example.com",
        "guest": false
      },
      "modified_by": {
        "group": false,
        "entity": 182,
        "display_name": "Mander, Jens",
        "email_address": "jens.mander@example.com",
        "guest": false
      },
      "version": "6",
      "version_comment": "Uploaded with OX Drive (TestDrive)"
    }],
    "jump": ["preview",
    "edit",
    "permissions",
    "version_history"]
  },
  {
    "name": "Kalimba.mp3",
    "created": 1418026529047,
    "modified": 1247549551659,
    "created_by": {
      "group": false,
      "entity": 182,
      "display_name": "Mander, Jens",
      "email_address": "jens.mander@example.com",
      "guest": false
    },
    "modified_by": {
      "group": false,
      "entity": 182,
      "display_name": "Mander, Jens",
      "email_address": "jens.mander@example.com",
      "guest": false
    },
    "preview": "http://192.168.32.191/ajax/image/file/mp3Cover?folder=268931&id=268931/297623&version=1&delivery=download&scaleType=contain&width=800&height=800",
    "thumbnail": "http://192.168.32.191/ajax/image/file/mp3Cover?folder=268931&id=268931/297623&version=1&delivery=download&scaleType=contain&width=100&height=100",
    "number_of_versions": 1,
    "version": "1",
    "version_comment": "Uploaded with OX Drive (TestDrive)",
    "jump": ["preview",
    "permissions",
    "version_history"]
  }]
}

The following objects describe the JSON structure of the metadata for a directory:

Directory Metadata
Name Type Value
id String The server-side unique identifier of the directory.
name String The display name of the directory.
path String The path of the directory the metadata belongs to.
created Timestamp The folder's last modification time (always UTC, not translated into user time).
modified Timestamp The folder's last modification time (always UTC, not translated into user time).
own_rights Number Folder permissions which apply to the current user, as described in [| permission flags].
permissions Array All folder permissions, each element is an object as described in Folder Permission.
default_folder Boolean true if the folder is a default folder, false or not set, otherwise.
has_subfolders Boolean true if the folder (potentially) has subfolders, false or not set, otherwise.
shared Boolean true if the folder is shared, false or not set, otherwise.
type Number The special folder type, or not set, if not available.
jump Array An array containing the names of possible jump methods to use for the folder.
files Array Metadata for the contained files, each element is an object as described in File Metadata.


File Metadata
Name Type Value
name String The name of the file the metadata belongs to.
created Timestamp The file's last modification time (always UTC, not translated into user time).
modified Timestamp The file's last modification time (always UTC, not translated into user time).
created_by Object Information about the file's creator as described in Entity Information.
modified_by Object Information about the file's last editor as described in Entity information.
preview String A URL to a preview image for the file.
thumbnail String A URL to a thumbnail image for the file.
object_permissions All file permissions, each element is an object as described in Object Permission.
shared Boolean true if the file is shared, false or not set, otherwise.
locked Boolean true if the file is locked, false or not set, otherwise.
jump Array An array containing the names of possible jump methods to use for the file.
number_of_versions The number of all versions of the file.
version String The current version identifier (usually, but not necessarily a numerical value) of the file.
version_comment An additional comment for the file version.
versions Array Metadata for all versions of the file, each element is an object as described in File Version.
Entity Information
Name Type Value
entity Number The unique identifier of the entity.
group Boolean true if the entity is a group, false or not set, if it is a single user or guest.
display_name String A display name for the entity if available.
email_address String An e-mail address for the entity if available.
group Boolean true if the entity is an external guest, false or not set, otherwise.
Folder Permission
Name Type Value
entity Number The unique identifier of the entity.
group Boolean true if the entity is a group, false or not set, if it is a single user or guest.
display_name String A display name for the entity if available.
email_address String An e-mail address for the entity if available.
group Boolean true if the entity is an external guest, false or not set, otherwise.
bits Number Permission level, as described in [| permission flags].
Object Permission
Name Type Value
entity Number The unique identifier of the entity.
group Boolean true if the entity is a group, false or not set, if it is a single user or guest.
display_name String A display name for the entity if available.
email_address String An e-mail address for the entity if available.
group Boolean true if the entity is an external guest, false or not set, otherwise.
bits Number Object permission level, as described in [| permission flags].
File Version
Name Type Value
name String The name of the file version.
file_size Number The file size of the version in bytes.
created Timestamp The file version's last modification time (always UTC, not translated into user time).
modified Timestamp The file version's last modification time (always UTC, not translated into user time).
created_by Object Information about the file version's creator as described in Entity Information.
modified_by Object Information about the file version's last editor as described in Entity information.
version String The version identifier (usually, but not necessarily a numerical value) of the file version.
version_comment String An additional comment for the file version.

Client-side implementation

In order to make use of the metadata, clients should roughly implement the following:

  • Include the apiVersion parameter in each request, and set it to at least 3 in order to include .drive-meta during synchronization
  • Evaluate .drive-meta files and store the information, as well as the file's checksums in a local database
  • Include this file in the calculation of the parent directory checksum, just like an ordinary file in that directory
  • Do something useful with the metadata information.

Additional notes

  • The metadata synchronization via .drive-meta files embedded into the synchronization protocol obsoletes the previously used methods to receive metadata information (#Get file metadata and columns parameter in #Synchronize files in a folder.
  • Depending on the underlying file storage backend, the included metadata may vary, so each information should be treatened as optional.

Possible use cases

  • For files where the locked property is true, display some kind of "lock" icon (-overlay) in the file list / explorer view
  • For files or folders where the shared property is true, display some kind of "cloud" icon (-overlay) in the file list / explorer view
  • For files or folders where the user is not allowed to perform an action with, don't offer such actions (e.g. if a file cannot be deleted or renamed by the user due to insufficient permissions, disable the corresponding options)
  • Use the URLs in preview and thumbnail to get a preview image for the files
  • Display the server creation / last modification timestamps of files and folders
  • Embed a version history for files with multiple versions
  • Show to which users a file or folder is currently shared
  • Offer appropriate "jump" actions to the groupware web interface for more advanced options (e.g. to directly edit an .xlsx file in the spreadsheet application of the web interface, or to manage a folder's permission