| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of dart.io; | 5 part of dart.io; |
| 6 | 6 |
| 7 // Read the file in blocks of size 64k. | 7 // Read the file in blocks of size 64k. |
| 8 const int _BLOCK_SIZE = 64 * 1024; | 8 const int _BLOCK_SIZE = 64 * 1024; |
| 9 | 9 |
| 10 | 10 |
| (...skipping 569 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 580 length(); | 580 length(); |
| 581 flush(); | 581 flush(); |
| 582 lock(int lock, int start, int end); | 582 lock(int lock, int start, int end); |
| 583 } | 583 } |
| 584 | 584 |
| 585 class _RandomAccessFile implements RandomAccessFile { | 585 class _RandomAccessFile implements RandomAccessFile { |
| 586 static bool _connectedResourceHandler = false; | 586 static bool _connectedResourceHandler = false; |
| 587 | 587 |
| 588 final String path; | 588 final String path; |
| 589 | 589 |
| 590 // Calling this function will increase the reference count on the native | |
| 591 // object that implements the file operations. It should only be called to | |
| 592 // pass the pointer to the IO Service, which will decrement the reference | |
| 593 // count when it is finished with it. | |
| 594 int _pointer() => _ops.getPointer(); | |
| 595 | |
| 596 bool _asyncDispatched = false; | 590 bool _asyncDispatched = false; |
| 597 SendPort _fileService; | 591 SendPort _fileService; |
| 598 | 592 |
| 599 _FileResourceInfo _resourceInfo; | 593 _FileResourceInfo _resourceInfo; |
| 600 _RandomAccessFileOps _ops; | 594 _RandomAccessFileOps _ops; |
| 601 | 595 |
| 602 _RandomAccessFile(int pointer, this.path) { | 596 _RandomAccessFile(int pointer, this.path) { |
| 603 _ops = new _RandomAccessFileOps(pointer); | 597 _ops = new _RandomAccessFileOps(pointer); |
| 604 _resourceInfo = new _FileResourceInfo(this); | 598 _resourceInfo = new _FileResourceInfo(this); |
| 605 _maybeConnectHandler(); | 599 _maybeConnectHandler(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 619 // open. | 613 // open. |
| 620 registerExtension('ext.dart.io.getOpenFiles', | 614 registerExtension('ext.dart.io.getOpenFiles', |
| 621 _FileResourceInfo.getOpenFiles); | 615 _FileResourceInfo.getOpenFiles); |
| 622 registerExtension('ext.dart.io.getFileByID', | 616 registerExtension('ext.dart.io.getFileByID', |
| 623 _FileResourceInfo.getFileInfoMapByID); | 617 _FileResourceInfo.getFileInfoMapByID); |
| 624 _connectedResourceHandler = true; | 618 _connectedResourceHandler = true; |
| 625 } | 619 } |
| 626 } | 620 } |
| 627 | 621 |
| 628 Future<RandomAccessFile> close() { | 622 Future<RandomAccessFile> close() { |
| 629 return _dispatch(_FILE_CLOSE, [_pointer()], markClosed: true).then((result)
{ | 623 return _dispatch(_FILE_CLOSE, [null], markClosed: true).then((result) { |
| 630 if (result != -1) { | 624 if (result != -1) { |
| 631 closed = closed || (result == 0); | 625 closed = closed || (result == 0); |
| 632 _maybePerformCleanup(); | 626 _maybePerformCleanup(); |
| 633 return this; | 627 return this; |
| 634 } else { | 628 } else { |
| 635 throw new FileSystemException("Cannot close file", path); | 629 throw new FileSystemException("Cannot close file", path); |
| 636 } | 630 } |
| 637 }); | 631 }); |
| 638 } | 632 } |
| 639 | 633 |
| 640 void closeSync() { | 634 void closeSync() { |
| 641 _checkAvailable(); | 635 _checkAvailable(); |
| 642 var id = _ops.close(); | 636 var id = _ops.close(); |
| 643 if (id == -1) { | 637 if (id == -1) { |
| 644 throw new FileSystemException("Cannot close file", path); | 638 throw new FileSystemException("Cannot close file", path); |
| 645 } | 639 } |
| 646 closed = closed || (id == 0); | 640 closed = closed || (id == 0); |
| 647 _maybePerformCleanup(); | 641 _maybePerformCleanup(); |
| 648 } | 642 } |
| 649 | 643 |
| 650 Future<int> readByte() { | 644 Future<int> readByte() { |
| 651 return _dispatch(_FILE_READ_BYTE, [_pointer()]).then((response) { | 645 return _dispatch(_FILE_READ_BYTE, [null]).then((response) { |
| 652 if (_isErrorResponse(response)) { | 646 if (_isErrorResponse(response)) { |
| 653 throw _exceptionFromResponse(response, "readByte failed", path); | 647 throw _exceptionFromResponse(response, "readByte failed", path); |
| 654 } | 648 } |
| 655 _resourceInfo.addRead(1); | 649 _resourceInfo.addRead(1); |
| 656 return response; | 650 return response; |
| 657 }); | 651 }); |
| 658 } | 652 } |
| 659 | 653 |
| 660 int readByteSync() { | 654 int readByteSync() { |
| 661 _checkAvailable(); | 655 _checkAvailable(); |
| 662 var result = _ops.readByte(); | 656 var result = _ops.readByte(); |
| 663 if (result is OSError) { | 657 if (result is OSError) { |
| 664 throw new FileSystemException("readByte failed", path, result); | 658 throw new FileSystemException("readByte failed", path, result); |
| 665 } | 659 } |
| 666 _resourceInfo.addRead(1); | 660 _resourceInfo.addRead(1); |
| 667 return result; | 661 return result; |
| 668 } | 662 } |
| 669 | 663 |
| 670 Future<List<int>> read(int bytes) { | 664 Future<List<int>> read(int bytes) { |
| 671 if (bytes is !int) { | 665 if (bytes is !int) { |
| 672 throw new ArgumentError(bytes); | 666 throw new ArgumentError(bytes); |
| 673 } | 667 } |
| 674 return _dispatch(_FILE_READ, [_pointer(), bytes]).then((response) { | 668 return _dispatch(_FILE_READ, [null, bytes]).then((response) { |
| 675 if (_isErrorResponse(response)) { | 669 if (_isErrorResponse(response)) { |
| 676 throw _exceptionFromResponse(response, "read failed", path); | 670 throw _exceptionFromResponse(response, "read failed", path); |
| 677 } | 671 } |
| 678 _resourceInfo.addRead(response[1].length); | 672 _resourceInfo.addRead(response[1].length); |
| 679 return response[1]; | 673 return response[1]; |
| 680 }); | 674 }); |
| 681 } | 675 } |
| 682 | 676 |
| 683 List<int> readSync(int bytes) { | 677 List<int> readSync(int bytes) { |
| 684 _checkAvailable(); | 678 _checkAvailable(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 697 if ((buffer is !List) || | 691 if ((buffer is !List) || |
| 698 ((start != null) && (start is !int)) || | 692 ((start != null) && (start is !int)) || |
| 699 ((end != null) && (end is !int))) { | 693 ((end != null) && (end is !int))) { |
| 700 throw new ArgumentError(); | 694 throw new ArgumentError(); |
| 701 } | 695 } |
| 702 end = RangeError.checkValidRange(start, end, buffer.length); | 696 end = RangeError.checkValidRange(start, end, buffer.length); |
| 703 if (end == start) { | 697 if (end == start) { |
| 704 return new Future.value(0); | 698 return new Future.value(0); |
| 705 } | 699 } |
| 706 int length = end - start; | 700 int length = end - start; |
| 707 return _dispatch(_FILE_READ_INTO, [_pointer(), length]).then((response) { | 701 return _dispatch(_FILE_READ_INTO, [null, length]).then((response) { |
| 708 if (_isErrorResponse(response)) { | 702 if (_isErrorResponse(response)) { |
| 709 throw _exceptionFromResponse(response, "readInto failed", path); | 703 throw _exceptionFromResponse(response, "readInto failed", path); |
| 710 } | 704 } |
| 711 var read = response[1]; | 705 var read = response[1]; |
| 712 var data = response[2]; | 706 var data = response[2]; |
| 713 buffer.setRange(start, start + read, data); | 707 buffer.setRange(start, start + read, data); |
| 714 _resourceInfo.addRead(read); | 708 _resourceInfo.addRead(read); |
| 715 return read; | 709 return read; |
| 716 }); | 710 }); |
| 717 } | 711 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 732 throw new FileSystemException("readInto failed", path, result); | 726 throw new FileSystemException("readInto failed", path, result); |
| 733 } | 727 } |
| 734 _resourceInfo.addRead(result); | 728 _resourceInfo.addRead(result); |
| 735 return result; | 729 return result; |
| 736 } | 730 } |
| 737 | 731 |
| 738 Future<RandomAccessFile> writeByte(int value) { | 732 Future<RandomAccessFile> writeByte(int value) { |
| 739 if (value is !int) { | 733 if (value is !int) { |
| 740 throw new ArgumentError(value); | 734 throw new ArgumentError(value); |
| 741 } | 735 } |
| 742 return _dispatch(_FILE_WRITE_BYTE, [_pointer(), value]).then((response) { | 736 return _dispatch(_FILE_WRITE_BYTE, [null, value]).then((response) { |
| 743 if (_isErrorResponse(response)) { | 737 if (_isErrorResponse(response)) { |
| 744 throw _exceptionFromResponse(response, "writeByte failed", path); | 738 throw _exceptionFromResponse(response, "writeByte failed", path); |
| 745 } | 739 } |
| 746 _resourceInfo.addWrite(1); | 740 _resourceInfo.addWrite(1); |
| 747 return this; | 741 return this; |
| 748 }); | 742 }); |
| 749 } | 743 } |
| 750 | 744 |
| 751 int writeByteSync(int value) { | 745 int writeByteSync(int value) { |
| 752 _checkAvailable(); | 746 _checkAvailable(); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 773 return new Future.value(this); | 767 return new Future.value(this); |
| 774 } | 768 } |
| 775 _BufferAndStart result; | 769 _BufferAndStart result; |
| 776 try { | 770 try { |
| 777 result = _ensureFastAndSerializableByteData(buffer, start, end); | 771 result = _ensureFastAndSerializableByteData(buffer, start, end); |
| 778 } catch (e) { | 772 } catch (e) { |
| 779 return new Future.error(e); | 773 return new Future.error(e); |
| 780 } | 774 } |
| 781 | 775 |
| 782 List request = new List(4); | 776 List request = new List(4); |
| 783 request[0] = _pointer(); | 777 request[0] = null; |
| 784 request[1] = result.buffer; | 778 request[1] = result.buffer; |
| 785 request[2] = result.start; | 779 request[2] = result.start; |
| 786 request[3] = end - (start - result.start); | 780 request[3] = end - (start - result.start); |
| 787 return _dispatch(_FILE_WRITE_FROM, request).then((response) { | 781 return _dispatch(_FILE_WRITE_FROM, request).then((response) { |
| 788 if (_isErrorResponse(response)) { | 782 if (_isErrorResponse(response)) { |
| 789 throw _exceptionFromResponse(response, "writeFrom failed", path); | 783 throw _exceptionFromResponse(response, "writeFrom failed", path); |
| 790 } | 784 } |
| 791 _resourceInfo.addWrite(end - (start - result.start)); | 785 _resourceInfo.addWrite(end - (start - result.start)); |
| 792 return this; | 786 return this; |
| 793 }); | 787 }); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 826 | 820 |
| 827 void writeStringSync(String string, {Encoding encoding: UTF8}) { | 821 void writeStringSync(String string, {Encoding encoding: UTF8}) { |
| 828 if (encoding is! Encoding) { | 822 if (encoding is! Encoding) { |
| 829 throw new ArgumentError(encoding); | 823 throw new ArgumentError(encoding); |
| 830 } | 824 } |
| 831 var data = encoding.encode(string); | 825 var data = encoding.encode(string); |
| 832 writeFromSync(data, 0, data.length); | 826 writeFromSync(data, 0, data.length); |
| 833 } | 827 } |
| 834 | 828 |
| 835 Future<int> position() { | 829 Future<int> position() { |
| 836 return _dispatch(_FILE_POSITION, [_pointer()]).then((response) { | 830 return _dispatch(_FILE_POSITION, [null]).then((response) { |
| 837 if (_isErrorResponse(response)) { | 831 if (_isErrorResponse(response)) { |
| 838 throw _exceptionFromResponse(response, "position failed", path); | 832 throw _exceptionFromResponse(response, "position failed", path); |
| 839 } | 833 } |
| 840 return response; | 834 return response; |
| 841 }); | 835 }); |
| 842 } | 836 } |
| 843 | 837 |
| 844 int positionSync() { | 838 int positionSync() { |
| 845 _checkAvailable(); | 839 _checkAvailable(); |
| 846 var result = _ops.position(); | 840 var result = _ops.position(); |
| 847 if (result is OSError) { | 841 if (result is OSError) { |
| 848 throw new FileSystemException("position failed", path, result); | 842 throw new FileSystemException("position failed", path, result); |
| 849 } | 843 } |
| 850 return result; | 844 return result; |
| 851 } | 845 } |
| 852 | 846 |
| 853 Future<RandomAccessFile> setPosition(int position) { | 847 Future<RandomAccessFile> setPosition(int position) { |
| 854 return _dispatch(_FILE_SET_POSITION, [_pointer(), position]) | 848 return _dispatch(_FILE_SET_POSITION, [null, position]) |
| 855 .then((response) { | 849 .then((response) { |
| 856 if (_isErrorResponse(response)) { | 850 if (_isErrorResponse(response)) { |
| 857 throw _exceptionFromResponse(response, "setPosition failed", path); | 851 throw _exceptionFromResponse(response, "setPosition failed", path); |
| 858 } | 852 } |
| 859 return this; | 853 return this; |
| 860 }); | 854 }); |
| 861 } | 855 } |
| 862 | 856 |
| 863 void setPositionSync(int position) { | 857 void setPositionSync(int position) { |
| 864 _checkAvailable(); | 858 _checkAvailable(); |
| 865 var result = _ops.setPosition(position); | 859 var result = _ops.setPosition(position); |
| 866 if (result is OSError) { | 860 if (result is OSError) { |
| 867 throw new FileSystemException("setPosition failed", path, result); | 861 throw new FileSystemException("setPosition failed", path, result); |
| 868 } | 862 } |
| 869 } | 863 } |
| 870 | 864 |
| 871 Future<RandomAccessFile> truncate(int length) { | 865 Future<RandomAccessFile> truncate(int length) { |
| 872 return _dispatch(_FILE_TRUNCATE, [_pointer(), length]).then((response) { | 866 return _dispatch(_FILE_TRUNCATE, [null, length]).then((response) { |
| 873 if (_isErrorResponse(response)) { | 867 if (_isErrorResponse(response)) { |
| 874 throw _exceptionFromResponse(response, "truncate failed", path); | 868 throw _exceptionFromResponse(response, "truncate failed", path); |
| 875 } | 869 } |
| 876 return this; | 870 return this; |
| 877 }); | 871 }); |
| 878 } | 872 } |
| 879 | 873 |
| 880 void truncateSync(int length) { | 874 void truncateSync(int length) { |
| 881 _checkAvailable(); | 875 _checkAvailable(); |
| 882 var result = _ops.truncate(length); | 876 var result = _ops.truncate(length); |
| 883 if (result is OSError) { | 877 if (result is OSError) { |
| 884 throw new FileSystemException("truncate failed", path, result); | 878 throw new FileSystemException("truncate failed", path, result); |
| 885 } | 879 } |
| 886 } | 880 } |
| 887 | 881 |
| 888 Future<int> length() { | 882 Future<int> length() { |
| 889 return _dispatch(_FILE_LENGTH, [_pointer()]).then((response) { | 883 return _dispatch(_FILE_LENGTH, [null]).then((response) { |
| 890 if (_isErrorResponse(response)) { | 884 if (_isErrorResponse(response)) { |
| 891 throw _exceptionFromResponse(response, "length failed", path); | 885 throw _exceptionFromResponse(response, "length failed", path); |
| 892 } | 886 } |
| 893 return response; | 887 return response; |
| 894 }); | 888 }); |
| 895 } | 889 } |
| 896 | 890 |
| 897 int lengthSync() { | 891 int lengthSync() { |
| 898 _checkAvailable(); | 892 _checkAvailable(); |
| 899 var result = _ops.length(); | 893 var result = _ops.length(); |
| 900 if (result is OSError) { | 894 if (result is OSError) { |
| 901 throw new FileSystemException("length failed", path, result); | 895 throw new FileSystemException("length failed", path, result); |
| 902 } | 896 } |
| 903 return result; | 897 return result; |
| 904 } | 898 } |
| 905 | 899 |
| 906 Future<RandomAccessFile> flush() { | 900 Future<RandomAccessFile> flush() { |
| 907 return _dispatch(_FILE_FLUSH, [_pointer()]).then((response) { | 901 return _dispatch(_FILE_FLUSH, [null]).then((response) { |
| 908 if (_isErrorResponse(response)) { | 902 if (_isErrorResponse(response)) { |
| 909 throw _exceptionFromResponse(response, | 903 throw _exceptionFromResponse(response, |
| 910 "flush failed", | 904 "flush failed", |
| 911 path); | 905 path); |
| 912 } | 906 } |
| 913 return this; | 907 return this; |
| 914 }); | 908 }); |
| 915 } | 909 } |
| 916 | 910 |
| 917 void flushSync() { | 911 void flushSync() { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 928 | 922 |
| 929 Future<RandomAccessFile> lock( | 923 Future<RandomAccessFile> lock( |
| 930 [FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end = -1]) { | 924 [FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end = -1]) { |
| 931 if ((mode is !FileLock) || (start is !int) || (end is !int)) { | 925 if ((mode is !FileLock) || (start is !int) || (end is !int)) { |
| 932 throw new ArgumentError(); | 926 throw new ArgumentError(); |
| 933 } | 927 } |
| 934 if ((start < 0) || (end < -1) || ((end != -1) && (start >= end))) { | 928 if ((start < 0) || (end < -1) || ((end != -1) && (start >= end))) { |
| 935 throw new ArgumentError(); | 929 throw new ArgumentError(); |
| 936 } | 930 } |
| 937 int lock = (mode == FileLock.EXCLUSIVE) ? LOCK_EXCLUSIVE : LOCK_SHARED; | 931 int lock = (mode == FileLock.EXCLUSIVE) ? LOCK_EXCLUSIVE : LOCK_SHARED; |
| 938 return _dispatch(_FILE_LOCK, [_pointer(), lock, start, end]) | 932 return _dispatch(_FILE_LOCK, [null, lock, start, end]) |
| 939 .then((response) { | 933 .then((response) { |
| 940 if (_isErrorResponse(response)) { | 934 if (_isErrorResponse(response)) { |
| 941 throw _exceptionFromResponse(response, 'lock failed', path); | 935 throw _exceptionFromResponse(response, 'lock failed', path); |
| 942 } | 936 } |
| 943 return this; | 937 return this; |
| 944 }); | 938 }); |
| 945 } | 939 } |
| 946 | 940 |
| 947 Future<RandomAccessFile> unlock([int start = 0, int end = -1]) { | 941 Future<RandomAccessFile> unlock([int start = 0, int end = -1]) { |
| 948 if ((start is !int) || (end is !int)) { | 942 if ((start is !int) || (end is !int)) { |
| 949 throw new ArgumentError(); | 943 throw new ArgumentError(); |
| 950 } | 944 } |
| 951 if (start == end) { | 945 if (start == end) { |
| 952 throw new ArgumentError(); | 946 throw new ArgumentError(); |
| 953 } | 947 } |
| 954 return _dispatch(_FILE_LOCK, [_pointer(), LOCK_UNLOCK, start, end]) | 948 return _dispatch(_FILE_LOCK, [null, LOCK_UNLOCK, start, end]) |
| 955 .then((response) { | 949 .then((response) { |
| 956 if (_isErrorResponse(response)) { | 950 if (_isErrorResponse(response)) { |
| 957 throw _exceptionFromResponse(response, 'unlock failed', path); | 951 throw _exceptionFromResponse(response, 'unlock failed', path); |
| 958 } | 952 } |
| 959 return this; | 953 return this; |
| 960 }); | 954 }); |
| 961 } | 955 } |
| 962 | 956 |
| 963 void lockSync( | 957 void lockSync( |
| 964 [FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end = -1]) { | 958 [FileLock mode = FileLock.EXCLUSIVE, int start = 0, int end = -1]) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 985 throw new ArgumentError(); | 979 throw new ArgumentError(); |
| 986 } | 980 } |
| 987 var result = _ops.lock(LOCK_UNLOCK, start, end); | 981 var result = _ops.lock(LOCK_UNLOCK, start, end); |
| 988 if (result is OSError) { | 982 if (result is OSError) { |
| 989 throw new FileSystemException('unlock failed', path, result); | 983 throw new FileSystemException('unlock failed', path, result); |
| 990 } | 984 } |
| 991 } | 985 } |
| 992 | 986 |
| 993 bool closed = false; | 987 bool closed = false; |
| 994 | 988 |
| 989 // Calling this function will increase the reference count on the native |
| 990 // object that implements the file operations. It should only be called to |
| 991 // pass the pointer to the IO Service, which will decrement the reference |
| 992 // count when it is finished with it. |
| 993 int _pointer() => _ops.getPointer(); |
| 994 |
| 995 Future _dispatch(int request, List data, { bool markClosed: false }) { | 995 Future _dispatch(int request, List data, { bool markClosed: false }) { |
| 996 if (closed) { | 996 if (closed) { |
| 997 return new Future.error(new FileSystemException("File closed", path)); | 997 return new Future.error(new FileSystemException("File closed", path)); |
| 998 } | 998 } |
| 999 if (_asyncDispatched) { | 999 if (_asyncDispatched) { |
| 1000 var msg = "An async operation is currently pending"; | 1000 var msg = "An async operation is currently pending"; |
| 1001 return new Future.error(new FileSystemException(msg, path)); | 1001 return new Future.error(new FileSystemException(msg, path)); |
| 1002 } | 1002 } |
| 1003 if (markClosed) { | 1003 if (markClosed) { |
| 1004 // Set closed to true to ensure that no more async requests can be issued | 1004 // Set closed to true to ensure that no more async requests can be issued |
| 1005 // for this file. | 1005 // for this file. |
| 1006 closed = true; | 1006 closed = true; |
| 1007 } | 1007 } |
| 1008 _asyncDispatched = true; | 1008 _asyncDispatched = true; |
| 1009 data[0] = _pointer(); |
| 1009 return _IOService._dispatch(request, data) | 1010 return _IOService._dispatch(request, data) |
| 1010 .whenComplete(() { | 1011 .whenComplete(() { |
| 1011 _asyncDispatched = false; | 1012 _asyncDispatched = false; |
| 1012 }); | 1013 }); |
| 1013 } | 1014 } |
| 1014 | 1015 |
| 1015 void _checkAvailable() { | 1016 void _checkAvailable() { |
| 1016 if (_asyncDispatched) { | 1017 if (_asyncDispatched) { |
| 1017 throw new FileSystemException("An async operation is currently pending", | 1018 throw new FileSystemException("An async operation is currently pending", |
| 1018 path); | 1019 path); |
| 1019 } | 1020 } |
| 1020 if (closed) { | 1021 if (closed) { |
| 1021 throw new FileSystemException("File closed", path); | 1022 throw new FileSystemException("File closed", path); |
| 1022 } | 1023 } |
| 1023 } | 1024 } |
| 1024 } | 1025 } |
| OLD | NEW |