• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

taosdata / TDengine / #5005

26 Mar 2026 12:51PM UTC coverage: 72.152% (-0.2%) from 72.338%
#5005

push

travis-ci

web-flow
merge: from main to 3.0 branch #34951

512 of 851 new or added lines in 47 files covered. (60.16%)

6189 existing lines in 147 files now uncovered.

253282 of 351039 relevant lines covered (72.15%)

132156710.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.48
/source/os/src/osFile.c
1
/*
2
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
3
 *
4
 * This program is free software: you can use, redistribute, and/or modify
5
 * it under the terms of the GNU Affero General Public License, version 3
6
 * or later ("AGPL"), as published by the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 * FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * You should have received a copy of the GNU Affero General Public License
13
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14
 */
15
#define ALLOW_FORBID_FUNC
16
#include "os.h"
17
#include "osSemaphore.h"
18
#include "tdef.h"
19
#include "zlib.h"
20

21
#ifdef WINDOWS
22
#include <WinBase.h>
23
#include <io.h>
24
#include <ktmw32.h>
25
#include <windows.h>
26
#define F_OK 0
27
#define X_OK 1
28
#define W_OK 2
29
#define R_OK 4
30

31
#define _SEND_FILE_STEP_ 1024
32

33
#else
34
#include <fcntl.h>
35
#ifndef TD_ASTRA
36
#include <sys/file.h>
37

38
#if !defined(_TD_DARWIN_64)
39
#include <sys/sendfile.h>
40
#endif
41
#endif
42
#include <sys/stat.h>
43
#include <sys/uio.h>
44
#include <unistd.h>
45
#define LINUX_FILE_NO_TEXT_OPTION 0
46
#define O_TEXT                    LINUX_FILE_NO_TEXT_OPTION
47

48
#define _SEND_FILE_STEP_ 1000
49
#endif
50

51
typedef int32_t FileFd;
52

53
#ifdef WINDOWS
54
typedef struct TdFile {
55
  TdThreadRwlock rwlock;
56
  HANDLE         hFile;
57
  FILE          *fp;
58
  int32_t        tdFileOptions;
59
} TdFile;
60
#else
61
typedef struct TdFile {
62
  TdThreadRwlock rwlock;
63
  FileFd         fd;
64
  FILE          *fp;
65
} TdFile;
66
#endif  // WINDOWS
67

68
#define FILE_WITH_LOCK 1
69

70
#ifdef BUILD_WITH_RAND_ERR
71
#define STUB_RAND_IO_ERR(ret)                                \
72
  if (tsEnableRandErr && (tsRandErrScope & RAND_ERR_FILE)) { \
73
    uint32_t r = taosRand() % tsRandErrDivisor;              \
74
    if ((r + 1) <= tsRandErrChance) {                        \
75
      errno = EIO;                                           \
76
      terrno = TAOS_SYSTEM_ERROR(errno);                     \
77
      return (ret);                                          \
78
    }                                                        \
79
  }
80
#else
81
#define STUB_RAND_IO_ERR(ret)
82
#endif
83

84
void taosGetTmpfilePath(const char *inputTmpDir, const char *fileNamePrefix, char *dstPath) {
3,014,900✔
85
  if (inputTmpDir == NULL || fileNamePrefix == NULL) return;
3,014,900✔
86
#ifdef WINDOWS
87

88
  char tmpPath[PATH_MAX];
89

90
  int32_t len = (int32_t)strlen(inputTmpDir);
91
  memcpy(tmpPath, inputTmpDir, len);
92

93
  if (tmpPath[len - 1] != '/' && tmpPath[len - 1] != '\\') {
94
    tmpPath[len++] = '\\';
95
  }
96

97
  snprintf(tmpPath + len, sizeof(tmpPath) - len, "%s%s%s", TD_TMP_FILE_PREFIX, fileNamePrefix, "-%d-%s");
98

99
  char rand[8] = {0};
100
  taosRandStr(rand, tListLen(rand) - 1);
101
  snprintf(dstPath, PATH_MAX, tmpPath, taosGetPId(), rand);
102

103
#else
104

105
  char    tmpPath[PATH_MAX];
3,015,129✔
106
  int32_t len = strlen(inputTmpDir);
3,016,129✔
107
  (void)memcpy(tmpPath, inputTmpDir, len);
3,016,129✔
108
  static uint64_t seqId = 0;
109

110
  if (tmpPath[len - 1] != '/') {
3,016,129✔
111
    tmpPath[len++] = '/';
200✔
112
  }
113

114
  snprintf(tmpPath + len, sizeof(tmpPath) - len, "%s%s%s", TD_TMP_FILE_PREFIX, fileNamePrefix, "-%d-%s");
3,017,016✔
115

116
  char rand[32] = {0};
3,007,683✔
117

118
  (void)snprintf(rand, sizeof(rand), "%" PRIu64, atomic_add_fetch_64(&seqId, 1));
3,018,188✔
119

120
  (void)snprintf(dstPath, PATH_MAX, tmpPath, taosGetPId(), rand);
3,017,059✔
121

122
#endif
123
}
124

125
int64_t taosCopyFile(const char *from, const char *to) {
2,151✔
126
  if (from == NULL || to == NULL) {
2,151✔
127
    terrno = TSDB_CODE_INVALID_PARA;
400✔
128
    return -1;
400✔
129
  }
130
#ifdef WINDOWS
131
  if (CopyFile(from, to, 0)) {
132
    return 1;
133
  } else {
134
    terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
135
    return -1;
136
  }
137
#else
138
  char    buffer[4096];
154✔
139
  int64_t size = 0;
1,751✔
140
  int64_t bytes;
141
  int32_t code = TSDB_CODE_SUCCESS;
1,751✔
142

143
  TdFilePtr pFileFrom = NULL;
1,751✔
144
  TdFilePtr pFileTo = NULL;
1,751✔
145
  pFileFrom = taosOpenFile(from, TD_FILE_READ);
1,751✔
146
  if (pFileFrom == NULL) {
1,751✔
147
    code = terrno;
200✔
148
    goto _err;
200✔
149
  }
150

151
  pFileTo = taosOpenFile(to, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_EXCL);
1,551✔
152
  if (pFileTo == NULL) {
1,551✔
153
    code = terrno;
200✔
154
    goto _err;
200✔
155
  }
156

157
  while (true) {
158
    bytes = taosReadFile(pFileFrom, buffer, sizeof(buffer));
3,707✔
159
    if (bytes < 0) {
3,707✔
160
      code = terrno;
×
161
      goto _err;
×
162
    }
163

164
    if (bytes == 0) break;
3,707✔
165

166
    size += bytes;
3,553✔
167

168
    if (taosWriteFile(pFileTo, (void *)buffer, bytes) < bytes) {
3,553✔
169
      code = terrno;
×
170
      goto _err;
×
171
    }
172
    if (bytes < sizeof(buffer)) break;
3,553✔
173
  }
174

175
  code = taosFsyncFile(pFileTo);
1,351✔
176
  if (code != 0) {
1,351✔
177
    goto _err;
×
178
  }
179

180
  TAOS_UNUSED(taosCloseFile(&pFileFrom));
1,351✔
181
  TAOS_UNUSED(taosCloseFile(&pFileTo));
1,351✔
182

183
  if (code != 0) {
1,351✔
184
    terrno = code;
×
185
    return -1;
×
186
  }
187

188
  return size;
1,351✔
189

190
_err:
400✔
191

192
  if (pFileFrom != NULL) TAOS_SKIP_ERROR(taosCloseFile(&pFileFrom));
400✔
193
  if (pFileTo != NULL) TAOS_SKIP_ERROR(taosCloseFile(&pFileTo));
400✔
194
  /* coverity[+retval] */
195
  TAOS_SKIP_ERROR(taosRemoveFile(to));
400✔
196

197
  terrno = code;
400✔
198
  return -1;
400✔
199
#endif
200
}
201

202
TdFilePtr taosCreateFile(const char *path, int32_t tdFileOptions) {
3,800✔
203
  if (path == NULL) {
3,800✔
204
    terrno = TSDB_CODE_INVALID_PARA;
200✔
205
    return NULL;
200✔
206
  }
207
  TdFilePtr fp = taosOpenFile(path, tdFileOptions);
3,600✔
208
  if (!fp) {
3,600✔
209
    if (errorIsFileNotExist(terrno)) {
400✔
210
      // Try to create directory recursively
211
      char s[PATH_MAX];
×
212
      tstrncpy(s, path, sizeof(s));
400✔
213
      if (taosMulMkDir(taosDirName(s)) != 0) {
400✔
214
        return NULL;
200✔
215
      }
216
      fp = taosOpenFile(path, tdFileOptions);
200✔
217
      if (!fp) {
200✔
218
        return NULL;
×
219
      }
220
    }
221
  }
222

223
  return fp;
3,400✔
224
}
225

226
int32_t taosRemoveFile(const char *path) {
61,728,577✔
227
  OS_PARAM_CHECK(path);
61,728,577✔
228
  int32_t code = remove(path);
61,728,377✔
229
  if (-1 == code) {
61,732,020✔
230
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
3,032,325✔
231
    return terrno;
3,030,391✔
232
  }
233
  return code;
58,699,695✔
234
}
235

236
int32_t taosRenameFile(const char *oldName, const char *newName) {
112,213,418✔
237
  OS_PARAM_CHECK(oldName);
112,213,418✔
238
  OS_PARAM_CHECK(newName);
112,213,218✔
239
#ifdef WINDOWS
240
  bool finished = false;
241

242
  HANDLE transactionHandle = CreateTransaction(NULL, NULL, 0, 0, 0, INFINITE, NULL);
243
  if (transactionHandle == INVALID_HANDLE_VALUE) {
244
    DWORD error = GetLastError();
245
    ERRNO = error;
246
    terrno = TAOS_SYSTEM_WINAPI_ERROR(error);
247
    return terrno;
248
  }
249

250
  BOOL result = MoveFileTransacted(oldName, newName, NULL, NULL, MOVEFILE_REPLACE_EXISTING, transactionHandle);
251

252
  if (result) {
253
    finished = CommitTransaction(transactionHandle);
254
    if (!finished) {
255
      DWORD error = GetLastError();
256
      ERRNO = error;
257
      terrno = TAOS_SYSTEM_WINAPI_ERROR(error);
258
    }
259
  } else {
260
    RollbackTransaction(transactionHandle);
261
    DWORD error = GetLastError();
262
    ERRNO = error;
263
    terrno = TAOS_SYSTEM_WINAPI_ERROR(error);
264
    finished = false;
265
  }
266

267
  CloseHandle(transactionHandle);
268

269
  return finished ? 0 : terrno;
270
#else
271
#ifdef TD_ASTRA // TD_ASTRA_TODO
272
  if (taosCheckExistFile(newName)) taosRemoveFile(newName);
273
#endif
274
  int32_t code = rename(oldName, newName);
112,213,018✔
275
  if (-1 == code) {
112,222,476✔
276
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
16,557✔
277
    return terrno;
12,975✔
278
  }
279

280
  return TSDB_CODE_SUCCESS;
112,205,919✔
281
#endif
282
}
283

