Skip to content

Commit

Permalink
Merge pull request #205 from dduponchel/update_permissions
Browse files Browse the repository at this point in the history
Update permissions
  • Loading branch information
Stuk committed Mar 10, 2015
2 parents d329558 + 3b6c23f commit e930e39
Show file tree
Hide file tree
Showing 13 changed files with 217 additions and 107 deletions.
33 changes: 11 additions & 22 deletions documentation/api_jszip/file_data.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,34 +26,25 @@ compressionOptions | object | `null` | the options to use when compressing the f
comment | string | null | The comment for this file.
optimizedBinaryString | boolean | `false` | Set to true if (and only if) the input is a "binary string" and has already been prepared with a 0xFF mask.
createFolders | boolean | `false` | Set to true if folders in the file path should be automatically created, otherwise there will only be virtual folders that represent the path to the file.
unixPermissions | object | null | The UNIX permissions of the file, if any.
dosPermissions | object | null | The DOS permissions of the file, if any.
unixPermissions | 16 bits number | null | The UNIX permissions of the file, if any.
dosPermissions | 6 bits number | null | The DOS permissions of the file, if any.
dir | boolean | false | Set to true if this is a directory and content should be ignored.

You shouldn't update the data given to this method : it is kept as it so any
update will impact the stored data.

__For the permissions__ :

