xref: /reactos/sdk/lib/ucrt/lowio/lseek.cpp (revision e98e9000)
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