284
int32_t taosStatFile(const char *path, int64_t *size, int64_t *mtime, int64_t *atime) {
280,711,795✔
285
  OS_PARAM_CHECK(path);
280,711,795✔
286
#ifdef WINDOWS
287
  struct _stati64 fileStat;
288
  int32_t         code = _stati64(path, &fileStat);
289
#else
290
  struct stat fileStat;
280,456,396✔
291
  int32_t     code = stat(path, &fileStat);
280,711,987✔
292
#endif
293
  if (-1 == code) {
280,712,311✔
294
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
17,013,614✔
295
    return terrno;
16,987,491✔
296
  }
297

298
  if (size != NULL) {
263,698,697✔
299
    *size = fileStat.st_size;
258,014,237✔
300
  }
301

302
  if (mtime != NULL) {
263,708,840✔
303
    *mtime = fileStat.st_mtime;
1,244,236✔
304
  }
305

306
  if (atime != NULL) {
263,708,840✔
307
    *atime = fileStat.st_atime;
200✔
308
  }
309

310
  return 0;
263,708,840✔
311
}
312

313
int32_t taosGetFileDiskID(const char *path, int64_t *diskid) {
695,031✔
314
  OS_PARAM_CHECK(path);
695,031✔
315
#ifdef WINDOWS
316
  struct _stati64 fileStat;
317
  int32_t         code = _stati64(path, &fileStat);
318
#else
319
  struct stat fileStat;
693,982✔
320
  int32_t     code = stat(path, &fileStat);
694,831✔
321
#endif
322
  if (-1 == code) {
694,831✔
323
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
200✔
324
    return terrno;
200✔
325
  }
326

327
  if (diskid != NULL) {
694,631✔
328
    *diskid = fileStat.st_dev;
694,431✔
329
  }
330

331
  return 0;
694,631✔
332
}
333

334
int32_t taosDevInoFile(TdFilePtr pFile, int64_t *stDev, int64_t *stIno) {
8,523,480✔
335
#ifdef WINDOWS
336
  if (pFile == NULL || pFile->hFile == NULL) {
337
    terrno = TSDB_CODE_INVALID_PARA;
338
    return terrno;
339
  }
340
  BY_HANDLE_FILE_INFORMATION bhfi;
341
  if (GetFileInformationByHandle(pFile->hFile, &bhfi) == FALSE) {
342
    DWORD error = GetLastError();
343
    terrno = TAOS_SYSTEM_WINAPI_ERROR(error);
344
    return terrno;
345
  }
346

347
  if (stDev != NULL) {
348
    *stDev = (int64_t)(bhfi.dwVolumeSerialNumber);
349
  }
350

351
  if (stIno != NULL) {
352
    *stIno = (int64_t)((((uint64_t)bhfi.nFileIndexHigh) << 32) + bhfi.nFileIndexLow);
353
  }
354

355
#else
356
  if (pFile == NULL || pFile->fd < 0) {
8,523,480✔
357
    terrno = TSDB_CODE_INVALID_PARA;
3,774✔
358
    return terrno;
200✔
359
  }
360

361
  struct stat fileStat;
8,509,664✔
362
  int32_t     code = fstat(pFile->fd, &fileStat);
8,523,413✔
363
  if (-1 == code) {
8,526,130✔
UNCOV
364
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
×
UNCOV
365
    return terrno;
×
366
  }
367

368
  if (stDev != NULL) {
8,526,130✔
369
    *stDev = fileStat.st_dev;
8,526,280✔
370
  }
371

372
  if (stIno != NULL) {
8,528,979✔
373
    *stIno = fileStat.st_ino;
8,528,193✔
374
  }
375
#endif
376

377
  return 0;
8,528,348✔
378
}
379

380
FILE *taosOpenFileForStream(const char *path, int32_t tdFileOptions) {
2,147,483,647✔
381
  if (path == NULL) {
2,147,483,647✔
382
    terrno = TSDB_CODE_INVALID_PARA;
200✔
383
    return NULL;
200✔
384
  }
385
  char *mode = NULL;
2,147,483,647✔
386
  if (tdFileOptions & TD_FILE_APPEND) {
2,147,483,647✔
387
    mode = (tdFileOptions & TD_FILE_TEXT) ? "at+" : "ab+";
928,450✔
388
  } else if (tdFileOptions & TD_FILE_TRUNC) {
2,147,483,647✔
389
    mode = (tdFileOptions & TD_FILE_TEXT) ? "wt+" : "wb+";
795,252✔
390
  } else if ((tdFileOptions & TD_FILE_READ) && !(tdFileOptions & TD_FILE_WRITE)) {
2,147,483,647✔
391
    mode = (tdFileOptions & TD_FILE_TEXT) ? "rt" : "rb";
2,147,483,647✔
392
  } else {
UNCOV
393
    mode = (tdFileOptions & TD_FILE_TEXT) ? "rt+" : "rb+";
×
394
  }
395
  if (tdFileOptions & TD_FILE_EXCL) {
2,147,483,647✔
396
    terrno = TSDB_CODE_INVALID_PARA;
×
UNCOV
397
    return NULL;
×
398
  }
399
  FILE *f = fopen(path, mode);
2,147,483,647✔
400
  if (NULL == f) {
2,147,483,647✔
401
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
1,772,388✔
402
  }
403
  return f;
2,147,483,647✔
404
}
405

406
#ifdef WINDOWS
407
HANDLE taosOpenFileNotStream(const char *path, int32_t tdFileOptions) {
408
  if (path == NULL) {
409
    terrno = TSDB_CODE_INVALID_PARA;
410
    return INVALID_HANDLE_VALUE;
411
  }
412
  DWORD openMode = 0;
413
  DWORD access = 0;
414
  DWORD fileFlag = FILE_ATTRIBUTE_NORMAL;
415
  DWORD shareMode = FILE_SHARE_READ;
416

417
  openMode = OPEN_EXISTING;
418
  if (tdFileOptions & TD_FILE_CREATE) {
419
    openMode = OPEN_ALWAYS;
420
  } else if (tdFileOptions & TD_FILE_EXCL) {
421
    openMode = CREATE_NEW;
422
  } else if ((tdFileOptions & TD_FILE_TRUNC)) {
423
    openMode = TRUNCATE_EXISTING;
424
    access |= GENERIC_WRITE;
425
  }
426
  if (tdFileOptions & TD_FILE_APPEND) {
427
    access |= FILE_APPEND_DATA;
428
  }
429
  if (tdFileOptions & TD_FILE_WRITE) {
430
    access |= GENERIC_WRITE;
431
  }
432

433
  shareMode |= FILE_SHARE_WRITE;
434

435
  access |= GENERIC_READ;
436

437
  if (tdFileOptions & TD_FILE_AUTO_DEL) {
438
    fileFlag |= FILE_ATTRIBUTE_TEMPORARY;
439
  }
440
  if (tdFileOptions & TD_FILE_WRITE_THROUGH) {
441
    fileFlag |= FILE_FLAG_WRITE_THROUGH;
442
  }
443

444
  HANDLE h = CreateFile(path, access, shareMode, NULL, openMode, fileFlag, NULL);
445
  if (h != INVALID_HANDLE_VALUE && (tdFileOptions & TD_FILE_APPEND) && (tdFileOptions & TD_FILE_WRITE)) {
446
    SetFilePointer(h, 0, NULL, FILE_END);
447
  }
448
  if (h == INVALID_HANDLE_VALUE) {
449
    DWORD dwError = GetLastError();
450
    terrno = TAOS_SYSTEM_WINAPI_ERROR(dwError);
451
    // LPVOID lpMsgBuf;
452
    // FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, (LPTSTR)&lpMsgBuf,
453
    // 0,
454
    //               NULL);
455
    // printf("CreateFile failed with error %d: %s", dwError, (char *)lpMsgBuf);
456
    // LocalFree(lpMsgBuf);
457
  }
458
  return h;
459
}
460

461
int64_t taosReadFile(TdFilePtr pFile, void *buf, int64_t count) {
462
  if (pFile == NULL || buf == NULL) {
463
    terrno = TSDB_CODE_INVALID_PARA;
464
    return terrno;
465
  }
466
#if FILE_WITH_LOCK
467
  (void)taosThreadRwlockRdlock(&(pFile->rwlock));
468
#endif
469
  if (pFile->hFile == NULL) {
470
#if FILE_WITH_LOCK
471
    (void)taosThreadRwlockUnlock(&(pFile->rwlock));
472
#endif
473
    terrno = TSDB_CODE_INVALID_PARA;
474
    return terrno;
475
  }
476

477
  int64_t res = 0;
478
  DWORD   bytesRead;
479
  if (!ReadFile(pFile->hFile, buf, count, &bytesRead, NULL)) {
480
    DWORD errCode = GetLastError();
481
    terrno = TAOS_SYSTEM_WINAPI_ERROR(errCode);
482
    res = -1;
483
  } else {
484
    res = bytesRead;
485
  }
486
#if FILE_WITH_LOCK
487
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
488
#endif
489
  return res;
490
}
491

492
int64_t taosWriteFile(TdFilePtr pFile, const void *buf, int64_t count) {
493
  if (pFile == NULL || pFile->hFile == NULL || buf == NULL) {
494
    terrno = TSDB_CODE_INVALID_PARA;
495
    return 0;
496
  }
497
#if FILE_WITH_LOCK
498
  (void)taosThreadRwlockWrlock(&(pFile->rwlock));
499
#endif
500

501
  DWORD bytesWritten;
502
  if (!WriteFile(pFile->hFile, buf, count, &bytesWritten, NULL)) {
503
    SET_ERRNO(GetLastError());
504
    terrno = TAOS_SYSTEM_WINAPI_ERROR(ERRNO);
505
    bytesWritten = -1;
506
  }
507

508
#if FILE_WITH_LOCK
509
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
510
#endif
511
  return bytesWritten;
512
}
513