The `*Permissions` fields has the following structure (the value is the default behavior) :
The field `unixPermissions` also accepts a string representing the octal value :
"644", "755", etc. On nodejs you can use the `mode` attribute of
[nodejs' fs.Stats](http://nodejs.org/api/fs.html#fs_class_fs_stats).

```js
unixPermissions : {
executable : false,
readOnly : false
}

dosPermissions : {
hidden : false,
readOnly : false
}
```
See also [the platform option of generate()]({{site.baseurl}}/documentation/api_jszip/generate.html).

The field `unixPermissions` also accepts a number (the 2 bytes file attributes) :
you can use the `mode` attribute of [nodejs' fs.Stats](http://nodejs.org/api/fs.html#fs_class_fs_stats).
In that case, the executable/readOnly boolean will be extracted from the "user"
part (ignoring the "group" and "other").
__About `dir`__ :

See also [the platform option of generate()]({{site.baseurl}}/documentation/api_jszip/generate.html).
If `dir` is true or if a permission says it's a folder, this entry be flagged
as a folder and the content will be ignored.

__Returns__ : The current JSZip object, for chaining.

Expand Down Expand Up @@ -93,9 +84,7 @@ zip.file("folder/file.txt", "file in folder", {createFolders: true});
// It will exist whether or not "file.txt" is present.

zip.file("script.sh", "echo 'hello world'", {
unixPermissions : {
executable : true
}
unixPermissions : "755"
});
// when generated with platform:UNIX, the script.sh file will be executable
```
5 changes: 4 additions & 1 deletion documentation/api_jszip/folder_data.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ layout: default
section: api
---

__Description__ : Add a directory to the zip file.
__Description__ : Create a directory if it doesn't exist, return a new JSZip
object with the new folder as root.

See also [the `dir` option of file()]({{site.baseurl}}/documentation/api_jszip/file_data.html).

__Arguments__

Expand Down
20 changes: 20 additions & 0 deletions documentation/api_jszip/generate.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ Possible values for `platform` : `DOS` and `UNIX`. It also accepts nodejs
When using `DOS`, the attribute `dosPermissions` of each file is used.
When using `UNIX`, the attribute `unixPermissions` of each file is used.

If you set the platform value on nodejs, be sure to use `process.platform`.
`fs.stats` returns a non executable mode for folders on windows, if you
force the platform to `UNIX` the generated zip file will have a strange
behavior on UNIX platforms.

__Returns__ : The generated zip file.

__Throws__ : An exception if the asked `type` is not available in the browser,
Expand All @@ -78,6 +83,21 @@ var content = zip.generate({type:"nodebuffer"});
require("fs").writeFile("hello.zip", content, function(err){/*...*/});
```

```js
// on nodejs
zip.file(pathname, content, {
date: stat.mtime,
unixPermissions: stat.mode
});

// ...

zip.generate({
type: 'nodebuffer',
platform: process.platform
});
```

```js
//This example will Generate a Open Document Spreasheet, with the correct mime type
var zip = new JSZip();
Expand Down
2 changes: 2 additions & 0 deletions documentation/api_zipobject.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ attribute name | type | description
`dir` | boolean | true if this is a directory
`date` | date | the last modification date
`comment` | string | the comment for this file
`unixPermissions` | 16 bits number | The UNIX permissions of the file, if any.
`dosPermissions` | 6 bits number | The DOS permissions of the file, if any.
`options` | object | the options of the file. The available options are :
`options.base64` | boolean | **Deprecated**, see [file(name, data [,options])]({{site.baseurl}}/documentation/api_jszip/file_data.html)
`options.binary` | boolean | **Deprecated**, see [file(name, data [,options])]({{site.baseurl}}/documentation/api_jszip/file_data.html)
Expand Down
93 changes: 44 additions & 49 deletions lib/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,23 @@ var fileAdd = function(name, data, o) {

o = prepareFileAttrs(o);

if (typeof o.unixPermissions === "string") {
o.unixPermissions = parseInt(o.unixPermissions, 8);
}

// UNX_IFDIR 0040000 see zipinfo.c
if (o.unixPermissions && (o.unixPermissions & 0x4000)) {
o.dir = true;
}
// Bit 4 Directory
if (o.dosPermissions && (o.dosPermissions & 0x0010)) {
o.dir = true;
}

if (o.dir) {
name = forceTrailingSlash(name);
}

if (o.createFolders && (parent = parentFolder(name))) {
folderAdd.call(this, parent, true);
}
Expand All @@ -233,6 +250,7 @@ var fileAdd = function(name, data, o) {
o.base64 = false;
o.binary = false;
data = null;
dataType = null;
}
else if (dataType === "string") {
if (o.binary && !o.base64) {
Expand All @@ -258,15 +276,6 @@ var fileAdd = function(name, data, o) {
}
}

if (typeof o.unixPermissions === "number") {
o.unixPermissions = {
// executable for the owner
executable: !!(o.unixPermissions & 0x0040),
// NOT writable for the owner
readOnly: (o.unixPermissions & 0x0080) === 0
};
}

var object = new ZipObject(name, data, o);
this.files[name] = object;
return object;
Expand All @@ -286,6 +295,20 @@ var parentFolder = function (path) {
return (lastSlash > 0) ? path.substring(0, lastSlash) : "";
};


/**
* Returns the path with a slash at the end.
* @private
* @param {String} path the path to check.
* @return {String} the path with a trailing slash.
*/
var forceTrailingSlash = function(path) {
// Check the name ends with a /
if (path.slice(-1) != "/") {
path += "/"; // IE doesn't like substr(-1)
}
return path;
};
/**
* Add a (sub) folder in the current folder.
* @private
Expand All @@ -295,13 +318,10 @@ var parentFolder = function (path) {
* @return {Object} the new folder.
*/
var folderAdd = function(name, createFolders) {
// Check the name ends with a /
if (name.slice(-1) != "/") {
name += "/"; // IE doesn't like substr(-1)
}

createFolders = (typeof createFolders !== 'undefined') ? createFolders : false;

name = forceTrailingSlash(name);

// Does this folder already exist?
if (!this.files[name]) {
fileAdd.call(this, name, null, {
Expand Down Expand Up @@ -380,29 +400,15 @@ var generateCompressedObjectFrom = function(file, compression, compressionOption
*/
var generateUnixExternalFileAttr = function (unixPermissions, isDir) {

// I can't use octal values in strict mode, hence the hexa.
var umask = 0x12; // 022

var permissions = 0x1FF; // 0777

permissions &= ~umask;

if (!(unixPermissions && unixPermissions.executable) && !isDir) {
permissions &= 0x1B6; // 0666
}
if (unixPermissions && unixPermissions.readOnly) {
permissions &= 0x16D; // 0555
}

var extFileAttr = permissions << 16;

if (isDir) {
extFileAttr |= 0x4000 << 16; // UNX_IFDIR 0040000 see zipinfo.c
} else {
extFileAttr |= 0x8000 << 16; // UNX_IFREG 0100000 see zipinfo.c
var result = unixPermissions;
if (!unixPermissions) {
// I can't use octal values in strict mode, hence the hexa.
// 040775 => 0x41fd
// 0100664 => 0x81b4
result = isDir ? 0x41fd : 0x81b4;
}

return extFileAttr;
return (result & 0xFFFF) << 16;
};

/**
Expand All @@ -420,20 +426,9 @@ var generateUnixExternalFileAttr = function (unixPermissions, isDir) {
*/
var generateDosExternalFileAttr = function (dosPermissions, isDir) {

var permissions = 0;

if (!dosPermissions) {
return permissions;
}

if (dosPermissions.hidden) {
permissions |= 0x0002;
}
if (dosPermissions.readOnly) {
permissions |= 0x0001;
}
// the dir flag is already set for compatibility

return permissions;
return (dosPermissions || 0) & 0x3F;
};

/**
Expand Down Expand Up @@ -482,7 +477,7 @@ var generateZipParts = function(name, file, compressedObject, offset, platform)
extFileAttr |= 0x00010;
}
if(platform === "UNIX") {
versionMadeBy = 0x0314; // UNIX, version 2.0
versionMadeBy = 0x031E; // UNIX, version 3.0
extFileAttr |= generateUnixExternalFileAttr(file.unixPermissions, dir);
} else { // DOS or other, fallback to DOS
versionMadeBy = 0x0014; // DOS, version 2.0
Expand Down
21 changes: 9 additions & 12 deletions lib/zipEntry.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,22 +167,19 @@ ZipEntry.prototype = {
this.dosPermissions = null;
var madeBy = this.versionMadeBy >> 8;

// Check if we have the DOS directory flag set.
// We look for it in the DOS and UNIX permissions
// but some unknown platform could set it as a compatibility flag.
this.dir = this.externalFileAttributes & 0x0010 ? true : false;

if(madeBy === MADE_BY_DOS) {
this.dosPermissions = {
// Bit 1 Hidden
hidden: !!(this.externalFileAttributes & 0x0002),
// Bit 0 Read-Only
readOnly: !!(this.externalFileAttributes & 0x0001)
};
// Bit 5 Archive
this.dir = !!(this.externalFileAttributes & 0x0010);
// first 6 bits (0 to 5)
this.dosPermissions = this.externalFileAttributes & 0x3F;
}

if(madeBy === MADE_BY_UNIX) {
var fullFilePermissions = this.externalFileAttributes >> 16;
this.unixPermissions = fullFilePermissions;
// the octal permissions are in (fullFilePermissions & 0x01FF).toString(8);
this.dir = !!(fullFilePermissions & 0x4000);
this.unixPermissions = (this.externalFileAttributes >> 16) & 0xFFFF;
// the octal permissions are in (this.unixPermissions & 0x01FF).toString(8);
}

// fail safe : if the name ends with a / it probably means a folder
Expand Down
Binary file modified test/ref/permissions/linux_7z.zip
Binary file not shown.
Binary file modified test/ref/permissions/linux_ark.zip
Binary file not shown.
Binary file modified test/ref/permissions/linux_file_roller-ubuntu.zip
Binary file not shown.
Binary file modified test/ref/permissions/linux_file_roller-xubuntu.zip
Binary file not shown.
Binary file modified test/ref/permissions/linux_zip.zip
Binary file not shown.
Binary file modified test/ref/permissions/mac_finder.zip
Binary file not shown.
Loading

0 comments on commit e930e39

Please sign in to comment.