OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 #library("entry"); |
| 6 |
| 7 #import("dart:io"); |
| 8 #import("read_request.dart"); |
| 9 #import("utils.dart"); |
| 10 |
| 11 /** |
| 12 * A single file in an archive. |
| 13 * |
| 14 * This is accessible via [ArchiveInputStream.onEntry]. |
| 15 */ |
| 16 class ArchiveEntry { |
| 17 /** |
| 18 * The various properties of this archive entry, as sent over from the C |
| 19 * extension. |
| 20 */ |
| 21 final List _properties; |
| 22 |
| 23 /** |
| 24 * The id of the archive to which this entry belongs. Used to read the entry |
| 25 * data. This will be set to null once there's no longer data available to be |
| 26 * read for this entry. |
| 27 */ |
| 28 int _archiveId; |
| 29 |
| 30 /** |
| 31 * The input stream being used to read data from this entry. This is null |
| 32 * until [openInputStream] is called. |
| 33 */ |
| 34 InputStream _input; |
| 35 |
| 36 // TODO(nweiz): Get rid of this once issue 4202 is fixed. |
| 37 /** |
| 38 * A future that only exists once [openInputStream] is called, and completes |
| 39 * once the input stream is closed. |
| 40 * |
| 41 * For internal use only. |
| 42 */ |
| 43 Future inputComplete; |
| 44 |
| 45 ArchiveEntry(this._archiveId, this._properties); |
| 46 |
| 47 /** If this entry is a hardlink, this is the destination. Otherwise, null. */ |
| 48 String get hardlink() => _properties[0]; |
| 49 |
| 50 /** The path to this entry in the archive. */ |
| 51 String get pathname() => _properties[1]; |
| 52 |
| 53 /** The path to this entry on disk, */ |
| 54 String get sourcepath() => _properties[2]; |
| 55 |
| 56 /** If this entry is a symlink, this is the destination. Otherwise, null. */ |
| 57 String get symlink() => _properties[3]; |
| 58 |
| 59 /** The group identifier for this entry. */ |
| 60 int get gid() => _properties[4]; |
| 61 |
| 62 /** The user identifier for this entry. */ |
| 63 int get uid() => _properties[5]; |
| 64 |
| 65 /** The permissions bitmask for this entry. */ |
| 66 int get perm_mask() => _properties[6]; |
| 67 |
| 68 /** The String representation of the permissions for this entry. */ |
| 69 String get strmode() => _properties[7]; |
| 70 |
| 71 /** The name of the group this entry belongs to. */ |
| 72 String get gname() => _properties[8]; |
| 73 |
| 74 /** The name of the user this entry belongs to. */ |
| 75 String get uname() => _properties[9]; |
| 76 |
| 77 /** The file flag bits that should be set for this entry. */ |
| 78 int get fflags_set() => _properties[10]; |
| 79 |
| 80 /** The file flag bits that should be cleared for this entry. */ |
| 81 int get fflags_clear() => _properties[11]; |
| 82 |
| 83 /** The textual representation of the file flags for this entry. */ |
| 84 String get fflags_text() => _properties[12]; |
| 85 |
| 86 /** The filetype bitmask for this entry. */ |
| 87 int get filetype_mask() => _properties[13]; |
| 88 |
| 89 /** The filetype and permissions bitmask for this entry. */ |
| 90 int get mode_mask() => _properties[14]; |
| 91 |
| 92 /** The size of this entry in bytes, or null if it's unset. */ |
| 93 int get size() => _properties[15]; |
| 94 |
| 95 /** The ID of the device containing this entry, or null if it's unset. */ |
| 96 int get dev() => _properties[16]; |
| 97 |
| 98 /** The major number of the ID of the device containing this entry. */ |
| 99 int get devmajor() => _properties[17]; |
| 100 |
| 101 /** The minor number of the ID of the device containing this entry. */ |
| 102 int get devminor() => _properties[18]; |
| 103 |
| 104 /** The inode number of this entry, or null if it's unset. */ |
| 105 int get ino() => _properties[19]; |
| 106 |
| 107 /** The number of references to this entry. */ |
| 108 int get nlink() => _properties[20]; |
| 109 |
| 110 /** The device ID of this entry. */ |
| 111 int get rdev() => _properties[21]; |
| 112 |
| 113 /** The major number of the device ID of this entry. */ |
| 114 int get rdevmajor() => _properties[22]; |
| 115 |
| 116 /** The minor number of the device ID of this entry. */ |
| 117 int get rdevminor() => _properties[23]; |
| 118 |
| 119 /** The last time this entry was accessed. */ |
| 120 Date get atime() => new Date.fromMillisecondsSinceEpoch(_properties[24]); |
| 121 |
| 122 /** The nanoseconds at the last time this entry was accessed. */ |
| 123 int get atime_nsec() => _properties[25]; |
| 124 |
| 125 /** The time this entry was created. */ |
| 126 Date get birthtime() => new Date.fromMillisecondsSinceEpoch(_properties[26]); |
| 127 |
| 128 /** The nanoseconds at the time this entry was created. */ |
| 129 int get birthtime_nsec() => _properties[27]; |
| 130 |
| 131 /** The last time an inode property of this entry was changed. */ |
| 132 Date get ctime() => new Date.fromMillisecondsSinceEpoch(_properties[28]); |
| 133 |
| 134 /** |
| 135 * The nanoseconds at the last time an inode property of this entry was |
| 136 * changed. |
| 137 */ |
| 138 int get ctime_nsec() => _properties[29]; |
| 139 |
| 140 /** The last time this entry was modified. */ |
| 141 Date get mtime() => new Date.fromMillisecondsSinceEpoch(_properties[30]); |
| 142 |
| 143 /** The nanoseconds at the last time this entry was modified. */ |
| 144 int get mtime_nsec() => _properties[31]; |
| 145 |
| 146 /** Whether [openInputStream] has been called. */ |
| 147 bool get isInputOpen() => _input != null; |
| 148 |
| 149 /** |
| 150 * Creates a new input stream for reading the contents of this entry. |
| 151 * |
| 152 * The contents of an entry must be consumed before the next entry is read |
| 153 * from the parent [ArchiveInputStream]. This means that [openInputStream] |
| 154 * must be called from the [ArchiveInputStream.onEntry] callback, or before |
| 155 * the future returned by that callback completes. Once the next entry has |
| 156 * been read, calling [openInputStream] will throw an [ArchiveException]. |
| 157 * |
| 158 * Only one input stream may be opened per entry. |
| 159 */ |
| 160 InputStream openInputStream() { |
| 161 if (_archiveId == null) { |
| 162 throw new UnsupportedOperationException("Archive entry $pathname is no " |
| 163 "longer being read from the archive."); |
| 164 } else if (_input != null) { |
| 165 throw new UnsupportedOperationException("An input stream has already been" |
| 166 "opened for archive entry $pathname."); |
| 167 } |
| 168 |
| 169 var inputCompleter = new Completer(); |
| 170 inputComplete = inputCompleter.future; |
| 171 |
| 172 _input = new ListInputStream(); |
| 173 // TODO(nweiz): Report errors once issue 3657 is fixed |
| 174 var future = _consumeInput().chain((_) { |
| 175 if (!_input.closed) _input.markEndOfStream(); |
| 176 // Asynchronously complete to give the InputStream callbacks a chance to |
| 177 // fire. |
| 178 return async(); |
| 179 }).transform((_) => inputCompleter.complete(null)); |
| 180 |
| 181 future.handleException((e) { |
| 182 print(e); |
| 183 print(future.stackTrace); |
| 184 }); |
| 185 return _input; |
| 186 } |
| 187 |
| 188 /** |
| 189 * Close this entry so that its input stream no longer produces data. |
| 190 * |
| 191 * In addition to closing the associated input stream, this will prevent new |
| 192 * input streams from being opened. |
| 193 */ |
| 194 void close() { |
| 195 _archiveId = null; |
| 196 if (_input != null) _input.close(); |
| 197 } |
| 198 |
| 199 /** |
| 200 * Read all data from the archive and write it to [_input]. Returns a future |
| 201 * that completes once this is done. |
| 202 * |
| 203 * This assumes that both [_input] and [_archiveId] are non-null and that |
| 204 * [_input] is open, although if that changes before this completes it will |
| 205 * handle it gracefully. |
| 206 */ |
| 207 Future _consumeInput() { |
| 208 var data; |
| 209 return call(DATA_BLOCK, _archiveId).chain((_data) { |
| 210 data = _data; |
| 211 // TODO(nweiz): This async() call is only necessary because of issue 4222. |
| 212 return async(); |
| 213 }).chain((_) { |
| 214 if (_input.closed || _archiveId == null || data == null) { |
| 215 return new Future.immediate(null); |
| 216 } |
| 217 _input.write(data); |
| 218 return _consumeInput(); |
| 219 }); |
| 220 } |
| 221 } |
OLD | NEW |