514
int64_t taosPWriteFile(TdFilePtr pFile, const void *buf, int64_t count, int64_t offset) {
515
  if (pFile == NULL || buf == NULL) {
516
    terrno = TSDB_CODE_INVALID_PARA;
517
    return 0;
518
  }
519
#if FILE_WITH_LOCK
520
  (void)taosThreadRwlockWrlock(&(pFile->rwlock));
521
#endif
522
  if (pFile->hFile == NULL) {
523
#if FILE_WITH_LOCK
524
    (void)taosThreadRwlockUnlock(&(pFile->rwlock));
525
#endif
526
    return 0;
527
  }
528

529
  DWORD      ret = 0;
530
  OVERLAPPED ol = {0};
531
  ol.OffsetHigh = (uint32_t)((offset & 0xFFFFFFFF00000000LL) >> 0x20);
532
  ol.Offset = (uint32_t)(offset & 0xFFFFFFFFLL);
533

534
  SetLastError(0);
535
  BOOL result = WriteFile(pFile->hFile, buf, count, &ret, &ol);
536
  if (!result) {
537
    SET_ERRNO(GetLastError());
538
    terrno = TAOS_SYSTEM_WINAPI_ERROR(ERRNO);
539
    ret = -1;
540
  }
541

542
#if FILE_WITH_LOCK
543
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
544
#endif
545
  return ret;
546
}
547

548
int64_t taosLSeekFile(TdFilePtr pFile, int64_t offset, int32_t whence) {
549
  if (pFile == NULL || pFile->hFile == NULL) {
550
    terrno = TSDB_CODE_INVALID_PARA;
551
    return -1;
552
  }
553
#if FILE_WITH_LOCK
554
  (void)taosThreadRwlockRdlock(&(pFile->rwlock));
555
#endif
556

557
  LARGE_INTEGER liOffset;
558
  liOffset.QuadPart = offset;
559
  if (!SetFilePointerEx(pFile->hFile, liOffset, NULL, whence)) {
560
    SET_ERRNO(GetLastError());
561
    terrno = TAOS_SYSTEM_WINAPI_ERROR(ERRNO);
562
    return -1;
563
  }
564

565
  liOffset.QuadPart = 0;
566
  if (!SetFilePointerEx(pFile->hFile, liOffset, &liOffset, FILE_CURRENT)) {
567
    SET_ERRNO(GetLastError());
568
    terrno = TAOS_SYSTEM_WINAPI_ERROR(ERRNO);
569
    return -1;
570
  }
571
#if FILE_WITH_LOCK
572
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
573
#endif
574
  return liOffset.QuadPart;
575
}
576

577
int32_t taosFStatFile(TdFilePtr pFile, int64_t *size, int64_t *mtime) {
578
  if (pFile == NULL || pFile->hFile == NULL) {
579
    terrno = TSDB_CODE_INVALID_PARA;
580
    return terrno;
581
  }
582

583
  if (size != NULL) {
584
    LARGE_INTEGER fileSize;
585
    if (!GetFileSizeEx(pFile->hFile, &fileSize)) {
586
      SET_ERRNO(GetLastError());
587
      terrno = TAOS_SYSTEM_WINAPI_ERROR(ERRNO);
588
      return terrno;  // Error getting file size
589
    }
590
    *size = fileSize.QuadPart;
591
  }
592

593
  if (mtime != NULL) {
594
    FILETIME creationTime, lastAccessTime, lastWriteTime;
595
    if (!GetFileTime(pFile->hFile, &creationTime, &lastAccessTime, &lastWriteTime)) {
596
      SET_ERRNO(GetLastError());
597
      terrno = TAOS_SYSTEM_WINAPI_ERROR(ERRNO);
598
      return terrno;  // Error getting file time
599
    }
600
    // Convert the FILETIME structure to a time_t value
601
    ULARGE_INTEGER ull;
602
    ull.LowPart = lastWriteTime.dwLowDateTime;
603
    ull.HighPart = lastWriteTime.dwHighDateTime;
604
    *mtime = (int64_t)((ull.QuadPart - 116444736000000000ULL) / 10000000ULL);
605
  }
606
  return 0;
607
}
608

609
int32_t taosLockFile(TdFilePtr pFile) {
610
  if (pFile == NULL || pFile->hFile == NULL) {
611
    terrno = TSDB_CODE_INVALID_PARA;
612
    return terrno;
613
  }
614

615
  BOOL          fSuccess = FALSE;
616
  LARGE_INTEGER fileSize;
617
  OVERLAPPED    overlapped = {0};
618

619
  fSuccess = LockFileEx(pFile->hFile, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY,
620
                        0,           // reserved
621
                        ~0,          // number of bytes to lock low
622
                        ~0,          // number of bytes to lock high
623
                        &overlapped  // overlapped structure
624
  );
625
  if (!fSuccess) {
626
    return TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
627
  }
628
  return 0;
629
}
630

631
int32_t taosUnLockFile(TdFilePtr pFile) {
632
  if (pFile == NULL || pFile->hFile == NULL) {
633
    return 0;
634
  }
635
  BOOL       fSuccess = FALSE;
636
  OVERLAPPED overlapped = {0};
637

638
  fSuccess = UnlockFileEx(pFile->hFile, 0, ~0, ~0, &overlapped);
639
  if (!fSuccess) {
640
    return TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
641
  }
642
  return 0;
643
}
644

645
int32_t taosFtruncateFile(TdFilePtr pFile, int64_t l_size) {
646
  if (pFile == NULL) {
647
    terrno = TSDB_CODE_INVALID_PARA;
648
    return terrno;
649
  }
650
  if (pFile->hFile == NULL) {
651
    printf("Ftruncate file error, hFile was null\n");
652
    terrno = TSDB_CODE_INVALID_PARA;
653
    return terrno;
654
  }
655

656
  LARGE_INTEGER li_0;
657
  li_0.QuadPart = (int64_t)0;
658
  BOOL cur = SetFilePointerEx(pFile->hFile, li_0, NULL, FILE_CURRENT);
659
  if (!cur) {
660
    printf("SetFilePointerEx Error getting current position in file.\n");
661
    terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
662
    return terrno;
663
  }
664

665
  LARGE_INTEGER li_size;
666
  li_size.QuadPart = l_size;
667
  BOOL cur2 = SetFilePointerEx(pFile->hFile, li_size, NULL, FILE_BEGIN);
668
  if (cur2 == 0) {
669
    int error = GetLastError();
670
    switch (error) {
671
      case ERROR_INVALID_HANDLE:
672
        SET_ERRNO(EBADF);
673
        break;
674
      default:
675
        SET_ERRNO(EIO);
676
        break;
677
    }
678
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
679
    return terrno;
680
  }
681

682
  if (!SetEndOfFile(pFile->hFile)) {
683
    int error = GetLastError();
684
    printf("SetEndOfFile GetLastError is:%d", error);
685
    switch (error) {
686
      case ERROR_INVALID_HANDLE:
687
        SET_ERRNO(EBADF);
688
        break;
689
      default:
690
        SET_ERRNO(EIO);
691
        break;
692
    }
693
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
694
    return terrno;
695
  }
696
  return 0;
697
}
698

699
int64_t taosFSendFile(TdFilePtr pFileOut, TdFilePtr pFileIn, int64_t *offset, int64_t size) {
700
  if (pFileOut == NULL || pFileIn == NULL) {
701
    terrno = TSDB_CODE_INVALID_PARA;
702
    return -1;
703
  }
704
  if (pFileIn->hFile == NULL || pFileOut->hFile == NULL) {
705
    terrno = TSDB_CODE_INVALID_PARA;
706
    return -1;
707
  }
708

709
  LARGE_INTEGER fileOffset;
710
  fileOffset.QuadPart = *offset;
711

712
  if (!SetFilePointerEx(pFileIn->hFile, fileOffset, &fileOffset, FILE_BEGIN)) {
713
    terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
714
    return -1;
715
  }
716

717
  int64_t writeLen = 0;
718
  uint8_t buffer[_SEND_FILE_STEP_] = {0};
719

720
  DWORD bytesRead;
721
  DWORD bytesWritten;
722
  for (int64_t len = 0; len < (size - _SEND_FILE_STEP_); len += _SEND_FILE_STEP_) {
723
    if (!ReadFile(pFileIn->hFile, buffer, _SEND_FILE_STEP_, &bytesRead, NULL)) {
724
      terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
725
      return writeLen;
726
    }
727

728
    if (bytesRead <= 0) {
729
      return writeLen;
730
    } else if (bytesRead < _SEND_FILE_STEP_) {
731
      if (!WriteFile(pFileOut->hFile, buffer, bytesRead, &bytesWritten, NULL)) {
732
        terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
733
        return -1;
734
      } else {
735
        return (int64_t)(writeLen + bytesRead);
736
      }
737
    } else {
738
      if (!WriteFile(pFileOut->hFile, buffer, _SEND_FILE_STEP_, &bytesWritten, NULL)) {
739
        terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
740
        return -1;
741
      } else {
742
        writeLen += _SEND_FILE_STEP_;
743
      }
744
    }
745
  }
746

747
  int64_t remain = size - writeLen;
748
  if (remain > 0) {
749
    DWORD bytesRead;
750
    if (!ReadFile(pFileIn->hFile, buffer, (DWORD)remain, &bytesRead, NULL)) {
751
      terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
752
      return -1;
753
    }
754

755
    if (bytesRead <= 0) {
756
      return writeLen;
757
    } else {
758
      DWORD bytesWritten;
759
      if (!WriteFile(pFileOut->hFile, buffer, bytesRead, &bytesWritten, NULL)) {
760
        terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
761
        return -1;
762
      } else {
763
        writeLen += bytesWritten;
764
      }
765
    }
766
  }
767
  return writeLen;
768
}
769

