Reactos
at listview 148 lines 4.7 kB view raw
1// 2// chsize.cpp 3// 4// Copyright (c) Microsoft Corporation. All rights reserved. 5// 6// Defines _chsize() and _chsize_s(), which change the size of a file. 7// 8#include <corecrt_internal_lowio.h> 9#include <corecrt_internal_ptd_propagation.h> 10 11 12// Changes the size of the given file, either extending or truncating it. The 13// file must have been opened with write permissions or this will fail. Returns 14// 0 on success; returns an errno error code on failure, 15static errno_t __cdecl _chsize_s_internal(int const fh, __int64 const size, __crt_cached_ptd_host& ptd) 16{ 17 _UCRT_CHECK_FH_CLEAR_OSSERR_RETURN_ERRCODE(ptd, fh, EBADF); 18 _UCRT_VALIDATE_CLEAR_OSSERR_RETURN_ERRCODE(ptd, (fh >= 0 && (unsigned)fh < (unsigned)_nhandle), EBADF); 19 _UCRT_VALIDATE_CLEAR_OSSERR_RETURN_ERRCODE(ptd, (_osfile(fh) & FOPEN), EBADF); 20 _UCRT_VALIDATE_CLEAR_OSSERR_RETURN_ERRCODE(ptd, (size >= 0), EINVAL); 21 22 return __acrt_lowio_lock_fh_and_call(fh, [&]() 23 { 24 if (_osfile(fh) & FOPEN) 25 { 26 return _chsize_nolock_internal(fh, size, ptd); 27 } 28 else 29 { 30 _ASSERTE(("Invalid file descriptor. File possibly closed by a different thread", 0)); 31 return ptd.get_errno().set(EBADF); 32 } 33 }); 34} 35 36extern "C" errno_t __cdecl _chsize_s(int const fh, __int64 const size) 37{ 38 __crt_cached_ptd_host ptd; 39 return _chsize_s_internal(fh, size, ptd); 40} 41 42struct __crt_seek_guard 43{ 44 45 __crt_seek_guard(int const fh, __int64 const size) 46 : place(_lseeki64_nolock(fh, 0, SEEK_CUR)), 47 end(_lseeki64_nolock(fh, 0, SEEK_END)), 48 extend(size - end), 49 fhh(fh) 50 { 51 } 52 53 ~__crt_seek_guard() 54 { 55 _lseeki64_nolock(fhh, place, SEEK_SET); 56 } 57 58 __crt_seek_guard(__crt_seek_guard const &) = delete; 59 __crt_seek_guard& operator=(__crt_seek_guard const &) = delete; 60 61 __int64 place; 62 __int64 end; 63 __int64 extend; 64 int fhh; 65}; 66 67extern "C" errno_t __cdecl _chsize_nolock_internal(int const fh, __int64 const size, __crt_cached_ptd_host& ptd) 68{ 69 // Get current file position and seek to end 70 __crt_seek_guard seek_guard(fh, size); 71 72 if (seek_guard.place == -1 || seek_guard.end == -1) 73 { 74 // EBADF if earlier lseek (in __crt_seek_guard) failed 75 // EINVAL otherwise (ex: too large of a offset) 76 return ptd.get_errno().value_or(EINVAL); 77 } 78 79 // Grow or shrink the file as necessary: 80 if (seek_guard.extend > 0) 81 { 82 // Extend the file by filling the new area with zeroes: 83 __crt_unique_heap_ptr<char> const zero_buffer(_calloc_crt_t(char, _INTERNAL_BUFSIZ)); 84 if (!zero_buffer) 85 { 86 return ptd.get_errno().set(ENOMEM); 87 } 88 89 int const old_mode = _setmode_nolock(fh, _O_BINARY); 90 91 do 92 { 93 int const bytes_to_write = seek_guard.extend >= static_cast<__int64>(_INTERNAL_BUFSIZ) 94 ? _INTERNAL_BUFSIZ 95 : static_cast<int>(seek_guard.extend); 96 97 int const bytes_written = _write_nolock(fh, zero_buffer.get(), bytes_to_write, ptd); 98 if (bytes_written == -1) 99 { 100 // Error on write: 101 if (ptd.get_doserrno().check(ERROR_ACCESS_DENIED)) 102 { 103 ptd.get_errno().set(EACCES); 104 } 105 106 return ptd.get_errno().value_or(0); 107 } 108 109 seek_guard.extend -= bytes_written; 110 } while (seek_guard.extend > 0); 111 112#pragma warning(suppress:6031) // return value ignored 113 _setmode_nolock(fh, old_mode); 114 } 115 else if (seek_guard.extend < 0) 116 { 117 // Shorten the file by truncating it: 118 __int64 const new_end = _lseeki64_nolock(fh, size, SEEK_SET); 119 if (new_end == -1) 120 { 121 return ptd.get_errno().value_or(0); 122 } 123 124 if (!SetEndOfFile(reinterpret_cast<HANDLE>(_get_osfhandle(fh)))) 125 { 126 ptd.get_doserrno().set(GetLastError()); 127 return ptd.get_errno().set(EACCES); 128 } 129 } 130 131 return 0; 132} 133 134extern "C" errno_t __cdecl _chsize_nolock(int const fh, __int64 const size) 135{ // TODO: _chsize_nolock is already internal-only. 136 // Once PTD is propagated everywhere, rename _chsize_nolock_internal to _chsize_nolock. 137 __crt_cached_ptd_host ptd; 138 return _chsize_nolock_internal(fh, size, ptd); 139} 140 141 142// Changes the size of the given file, either extending or truncating it. The 143// file must have been opened with write permissions or this will fail. Returns 144// 0 on success; returns -1 and sets errno on failure. 145extern "C" int __cdecl _chsize(int const fh, long const size) 146{ 147 return _chsize_s(fh, size) == 0 ? 0 : -1; 148}