1 //
2 // lseek.cpp
3 //
4 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //
6 // Defines _lseek(), which seeks the file pointer of a file.
7 //
8 #include <corecrt_internal_lowio.h>
9 #include <corecrt_internal_ptd_propagation.h>
10 #include <stdlib.h>
11
12 #if SEEK_SET != FILE_BEGIN || SEEK_CUR != FILE_CURRENT || SEEK_END != FILE_END
13 #error Xenix and Win32 seek constants not compatible
14 #endif
15
16
17
18 // These functions actually seek the underlying operating system file handle.
19 // The logic is different for 32-bit and 64-bit seek values because a seek may
20 // end up moving out of range of 32-bit values.
common_lseek_do_seek_nolock(HANDLE const os_handle,long const offset,int const origin,__crt_cached_ptd_host & ptd)21 static long __cdecl common_lseek_do_seek_nolock(HANDLE const os_handle, long const offset, int const origin, __crt_cached_ptd_host& ptd) throw()
22 {
23 LARGE_INTEGER const origin_pos = { 0 };
24
25 LARGE_INTEGER saved_pos;
26 if (!SetFilePointerEx(os_handle, origin_pos, &saved_pos, FILE_CURRENT))
27 {
28 __acrt_errno_map_os_error_ptd(GetLastError(), ptd);
29 return -1;
30 }
31
32 LARGE_INTEGER seek_pos = { 0 };
33 seek_pos.QuadPart = offset;
34
35 LARGE_INTEGER new_pos = { 0 };
36 if (!SetFilePointerEx(os_handle, seek_pos, &new_pos, origin))
37 {
38 __acrt_errno_map_os_error_ptd(GetLastError(), ptd);
39 return -1;
40 }
41
42 // The call succeeded, but the new file pointer location is too large for
43 // the return type or is a negative value. So, restore the file pointer
44 // to the saved location and return an error:
45 if (new_pos.QuadPart > LONG_MAX)
46 {
47 SetFilePointerEx(os_handle, saved_pos, nullptr, FILE_BEGIN);
48 ptd.get_errno().set(EINVAL);
49 return -1;
50 }
51
52 return static_cast<long>(new_pos.LowPart);
53 }
54
common_lseek_do_seek_nolock(HANDLE const os_handle,__int64 const offset,int const origin,__crt_cached_ptd_host & ptd)55 static __int64 __cdecl common_lseek_do_seek_nolock(HANDLE const os_handle, __int64 const offset, int const origin, __crt_cached_ptd_host& ptd) throw()
56 {
57 LARGE_INTEGER new_pos;
58 if (!SetFilePointerEx(os_handle, *reinterpret_cast<LARGE_INTEGER const*>(&offset), &new_pos, origin))
59 {
60 __acrt_errno_map_os_error_ptd(GetLastError(), ptd);
61 return -1;
62 }
63
64 return new_pos.QuadPart;
65 }
66
67
68 template <typename Integer>
common_lseek_nolock(int const fh,Integer const offset,int const origin,__crt_cached_ptd_host & ptd)69 static Integer __cdecl common_lseek_nolock(int const fh, Integer const offset, int const origin, __crt_cached_ptd_host& ptd) throw()
70 {
71 HANDLE const os_handle = reinterpret_cast<HANDLE>(_get_osfhandle(fh));
72 if (os_handle == reinterpret_cast<HANDLE>(-1))
73 {
74 ptd.get_errno().set(EBADF);
75 _ASSERTE(("Invalid file descriptor",0));
76 return -1;
77 }
78
79 Integer const new_position = common_lseek_do_seek_nolock(os_handle, offset, origin, ptd);
80 if (new_position == -1)
81 {
82 return -1;
83 }
84
85 // The call succeeded, so return success:
86 _osfile(fh) &= ~FEOFLAG; // Clear the Ctrl-Z flag
87 return new_position;
88 }
89
90 // Moves the file pointer associated with the given file to a new position. The
91 // new position is 'offset' bytes (the offset may be negative) away from the
92 // origin specified by 'origin'.
93 //
94 // If origin == SEEK_SET, the origin in the beginning of file
95 // If origin == SEEK_CUR, the origin is the current file pointer position
96 // If origin == SEEK_END, the origin is the end of the file
97 //
98 // Returns the offset, in bytes, of the new position, from the beginning of the
99 // file. Returns -1 and sets errno on failure. Note that seeking beyond the
100 // end of the file is not an error, but seeking before the beginning is.
101 template <typename Integer>
common_lseek(int const fh,Integer const offset,int const origin,__crt_cached_ptd_host & ptd)102 static Integer __cdecl common_lseek(int const fh, Integer const offset, int const origin, __crt_cached_ptd_host& ptd) throw()
103 {
104 _UCRT_CHECK_FH_CLEAR_OSSERR_RETURN(ptd, fh, EBADF, -1);
105 _UCRT_VALIDATE_CLEAR_OSSERR_RETURN(ptd, fh >= 0 && (unsigned)fh < (unsigned)_nhandle, EBADF, -1);
106 _UCRT_VALIDATE_CLEAR_OSSERR_RETURN(ptd, _osfile(fh) & FOPEN, EBADF, -1);
107
108 __acrt_lowio_lock_fh(fh);
109 Integer result = -1;
110 __try
111 {
112 if ((_osfile(fh) & FOPEN) == 0)
113 {
114 ptd.get_errno().set(EBADF);
115 ptd.get_doserrno().set(0);
116 _ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0));
117 __leave;
118 }
119
120 result = common_lseek_nolock(fh, offset, origin, ptd);
121 }
122 __finally
123 {
124 __acrt_lowio_unlock_fh(fh);
125 }
126 __endtry
127 return result;
128 }
129
_lseek_internal(int const fh,long const offset,int const origin,__crt_cached_ptd_host & ptd)130 extern "C" long __cdecl _lseek_internal(int const fh, long const offset, int const origin, __crt_cached_ptd_host& ptd)
131 {
132 return common_lseek(fh, offset, origin, ptd);
133 }
134
_lseeki64_internal(int const fh,__int64 const offset,int const origin,__crt_cached_ptd_host & ptd)135 extern "C" __int64 __cdecl _lseeki64_internal(int const fh, __int64 const offset, int const origin, __crt_cached_ptd_host& ptd)
136 {
137 return common_lseek(fh, offset, origin, ptd);
138 }
139
_lseek_nolock_internal(int const fh,long const offset,int const origin,__crt_cached_ptd_host & ptd)140 extern "C" long __cdecl _lseek_nolock_internal(int const fh, long const offset, int const origin, __crt_cached_ptd_host& ptd)
141 {
142 return common_lseek_nolock(fh, offset, origin, ptd);
143 }
144
_lseeki64_nolock_internal(int const fh,__int64 const offset,int const origin,__crt_cached_ptd_host & ptd)145 extern "C" __int64 __cdecl _lseeki64_nolock_internal(int const fh, __int64 const offset, int const origin, __crt_cached_ptd_host& ptd)
146 {
147 return common_lseek_nolock(fh, offset, origin, ptd);
148 }
149
_lseek(int const fh,long const offset,int const origin)150 extern "C" long __cdecl _lseek(int const fh, long const offset, int const origin)
151 {
152 __crt_cached_ptd_host ptd;
153 return common_lseek(fh, offset, origin, ptd);
154 }
155
_lseeki64(int const fh,__int64 const offset,int const origin)156 extern "C" __int64 __cdecl _lseeki64(int const fh, __int64 const offset, int const origin)
157 {
158 __crt_cached_ptd_host ptd;
159 return common_lseek(fh, offset, origin, ptd);
160 }
161
_lseek_nolock(int const fh,long const offset,int const origin)162 extern "C" long __cdecl _lseek_nolock(int const fh, long const offset, int const origin)
163 {
164 __crt_cached_ptd_host ptd;
165 return common_lseek_nolock(fh, offset, origin, ptd);
166 }
167
_lseeki64_nolock(int const fh,__int64 const offset,int const origin)168 extern "C" __int64 __cdecl _lseeki64_nolock(int const fh, __int64 const offset, int const origin)
169 {
170 __crt_cached_ptd_host ptd;
171 return common_lseek_nolock(fh, offset, origin, ptd);
172 }
173