770
bool errorIsFileNotExist(int32_t code) {
771
   return code == TAOS_SYSTEM_ERROR(ENOENT) ||
772
          code == TAOS_SYSTEM_WINAPI_ERROR(ERROR_FILE_NOT_FOUND) ||
773
          code == TAOS_SYSTEM_WINAPI_ERROR(ERROR_PATH_NOT_FOUND);
774
}
775
#else
776
int taosOpenFileNotStream(const char *path, int32_t tdFileOptions) {
1,070,619,163✔
777
  if (path == NULL) {
1,070,619,163✔
UNCOV
778
    terrno = TSDB_CODE_INVALID_PARA;
×
UNCOV
779
    return -1;
×
780
  }
781
  int access = O_BINARY;
1,070,619,163✔
782
  access |= (tdFileOptions & TD_FILE_CREATE) ? O_CREAT : 0;
1,070,619,163✔
783
  if ((tdFileOptions & TD_FILE_WRITE) && (tdFileOptions & TD_FILE_READ)) {
1,070,619,163✔
784
    access |= O_RDWR;
133,035,315✔
785
  } else if (tdFileOptions & TD_FILE_WRITE) {
937,583,848✔
786
    access |= O_WRONLY;
77,594,704✔
787
  } else if (tdFileOptions & TD_FILE_READ) {
859,989,144✔
788
    access |= O_RDONLY;
859,248,101✔
789
  }
790
  access |= (tdFileOptions & TD_FILE_TRUNC) ? O_TRUNC : 0;
1,070,619,163✔
791
  access |= (tdFileOptions & TD_FILE_APPEND) ? O_APPEND : 0;
1,070,619,163✔
792
  access |= (tdFileOptions & TD_FILE_TEXT) ? O_TEXT : 0;
1,070,619,163✔
793
  access |= (tdFileOptions & TD_FILE_EXCL) ? O_EXCL : 0;
1,070,619,163✔
794
  access |= (tdFileOptions & TD_FILE_CLOEXEC) ? O_CLOEXEC : 0;
1,070,619,163✔
795

796
  int fd = open(path, access, S_IRWXU | S_IRWXG | S_IRWXO);
1,070,619,163✔
797
  if (-1 == fd) {
1,070,878,646✔
798
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
7,290,325✔
799
  }
800
  return fd;
1,070,480,041✔
801
}
802

803
int64_t taosReadFile(TdFilePtr pFile, void *buf, int64_t count) {
2,147,483,647✔
804
  if (pFile == NULL || buf == NULL) {
2,147,483,647✔
805
    terrno = TSDB_CODE_INVALID_PARA;
808✔
806
    return -1;
400✔
807
  }
808
  STUB_RAND_IO_ERR(terrno)
809
#if FILE_WITH_LOCK
810
  (void)taosThreadRwlockRdlock(&(pFile->rwlock));
2,147,483,647✔
811
#endif
812

813
  if (pFile->fd < 0) {
2,147,483,647✔
814
#if FILE_WITH_LOCK
UNCOV
815
    (void)taosThreadRwlockUnlock(&(pFile->rwlock));
×
816
#endif
UNCOV
817
    terrno = TSDB_CODE_INVALID_PARA;
×
818
    return -1;
×
819
  }
820

821
  int64_t leftbytes = count;
2,147,483,647✔
822
  int64_t readbytes;
823
  char   *tbuf = (char *)buf;
2,147,483,647✔
824
  int32_t code = 0;
2,147,483,647✔
825

826
  while (leftbytes > 0) {
2,147,483,647✔
827
#ifdef WINDOWS
828
    readbytes = _read(pFile->fd, (void *)tbuf, (uint32_t)leftbytes);
829
#else
830
    readbytes = read(pFile->fd, (void *)tbuf, (uint32_t)leftbytes);
2,147,483,647✔
831
#endif
832
    if (readbytes < 0) {
2,147,483,647✔
833
      if (ERRNO == EINTR) {
5,834✔
UNCOV
834
        continue;
×
835
      } else {
836
        code = TAOS_SYSTEM_ERROR(ERRNO);
5,834✔
837
#if FILE_WITH_LOCK
838
        (void)taosThreadRwlockUnlock(&(pFile->rwlock));
5,834✔
839
#endif
840
        terrno = code;
5,834✔
841
        return -1;
5,834✔
842
      }
843
    } else if (readbytes == 0) {
2,147,483,647✔
844
#if FILE_WITH_LOCK
845
      (void)taosThreadRwlockUnlock(&(pFile->rwlock));
2,529,760✔
846
#endif
847
      return (int64_t)(count - leftbytes);
2,529,760✔
848
    }
849

850
    leftbytes -= readbytes;
2,147,483,647✔
851
    tbuf += readbytes;
2,147,483,647✔
852
  }
853

854
#if FILE_WITH_LOCK
855
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
2,147,483,647✔
856
#endif
857

858
  return count;
2,147,483,647✔
859
}
860

861
int64_t taosWriteFile(TdFilePtr pFile, const void *buf, int64_t count) {
2,147,483,647✔
862
  STUB_RAND_IO_ERR(terrno)
863
  if (pFile == NULL || buf == NULL) {
2,147,483,647✔
UNCOV
864
    terrno = TSDB_CODE_INVALID_PARA;
×
865
    return 0;
400✔
866
  }
867
#if FILE_WITH_LOCK
868
  (void)taosThreadRwlockWrlock(&(pFile->rwlock));
2,147,483,647✔
869
#endif
870
  if (pFile->fd < 0) {
2,147,483,647✔
871
#if FILE_WITH_LOCK
UNCOV
872
    (void)taosThreadRwlockUnlock(&(pFile->rwlock));
×
873
#endif
UNCOV
874
    terrno = TSDB_CODE_INVALID_PARA;
×
UNCOV
875
    return 0;
×
876
  }
877

878
  int64_t nleft = count;
2,147,483,647✔
879
  int64_t nwritten = 0;
2,147,483,647✔
880
  char   *tbuf = (char *)buf;
2,147,483,647✔
881
  int32_t code = 0;
2,147,483,647✔
882

883
  while (nleft > 0) {
2,147,483,647✔
884
    nwritten = write(pFile->fd, (void *)tbuf, (uint32_t)nleft);
2,147,483,647✔
885
    if (nwritten < 0) {
2,147,483,647✔
886
      if (ERRNO == EINTR) {
200✔
UNCOV
887
        continue;
×
888
      }
889
      code = TAOS_SYSTEM_ERROR(ERRNO);
200✔
890
#if FILE_WITH_LOCK
891
      (void)taosThreadRwlockUnlock(&(pFile->rwlock));
200✔
892
#endif
893
      terrno = code;
200✔
894
      return -1;
200✔
895
    }
896
    nleft -= nwritten;
2,147,483,647✔
897
    tbuf += nwritten;
2,147,483,647✔
898
  }
899

900
#if FILE_WITH_LOCK
901
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
2,147,483,647✔
902
#endif
903

904
  return count;
2,147,483,647✔
905
}
906

907
int64_t taosPWriteFile(TdFilePtr pFile, const void *buf, int64_t count, int64_t offset) {
280,516,959✔
908
  STUB_RAND_IO_ERR(terrno)
909
  if (pFile == NULL || buf == NULL) {
280,516,959✔
910
    terrno = TSDB_CODE_INVALID_PARA;
400✔
911
    return 0;
400✔
912
  }
913

914
  int32_t code = 0;
280,534,963✔
915
#if FILE_WITH_LOCK
916
  (void)taosThreadRwlockWrlock(&(pFile->rwlock));
280,534,963✔
917
#endif
918

919
#if FILE_WITH_LOCK
920
  if (pFile->fd < 0) {
280,544,611✔
UNCOV
921
    (void)taosThreadRwlockUnlock(&(pFile->rwlock));
×
UNCOV
922
    return 0;
×
923
  }
924
#endif
925
#ifndef TD_ASTRA
926
  int64_t ret = pwrite(pFile->fd, buf, count, offset);
280,533,183✔
927
  if (-1 == ret) {
280,545,607✔
UNCOV
928
    code = TAOS_SYSTEM_ERROR(ERRNO);
×
929
  }
930
#else  // TD_ASTRA_TODO
931
  int64_t ret = -1;
932
  int64_t cur = lseek(pFile->fd, 0, SEEK_CUR);
933
  if (cur < 0) {
934
    code = TAOS_SYSTEM_ERROR(ERRNO);
935
    goto _exit;
936
  }
937
  if (lseek(pFile->fd, offset, SEEK_SET) < 0) {
938
    code = TAOS_SYSTEM_ERROR(ERRNO);
939
    goto _exit;
940
  }
941
  if ((ret = write(pFile->fd, buf, count)) < 0) {
942
    code = TAOS_SYSTEM_ERROR(ERRNO);
943
    goto _exit;
944
  }
945
_exit:
946
  if (cur >= 0 && lseek(pFile->fd, cur, SEEK_SET) < 0) {
947
    code = TAOS_SYSTEM_ERROR(ERRNO);
948
  }
949
#endif
950
#if FILE_WITH_LOCK
951
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
280,545,607✔
952
#endif
953

954
  if (code) {
280,540,876✔
UNCOV
955
    terrno = code;
×
956
  }
957

958
  return ret;
280,551,272✔
959
}
960

961
int64_t taosLSeekFile(TdFilePtr pFile, int64_t offset, int32_t whence) {
2,147,483,647✔
962
  if (pFile == NULL || pFile->fd < 0) {
2,147,483,647✔
963
    terrno = TSDB_CODE_INVALID_PARA;
258✔
964
    return -1;
200✔
965
  }
966
#if FILE_WITH_LOCK
967
  (void)taosThreadRwlockRdlock(&(pFile->rwlock));
2,147,483,647✔
968
#endif
969

970
  int32_t code = 0;
2,147,483,647✔
971

972
  int64_t ret = lseek(pFile->fd, offset, whence);
2,147,483,647✔
973
  if (-1 == ret) {
2,147,483,647✔
UNCOV
974
    code = TAOS_SYSTEM_ERROR(ERRNO);
×
975
  }
976

977
#if FILE_WITH_LOCK
978
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
2,147,483,647✔
979
#endif
980

981
  if (code) {
2,147,483,647✔
UNCOV
982
    terrno = code;
×
UNCOV
983
    return -1;
×
984
  }
985

986
  return ret;
2,147,483,647✔
987
}
988

989
int32_t taosFStatFile(TdFilePtr pFile, int64_t *size, int64_t *mtime) {
27,885,756✔
990
  if (pFile == NULL) {
27,885,756✔
991
    terrno = TSDB_CODE_INVALID_PARA;
400✔
992
    return terrno;
400✔
993
  }
994

995
  if (pFile->fd < 0) {
27,885,356✔
UNCOV
996
    terrno = TSDB_CODE_INVALID_PARA;
×
UNCOV
997
    return terrno;
×
998
  }
999

1000
  struct stat fileStat;
27,818,165✔
1001
  int32_t     code = fstat(pFile->fd, &fileStat);
27,885,280✔
1002
  if (-1 == code) {
27,877,090✔
UNCOV
1003
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
×
UNCOV
1004
    return terrno;
×
1005
  }
1006

1007
  if (size != NULL) {
27,877,090✔
1008
    *size = fileStat.st_size;
27,886,892✔
1009
  }
1010

1011
  if (mtime != NULL) {
27,884,242✔
1012
    *mtime = fileStat.st_mtime;
200✔
1013
  }
1014

1015
  return 0;
27,884,242✔
1016
}
1017

