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 550 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
561 if (result is OSError) { | 561 if (result is OSError) { |
562 throw new FileSystemException(msg, path, result); | 562 throw new FileSystemException(msg, path, result); |
563 } | 563 } |
564 } | 564 } |
565 } | 565 } |
566 | 566 |
567 | 567 |
568 class _RandomAccessFile | 568 class _RandomAccessFile |
569 extends Object with _ServiceObject | 569 extends Object with _ServiceObject |
570 implements RandomAccessFile { | 570 implements RandomAccessFile { |
571 // Use default Map so we keep order. | 571 static bool _connectedResourceHandler = false; |
572 static Map<int, _RandomAccessFile> _files = new Map<int, _RandomAccessFile>(); | |
573 | 572 |
574 final String path; | 573 final String path; |
575 int _id; | 574 int _id; |
576 bool _asyncDispatched = false; | 575 bool _asyncDispatched = false; |
577 SendPort _fileService; | 576 SendPort _fileService; |
578 | 577 |
579 int _totalRead = 0; | 578 _FileResourceInfo _resourceInfo; |
580 int _totalWritten = 0; | |
581 int _readCount = 0; | |
582 int _writeCount = 0; | |
583 | |
584 | 579 |
585 _RandomAccessFile(this._id, this.path) { | 580 _RandomAccessFile(this._id, this.path) { |
586 _files[_serviceId] = this; | 581 _resourceInfo = new _FileResourceInfo(this); |
587 } | 582 _maybeConnectHandler(); |
588 | |
589 String get _serviceTypePath => 'io/file/randomaccessfiles'; | |
590 String get _serviceTypeName => 'RandomAccessFile'; | |
591 | |
592 Map _toJSON(bool ref) { | |
593 var r = { | |
594 'id': _servicePath, | |
595 'type': _serviceType(ref), | |
596 'name': '$path', | |
597 'user_name': '$path', | |
598 }; | |
599 if (ref) { | |
600 return r; | |
601 } | |
602 r['asyncDispatched'] = _asyncDispatched; | |
603 r['fd'] = _getFD(_id); | |
604 r['totalRead'] = _totalRead; | |
605 r['totalWritten'] = _totalWritten; | |
606 r['readCount'] = _totalWritten; | |
607 r['writeCount'] = _writeCount; | |
608 return r; | |
609 } | 583 } |
610 | 584 |
611 void _maybePerformCleanup() { | 585 void _maybePerformCleanup() { |
612 if (closed) { | 586 if (closed) { |
613 _files.remove(_serviceId); | 587 _FileResourceInfo.FileClosed(_resourceInfo); |
614 } | 588 } |
615 } | 589 } |
616 | 590 |
617 external static int _getFD(int id); | 591 external static int _getFD(int id); |
618 | 592 |
| 593 _maybeConnectHandler() { |
| 594 if (!_connectedResourceHandler) { |
| 595 // TODO(ricow): we probably need set these in some initialization code. |
| 596 // We need to make sure that these are always awailable from the |
| 597 // observatory even if no files (or sockets for the socket ones) are |
| 598 // open. |
| 599 registerExtension('__getOpenFiles', |
| 600 _FileResourceInfo.getOpenFiles); |
| 601 registerExtension('__getFileByID', |
| 602 _FileResourceInfo.getFileInfoMapByID); |
| 603 _connectedResourceHandler = true; |
| 604 } |
| 605 } |
| 606 |
619 Future<RandomAccessFile> close() { | 607 Future<RandomAccessFile> close() { |
620 return _dispatch(_FILE_CLOSE, [_id], markClosed: true).then((result) { | 608 return _dispatch(_FILE_CLOSE, [_id], markClosed: true).then((result) { |
621 if (result != -1) { | 609 if (result != -1) { |
622 _id = result; | 610 _id = result; |
623 _maybePerformCleanup(); | 611 _maybePerformCleanup(); |
624 return this; | 612 return this; |
625 } else { | 613 } else { |
626 throw new FileSystemException("Cannot close file", path); | 614 throw new FileSystemException("Cannot close file", path); |
627 } | 615 } |
628 }); | 616 }); |
629 } | 617 } |
630 | 618 |
631 external static int _close(int id); | 619 external static int _close(int id); |
632 | 620 |
633 void closeSync() { | 621 void closeSync() { |
634 _checkAvailable(); | 622 _checkAvailable(); |
635 var id = _close(_id); | 623 var id = _close(_id); |
636 if (id == -1) { | 624 if (id == -1) { |
637 throw new FileSystemException("Cannot close file", path); | 625 throw new FileSystemException("Cannot close file", path); |
638 } | 626 } |
639 _id = id; | 627 _id = id; |
640 _maybePerformCleanup(); | 628 _maybePerformCleanup(); |
641 } | 629 } |
642 | 630 |
643 Future<int> readByte() { | 631 Future<int> readByte() { |
644 return _dispatch(_FILE_READ_BYTE, [_id]).then((response) { | 632 return _dispatch(_FILE_READ_BYTE, [_id]).then((response) { |
645 if (_isErrorResponse(response)) { | 633 if (_isErrorResponse(response)) { |
646 throw _exceptionFromResponse(response, "readByte failed", path); | 634 throw _exceptionFromResponse(response, "readByte failed", path); |
647 } | 635 } |
648 _readCount++; | 636 _resourceInfo.readCount++; |
649 _totalRead++; | 637 _resourceInfo.totalRead++; |
650 return response; | 638 return response; |
651 }); | 639 }); |
652 } | 640 } |
653 | 641 |
654 external static _readByte(int id); | 642 external static _readByte(int id); |
655 | 643 |
656 int readByteSync() { | 644 int readByteSync() { |
657 _checkAvailable(); | 645 _checkAvailable(); |
658 var result = _readByte(_id); | 646 var result = _readByte(_id); |
659 if (result is OSError) { | 647 if (result is OSError) { |
660 throw new FileSystemException("readByte failed", path, result); | 648 throw new FileSystemException("readByte failed", path, result); |
661 } | 649 } |
662 _readCount++; | 650 _resourceInfo.readCount++; |
663 _totalRead++; | 651 _resourceInfo.totalRead++; |
664 return result; | 652 return result; |
665 } | 653 } |
666 | 654 |
667 Future<List<int>> read(int bytes) { | 655 Future<List<int>> read(int bytes) { |
668 if (bytes is !int) { | 656 if (bytes is !int) { |
669 throw new ArgumentError(bytes); | 657 throw new ArgumentError(bytes); |
670 } | 658 } |
671 return _dispatch(_FILE_READ, [_id, bytes]).then((response) { | 659 return _dispatch(_FILE_READ, [_id, bytes]).then((response) { |
672 if (_isErrorResponse(response)) { | 660 if (_isErrorResponse(response)) { |
673 throw _exceptionFromResponse(response, "read failed", path); | 661 throw _exceptionFromResponse(response, "read failed", path); |
674 } | 662 } |
675 _readCount++; | 663 _resourceInfo.readCount++; |
676 _totalRead += response[1].length; | 664 _resourceInfo.totalRead += response[1].length; |
677 return response[1]; | 665 return response[1]; |
678 }); | 666 }); |
679 } | 667 } |
680 | 668 |
681 external static _read(int id, int bytes); | 669 external static _read(int id, int bytes); |
682 | 670 |
683 List<int> readSync(int bytes) { | 671 List<int> readSync(int bytes) { |
684 _checkAvailable(); | 672 _checkAvailable(); |
685 if (bytes is !int) { | 673 if (bytes is !int) { |
686 throw new ArgumentError(bytes); | 674 throw new ArgumentError(bytes); |
687 } | 675 } |
688 var result = _read(_id, bytes); | 676 var result = _read(_id, bytes); |
689 if (result is OSError) { | 677 if (result is OSError) { |
690 throw new FileSystemException("readSync failed", path, result); | 678 throw new FileSystemException("readSync failed", path, result); |
691 } | 679 } |
692 _readCount++; | 680 _resourceInfo.readCount++; |
693 _totalRead += result.length; | 681 _resourceInfo.totalRead += result.length; |
694 return result; | 682 return result; |
695 } | 683 } |
696 | 684 |
697 Future<int> readInto(List<int> buffer, [int start = 0, int end]) { | 685 Future<int> readInto(List<int> buffer, [int start = 0, int end]) { |
698 if (buffer is !List || | 686 if (buffer is !List || |
699 (start != null && start is !int) || | 687 (start != null && start is !int) || |
700 (end != null && end is !int)) { | 688 (end != null && end is !int)) { |
701 throw new ArgumentError(); | 689 throw new ArgumentError(); |
702 } | 690 } |
703 end = RangeError.checkValidRange(start, end, buffer.length); | 691 end = RangeError.checkValidRange(start, end, buffer.length); |
704 if (end == start) return new Future.value(0); | 692 if (end == start) return new Future.value(0); |
705 int length = end - start; | 693 int length = end - start; |
706 return _dispatch(_FILE_READ_INTO, [_id, length]).then((response) { | 694 return _dispatch(_FILE_READ_INTO, [_id, length]).then((response) { |
707 if (_isErrorResponse(response)) { | 695 if (_isErrorResponse(response)) { |
708 throw _exceptionFromResponse(response, "readInto failed", path); | 696 throw _exceptionFromResponse(response, "readInto failed", path); |
709 } | 697 } |
710 var read = response[1]; | 698 var read = response[1]; |
711 var data = response[2]; | 699 var data = response[2]; |
712 buffer.setRange(start, start + read, data); | 700 buffer.setRange(start, start + read, data); |
713 _readCount++; | 701 _resourceInfo.readCount++; |
714 _totalRead += read; | 702 _resourceInfo.totalRead += read; |
715 return read; | 703 return read; |
716 }); | 704 }); |
717 } | 705 } |
718 | 706 |
719 external static _readInto(int id, List<int> buffer, int start, int end); | 707 external static _readInto(int id, List<int> buffer, int start, int end); |
720 | 708 |
721 int readIntoSync(List<int> buffer, [int start = 0, int end]) { | 709 int readIntoSync(List<int> buffer, [int start = 0, int end]) { |
722 _checkAvailable(); | 710 _checkAvailable(); |
723 if (buffer is !List || | 711 if (buffer is !List || |
724 (start != null && start is !int) || | 712 (start != null && start is !int) || |
725 (end != null && end is !int)) { | 713 (end != null && end is !int)) { |
726 throw new ArgumentError(); | 714 throw new ArgumentError(); |
727 } | 715 } |
728 end = RangeError.checkValidRange(start, end, buffer.length); | 716 end = RangeError.checkValidRange(start, end, buffer.length); |
729 if (end == start) return 0; | 717 if (end == start) return 0; |
730 var result = _readInto(_id, buffer, start, end); | 718 var result = _readInto(_id, buffer, start, end); |
731 if (result is OSError) { | 719 if (result is OSError) { |
732 throw new FileSystemException("readInto failed", path, result); | 720 throw new FileSystemException("readInto failed", path, result); |
733 } | 721 } |
734 _readCount++; | 722 _resourceInfo.readCount++; |
735 _totalRead += result; | 723 _resourceInfo.totalRead += result; |
736 return result; | 724 return result; |
737 } | 725 } |
738 | 726 |
739 Future<RandomAccessFile> writeByte(int value) { | 727 Future<RandomAccessFile> writeByte(int value) { |
740 if (value is !int) { | 728 if (value is !int) { |
741 throw new ArgumentError(value); | 729 throw new ArgumentError(value); |
742 } | 730 } |
743 return _dispatch(_FILE_WRITE_BYTE, [_id, value]).then((response) { | 731 return _dispatch(_FILE_WRITE_BYTE, [_id, value]).then((response) { |
744 if (_isErrorResponse(response)) { | 732 if (_isErrorResponse(response)) { |
745 throw _exceptionFromResponse(response, "writeByte failed", path); | 733 throw _exceptionFromResponse(response, "writeByte failed", path); |
746 } | 734 } |
747 _writeCount++; | 735 _resourceInfo.writeCount++; |
748 _totalWritten++; | 736 _resourceInfo.totalWritten++; |
749 return this; | 737 return this; |
750 }); | 738 }); |
751 } | 739 } |
752 | 740 |
753 external static _writeByte(int id, int value); | 741 external static _writeByte(int id, int value); |
754 | 742 |
755 int writeByteSync(int value) { | 743 int writeByteSync(int value) { |
756 _checkAvailable(); | 744 _checkAvailable(); |
757 if (value is !int) { | 745 if (value is !int) { |
758 throw new ArgumentError(value); | 746 throw new ArgumentError(value); |
759 } | 747 } |
760 var result = _writeByte(_id, value); | 748 var result = _writeByte(_id, value); |
761 if (result is OSError) { | 749 if (result is OSError) { |
762 throw new FileSystemException("writeByte failed", path, result); | 750 throw new FileSystemException("writeByte failed", path, result); |
763 } | 751 } |
764 _writeCount++; | 752 _resourceInfo.writeCount++; |
765 _totalWritten++; | 753 _resourceInfo.totalWritten++; |
766 return result; | 754 return result; |
767 } | 755 } |
768 | 756 |
769 Future<RandomAccessFile> writeFrom( | 757 Future<RandomAccessFile> writeFrom( |
770 List<int> buffer, [int start = 0, int end]) { | 758 List<int> buffer, [int start = 0, int end]) { |
771 if ((buffer is !List) || | 759 if ((buffer is !List) || |
772 (start != null && start is !int) || | 760 (start != null && start is !int) || |
773 (end != null && end is !int)) { | 761 (end != null && end is !int)) { |
774 throw new ArgumentError("Invalid arguments to writeFrom"); | 762 throw new ArgumentError("Invalid arguments to writeFrom"); |
775 } | 763 } |
776 end = RangeError.checkValidRange(start, end, buffer.length); | 764 end = RangeError.checkValidRange(start, end, buffer.length); |
777 if (end == start) return new Future.value(this); | 765 if (end == start) return new Future.value(this); |
778 _BufferAndStart result; | 766 _BufferAndStart result; |
779 try { | 767 try { |
780 result = _ensureFastAndSerializableByteData(buffer, start, end); | 768 result = _ensureFastAndSerializableByteData(buffer, start, end); |
781 } catch (e) { | 769 } catch (e) { |
782 return new Future.error(e); | 770 return new Future.error(e); |
783 } | 771 } |
784 | 772 |
785 List request = new List(4); | 773 List request = new List(4); |
786 request[0] = _id; | 774 request[0] = _id; |
787 request[1] = result.buffer; | 775 request[1] = result.buffer; |
788 request[2] = result.start; | 776 request[2] = result.start; |
789 request[3] = end - (start - result.start); | 777 request[3] = end - (start - result.start); |
790 return _dispatch(_FILE_WRITE_FROM, request).then((response) { | 778 return _dispatch(_FILE_WRITE_FROM, request).then((response) { |
791 if (_isErrorResponse(response)) { | 779 if (_isErrorResponse(response)) { |
792 throw _exceptionFromResponse(response, "writeFrom failed", path); | 780 throw _exceptionFromResponse(response, "writeFrom failed", path); |
793 } | 781 } |
794 _writeCount++; | 782 _resourceInfo.writeCount++; |
795 _totalWritten += end - (start - result.start); | 783 _resourceInfo.totalWritten += end - (start - result.start); |
796 return this; | 784 return this; |
797 }); | 785 }); |
798 } | 786 } |
799 | 787 |
800 external static _writeFrom(int id, List<int> buffer, int start, int end); | 788 external static _writeFrom(int id, List<int> buffer, int start, int end); |
801 | 789 |
802 void writeFromSync(List<int> buffer, [int start = 0, int end]) { | 790 void writeFromSync(List<int> buffer, [int start = 0, int end]) { |
803 _checkAvailable(); | 791 _checkAvailable(); |
804 if (buffer is !List || | 792 if (buffer is !List || |
805 (start != null && start is !int) || | 793 (start != null && start is !int) || |
806 (end != null && end is !int)) { | 794 (end != null && end is !int)) { |
807 throw new ArgumentError("Invalid arguments to writeFromSync"); | 795 throw new ArgumentError("Invalid arguments to writeFromSync"); |
808 } | 796 } |
809 end = RangeError.checkValidRange(start, end, buffer.length); | 797 end = RangeError.checkValidRange(start, end, buffer.length); |
810 if (end == start) return; | 798 if (end == start) return; |
811 _BufferAndStart bufferAndStart = | 799 _BufferAndStart bufferAndStart = |
812 _ensureFastAndSerializableByteData(buffer, start, end); | 800 _ensureFastAndSerializableByteData(buffer, start, end); |
813 var result = _writeFrom(_id, | 801 var result = _writeFrom(_id, |
814 bufferAndStart.buffer, | 802 bufferAndStart.buffer, |
815 bufferAndStart.start, | 803 bufferAndStart.start, |
816 end - (start - bufferAndStart.start)); | 804 end - (start - bufferAndStart.start)); |
817 if (result is OSError) { | 805 if (result is OSError) { |
818 throw new FileSystemException("writeFrom failed", path, result); | 806 throw new FileSystemException("writeFrom failed", path, result); |
819 } | 807 } |
820 _writeCount++; | 808 _resourceInfo.writeCount++; |
821 _totalWritten += end - (start - bufferAndStart.start); | 809 _resourceInfo.totalWritten += end - (start - bufferAndStart.start); |
822 } | 810 } |
823 | 811 |
824 Future<RandomAccessFile> writeString(String string, | 812 Future<RandomAccessFile> writeString(String string, |
825 {Encoding encoding: UTF8}) { | 813 {Encoding encoding: UTF8}) { |
826 if (encoding is! Encoding) { | 814 if (encoding is! Encoding) { |
827 throw new ArgumentError(encoding); | 815 throw new ArgumentError(encoding); |
828 } | 816 } |
829 var data = encoding.encode(string); | 817 var data = encoding.encode(string); |
830 return writeFrom(data, 0, data.length); | 818 return writeFrom(data, 0, data.length); |
831 } | 819 } |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1042 void _checkAvailable() { | 1030 void _checkAvailable() { |
1043 if (_asyncDispatched) { | 1031 if (_asyncDispatched) { |
1044 throw new FileSystemException("An async operation is currently pending", | 1032 throw new FileSystemException("An async operation is currently pending", |
1045 path); | 1033 path); |
1046 } | 1034 } |
1047 if (closed) { | 1035 if (closed) { |
1048 throw new FileSystemException("File closed", path); | 1036 throw new FileSystemException("File closed", path); |
1049 } | 1037 } |
1050 } | 1038 } |
1051 } | 1039 } |
OLD | NEW |