1018
int32_t taosLockFile(TdFilePtr pFile) {
3,716,052✔
1019
  if (NULL == pFile || pFile->fd < 0) {
3,716,052✔
1020
    terrno = TSDB_CODE_INVALID_PARA;
400✔
1021
    return terrno;
400✔
1022
  }
1023
#ifndef TD_ASTRA
1024
  int32_t code = (int32_t)flock(pFile->fd, LOCK_EX | LOCK_NB);
3,715,652✔
1025
  if (-1 == code) {
3,715,652✔
1026
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
754,140✔
1027
    return terrno;
754,140✔
1028
  }
1029
#else // TD_ASTRA_TODO
1030
  struct flock lock;
1031
  lock.l_type = F_WRLCK;
1032
  lock.l_whence = SEEK_SET;
1033
  lock.l_start = 0;
1034
  lock.l_len = 0;
1035
  int32_t code = fcntl(pFile->fd, F_SETLK, &lock);
1036
  if (-1 == code) {
1037
    //    terrno = TAOS_SYSTEM_ERROR(ERRNO); // TD_ASTRA_TODO
1038
    //    return terrno;                     // TD_ASTRA_TODO
1039
  }
1040
#endif
1041
  return 0;
2,961,512✔
1042
}
1043

1044
int32_t taosUnLockFile(TdFilePtr pFile) {
1,588,947✔
1045
  if (NULL == pFile || pFile->fd < 0) {
1,588,947✔
1046
    terrno = TSDB_CODE_INVALID_PARA;
400✔
1047
    return terrno;
400✔
1048
  }
1049
#ifndef TD_ASTRA
1050
  int32_t code = (int32_t)flock(pFile->fd, LOCK_UN | LOCK_NB);
1,588,547✔
1051
  if (-1 == code) {
1,588,547✔
UNCOV
1052
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
×
UNCOV
1053
    return terrno;
×
1054
  }
1055
#else // TD_ASTRA_TODO
1056
  struct flock lock;
1057
  lock.l_type = F_UNLCK;
1058
  lock.l_whence = SEEK_SET;
1059
  lock.l_start = 0;
1060
  lock.l_len = 0;
1061
  int32_t code = fcntl(pFile->fd, F_SETLK, &lock);
1062
  if (-1 == code) {
1063
    //    terrno = TAOS_SYSTEM_ERROR(ERRNO);// TD_ASTRA_TODO
1064
    //    return terrno;// TD_ASTRA_TODO
1065
  }
1066
#endif
1067
  return 0;
1,588,547✔
1068
}
1069

1070
int32_t taosFtruncateFile(TdFilePtr pFile, int64_t l_size) {
103,739✔
1071
  if (NULL == pFile || pFile->fd < 0) {
103,739✔
1072
    terrno = TSDB_CODE_INVALID_PARA;
400✔
1073
    return terrno;
400✔
1074
  }
1075

1076
  int32_t code = ftruncate(pFile->fd, l_size);
103,339✔
1077
  if (-1 == code) {
103,339✔
UNCOV
1078
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
×
UNCOV
1079
    return terrno;
×
1080
  }
1081
  return 0;
103,339✔
1082
}
1083

1084
int64_t taosFSendFile(TdFilePtr pFileOut, TdFilePtr pFileIn, int64_t *offset, int64_t size) {
72,725✔
1085
  if (pFileOut == NULL || pFileIn == NULL) {
72,725✔
1086
    terrno = TSDB_CODE_INVALID_PARA;
600✔
1087
    return -1;
600✔
1088
  }
1089
  if (pFileIn->fd < 0 || pFileOut->fd < 0) {
72,125✔
UNCOV
1090
    terrno = TSDB_CODE_INVALID_PARA;
×
UNCOV
1091
    return -1;
×
1092
  }
1093

1094
#if defined(_TD_DARWIN_64) || defined(TD_ASTRA)  // TD_ASTRA_TODO
1095
  if (lseek(pFileIn->fd, (int32_t)(*offset), 0) < 0) {
1096
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
1097
    return -1;
1098
  }
1099
  int64_t writeLen = 0;
1100
  uint8_t buffer[_SEND_FILE_STEP_] = {0};
1101

1102
  for (int64_t len = 0; len < (size - _SEND_FILE_STEP_); len += _SEND_FILE_STEP_) {
1103
    size_t rlen = read(pFileIn->fd, (void *)buffer, _SEND_FILE_STEP_);
1104
    if (rlen <= 0) {
1105
      return writeLen;
1106
    } else if (rlen < _SEND_FILE_STEP_) {
1107
      write(pFileOut->fd, (void *)buffer, (uint32_t)rlen);
1108
      return (int64_t)(writeLen + rlen);
1109
    } else {
1110
      write(pFileOut->fd, (void *)buffer, _SEND_FILE_STEP_);
1111
      writeLen += _SEND_FILE_STEP_;
1112
    }
1113
  }
1114

1115
  int64_t remain = size - writeLen;
1116
  if (remain > 0) {
1117
    size_t rlen = read(pFileIn->fd, (void *)buffer, (size_t)remain);
1118
    if (rlen <= 0) {
1119
      return writeLen;
1120
    } else {
1121
      write(pFileOut->fd, (void *)buffer, (uint32_t)remain);
1122
      writeLen += remain;
1123
    }
1124
  }
1125
  return writeLen;
1126

1127
#else  // for linux
1128

1129
  int64_t leftbytes = size;
72,125✔
1130
  int64_t sentbytes;
1131

1132
  while (leftbytes > 0) {
144,250✔
1133
#ifdef _TD_ARM_32
1134
    sentbytes = sendfile(pFileOut->fd, pFileIn->fd, (long int *)offset, leftbytes);
1135
#else
1136
    sentbytes = sendfile(pFileOut->fd, pFileIn->fd, offset, leftbytes);
72,125✔
1137
#endif
1138
    if (sentbytes == -1) {
72,125✔
UNCOV
1139
      if (ERRNO == EINTR || ERRNO == EAGAIN || ERRNO == EWOULDBLOCK) {
×
UNCOV
1140
        continue;
×
1141
      } else {
1142
        terrno = TAOS_SYSTEM_ERROR(ERRNO);
×
1143
        return -1;
×
1144
      }
1145
    } else if (sentbytes == 0) {
72,125✔
1146
      return (int64_t)(size - leftbytes);
×
1147
    }
1148

1149
    leftbytes -= sentbytes;
72,125✔
1150
  }
1151

1152
  return size;
72,125✔
1153
#endif
1154
}
1155

1156
bool errorIsFileNotExist(int32_t code) { return code == TAOS_SYSTEM_ERROR(ENOENT); }
4,274,365✔
1157

1158
#endif  // WINDOWS
1159

1160
bool lastErrorIsFileNotExist() {
2,550,294✔
1161
  return errorIsFileNotExist(terrno);
2,550,294✔
1162
}
1163

1164
TdFilePtr taosOpenFile(const char *path, int32_t tdFileOptions) {
2,147,483,647✔
1165
  if (path == NULL) {
2,147,483,647✔
1166
    terrno = TSDB_CODE_INVALID_PARA;
200✔
1167
    return NULL;
200✔
1168
  }
1169
  STUB_RAND_IO_ERR(NULL)
1170
  FILE *fp = NULL;
2,147,483,647✔
1171
#ifdef WINDOWS
1172
  HANDLE hFile = NULL;
1173
#else
1174
  int fd = -1;
2,147,483,647✔
1175
#endif
1176
  if (tdFileOptions & TD_FILE_STREAM) {
2,147,483,647✔
1177
    fp = taosOpenFileForStream(path, tdFileOptions);
2,147,483,647✔
1178
    if (fp == NULL) return NULL;
2,147,483,647✔
1179
  } else {
1180
#ifdef WINDOWS
1181
    hFile = taosOpenFileNotStream(path, tdFileOptions);
1182
    if (hFile == INVALID_HANDLE_VALUE) return NULL;
1183
#else
1184
    fd = taosOpenFileNotStream(path, tdFileOptions);
1,070,684,977✔
1185
    if (fd == -1) return NULL;
1,070,555,246✔
1186
#endif
1187
  }
1188

1189
  TdFilePtr pFile = (TdFilePtr)taosMemoryMalloc(sizeof(TdFile));
2,147,483,647✔
1190
  if (pFile == NULL) {
2,147,483,647✔
1191
#ifdef WINDOWS
1192
    if (hFile != NULL) CloseHandle(hFile);
1193
#else
UNCOV
1194
    if (fd >= 0) (void)close(fd);
×
1195
#endif
UNCOV
1196
    if (fp != NULL) (void)fclose(fp);
×
UNCOV
1197
    terrno = TSDB_CODE_OUT_OF_MEMORY;
×
UNCOV
1198
    return NULL;
×
1199
  }
1200

1201
#if FILE_WITH_LOCK
1202
  (void)taosThreadRwlockInit(&(pFile->rwlock), NULL);
2,147,483,647✔
1203
#endif
1204
  pFile->fp = fp;
2,147,483,647✔
1205

1206
#ifdef WINDOWS
1207
  pFile->hFile = hFile;
1208
  pFile->tdFileOptions = tdFileOptions;
1209
  // do nothing, since the property of pmode is set with _O_TEMPORARY; the OS will recycle
1210
  // the file handle, as well as the space on disk.
1211
#else
1212
  pFile->fd = fd;
2,147,483,647✔
1213
  // Remove it instantly, so when the program exits normally/abnormally, the file
1214
  // will be automatically remove by OS.
1215
  if (tdFileOptions & TD_FILE_AUTO_DEL) {
2,147,483,647✔
1216
    if (-1 == unlink(path)) {
250,348✔
1217
      terrno = TAOS_SYSTEM_ERROR(ERRNO);
367,392✔
UNCOV
1218
      (void)close(fd);
×
UNCOV
1219
      taosMemoryFree(pFile);
×
UNCOV
1220
      return NULL;
×
1221
    }
1222
  }
1223
#endif
1224

1225
  return pFile;
2,147,483,647✔
1226
}
1227

1228
int32_t taosCloseFile(TdFilePtr *ppFile) {
2,147,483,647✔
1229
  int32_t code = 0;
2,147,483,647✔
1230
  if (ppFile == NULL || *ppFile == NULL) {
2,147,483,647✔
1231
    return 0;
713,311,626✔
1232
  }
1233
#if FILE_WITH_LOCK
1234
  (void)taosThreadRwlockWrlock(&((*ppFile)->rwlock));
2,147,483,647✔
1235
#endif
1236
  if ((*ppFile)->fp != NULL) {
2,147,483,647✔
1237
    TAOS_UNUSED(fflush((*ppFile)->fp));
2,147,483,647✔
1238
    TAOS_UNUSED(fclose((*ppFile)->fp));
2,147,483,647✔
1239
    (*ppFile)->fp = NULL;
2,147,483,647✔
1240
  }
1241
#ifdef WINDOWS
1242
  if ((*ppFile)->hFile != NULL) {
1243
    // FlushFileBuffers((*ppFile)->hFile);
1244
    if (!CloseHandle((*ppFile)->hFile)) {
1245
      terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
1246
      code = -1;
1247
    }
1248
    (*ppFile)->hFile = NULL;
1249
#else
1250
  if ((*ppFile)->fd >= 0) {
2,147,483,647✔
1251
    // warning: never fsync silently in base lib
1252
    /*fsync((*ppFile)->fd);*/
1253
    code = close((*ppFile)->fd);
1,063,724,401✔
1254
    if (-1 == code) {
1,063,966,312✔
UNCOV
1255
      terrno = TAOS_SYSTEM_ERROR(ERRNO);
×
1256
    }
1257
    (*ppFile)->fd = -1;
1,063,971,650✔
1258
#endif
1259
  }
1260
#if FILE_WITH_LOCK
1261
  (void)taosThreadRwlockUnlock(&((*ppFile)->rwlock));
2,147,483,647✔
1262
  (void)taosThreadRwlockDestroy(&((*ppFile)->rwlock));
2,147,483,647✔
1263
#endif
1264
  taosMemoryFree(*ppFile);
2,147,483,647✔
1265
  *ppFile = NULL;
2,147,483,647✔
1266
  return code;
2,147,483,647✔
1267
}
1268

1269
int64_t taosPReadFile(TdFilePtr pFile, void *buf, int64_t count, int64_t offset) {
245,366,930✔
1270
  STUB_RAND_IO_ERR(terrno)
1271
  if (pFile == NULL) {
245,366,930✔
1272
    terrno = TSDB_CODE_INVALID_PARA;
200✔
1273
    return -1;
200✔
1274
  }
1275

1276
  int32_t code = 0;
245,366,730✔
1277

1278
#ifdef WINDOWS
1279
#if FILE_WITH_LOCK
1280
  (void)taosThreadRwlockRdlock(&(pFile->rwlock));
1281
#endif
1282

1283
  if (pFile->hFile == NULL) {
1284
#if FILE_WITH_LOCK
1285
    (void)taosThreadRwlockUnlock(&(pFile->rwlock));
1286
#endif
1287

1288
    terrno = TSDB_CODE_INVALID_PARA;
1289
    return -1;
1290
  }
1291

1292
  DWORD      ret = 0;
1293
  OVERLAPPED ol = {0};
1294
  ol.OffsetHigh = (uint32_t)((offset & 0xFFFFFFFF00000000LL) >> 0x20);
1295
  ol.Offset = (uint32_t)(offset & 0xFFFFFFFFLL);
1296

1297
  SetLastError(0);
1298
  BOOL result = ReadFile(pFile->hFile, buf, count, &ret, &ol);
1299
  if (!result && GetLastError() != ERROR_HANDLE_EOF) {
1300
    code = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
1301
    ret = -1;
1302
  }
1303
#else
1304
#if FILE_WITH_LOCK
1305
  (void)taosThreadRwlockRdlock(&(pFile->rwlock));
245,366,730✔
1306
#endif
1307

1308
  if (pFile->fd < 0) {
245,378,893✔
1309
#if FILE_WITH_LOCK
UNCOV
1310
    (void)taosThreadRwlockUnlock(&(pFile->rwlock));
×
1311
#endif
UNCOV
1312
    terrno = TSDB_CODE_INVALID_PARA;
×
UNCOV
1313
    return -1;
×
1314
  }
1315
#ifndef TD_ASTRA
1316
  int64_t ret = pread(pFile->fd, buf, count, offset);
245,366,560✔
1317
  if (-1 == ret) {
245,379,962✔
UNCOV
1318
    code = TAOS_SYSTEM_ERROR(ERRNO);
×
1319
  }
1320
#else  // TD_ASTRA_TODO
1321
  int64_t ret = -1;
1322
  int64_t cur = lseek(pFile->fd, 0, SEEK_CUR);
1323
  if (cur < 0) {
1324
    code = TAOS_SYSTEM_ERROR(ERRNO);
1325
    goto _exit;
1326
  }
1327
  if (lseek(pFile->fd, offset, SEEK_SET) < 0) {
1328
    code = TAOS_SYSTEM_ERROR(ERRNO);
1329
    goto _exit;
1330
  }
1331
  if ((ret = read(pFile->fd, buf, count)) < 0) {
1332
    code = TAOS_SYSTEM_ERROR(ERRNO);
1333
    goto _exit;
1334
  }
1335
_exit:
1336
  if (cur >= 0 && lseek(pFile->fd, cur, SEEK_SET) < 0) {
1337
    code = TAOS_SYSTEM_ERROR(ERRNO);
1338
  }
1339
#endif
1340
#endif
1341
#if FILE_WITH_LOCK
1342
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
245,379,962✔
1343
#endif
1344

1345
  if (code) {
245,373,740✔
UNCOV
1346
    terrno = code;
×
UNCOV
1347
    return -1;
×
1348
  }
1349

1350
  return ret;
245,373,740✔
1351
}
1352

1353
int32_t taosFsyncFile(TdFilePtr pFile) {
374,645,215✔
1354
  if (pFile == NULL) {
374,645,215✔
1355
    return 0;
1,029,022✔
1356
  }
1357

1358
  int32_t code = 0;
373,616,193✔
1359
  // this implementation is WRONG
1360
  // fflush is not a replacement of fsync
1361
  if (pFile->fp != NULL) {
373,616,193✔
1362
    code = fflush(pFile->fp);
46,919✔
1363
    if (0 != code) {
46,919✔
UNCOV
1364
      terrno = TAOS_SYSTEM_ERROR(ERRNO);
×
UNCOV
1365
      return terrno;
×
1366
    }
1367

1368
    return 0;
46,919✔
1369
  }
1370

1371
#ifdef WINDOWS
1372
  if (pFile->hFile != NULL) {
1373
    if (pFile->tdFileOptions & TD_FILE_WRITE_THROUGH) {
1374
      return 0;
1375
    }
1376
    bool ret = FlushFileBuffers(pFile->hFile);
1377
    if (!ret) {
1378
      terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
1379
      return terrno;
1380
    }
1381
    return 0;
1382
  }
1383
#else
1384
  if (pFile->fd >= 0) {
373,586,977✔
1385
    code = fsync(pFile->fd);
373,660,975✔
1386
    if (-1 == code) {
373,672,371✔
1387
#ifndef TD_ASTRA
UNCOV
1388
      terrno = TAOS_SYSTEM_ERROR(ERRNO);
×
1389
#else
1390
      terrno = 0;  // TD_ASTRA_TODO
1391
#endif
UNCOV
1392
      return terrno;
×
1393
    }
1394
  }
1395
#endif
1396

1397
  return 0;
373,663,306✔
1398
}
1399

1400
void taosFprintfFile(TdFilePtr pFile, const char *format, ...) {
2,147,483,647✔
1401
  if (pFile == NULL || pFile->fp == NULL) {
2,147,483,647✔
1402
    return;
2,147,483,647✔
1403
  }
1404
  va_list ap;
2,147,483,647✔
1405
  va_start(ap, format);
2,147,483,647✔
1406
  (void)vfprintf(pFile->fp, format, ap);
2,147,483,647✔
1407
  va_end(ap);
2,147,483,647✔
1408
}
1409

1410
bool taosValidFile(TdFilePtr pFile) {
600✔
1411
#ifdef WINDOWS
1412
  return pFile != NULL && pFile->hFile != NULL;
1413
#else
1414
  return pFile != NULL && pFile->fd > 0;
600✔
1415
#endif
1416
}
1417

1418
int32_t taosUmaskFile(int32_t maskVal) {
5,365,718✔
1419
#ifdef WINDOWS
1420
  return 0;
1421
#else
1422
  return umask(maskVal);
5,365,718✔
1423
#endif
1424
}
1425

1426
int64_t taosGetLineFile(TdFilePtr pFile, char **__restrict ptrBuf) {
182,490✔
1427
  int64_t ret = -1;
182,490✔
1428
  int32_t code = 0;
182,490✔
1429

1430
  if (pFile == NULL || ptrBuf == NULL) {
182,490✔
1431
    terrno = TSDB_CODE_INVALID_PARA;
600✔
1432
    goto END;
600✔
1433
  }
1434
  if (*ptrBuf != NULL) {
181,890✔
1435
    taosMemoryFreeClear(*ptrBuf);
179,070✔
1436
  }
1437

1438
  if (pFile->fp == NULL) {
181,890✔
UNCOV
1439
    terrno = TSDB_CODE_INVALID_PARA;
×
UNCOV
1440
    goto END;
×
1441
  }
1442

1443
#if FILE_WITH_LOCK
1444
  (void)taosThreadRwlockRdlock(&(pFile->rwlock));
181,890✔
1445
#endif
1446

1447
#ifdef WINDOWS
1448
  size_t bufferSize = 512;
1449
  *ptrBuf = taosMemoryMalloc(bufferSize);
1450
  if (*ptrBuf == NULL) {
1451
    goto END;
1452
  }
1453

1454
  size_t bytesRead = 0;
1455
  size_t totalBytesRead = 0;
1456

1457
  while (1) {
1458
    char *result = fgets(*ptrBuf + totalBytesRead, bufferSize - totalBytesRead, pFile->fp);
1459
    if (result == NULL) {
1460
      if (feof(pFile->fp)) {
1461
        break;
1462
      } else {
1463
        ret = -1;
1464
        terrno = TAOS_SYSTEM_ERROR(ferror(pFile->fp));
1465
        taosMemoryFreeClear(*ptrBuf);
1466
        goto END;
1467
      }
1468
    }
1469
    bytesRead = strlen(*ptrBuf + totalBytesRead);
1470
    totalBytesRead += bytesRead;
1471

1472
    if (totalBytesRead < bufferSize - 1 || (*ptrBuf)[totalBytesRead - 1] == '\n') {
1473
      break;
1474
    }
1475

1476
    bufferSize += 512;
1477
    void *newBuf = taosMemoryRealloc(*ptrBuf, bufferSize);
1478
    if (newBuf == NULL) {
1479
      taosMemoryFreeClear(*ptrBuf);
1480
      goto END;
1481
    }
1482

1483
    *ptrBuf = newBuf;
1484
  }
1485

1486
  (*ptrBuf)[totalBytesRead] = '\0';
1487
  ret = (totalBytesRead > 0 ? totalBytesRead : -1); // -1 means EOF
1488
#elif defined(TD_ASTRA)
1489
  size_t bufsize = 128;
1490
  if (*ptrBuf == NULL) {
1491
    *ptrBuf = (char *)taosMemoryMalloc(bufsize);
1492
    if (*ptrBuf == NULL) {
1493
      goto END;
1494
    }
1495
  }
1496
  size_t pos = 0;
1497
  int    c;
1498
  while ((c = fgetc(pFile->fp)) != EOF) {
1499
    if (pos + 1 >= bufsize) {
1500
      size_t new_size = bufsize << 1;
1501
      char  *new_line = (char *)taosMemoryRealloc(*ptrBuf, new_size);
1502
      if (new_line == NULL) {
1503
        goto END;
1504
      }
1505
      *ptrBuf = new_line;
1506
      bufsize = new_size;
1507
    }
1508
    (*ptrBuf)[pos++] = (char)c;
1509
    if (c == '\n') {
1510
      break;
1511
    }
1512
  }
1513
  if (pos == 0 && c == EOF) {
1514
    goto END;
1515
  }
1516
  (*ptrBuf)[pos] = '\0';
1517
  ret = pos;
1518
#else
1519
  size_t len = 0;
181,890✔
1520
  ret = getline(ptrBuf, &len, pFile->fp);
181,890✔
1521
  if (-1 == ret) {
181,890✔
1522
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
2,820✔
1523
  }
1524
#endif
1525

1526
END:
181,890✔
1527

1528
#if FILE_WITH_LOCK
1529
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
182,490✔
1530
#endif
1531

1532
  return ret;
182,490✔
1533
}
1534

1535
int64_t taosGetsFile(TdFilePtr pFile, int32_t maxSize, char *__restrict buf) {
2,147,483,647✔
1536
  if (pFile == NULL || buf == NULL) {
2,147,483,647✔
1537
    terrno = TSDB_CODE_INVALID_PARA;
600✔
1538
    return terrno;
600✔
1539
  }
1540

1541
  if (pFile->fp == NULL) {
2,147,483,647✔
UNCOV
1542
    terrno = TSDB_CODE_INVALID_PARA;
×
UNCOV
1543
    return terrno;
×
1544
  }
1545

1546
  if (fgets(buf, maxSize, pFile->fp) == NULL) {
2,147,483,647✔
1547
    if (feof(pFile->fp)) {
4,653,902✔
1548
      return 0;
4,653,902✔
1549
    } else {
1550
      terrno = TAOS_SYSTEM_ERROR(ferror(pFile->fp));
×
UNCOV
1551
      return terrno;
×
1552
    }
1553
  }
1554

1555
  return strlen(buf);
2,147,483,647✔
1556
}
1557

1558
int32_t taosEOFFile(TdFilePtr pFile) {
2,147,483,647✔
1559
  if (pFile == NULL) {
2,147,483,647✔
1560
    terrno = TSDB_CODE_INVALID_PARA;
400✔
1561
    return -1;
400✔
1562
  }
1563
  if (pFile->fp == NULL) {
2,147,483,647✔
UNCOV
1564
    terrno = TSDB_CODE_INVALID_PARA;
×
UNCOV
1565
    return -1;
×
1566
  }
1567

1568
  return feof(pFile->fp);
2,147,483,647✔
1569
}
1570

1571
bool taosCheckAccessFile(const char *pathname, int32_t tdFileAccessOptions) {
196,105,736✔
1572
  if (pathname == NULL) {
196,105,736✔
1573
    terrno = TSDB_CODE_INVALID_PARA;
200✔
1574
    return false;  // invalid parameter
200✔
1575
  }
1576
  int flags = 0;
196,105,536✔
1577

1578
  if (tdFileAccessOptions & TD_FILE_ACCESS_EXIST_OK) {
196,105,536✔
1579
    flags |= F_OK;
196,100,075✔
1580
  }
1581

1582
  if (tdFileAccessOptions & TD_FILE_ACCESS_READ_OK) {
196,105,536✔
1583
    flags |= R_OK;
4,551,862✔
1584
  }
1585

1586
  if (tdFileAccessOptions & TD_FILE_ACCESS_WRITE_OK) {
196,105,536✔
1587
    flags |= W_OK;
4,551,862✔
1588
  }
1589

1590
  if (tdFileAccessOptions & TD_FILE_ACCESS_EXEC_OK) {
196,105,536✔
UNCOV
1591
    flags |= X_OK;
×
1592
  }
1593
#ifdef WINDOWS
1594
  return _access(pathname, flags) == 0;
1595
#else
1596
  return access(pathname, flags) == 0;
196,105,536✔
1597
#endif
1598
}
1599

1600
bool taosCheckExistFile(const char *pathname) { return taosCheckAccessFile(pathname, TD_FILE_ACCESS_EXIST_OK); };
191,557,988✔
1601

1602
int32_t taosCompressFile(TdFilePtr pSrcFile, char *destFileName) {
200✔
1603
  OS_PARAM_CHECK(pSrcFile);
200✔
UNCOV
1604
  OS_PARAM_CHECK(destFileName);
×
NEW
1605
  int32_t compressSize = 163840;
×
NEW
1606
  int32_t ret = 0;
×
NEW
1607
  gzFile  dstFp = NULL;
×
NEW
1608
  int     fd = -1;
×
1609

1610
  char *data = taosMemoryMalloc(compressSize);
×
1611
  if (NULL == data) {
×
1612
    return terrno;
×
1613
  }
1614

UNCOV
1615
  int access = O_BINARY | O_WRONLY | O_TRUNC | O_CREAT;
×
1616
#ifdef WINDOWS
1617
  int32_t pmode = _S_IREAD | _S_IWRITE;
1618
#else
1619
  int32_t pmode = S_IRWXU | S_IRWXG | S_IRWXO;
×
1620
#endif
NEW
1621
  fd = open(destFileName, access, pmode);
×
1622
  if (-1 == fd) {
×
1623
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
×
1624
    ret = terrno;
×
1625
    goto cmp_end;
×
1626
  }
1627

1628
  // Both gzclose() and close() will close the associated fd, so they need to have different fds.
1629
  FileFd gzFd = dup(fd);
×
1630
  if (-1 == gzFd) {
×
1631
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
×
1632
    ret = terrno;
×
1633
    goto cmp_end;
×
1634
  }
1635
  dstFp = gzdopen(gzFd, "wb6f");
×
1636
  if (dstFp == NULL) {
×
1637
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
×
1638
    ret = terrno;
×
1639
    (void)close(gzFd);
×
1640
    goto cmp_end;
×
1641
  }
1642

NEW
1643
  while (1) {
×
NEW
1644
    int64_t readLen = taosReadFile(pSrcFile, data, compressSize);
×
NEW
1645
    if (readLen < 0) {
×
NEW
1646
      ret = terrno;
×
NEW
1647
      goto cmp_end;
×
1648
    }
NEW
1649
    if (readLen == 0) break;
×
NEW
1650
    if (gzwrite(dstFp, data, (int32_t)readLen) == 0) {
×
NEW
1651
      terrno = TAOS_SYSTEM_ERROR(ERRNO);
×
NEW
1652
      ret = terrno;
×
NEW
1653
      goto cmp_end;
×
1654
    }
1655
  }
1656

UNCOV
1657
cmp_end:
×
1658

UNCOV
1659
  if (fd >= 0) {
×
1660
    TAOS_SKIP_ERROR(close(fd));
×
1661
  }
1662
  if (dstFp) {
×
1663
    TAOS_SKIP_ERROR(gzclose(dstFp));
×
1664
  }
1665
  taosMemoryFree(data);
×
UNCOV
1666
  return ret;
×
1667
}
1668

1669
int32_t taosSetFileHandlesLimit() {
3,172,126✔
1670
#ifdef WINDOWS
1671
  const int max_handles = 8192;
1672
  int       res = _setmaxstdio(max_handles);
1673
  return res == max_handles ? 0 : -1;
1674
#endif
1675
  return 0;
3,172,126✔
1676
}
1677

1678
int32_t taosLinkFile(char *src, char *dst) {
200✔
1679
#ifndef WINDOWS
1680
  if (-1 == link(src, dst)) {
200✔
1681
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
200✔
1682
    return terrno;
200✔
1683
  }
1684
#endif
UNCOV
1685
  return 0;
×
1686
}
1687

1688
#ifdef WINDOWS
1689
// Create an NTFS directory junction (mount point) from linkpath -> target.
1690
// Junctions do not require elevated privileges or Developer Mode, unlike symlinks.
1691
static int32_t taosCreateJunction(const char *target, const char *linkpath) {
1692
  char fullTarget[MAX_PATH] = {0};
1693
  if (GetFullPathNameA(target, MAX_PATH, fullTarget, NULL) == 0) {
1694
    return (terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError()));
1695
  }
1696
  if (!CreateDirectoryA(linkpath, NULL)) {
1697
    return (terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError()));
1698
  }
1699
  HANDLE hDir = CreateFileA(linkpath, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
1700
                            FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
1701
  if (hDir == INVALID_HANDLE_VALUE) {
1702
    RemoveDirectoryA(linkpath);
1703
    return (terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError()));
1704
  }
1705
  // Build the substitute name: \??\<fullTarget>  (NT path prefix for junctions)
1706
  WCHAR wTarget[MAX_PATH] = {0};
1707
  WCHAR wSubst[MAX_PATH + 4] = {0};
1708
  MultiByteToWideChar(CP_ACP, 0, fullTarget, -1, wTarget, MAX_PATH);
1709
  wsprintfW(wSubst, L"\\??\\%s", wTarget);
1710
  int substLen = (int)wcslen(wSubst) * (int)sizeof(WCHAR);
1711
  int printLen = (int)wcslen(wTarget) * (int)sizeof(WCHAR);
1712
  // Reparse data buffer layout for IO_REPARSE_TAG_MOUNT_POINT:
1713
  //   ULONG  ReparseTag
1714
  //   USHORT ReparseDataLength
1715
  //   USHORT Reserved
1716
  //   USHORT SubstituteNameOffset
1717
  //   USHORT SubstituteNameLength
1718
  //   USHORT PrintNameOffset
1719
  //   USHORT PrintNameLength
1720
  //   WCHAR  PathBuffer[...]  (SubstituteName\0 + PrintName\0)
1721
  int headerSize = 8;   // ReparseTag(4) + ReparseDataLength(2) + Reserved(2)
1722
  int fixedSize = 8;    // SubstNameOff(2) + SubstNameLen(2) + PrintNameOff(2) + PrintNameLen(2)
1723
  int pathBufSize = substLen + (int)sizeof(WCHAR) + printLen + (int)sizeof(WCHAR);
1724
  int totalSize = headerSize + fixedSize + pathBufSize;
1725
  char *buf = (char *)taosMemoryCalloc(1, totalSize);
1726
  if (buf == NULL) {
1727
    CloseHandle(hDir);
1728
    RemoveDirectoryA(linkpath);
1729
    return (terrno = TSDB_CODE_OUT_OF_MEMORY);
1730
  }
1731
  *(ULONG *)(buf + 0) = IO_REPARSE_TAG_MOUNT_POINT;       // ReparseTag
1732
  *(USHORT *)(buf + 4) = (USHORT)(fixedSize + pathBufSize); // ReparseDataLength
1733
  *(USHORT *)(buf + 6) = 0;                                 // Reserved
1734
  *(USHORT *)(buf + 8) = 0;                                 // SubstituteNameOffset
1735
  *(USHORT *)(buf + 10) = (USHORT)substLen;                  // SubstituteNameLength
1736
  *(USHORT *)(buf + 12) = (USHORT)(substLen + sizeof(WCHAR)); // PrintNameOffset
1737
  *(USHORT *)(buf + 14) = (USHORT)printLen;                  // PrintNameLength
1738
  memcpy(buf + headerSize + fixedSize, wSubst, substLen);
1739
  memcpy(buf + headerSize + fixedSize + substLen + sizeof(WCHAR), wTarget, printLen);
1740
  DWORD bytesReturned = 0;
1741
  BOOL ok = DeviceIoControl(hDir, FSCTL_SET_REPARSE_POINT, buf, totalSize, NULL, 0, &bytesReturned, NULL);
1742
  DWORD jErr = ok ? 0 : GetLastError();
1743
  taosMemoryFree(buf);
1744
  CloseHandle(hDir);
1745
  if (!ok) {
1746
    RemoveDirectoryA(linkpath);
1747
    return (terrno = TAOS_SYSTEM_WINAPI_ERROR(jErr));
1748
  }
1749
  return 0;
1750
}
1751
#endif
1752

1753
int32_t taosSymLink(const char *target, const char *linkpath) {
5,878✔
1754
#ifdef WINDOWS
1755
  DWORD attributes = GetFileAttributesA(target);
1756
  BOOL  isDir = (attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY);
1757
  DWORD flags = isDir ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0;
1758
  // Try symlink with unprivileged flag first (requires Developer Mode on Win10 1703+)
1759
  if (!CreateSymbolicLinkA(linkpath, target, flags | 0x2 /*SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE*/)) {
1760
    DWORD err = GetLastError();
1761
    if (err == ERROR_INVALID_PARAMETER) {
1762
      // Flag not supported on older Windows, retry without it
1763
      if (!CreateSymbolicLinkA(linkpath, target, flags)) {
1764
        err = GetLastError();
1765
      } else {
1766
        err = 0;
1767
      }
1768
    }
1769
    if (err == ERROR_PRIVILEGE_NOT_HELD && isDir) {
1770
      // Symlink requires elevation or Developer Mode; fall back to directory junction
1771
      // which does not require special privileges on NTFS.
1772
      return taosCreateJunction(target, linkpath);
1773
    } else if (err != 0) {
1774
      return (terrno = TAOS_SYSTEM_WINAPI_ERROR(err));
1775
    }
1776
  }
1777
#else
1778
  if (symlink(target, linkpath) == -1) {
5,878✔
UNCOV
1779
    return (terrno = TAOS_SYSTEM_ERROR(ERRNO));
×
1780
  }
1781
#endif
1782
  return 0;
6,020✔
1783
}
1784

1785
FILE *taosOpenCFile(const char *filename, const char *mode) {
2,911,238✔
1786
  if (filename == NULL || mode == NULL) {
2,911,238✔
1787
    terrno = TSDB_CODE_INVALID_PARA;
4,916✔
1788
    return NULL;
400✔
1789
  }
1790
  STUB_RAND_IO_ERR(NULL)
1791
  FILE *f = fopen(filename, mode);
2,906,322✔
1792
  if (NULL == f) {
2,914,354✔
1793
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
200✔
1794
  }
1795
  return f;
2,914,354✔
1796
}
1797

1798
int taosSeekCFile(FILE *file, int64_t offset, int whence) {
2,288,019✔
1799
  if (NULL == file) {
2,288,019✔
1800
    terrno = TSDB_CODE_INVALID_PARA;
200✔
1801
    return terrno;
200✔
1802
  }
1803
#ifdef WINDOWS
1804
  return _fseeki64(file, offset, whence);
1805
#else
1806
  int     code = fseeko(file, offset, whence);
2,287,819✔
1807
  if (-1 == code) {
2,288,448✔
UNCOV
1808
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
×
UNCOV
1809
    code = terrno;
×
1810
  }
1811
  return code;
2,288,448✔
1812
#endif
1813
}
1814

1815
size_t taosReadFromCFile(void *buffer, size_t size, size_t count, FILE *stream) {
2,288,848✔
1816
  if (buffer == NULL || stream == NULL) {
2,288,848✔
1817
    terrno = TSDB_CODE_INVALID_PARA;
400✔
1818
    return 0;
400✔
1819
  }
1820
  STUB_RAND_IO_ERR(terrno)
1821
  return fread(buffer, size, count, stream);
2,289,449✔
1822
}
1823

1824
#if 0
1825
size_t taosWriteToCFile(const void *ptr, size_t size, size_t nitems, FILE *stream) {
1826
  STUB_RAND_IO_ERR(terrno)
1827
  return fwrite(ptr, size, nitems, stream);
1828
}
1829
#endif
1830

1831
int taosCloseCFile(FILE *f) { return fclose(f); }
2,914,354✔
1832

1833
int taosSetAutoDelFile(char *path) {
2,914,154✔
1834
#ifdef WINDOWS
1835
  bool succ = SetFileAttributes(path, FILE_ATTRIBUTE_TEMPORARY);
1836
  if (succ) {
1837
    return 0;
1838
  } else {
1839
    terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
1840
    return terrno;
1841
  }
1842
#else
1843
  if (-1 == unlink(path)) {
2,914,154✔
1844
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
200✔
1845
    return terrno;
200✔
1846
  }
1847
  return 0;
2,913,954✔
1848
#endif
1849
}
1850

1851
int64_t taosWritevFile(TdFilePtr pFile, const TaosIOVec *iov, int iovcnt) {
19,463,415✔
1852
  if (pFile == NULL || iov == NULL || iovcnt <= 0) {
19,463,415✔
1853
    terrno = TSDB_CODE_INVALID_PARA;
600✔
1854
    return -1;
600✔
1855
  }
1856
#if FILE_WITH_LOCK
1857
  (void)taosThreadRwlockWrlock(&(pFile->rwlock));
19,462,815✔
1858
#endif
1859

1860
#ifdef __linux__
1861
  if (pFile->fd < 0) {
19,462,815✔
1862
#if FILE_WITH_LOCK
UNCOV
1863
    (void)taosThreadRwlockUnlock(&(pFile->rwlock));
×
1864
#endif
UNCOV
1865
    terrno = TSDB_CODE_INVALID_PARA;
×
UNCOV
1866
    return -1;
×
1867
  }
1868
  ssize_t written = writev(pFile->fd, iov, iovcnt);
19,462,815✔
1869
  if (written < 0) {
19,462,815✔
UNCOV
1870
    terrno = TAOS_SYSTEM_ERROR(ERRNO);
×
1871
  }
1872
#if FILE_WITH_LOCK
1873
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
19,462,815✔
1874
#endif
1875
  return (int64_t)written;
19,462,815✔
1876
#elif defined(WINDOWS)
1877
  if (pFile == NULL || pFile->hFile == NULL) {
1878
#if FILE_WITH_LOCK
1879
    (void)taosThreadRwlockUnlock(&(pFile->rwlock));
1880
#endif
1881
    terrno = TSDB_CODE_INVALID_PARA;
1882
    return -1;
1883
  }
1884
  int64_t totalWritten = 0;
1885
  for (int i = 0; i < iovcnt; ++i) {
1886
    TaosIOVec *vec = &iov[i];
1887
    if (vec->iov_len <= 0) continue;
1888
    DWORD written;
1889
    if (!WriteFile(pFile->hFile, vec->iov_base, vec->iov_len, &written, NULL)) {
1890
      SET_ERRNO(GetLastError());
1891
      terrno = TAOS_SYSTEM_WINAPI_ERROR(ERRNO);
1892
      written = -1;
1893
      break;
1894
    }
1895
    totalWritten += written;
1896
  }
1897
#if FILE_WITH_LOCK
1898
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
1899
#endif
1900
  if (totalWritten < 0) {
1901
    return -1;
1902
  }
1903
  return (int64_t)totalWritten;
1904
#else
1905
  if (pFile->fd < 0) {
1906
#if FILE_WITH_LOCK
1907
    (void)taosThreadRwlockUnlock(&(pFile->rwlock));
1908
#endif
1909
    terrno = TSDB_CODE_INVALID_PARA;
1910
    return -1;
1911
  }
1912
  int64_t totalWritten = 0;
1913
  for (int i = 0; i < iovcnt; ++i) {
1914
    const struct iovec *vec = &iov[i];
1915
    if (vec->iov_len <= 0) continue;
1916
    ssize_t written = write(pFile->fd, vec->iov_base, vec->iov_len);
1917
    if (written < 0) {
1918
      if (ERRNO == EINTR || ERRNO == EAGAIN || ERRNO == EWOULDBLOCK) {
1919
        continue;
1920
      } else {
1921
        terrno = TAOS_SYSTEM_ERROR(ERRNO);
1922
        totalWritten = -1;
1923
        break;
1924
      }
1925
    }
1926
    totalWritten += written;
1927
  }
1928
#if FILE_WITH_LOCK
1929
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
1930
#endif
1931
  if (totalWritten < 0) {
1932
    return -1;
1933
  }
1934
  return (int64_t)totalWritten;
1935
#endif
1936
}
1937

1938
// ============================================================================
1939
// Encrypted File Operations Implementation
1940
// ============================================================================
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc