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

taosdata / TDengine / #3559

18 Dec 2024 12:59AM UTC coverage: 59.805% (+0.03%) from 59.778%
#3559

push

travis-ci

web-flow
Merge pull request #29187 from taosdata/merge/mainto3.0

merge: main to 3.0 branch

132705 of 287544 branches covered (46.15%)

Branch coverage included in aggregate %.

87 of 95 new or added lines in 19 files covered. (91.58%)

1132 existing lines in 133 files now uncovered.

209591 of 284807 relevant lines covered (73.59%)

8125235.78 hits per line

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

61.84
/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 W_OK 2
28
#define R_OK 4
29

30
#define _SEND_FILE_STEP_ 1024
31

32
#else
33
#include <fcntl.h>
34
#include <sys/file.h>
35

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

44
#define _SEND_FILE_STEP_ 1000
45
#endif
46

47
typedef int32_t FileFd;
48

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

66
#define FILE_WITH_LOCK 1
67

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

82
void taosGetTmpfilePath(const char *inputTmpDir, const char *fileNamePrefix, char *dstPath) {
14,903✔
83
  if (inputTmpDir == NULL || fileNamePrefix == NULL) return;
14,903!
84
#ifdef WINDOWS
85

86
  char tmpPath[PATH_MAX];
87

88
  int32_t len = (int32_t)strlen(inputTmpDir);
89
  memcpy(tmpPath, inputTmpDir, len);
90

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

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

97
  char rand[8] = {0};
98
  taosRandStr(rand, tListLen(rand) - 1);
99
  snprintf(dstPath, PATH_MAX, tmpPath, getpid(), rand);
100

101
#else
102

103
  char    tmpPath[PATH_MAX];
104
  int32_t len = strlen(inputTmpDir);
14,903✔
105
  (void)memcpy(tmpPath, inputTmpDir, len);
14,903✔
106
  static uint64_t seqId = 0;
107

108
  if (tmpPath[len - 1] != '/') {
14,903!
109
    tmpPath[len++] = '/';
×
110
  }
111

112
  snprintf(tmpPath + len, sizeof(tmpPath) - len, "%s%s%s", TD_TMP_FILE_PREFIX, fileNamePrefix, "-%d-%s");
14,903✔
113

114
  char rand[32] = {0};
14,903✔
115

116
  (void)snprintf(rand, sizeof(rand), "%" PRIu64, atomic_add_fetch_64(&seqId, 1));
14,903✔
117

118
  (void)snprintf(dstPath, PATH_MAX, tmpPath, getpid(), rand);
14,908✔
119

120
#endif
121
}
122

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

141
  TdFilePtr pFileFrom = NULL;
71✔
142
  TdFilePtr pFileTo = NULL;
71✔
143
  pFileFrom = taosOpenFile(from, TD_FILE_READ);
71✔
144
  if (pFileFrom == NULL) {
71!
145
    code = terrno;
×
146
    goto _err;
×
147
  }
148

149
  pFileTo = taosOpenFile(to, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_EXCL);
71✔
150
  if (pFileTo == NULL) {
71!
151
    code = terrno;
×
152
    goto _err;
×
153
  }
154

155
  while (true) {
156
    bytes = taosReadFile(pFileFrom, buffer, sizeof(buffer));
81✔
157
    if (bytes < 0) {
81!
158
      code = terrno;
×
159
      goto _err;
×
160
    }
161

162
    if (bytes == 0) break;
81!
163

164
    size += bytes;
81✔
165

166
    if (taosWriteFile(pFileTo, (void *)buffer, bytes) < bytes) {
81!
167
      code = terrno;
×
168
      goto _err;
×
169
    }
170
    if (bytes < sizeof(buffer)) break;
81✔
171
  }
172

173
  code = taosFsyncFile(pFileTo);
71✔
174
  if (code != 0) {
71!
175
    goto _err;
×
176
  }
177

178
  TAOS_UNUSED(taosCloseFile(&pFileFrom));
71✔
179
  TAOS_UNUSED(taosCloseFile(&pFileTo));
71✔
180

181
  if (code != 0) {
71!
182
    terrno = code;
×
183
    return -1;
×
184
  }
185

186
  return size;
71✔
187

188
_err:
×
189

190
  if (pFileFrom != NULL) TAOS_SKIP_ERROR(taosCloseFile(&pFileFrom));
×
191
  if (pFileTo != NULL) TAOS_SKIP_ERROR(taosCloseFile(&pFileTo));
×
192
  /* coverity[+retval] */
193
  TAOS_SKIP_ERROR(taosRemoveFile(to));
×
194

195
  terrno = code;
×
196
  return -1;
×
197
#endif
198
}
199

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

221
  return fp;
15✔
222
}
223

224
int32_t taosRemoveFile(const char *path) {
210,944✔
225
  OS_PARAM_CHECK(path);
210,944!
226
  int32_t code = remove(path);
210,944✔
227
  if (-1 == code) {
210,962✔
228
    terrno = TAOS_SYSTEM_ERROR(errno);
14,898✔
229
    return terrno;
14,898✔
230
  }
231
  return code;
196,064✔
232
}
233

234
int32_t taosRenameFile(const char *oldName, const char *newName) {
162,965✔
235
  OS_PARAM_CHECK(oldName);
162,965!
236
  OS_PARAM_CHECK(newName);
162,965!
237
#ifdef WINDOWS
238
  bool finished = false;
239

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

247
  BOOL result = MoveFileTransacted(oldName, newName, NULL, NULL, MOVEFILE_REPLACE_EXISTING, transactionHandle);
248

249
  if (result) {
250
    finished = CommitTransaction(transactionHandle);
251
    if (!finished) {
252
      DWORD error = GetLastError();
253
      terrno = TAOS_SYSTEM_WINAPI_ERROR(error);
254
    }
255
  } else {
256
    RollbackTransaction(transactionHandle);
257
    DWORD error = GetLastError();
258
    terrno = TAOS_SYSTEM_WINAPI_ERROR(error);
259
    finished = false;
260
  }
261

262
  CloseHandle(transactionHandle);
263

264
  return finished ? 0 : terrno;
265
#else
266
  int32_t code = rename(oldName, newName);
162,965✔
267
  if (-1 == code) {
162,964✔
268
    terrno = TAOS_SYSTEM_ERROR(errno);
281✔
269
    return terrno;
280✔
270
  }
271

272
  return TSDB_CODE_SUCCESS;
162,683✔
273
#endif
274
}
275

276
int32_t taosStatFile(const char *path, int64_t *size, int64_t *mtime, int64_t *atime) {
195,366✔
277
  OS_PARAM_CHECK(path);
195,366!
278
#ifdef WINDOWS
279
  struct _stati64 fileStat;
280
  int32_t         code = _stati64(path, &fileStat);
281
#else
282
  struct stat fileStat;
283
  int32_t     code = stat(path, &fileStat);
195,366✔
284
#endif
285
  if (-1 == code) {
195,348✔
286
    terrno = TAOS_SYSTEM_ERROR(errno);
35,573✔
287
    return terrno;
35,615✔
288
  }
289

290
  if (size != NULL) {
159,775✔
291
    *size = fileStat.st_size;
151,127✔
292
  }
293

294
  if (mtime != NULL) {
159,775✔
295
    *mtime = fileStat.st_mtime;
1,403✔
296
  }
297

298
  if (atime != NULL) {
159,775!
299
    *atime = fileStat.st_atime;
×
300
  }
301

302
  return 0;
159,775✔
303
}
304

305
int32_t taosGetFileDiskID(const char *path, int64_t *diskid) {
1,793✔
306
  OS_PARAM_CHECK(path);
1,793!
307
#ifdef WINDOWS
308
  struct _stati64 fileStat;
309
  int32_t         code = _stati64(path, &fileStat);
310
#else
311
  struct stat fileStat;
312
  int32_t     code = stat(path, &fileStat);
1,793✔
313
#endif
314
  if (-1 == code) {
1,793!
315
    terrno = TAOS_SYSTEM_ERROR(errno);
×
316
    return terrno;
×
317
  }
318

319
  if (diskid != NULL) {
1,793!
320
    *diskid = fileStat.st_dev;
1,793✔
321
  }
322

323
  return 0;
1,793✔
324
}
325

326
int32_t taosDevInoFile(TdFilePtr pFile, int64_t *stDev, int64_t *stIno) {
30,097✔
327
#ifdef WINDOWS
328
  if (pFile == NULL || pFile->hFile == NULL) {
329
    terrno = TSDB_CODE_INVALID_PARA;
330
    return terrno;
331
  }
332
  BY_HANDLE_FILE_INFORMATION bhfi;
333
  if (GetFileInformationByHandle(pFile->hFile, &bhfi) == FALSE) {
334
    DWORD error = GetLastError();
335
    terrno = TAOS_SYSTEM_WINAPI_ERROR(error);
336
    return terrno;
337
  }
338

339
  if (stDev != NULL) {
340
    *stDev = (int64_t)(bhfi.dwVolumeSerialNumber);
341
  }
342

343
  if (stIno != NULL) {
344
    *stIno = (int64_t)((((uint64_t)bhfi.nFileIndexHigh) << 32) + bhfi.nFileIndexLow);
345
  }
346

347
#else
348
  if (pFile == NULL || pFile->fd < 0) {
30,097!
349
    terrno = TSDB_CODE_INVALID_PARA;
×
350
    return terrno;
×
351
  }
352

353
  struct stat fileStat;
354
  int32_t     code = fstat(pFile->fd, &fileStat);
30,119✔
355
  if (-1 == code) {
30,130!
UNCOV
356
    terrno = TAOS_SYSTEM_ERROR(errno);
×
357
    return terrno;
×
358
  }
359

360
  if (stDev != NULL) {
30,138!
361
    *stDev = fileStat.st_dev;
30,142✔
362
  }
363

364
  if (stIno != NULL) {
30,138!
365
    *stIno = fileStat.st_ino;
30,170✔
366
  }
367
#endif
368

369
  return 0;
30,138✔
370
}
371

372
FILE *taosOpenFileForStream(const char *path, int32_t tdFileOptions) {
8,844,610✔
373
  if (path == NULL) {
8,844,610!
374
    terrno = TSDB_CODE_INVALID_PARA;
×
375
    return NULL;
×
376
  }
377
  char *mode = NULL;
8,844,610✔
378
  if (tdFileOptions & TD_FILE_APPEND) {
8,844,610✔
379
    mode = (tdFileOptions & TD_FILE_TEXT) ? "at+" : "ab+";
430!
380
  } else if (tdFileOptions & TD_FILE_TRUNC) {
8,844,180✔
381
    mode = (tdFileOptions & TD_FILE_TEXT) ? "wt+" : "wb+";
1,254✔
382
  } else if ((tdFileOptions & TD_FILE_READ) && !(tdFileOptions & TD_FILE_WRITE)) {
8,842,926!
383
    mode = (tdFileOptions & TD_FILE_TEXT) ? "rt" : "rb";
8,842,926!
384
  } else {
385
    mode = (tdFileOptions & TD_FILE_TEXT) ? "rt+" : "rb+";
×
386
  }
387
  if (tdFileOptions & TD_FILE_EXCL) {
8,844,610!
388
    terrno = TSDB_CODE_INVALID_PARA;
×
389
    return NULL;
×
390
  }
391
  FILE *f = fopen(path, mode);
8,844,610✔
392
  if (NULL == f) {
8,844,610✔
393
    terrno = TAOS_SYSTEM_ERROR(errno);
14✔
394
  }
395
  return f;
8,844,610✔
396
}
397

398
#ifdef WINDOWS
399
HANDLE taosOpenFileNotStream(const char *path, int32_t tdFileOptions) {
400
  if (path == NULL) {
401
    terrno = TSDB_CODE_INVALID_PARA;
402
    return INVALID_HANDLE_VALUE;
403
  }
404
  DWORD openMode = 0;
405
  DWORD access = 0;
406
  DWORD fileFlag = FILE_ATTRIBUTE_NORMAL;
407
  DWORD shareMode = FILE_SHARE_READ;
408

409
  openMode = OPEN_EXISTING;
410
  if (tdFileOptions & TD_FILE_CREATE) {
411
    openMode = OPEN_ALWAYS;
412
  } else if (tdFileOptions & TD_FILE_EXCL) {
413
    openMode = CREATE_NEW;
414
  } else if ((tdFileOptions & TD_FILE_TRUNC)) {
415
    openMode = TRUNCATE_EXISTING;
416
    access |= GENERIC_WRITE;
417
  }
418
  if (tdFileOptions & TD_FILE_APPEND) {
419
    access |= FILE_APPEND_DATA;
420
  }
421
  if (tdFileOptions & TD_FILE_WRITE) {
422
    access |= GENERIC_WRITE;
423
  }
424

425
  shareMode |= FILE_SHARE_WRITE;
426

427
  access |= GENERIC_READ;
428

429
  if (tdFileOptions & TD_FILE_AUTO_DEL) {
430
    fileFlag |= FILE_ATTRIBUTE_TEMPORARY;
431
  }
432
  if (tdFileOptions & TD_FILE_WRITE_THROUGH) {
433
    fileFlag |= FILE_FLAG_WRITE_THROUGH;
434
  }
435

436
  HANDLE h = CreateFile(path, access, shareMode, NULL, openMode, fileFlag, NULL);
437
  if (h != INVALID_HANDLE_VALUE && (tdFileOptions & TD_FILE_APPEND) && (tdFileOptions & TD_FILE_WRITE)) {
438
    SetFilePointer(h, 0, NULL, FILE_END);
439
  }
440
  if (h == INVALID_HANDLE_VALUE) {
441
    DWORD dwError = GetLastError();
442
    terrno = TAOS_SYSTEM_WINAPI_ERROR(dwError);
443
    // LPVOID lpMsgBuf;
444
    // FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, (LPTSTR)&lpMsgBuf,
445
    // 0,
446
    //               NULL);
447
    // printf("CreateFile failed with error %d: %s", dwError, (char *)lpMsgBuf);
448
    // LocalFree(lpMsgBuf);
449
  }
450
  return h;
451
}
452

453
int64_t taosReadFile(TdFilePtr pFile, void *buf, int64_t count) {
454
  if (pFile == NULL || buf == NULL) {
455
    terrno = TSDB_CODE_INVALID_PARA;
456
    return terrno;
457
  }
458
#if FILE_WITH_LOCK
459
  (void)taosThreadRwlockRdlock(&(pFile->rwlock));
460
#endif
461
  if (pFile->hFile == NULL) {
462
#if FILE_WITH_LOCK
463
    (void)taosThreadRwlockUnlock(&(pFile->rwlock));
464
#endif
465
    terrno = TSDB_CODE_INVALID_PARA;
466
    return terrno;
467
  }
468

469
  int64_t res = 0;
470
  DWORD   bytesRead;
471
  if (!ReadFile(pFile->hFile, buf, count, &bytesRead, NULL)) {
472
    DWORD errCode = GetLastError();
473
    terrno = TAOS_SYSTEM_WINAPI_ERROR(errCode);
474
    res = -1;
475
  } else {
476
    res = bytesRead;
477
  }
478
#if FILE_WITH_LOCK
479
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
480
#endif
481
  return res;
482
}
483

484
int64_t taosWriteFile(TdFilePtr pFile, const void *buf, int64_t count) {
485
  if (pFile == NULL || pFile->hFile == NULL || buf == NULL) {
486
    terrno = TSDB_CODE_INVALID_PARA;
487
    return 0;
488
  }
489
#if FILE_WITH_LOCK
490
  (void)taosThreadRwlockWrlock(&(pFile->rwlock));
491
#endif
492

493
  DWORD bytesWritten;
494
  if (!WriteFile(pFile->hFile, buf, count, &bytesWritten, NULL)) {
495
    errno = GetLastError();
496
    terrno = TAOS_SYSTEM_WINAPI_ERROR(errno);
497
    bytesWritten = -1;
498
  }
499

500
#if FILE_WITH_LOCK
501
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
502
#endif
503
  return bytesWritten;
504
}
505

506
int64_t taosPWriteFile(TdFilePtr pFile, const void *buf, int64_t count, int64_t offset) {
507
  if (pFile == NULL || buf == NULL) {
508
    terrno = TSDB_CODE_INVALID_PARA;
509
    return 0;
510
  }
511
#if FILE_WITH_LOCK
512
  (void)taosThreadRwlockWrlock(&(pFile->rwlock));
513
#endif
514
  if (pFile->hFile == NULL) {
515
#if FILE_WITH_LOCK
516
    (void)taosThreadRwlockUnlock(&(pFile->rwlock));
517
#endif
518
    return 0;
519
  }
520

521
  DWORD      ret = 0;
522
  OVERLAPPED ol = {0};
523
  ol.OffsetHigh = (uint32_t)((offset & 0xFFFFFFFF00000000LL) >> 0x20);
524
  ol.Offset = (uint32_t)(offset & 0xFFFFFFFFLL);
525

526
  SetLastError(0);
527
  BOOL result = WriteFile(pFile->hFile, buf, count, &ret, &ol);
528
  if (!result) {
529
    errno = GetLastError();
530
    terrno = TAOS_SYSTEM_WINAPI_ERROR(errno);
531
    ret = -1;
532
  }
533

534
#if FILE_WITH_LOCK
535
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
536
#endif
537
  return ret;
538
}
539

540
int64_t taosLSeekFile(TdFilePtr pFile, int64_t offset, int32_t whence) {
541
  if (pFile == NULL || pFile->hFile == NULL) {
542
    terrno = TSDB_CODE_INVALID_PARA;
543
    return -1;
544
  }
545
#if FILE_WITH_LOCK
546
  (void)taosThreadRwlockRdlock(&(pFile->rwlock));
547
#endif
548

549
  LARGE_INTEGER liOffset;
550
  liOffset.QuadPart = offset;
551
  if (!SetFilePointerEx(pFile->hFile, liOffset, NULL, whence)) {
552
    errno = GetLastError();
553
    terrno = TAOS_SYSTEM_WINAPI_ERROR(errno);
554
    return -1;
555
  }
556

557
  liOffset.QuadPart = 0;
558
  if (!SetFilePointerEx(pFile->hFile, liOffset, &liOffset, FILE_CURRENT)) {
559
    errno = GetLastError();
560
    terrno = TAOS_SYSTEM_WINAPI_ERROR(errno);
561
    return -1;
562
  }
563
#if FILE_WITH_LOCK
564
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
565
#endif
566
  return liOffset.QuadPart;
567
}
568

569
int32_t taosFStatFile(TdFilePtr pFile, int64_t *size, int64_t *mtime) {
570
  if (pFile == NULL || pFile->hFile == NULL) {
571
    terrno = TSDB_CODE_INVALID_PARA;
572
    return terrno;
573
  }
574

575
  if (size != NULL) {
576
    LARGE_INTEGER fileSize;
577
    if (!GetFileSizeEx(pFile->hFile, &fileSize)) {
578
      errno = GetLastError();
579
      terrno = TAOS_SYSTEM_WINAPI_ERROR(errno);
580
      return terrno;  // Error getting file size
581
    }
582
    *size = fileSize.QuadPart;
583
  }
584

585
  if (mtime != NULL) {
586
    FILETIME creationTime, lastAccessTime, lastWriteTime;
587
    if (!GetFileTime(pFile->hFile, &creationTime, &lastAccessTime, &lastWriteTime)) {
588
      errno = GetLastError();
589
      terrno = TAOS_SYSTEM_WINAPI_ERROR(errno);
590
      return terrno;  // Error getting file time
591
    }
592
    // Convert the FILETIME structure to a time_t value
593
    ULARGE_INTEGER ull;
594
    ull.LowPart = lastWriteTime.dwLowDateTime;
595
    ull.HighPart = lastWriteTime.dwHighDateTime;
596
    *mtime = (int64_t)((ull.QuadPart - 116444736000000000ULL) / 10000000ULL);
597
  }
598
  return 0;
599
}
600

601
int32_t taosLockFile(TdFilePtr pFile) {
602
  if (pFile == NULL || pFile->hFile == NULL) {
603
    terrno = TSDB_CODE_INVALID_PARA;
604
    return terrno;
605
  }
606

607
  BOOL          fSuccess = FALSE;
608
  LARGE_INTEGER fileSize;
609
  OVERLAPPED    overlapped = {0};
610

611
  fSuccess = LockFileEx(pFile->hFile, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY,
612
                        0,           // reserved
613
                        ~0,          // number of bytes to lock low
614
                        ~0,          // number of bytes to lock high
615
                        &overlapped  // overlapped structure
616
  );
617
  if (!fSuccess) {
618
    return TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
619
  }
620
  return 0;
621
}
622

623
int32_t taosUnLockFile(TdFilePtr pFile) {
624
  if (pFile == NULL || pFile->hFile == NULL) {
625
    return 0;
626
  }
627
  BOOL       fSuccess = FALSE;
628
  OVERLAPPED overlapped = {0};
629

630
  fSuccess = UnlockFileEx(pFile->hFile, 0, ~0, ~0, &overlapped);
631
  if (!fSuccess) {
632
    return TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
633
  }
634
  return 0;
635
}
636

637
int32_t taosFtruncateFile(TdFilePtr pFile, int64_t l_size) {
638
  if (pFile == NULL) {
639
    terrno = TSDB_CODE_INVALID_PARA;
640
    return terrno;
641
  }
642
  if (pFile->hFile == NULL) {
643
    printf("Ftruncate file error, hFile was null\n");
644
    terrno = TSDB_CODE_INVALID_PARA;
645
    return terrno;
646
  }
647

648
  LARGE_INTEGER li_0;
649
  li_0.QuadPart = (int64_t)0;
650
  BOOL cur = SetFilePointerEx(pFile->hFile, li_0, NULL, FILE_CURRENT);
651
  if (!cur) {
652
    printf("SetFilePointerEx Error getting current position in file.\n");
653
    terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
654
    return terrno;
655
  }
656

657
  LARGE_INTEGER li_size;
658
  li_size.QuadPart = l_size;
659
  BOOL cur2 = SetFilePointerEx(pFile->hFile, li_size, NULL, FILE_BEGIN);
660
  if (cur2 == 0) {
661
    int error = GetLastError();
662
    switch (error) {
663
      case ERROR_INVALID_HANDLE:
664
        errno = EBADF;
665
        break;
666
      default:
667
        errno = EIO;
668
        break;
669
    }
670
    terrno = TAOS_SYSTEM_ERROR(errno);
671
    return terrno;
672
  }
673

674
  if (!SetEndOfFile(pFile->hFile)) {
675
    int error = GetLastError();
676
    printf("SetEndOfFile GetLastError is:%d", error);
677
    switch (error) {
678
      case ERROR_INVALID_HANDLE:
679
        errno = EBADF;
680
        break;
681
      default:
682
        errno = EIO;
683
        break;
684
    }
685
    terrno = TAOS_SYSTEM_ERROR(errno);
686
    return terrno;
687
  }
688
  return 0;
689
}
690

691
int64_t taosFSendFile(TdFilePtr pFileOut, TdFilePtr pFileIn, int64_t *offset, int64_t size) {
692
  if (pFileOut == NULL || pFileIn == NULL) {
693
    terrno = TSDB_CODE_INVALID_PARA;
694
    return -1;
695
  }
696
  if (pFileIn->hFile == NULL || pFileOut->hFile == NULL) {
697
    terrno = TSDB_CODE_INVALID_PARA;
698
    return -1;
699
  }
700

701
  LARGE_INTEGER fileOffset;
702
  fileOffset.QuadPart = *offset;
703

704
  if (!SetFilePointerEx(pFileIn->hFile, fileOffset, &fileOffset, FILE_BEGIN)) {
705
    terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
706
    return -1;
707
  }
708

709
  int64_t writeLen = 0;
710
  uint8_t buffer[_SEND_FILE_STEP_] = {0};
711

712
  DWORD bytesRead;
713
  DWORD bytesWritten;
714
  for (int64_t len = 0; len < (size - _SEND_FILE_STEP_); len += _SEND_FILE_STEP_) {
715
    if (!ReadFile(pFileIn->hFile, buffer, _SEND_FILE_STEP_, &bytesRead, NULL)) {
716
      terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
717
      return writeLen;
718
    }
719

720
    if (bytesRead <= 0) {
721
      return writeLen;
722
    } else if (bytesRead < _SEND_FILE_STEP_) {
723
      if (!WriteFile(pFileOut->hFile, buffer, bytesRead, &bytesWritten, NULL)) {
724
        terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
725
        return -1;
726
      } else {
727
        return (int64_t)(writeLen + bytesRead);
728
      }
729
    } else {
730
      if (!WriteFile(pFileOut->hFile, buffer, _SEND_FILE_STEP_, &bytesWritten, NULL)) {
731
        terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
732
        return -1;
733
      } else {
734
        writeLen += _SEND_FILE_STEP_;
735
      }
736
    }
737
  }
738

739
  int64_t remain = size - writeLen;
740
  if (remain > 0) {
741
    DWORD bytesRead;
742
    if (!ReadFile(pFileIn->hFile, buffer, (DWORD)remain, &bytesRead, NULL)) {
743
      terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
744
      return -1;
745
    }
746

747
    if (bytesRead <= 0) {
748
      return writeLen;
749
    } else {
750
      DWORD bytesWritten;
751
      if (!WriteFile(pFileOut->hFile, buffer, bytesRead, &bytesWritten, NULL)) {
752
        terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
753
        return -1;
754
      } else {
755
        writeLen += bytesWritten;
756
      }
757
    }
758
  }
759
  return writeLen;
760
}
761

762
bool lastErrorIsFileNotExist() {
763
  DWORD dwError = GetLastError();
764
  return dwError == ERROR_FILE_NOT_FOUND;
765
}
766

767
#else
768
int taosOpenFileNotStream(const char *path, int32_t tdFileOptions) {
8,087,824✔
769
  if (path == NULL) {
8,087,824!
770
    terrno = TSDB_CODE_INVALID_PARA;
×
771
    return -1;
×
772
  }
773
  int access = O_BINARY;
8,087,824✔
774
  access |= (tdFileOptions & TD_FILE_CREATE) ? O_CREAT : 0;
8,087,824✔
775
  if ((tdFileOptions & TD_FILE_WRITE) && (tdFileOptions & TD_FILE_READ)) {
8,087,824✔
776
    access |= O_RDWR;
433,335✔
777
  } else if (tdFileOptions & TD_FILE_WRITE) {
7,654,489✔
778
    access |= O_WRONLY;
249,498✔
779
  } else if (tdFileOptions & TD_FILE_READ) {
7,404,991!
780
    access |= O_RDONLY;
7,406,273✔
781
  }
782
  access |= (tdFileOptions & TD_FILE_TRUNC) ? O_TRUNC : 0;
8,087,824✔
783
  access |= (tdFileOptions & TD_FILE_APPEND) ? O_APPEND : 0;
8,087,824✔
784
  access |= (tdFileOptions & TD_FILE_TEXT) ? O_TEXT : 0;
8,087,824✔
785
  access |= (tdFileOptions & TD_FILE_EXCL) ? O_EXCL : 0;
8,087,824✔
786
  access |= (tdFileOptions & TD_FILE_CLOEXEC) ? O_CLOEXEC : 0;
8,087,824✔
787

788
  int fd = open(path, access, S_IRWXU | S_IRWXG | S_IRWXO);
8,087,824✔
789
  if (-1 == fd) {
8,088,857✔
790
    terrno = TAOS_SYSTEM_ERROR(errno);
18,049✔
791
  }
792
  return fd;
8,088,526✔
793
}
794

795
int64_t taosReadFile(TdFilePtr pFile, void *buf, int64_t count) {
16,515,618✔
796
  if (pFile == NULL || buf == NULL) {
16,515,618!
797
    terrno = TSDB_CODE_INVALID_PARA;
×
798
    return -1;
×
799
  }
800
  STUB_RAND_IO_ERR(terrno)
801
#if FILE_WITH_LOCK
802
  (void)taosThreadRwlockRdlock(&(pFile->rwlock));
16,516,639✔
803
#endif
804

805
  if (pFile->fd < 0) {
16,521,815!
806
#if FILE_WITH_LOCK
807
    (void)taosThreadRwlockUnlock(&(pFile->rwlock));
×
808
#endif
809
    terrno = TSDB_CODE_INVALID_PARA;
×
810
    return -1;
×
811
  }
812

813
  int64_t leftbytes = count;
16,521,836✔
814
  int64_t readbytes;
815
  char   *tbuf = (char *)buf;
16,521,836✔
816
  int32_t code = 0;
16,521,836✔
817

818
  while (leftbytes > 0) {
33,038,220✔
819
#ifdef WINDOWS
820
    readbytes = _read(pFile->fd, (void *)tbuf, (uint32_t)leftbytes);
821
#else
822
    readbytes = read(pFile->fd, (void *)tbuf, (uint32_t)leftbytes);
16,521,838✔
823
#endif
824
    if (readbytes < 0) {
16,520,268✔
825
      if (errno == EINTR) {
70!
826
        continue;
×
827
      } else {
828
        code = TAOS_SYSTEM_ERROR(errno);
70✔
829
#if FILE_WITH_LOCK
830
        (void)taosThreadRwlockUnlock(&(pFile->rwlock));
70✔
831
#endif
832
        terrno = code;
70✔
833
        return -1;
70✔
834
      }
835
    } else if (readbytes == 0) {
16,520,198✔
836
#if FILE_WITH_LOCK
837
      (void)taosThreadRwlockUnlock(&(pFile->rwlock));
3,814✔
838
#endif
839
      return (int64_t)(count - leftbytes);
3,814✔
840
    }
841

842
    leftbytes -= readbytes;
16,516,384✔
843
    tbuf += readbytes;
16,516,384✔
844
  }
845

846
#if FILE_WITH_LOCK
847
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
16,516,382✔
848
#endif
849

850
  return count;
16,518,602✔
851
}
852

853
int64_t taosWriteFile(TdFilePtr pFile, const void *buf, int64_t count) {
534,159,010✔
854
  STUB_RAND_IO_ERR(terrno)
855
  if (pFile == NULL || buf == NULL) {
534,159,010!
856
    terrno = TSDB_CODE_INVALID_PARA;
×
857
    return 0;
×
858
  }
859
#if FILE_WITH_LOCK
860
  (void)taosThreadRwlockWrlock(&(pFile->rwlock));
534,179,910✔
861
#endif
862
  if (pFile->fd < 0) {
534,368,295✔
863
#if FILE_WITH_LOCK
864
    (void)taosThreadRwlockUnlock(&(pFile->rwlock));
108✔
865
#endif
866
    terrno = TSDB_CODE_INVALID_PARA;
×
867
    return 0;
×
868
  }
869

870
  int64_t nleft = count;
534,368,187✔
871
  int64_t nwritten = 0;
534,368,187✔
872
  char   *tbuf = (char *)buf;
534,368,187✔
873
  int32_t code = 0;
534,368,187✔
874

875
  while (nleft > 0) {
1,068,733,410✔
876
    nwritten = write(pFile->fd, (void *)tbuf, (uint32_t)nleft);
534,367,706✔
877
    if (nwritten < 0) {
534,365,223!
878
      if (errno == EINTR) {
×
879
        continue;
×
880
      }
881
      code = TAOS_SYSTEM_ERROR(errno);
×
882
#if FILE_WITH_LOCK
883
      (void)taosThreadRwlockUnlock(&(pFile->rwlock));
×
884
#endif
885
      terrno = code;
×
886
      return -1;
×
887
    }
888
    nleft -= nwritten;
534,365,223✔
889
    tbuf += nwritten;
534,365,223✔
890
  }
891

892
#if FILE_WITH_LOCK
893
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
534,365,704✔
894
#endif
895

896
  return count;
534,343,671✔
897
}
898

899
int64_t taosPWriteFile(TdFilePtr pFile, const void *buf, int64_t count, int64_t offset) {
570,732✔
900
  STUB_RAND_IO_ERR(terrno)
901
  if (pFile == NULL || buf == NULL) {
570,732!
902
    terrno = TSDB_CODE_INVALID_PARA;
×
903
    return 0;
×
904
  }
905

906
  int32_t code = 0;
570,758✔
907
#if FILE_WITH_LOCK
908
  (void)taosThreadRwlockWrlock(&(pFile->rwlock));
570,758✔
909
#endif
910

911
#if FILE_WITH_LOCK
912
  if (pFile->fd < 0) {
570,988!
913
    (void)taosThreadRwlockUnlock(&(pFile->rwlock));
×
914
    return 0;
×
915
  }
916
#endif
917

918
  int64_t ret = pwrite(pFile->fd, buf, count, offset);
570,988✔
919
  if (-1 == ret) {
570,691!
920
    code = TAOS_SYSTEM_ERROR(errno);
×
921
  }
922

923
#if FILE_WITH_LOCK
924
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
570,691✔
925
#endif
926

927
  if (code) {
570,907!
928
    terrno = code;
×
929
  }
930

931
  return ret;
570,935✔
932
}
933

934
int64_t taosLSeekFile(TdFilePtr pFile, int64_t offset, int32_t whence) {
26,952,105✔
935
  if (pFile == NULL || pFile->fd < 0) {
26,952,105!
936
    terrno = TSDB_CODE_INVALID_PARA;
×
937
    return -1;
×
938
  }
939
#if FILE_WITH_LOCK
940
  (void)taosThreadRwlockRdlock(&(pFile->rwlock));
26,953,469✔
941
#endif
942

943
  int32_t code = 0;
26,957,278✔
944

945
  int64_t ret = lseek(pFile->fd, offset, whence);
26,957,278✔
946
  if (-1 == ret) {
26,956,018!
947
    code = TAOS_SYSTEM_ERROR(errno);
×
948
  }
949

950
#if FILE_WITH_LOCK
951
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
26,956,018✔
952
#endif
953

954
  if (code) {
26,956,471!
UNCOV
955
    terrno = code;
×
956
    return -1;
×
957
  }
958

959
  return ret;
26,956,744✔
960
}
961

962
int32_t taosFStatFile(TdFilePtr pFile, int64_t *size, int64_t *mtime) {
76,009✔
963
  if (pFile == NULL) {
76,009!
964
    terrno = TSDB_CODE_INVALID_PARA;
×
965
    return terrno;
×
966
  }
967

968
  if (pFile->fd < 0) {
76,009!
969
    terrno = TSDB_CODE_INVALID_PARA;
×
970
    return terrno;
×
971
  }
972

973
  struct stat fileStat;
974
  int32_t     code = fstat(pFile->fd, &fileStat);
76,009✔
975
  if (-1 == code) {
76,041!
UNCOV
976
    terrno = TAOS_SYSTEM_ERROR(errno);
×
977
    return terrno;
×
978
  }
979

980
  if (size != NULL) {
76,050!
981
    *size = fileStat.st_size;
76,053✔
982
  }
983

984
  if (mtime != NULL) {
76,050!
985
    *mtime = fileStat.st_mtime;
×
986
  }
987

988
  return 0;
76,050✔
989
}
990

991
int32_t taosLockFile(TdFilePtr pFile) {
5,181✔
992
  if (NULL == pFile || pFile->fd < 0) {
5,181!
993
    terrno = TSDB_CODE_INVALID_PARA;
×
994
    return terrno;
×
995
  }
996
  int32_t code = (int32_t)flock(pFile->fd, LOCK_EX | LOCK_NB);
5,181✔
997
  if (-1 == code) {
5,181✔
998
    terrno = TAOS_SYSTEM_ERROR(errno);
1,164✔
999
    return terrno;
1,164✔
1000
  }
1001
  return 0;
4,017✔
1002
}
1003

1004
int32_t taosUnLockFile(TdFilePtr pFile) {
2,532✔
1005
  if (NULL == pFile || pFile->fd < 0) {
2,532!
1006
    terrno = TSDB_CODE_INVALID_PARA;
×
1007
    return terrno;
×
1008
  }
1009
  int32_t code = (int32_t)flock(pFile->fd, LOCK_UN | LOCK_NB);
2,532✔
1010
  if (-1 == code) {
2,532!
1011
    terrno = TAOS_SYSTEM_ERROR(errno);
×
1012
    return terrno;
×
1013
  }
1014
  return 0;
2,532✔
1015
}
1016

1017
int32_t taosFtruncateFile(TdFilePtr pFile, int64_t l_size) {
125✔
1018
  if (NULL == pFile || pFile->fd < 0) {
125!
1019
    terrno = TSDB_CODE_INVALID_PARA;
×
1020
    return terrno;
×
1021
  }
1022

1023
  int32_t code = ftruncate(pFile->fd, l_size);
125✔
1024
  if (-1 == code) {
125!
1025
    terrno = TAOS_SYSTEM_ERROR(errno);
×
1026
    return terrno;
×
1027
  }
1028
  return 0;
125✔
1029
}
1030

1031
int64_t taosFSendFile(TdFilePtr pFileOut, TdFilePtr pFileIn, int64_t *offset, int64_t size) {
×
1032
  if (pFileOut == NULL || pFileIn == NULL) {
×
1033
    terrno = TSDB_CODE_INVALID_PARA;
×
1034
    return -1;
×
1035
  }
1036
  if (pFileIn->fd < 0 || pFileOut->fd < 0) {
×
1037
    terrno = TSDB_CODE_INVALID_PARA;
×
1038
    return -1;
×
1039
  }
1040

1041
#ifdef _TD_DARWIN_64
1042
  if (lseek(pFileIn->fd, (int32_t)(*offset), 0) < 0) {
1043
    terrno = TAOS_SYSTEM_ERROR(errno);
1044
    return -1;
1045
  }
1046
  int64_t writeLen = 0;
1047
  uint8_t buffer[_SEND_FILE_STEP_] = {0};
1048

1049
  for (int64_t len = 0; len < (size - _SEND_FILE_STEP_); len += _SEND_FILE_STEP_) {
1050
    size_t rlen = read(pFileIn->fd, (void *)buffer, _SEND_FILE_STEP_);
1051
    if (rlen <= 0) {
1052
      return writeLen;
1053
    } else if (rlen < _SEND_FILE_STEP_) {
1054
      write(pFileOut->fd, (void *)buffer, (uint32_t)rlen);
1055
      return (int64_t)(writeLen + rlen);
1056
    } else {
1057
      write(pFileOut->fd, (void *)buffer, _SEND_FILE_STEP_);
1058
      writeLen += _SEND_FILE_STEP_;
1059
    }
1060
  }
1061

1062
  int64_t remain = size - writeLen;
1063
  if (remain > 0) {
1064
    size_t rlen = read(pFileIn->fd, (void *)buffer, (size_t)remain);
1065
    if (rlen <= 0) {
1066
      return writeLen;
1067
    } else {
1068
      write(pFileOut->fd, (void *)buffer, (uint32_t)remain);
1069
      writeLen += remain;
1070
    }
1071
  }
1072
  return writeLen;
1073

1074
#else  // for linux
1075

1076
  int64_t leftbytes = size;
×
1077
  int64_t sentbytes;
1078

1079
  while (leftbytes > 0) {
×
1080
#ifdef _TD_ARM_32
1081
    sentbytes = sendfile(pFileOut->fd, pFileIn->fd, (long int *)offset, leftbytes);
1082
#else
1083
    sentbytes = sendfile(pFileOut->fd, pFileIn->fd, offset, leftbytes);
×
1084
#endif
1085
    if (sentbytes == -1) {
×
1086
      if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
×
1087
        continue;
×
1088
      } else {
1089
        terrno = TAOS_SYSTEM_ERROR(errno);
×
1090
        return -1;
×
1091
      }
1092
    } else if (sentbytes == 0) {
×
1093
      return (int64_t)(size - leftbytes);
×
1094
    }
1095

1096
    leftbytes -= sentbytes;
×
1097
  }
1098

1099
  return size;
×
1100
#endif
1101
}
1102

1103
bool lastErrorIsFileNotExist() { return terrno == TAOS_SYSTEM_ERROR(ENOENT); }
3,292✔
1104

1105
#endif  // WINDOWS
1106

1107
TdFilePtr taosOpenFile(const char *path, int32_t tdFileOptions) {
16,932,989✔
1108
  if (path == NULL) {
16,932,989!
1109
    terrno = TSDB_CODE_INVALID_PARA;
×
1110
    return NULL;
×
1111
  }
1112
  STUB_RAND_IO_ERR(NULL)
1113
  FILE *fp = NULL;
16,932,989✔
1114
#ifdef WINDOWS
1115
  HANDLE hFile = NULL;
1116
#else
1117
  int fd = -1;
16,932,989✔
1118
#endif
1119
  if (tdFileOptions & TD_FILE_STREAM) {
16,932,989✔
1120
    fp = taosOpenFileForStream(path, tdFileOptions);
8,844,610✔
1121
    if (fp == NULL) return NULL;
8,844,610✔
1122
  } else {
1123
#ifdef WINDOWS
1124
    hFile = taosOpenFileNotStream(path, tdFileOptions);
1125
    if (hFile == INVALID_HANDLE_VALUE) return NULL;
1126
#else
1127
    fd = taosOpenFileNotStream(path, tdFileOptions);
8,088,379✔
1128
    if (fd == -1) return NULL;
8,088,372✔
1129
#endif
1130
  }
1131

1132
  TdFilePtr pFile = (TdFilePtr)taosMemoryMalloc(sizeof(TdFile));
16,915,250!
1133
  if (pFile == NULL) {
16,916,343!
1134
#ifdef WINDOWS
1135
    if (hFile != NULL) CloseHandle(hFile);
1136
#else
1137
    if (fd >= 0) (void)close(fd);
×
1138
#endif
1139
    if (fp != NULL) (void)fclose(fp);
×
1140
    terrno = TSDB_CODE_OUT_OF_MEMORY;
×
1141
    return NULL;
×
1142
  }
1143

1144
#if FILE_WITH_LOCK
1145
  (void)taosThreadRwlockInit(&(pFile->rwlock), NULL);
16,916,343✔
1146
#endif
1147
  pFile->fp = fp;
16,914,997✔
1148
  pFile->refId = 0;
16,914,997✔
1149

1150
#ifdef WINDOWS
1151
  pFile->hFile = hFile;
1152
  pFile->tdFileOptions = tdFileOptions;
1153
  // do nothing, since the property of pmode is set with _O_TEMPORARY; the OS will recycle
1154
  // the file handle, as well as the space on disk.
1155
#else
1156
  pFile->fd = fd;
16,914,997✔
1157
  // Remove it instantly, so when the program exits normally/abnormally, the file
1158
  // will be automatically remove by OS.
1159
  if (tdFileOptions & TD_FILE_AUTO_DEL) {
16,914,997✔
1160
    if (-1 == unlink(path)) {
742✔
1161
      terrno = TAOS_SYSTEM_ERROR(errno);
409✔
1162
      (void)close(fd);
×
1163
      taosMemoryFree(pFile);
×
1164
      return NULL;
×
1165
    }
1166
  }
1167
#endif
1168

1169
  return pFile;
16,914,588✔
1170
}
1171

1172
int32_t taosCloseFile(TdFilePtr *ppFile) {
32,408,701✔
1173
  int32_t code = 0;
32,408,701✔
1174
  if (ppFile == NULL || *ppFile == NULL) {
32,408,701!
1175
    return 0;
15,492,970✔
1176
  }
1177
#if FILE_WITH_LOCK
1178
  (void)taosThreadRwlockWrlock(&((*ppFile)->rwlock));
16,915,731✔
1179
#endif
1180
  if ((*ppFile)->fp != NULL) {
16,916,752✔
1181
    TAOS_UNUSED(fflush((*ppFile)->fp));
8,843,881✔
1182
    TAOS_UNUSED(fclose((*ppFile)->fp));
8,843,881✔
1183
    (*ppFile)->fp = NULL;
8,843,881✔
1184
  }
1185
#ifdef WINDOWS
1186
  if ((*ppFile)->hFile != NULL) {
1187
    // FlushFileBuffers((*ppFile)->hFile);
1188
    if (!CloseHandle((*ppFile)->hFile)) {
1189
      terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
1190
      code = -1;
1191
    }
1192
    (*ppFile)->hFile = NULL;
1193
#else
1194
  if ((*ppFile)->fd >= 0) {
16,916,752✔
1195
    // warning: never fsync silently in base lib
1196
    /*fsync((*ppFile)->fd);*/
1197
    code = close((*ppFile)->fd);
8,072,922✔
1198
    if (-1 == code) {
8,073,610!
1199
      terrno = TAOS_SYSTEM_ERROR(errno);
×
1200
    }
1201
    (*ppFile)->fd = -1;
8,073,656✔
1202
#endif
1203
  }
1204
  (*ppFile)->refId = 0;
16,917,486✔
1205
#if FILE_WITH_LOCK
1206
  (void)taosThreadRwlockUnlock(&((*ppFile)->rwlock));
16,917,486✔
1207
  (void)taosThreadRwlockDestroy(&((*ppFile)->rwlock));
16,917,478✔
1208
#endif
1209
  taosMemoryFree(*ppFile);
16,917,440!
1210
  *ppFile = NULL;
16,917,338✔
1211
  return code;
16,917,338✔
1212
}
1213

1214
int64_t taosPReadFile(TdFilePtr pFile, void *buf, int64_t count, int64_t offset) {
527,123✔
1215
  STUB_RAND_IO_ERR(terrno)
1216
  if (pFile == NULL) {
527,123!
1217
    terrno = TSDB_CODE_INVALID_PARA;
×
1218
    return -1;
×
1219
  }
1220

1221
  int32_t code = 0;
527,123✔
1222

1223
#ifdef WINDOWS
1224
#if FILE_WITH_LOCK
1225
  (void)taosThreadRwlockRdlock(&(pFile->rwlock));
1226
#endif
1227

1228
  if (pFile->hFile == NULL) {
1229
#if FILE_WITH_LOCK
1230
    (void)taosThreadRwlockUnlock(&(pFile->rwlock));
1231
#endif
1232

1233
    terrno = TSDB_CODE_INVALID_PARA;
1234
    return -1;
1235
  }
1236

1237
  DWORD      ret = 0;
1238
  OVERLAPPED ol = {0};
1239
  ol.OffsetHigh = (uint32_t)((offset & 0xFFFFFFFF00000000LL) >> 0x20);
1240
  ol.Offset = (uint32_t)(offset & 0xFFFFFFFFLL);
1241

1242
  SetLastError(0);
1243
  BOOL result = ReadFile(pFile->hFile, buf, count, &ret, &ol);
1244
  if (!result && GetLastError() != ERROR_HANDLE_EOF) {
1245
    code = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
1246
    ret = -1;
1247
  }
1248
#else
1249
#if FILE_WITH_LOCK
1250
  (void)taosThreadRwlockRdlock(&(pFile->rwlock));
527,123✔
1251
#endif
1252

1253
  if (pFile->fd < 0) {
527,252!
1254
#if FILE_WITH_LOCK
1255
    (void)taosThreadRwlockUnlock(&(pFile->rwlock));
×
1256
#endif
1257
    terrno = TSDB_CODE_INVALID_PARA;
×
1258
    return -1;
×
1259
  }
1260
  int64_t ret = pread(pFile->fd, buf, count, offset);
527,252✔
1261
  if (-1 == ret) {
527,126!
1262
    code = TAOS_SYSTEM_ERROR(errno);
×
1263
  }
1264
#endif
1265
#if FILE_WITH_LOCK
1266
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
527,126✔
1267
#endif
1268

1269
  if (code) {
527,209!
1270
    terrno = code;
×
1271
    return -1;
×
1272
  }
1273

1274
  return ret;
527,233✔
1275
}
1276

1277
int32_t taosFsyncFile(TdFilePtr pFile) {
1,611,499✔
1278
  if (pFile == NULL) {
1,611,499✔
1279
    return 0;
1,907✔
1280
  }
1281

1282
  int32_t code = 0;
1,609,592✔
1283
  // this implementation is WRONG
1284
  // fflush is not a replacement of fsync
1285
  if (pFile->fp != NULL) {
1,609,592✔
1286
    code = fflush(pFile->fp);
461,426✔
1287
    if (0 != code) {
461,426!
1288
      terrno = TAOS_SYSTEM_ERROR(errno);
×
1289
      return terrno;
×
1290
    }
1291

1292
    return 0;
461,426✔
1293
  }
1294

1295
#ifdef WINDOWS
1296
  if (pFile->hFile != NULL) {
1297
    if (pFile->tdFileOptions & TD_FILE_WRITE_THROUGH) {
1298
      return 0;
1299
    }
1300
    bool ret = FlushFileBuffers(pFile->hFile);
1301
    if (!ret) {
1302
      terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
1303
      return terrno;
1304
    }
1305
    return 0;
1306
  }
1307
#else
1308
  if (pFile->fd >= 0) {
1,148,166!
1309
    code = fsync(pFile->fd);
1,148,198✔
1310
    if (-1 == code) {
1,148,500!
1311
      terrno = TAOS_SYSTEM_ERROR(errno);
×
1312
      return terrno;
×
1313
    }
1314
  }
1315
#endif
1316

1317
  return 0;
1,148,522✔
1318
}
1319

1320
void taosFprintfFile(TdFilePtr pFile, const char *format, ...) {
165,280,968✔
1321
  if (pFile == NULL || pFile->fp == NULL) {
165,280,968!
1322
    return;
61,820,500✔
1323
  }
1324
  va_list ap;
1325
  va_start(ap, format);
103,460,468✔
1326
  (void)vfprintf(pFile->fp, format, ap);
103,460,468✔
1327
  va_end(ap);
103,545,100✔
1328
}
1329

1330
bool taosValidFile(TdFilePtr pFile) {
×
1331
#ifdef WINDOWS
1332
  return pFile != NULL && pFile->hFile != NULL;
1333
#else
1334
  return pFile != NULL && pFile->fd > 0;
×
1335
#endif
1336
}
1337

1338
int32_t taosUmaskFile(int32_t maskVal) {
7,934✔
1339
#ifdef WINDOWS
1340
  return 0;
1341
#else
1342
  return umask(maskVal);
7,934✔
1343
#endif
1344
}
1345

1346
int64_t taosGetLineFile(TdFilePtr pFile, char **__restrict ptrBuf) {
108,298✔
1347
  int64_t ret = -1;
108,298✔
1348
  int32_t code = 0;
108,298✔
1349

1350
#if FILE_WITH_LOCK
1351
  (void)taosThreadRwlockRdlock(&(pFile->rwlock));
108,298✔
1352
#endif
1353
  if (pFile == NULL || ptrBuf == NULL) {
108,298!
1354
    terrno = TSDB_CODE_INVALID_PARA;
×
1355
    goto END;
×
1356
  }
1357
  if (*ptrBuf != NULL) {
108,298✔
1358
    taosMemoryFreeClear(*ptrBuf);
108,270!
1359
  }
1360

1361
  if (pFile->fp == NULL) {
108,298!
1362
    terrno = TSDB_CODE_INVALID_PARA;
×
1363
    goto END;
×
1364
  }
1365

1366
#ifdef WINDOWS
1367
  size_t bufferSize = 512;
1368
  *ptrBuf = taosMemoryMalloc(bufferSize);
1369
  if (*ptrBuf == NULL) {
1370
    goto END;
1371
  }
1372

1373
  size_t bytesRead = 0;
1374
  size_t totalBytesRead = 0;
1375

1376
  while (1) {
1377
    char *result = fgets(*ptrBuf + totalBytesRead, bufferSize - totalBytesRead, pFile->fp);
1378
    if (result == NULL) {
1379
      if (feof(pFile->fp)) {
1380
        break;
1381
      } else {
1382
        ret = -1;
1383
        terrno = TAOS_SYSTEM_ERROR(ferror(pFile->fp));
1384
        taosMemoryFreeClear(*ptrBuf);
1385
        goto END;
1386
      }
1387
    }
1388
    bytesRead = strlen(*ptrBuf + totalBytesRead);
1389
    totalBytesRead += bytesRead;
1390

1391
    if (totalBytesRead < bufferSize - 1 || (*ptrBuf)[totalBytesRead - 1] == '\n') {
1392
      break;
1393
    }
1394

1395
    bufferSize += 512;
1396
    void *newBuf = taosMemoryRealloc(*ptrBuf, bufferSize);
1397
    if (newBuf == NULL) {
1398
      taosMemoryFreeClear(*ptrBuf);
1399
      goto END;
1400
    }
1401

1402
    *ptrBuf = newBuf;
1403
  }
1404

1405
  (*ptrBuf)[totalBytesRead] = '\0';
1406
  ret = totalBytesRead;
1407
#else
1408
  size_t len = 0;
108,298✔
1409
  ret = getline(ptrBuf, &len, pFile->fp);
108,298✔
1410
  if (-1 == ret) {
108,298✔
1411
    terrno = TAOS_SYSTEM_ERROR(errno);
28✔
1412
  }
1413
#endif
1414

1415
END:
108,270✔
1416

1417
#if FILE_WITH_LOCK
1418
  (void)taosThreadRwlockUnlock(&(pFile->rwlock));
108,298✔
1419
#endif
1420

1421
  return ret;
108,298✔
1422
}
1423

1424
int64_t taosGetsFile(TdFilePtr pFile, int32_t maxSize, char *__restrict buf) {
31,242,401✔
1425
  if (pFile == NULL || buf == NULL) {
31,242,401!
1426
    terrno = TSDB_CODE_INVALID_PARA;
×
1427
    return terrno;
×
1428
  }
1429

1430
  if (pFile->fp == NULL) {
31,242,401!
1431
    terrno = TSDB_CODE_INVALID_PARA;
×
1432
    return terrno;
×
1433
  }
1434

1435
  if (fgets(buf, maxSize, pFile->fp) == NULL) {
31,242,401✔
1436
    if (feof(pFile->fp)) {
13,445!
1437
      return 0;
13,445✔
1438
    } else {
1439
      terrno = TAOS_SYSTEM_ERROR(ferror(pFile->fp));
×
1440
      return terrno;
×
1441
    }
1442
  }
1443

1444
  return strlen(buf);
31,228,956✔
1445
}
1446

1447
int32_t taosEOFFile(TdFilePtr pFile) {
27,045,943✔
1448
  if (pFile == NULL) {
27,045,943!
1449
    terrno = TSDB_CODE_INVALID_PARA;
×
1450
    return -1;
×
1451
  }
1452
  if (pFile->fp == NULL) {
27,045,943!
1453
    terrno = TSDB_CODE_INVALID_PARA;
×
1454
    return -1;
×
1455
  }
1456

1457
  return feof(pFile->fp);
27,045,943✔
1458
}
1459

1460
bool taosCheckAccessFile(const char *pathname, int32_t tdFileAccessOptions) {
426,882✔
1461
  if (pathname == NULL) {
426,882!
1462
    terrno = TSDB_CODE_INVALID_PARA;
×
1463
    return false;  // invalid parameter
×
1464
  }
1465
  int flags = 0;
426,882✔
1466

1467
  if (tdFileAccessOptions & TD_FILE_ACCESS_EXIST_OK) {
426,882!
1468
    flags |= F_OK;
426,963✔
1469
  }
1470

1471
  if (tdFileAccessOptions & TD_FILE_ACCESS_READ_OK) {
426,882✔
1472
    flags |= R_OK;
12,487✔
1473
  }
1474

1475
  if (tdFileAccessOptions & TD_FILE_ACCESS_WRITE_OK) {
426,882✔
1476
    flags |= W_OK;
12,486✔
1477
  }
1478
#ifdef WINDOWS
1479
  return _access(pathname, flags) == 0;
1480
#else
1481
  return access(pathname, flags) == 0;
426,882✔
1482
#endif
1483
}
1484

1485
bool taosCheckExistFile(const char *pathname) { return taosCheckAccessFile(pathname, TD_FILE_ACCESS_EXIST_OK); };
414,411✔
1486

1487
int32_t taosCompressFile(char *srcFileName, char *destFileName) {
2✔
1488
  OS_PARAM_CHECK(srcFileName);
2!
1489
  OS_PARAM_CHECK(destFileName);
2!
1490
  int32_t   compressSize = 163840;
2✔
1491
  int32_t   ret = 0;
2✔
1492
  int32_t   len = 0;
2✔
1493
  gzFile    dstFp = NULL;
2✔
1494
  TdFilePtr pSrcFile = NULL;
2✔
1495

1496
  char *data = taosMemoryMalloc(compressSize);
2!
1497
  if (NULL == data) {
2!
1498
    return terrno;
×
1499
  }
1500

1501
  pSrcFile = taosOpenFile(srcFileName, TD_FILE_READ | TD_FILE_STREAM);
2✔
1502
  if (pSrcFile == NULL) {
2!
1503
    ret = terrno;
×
1504
    goto cmp_end;
×
1505
  }
1506

1507
  int access = O_BINARY | O_WRONLY | O_TRUNC | O_CREAT;
2✔
1508
#ifdef WINDOWS
1509
  int32_t pmode = _S_IREAD | _S_IWRITE;
1510
#else
1511
  int32_t pmode = S_IRWXU | S_IRWXG | S_IRWXO;
2✔
1512
#endif
1513
  int fd = open(destFileName, access, pmode);
2✔
1514
  if (-1 == fd) {
2!
1515
    terrno = TAOS_SYSTEM_ERROR(errno);
×
1516
    ret = terrno;
×
1517
    goto cmp_end;
×
1518
  }
1519

1520
  // Both gzclose() and fclose() will close the associated fd, so they need to have different fds.
1521
  FileFd gzFd = dup(fd);
2✔
1522
  if (-1 == gzFd) {
2!
1523
    terrno = TAOS_SYSTEM_ERROR(errno);
×
1524
    ret = terrno;
×
1525
    goto cmp_end;
×
1526
  }
1527
  dstFp = gzdopen(gzFd, "wb6f");
2✔
1528
  if (dstFp == NULL) {
2!
1529
    terrno = TAOS_SYSTEM_ERROR(errno);
×
1530
    ret = terrno;
×
1531
    (void)close(gzFd);
×
1532
    goto cmp_end;
×
1533
  }
1534

1535
  while (!feof(pSrcFile->fp)) {
4✔
1536
    len = (int32_t)fread(data, 1, compressSize, pSrcFile->fp);
2✔
1537
    if (len > 0) {
2!
1538
      if (gzwrite(dstFp, data, len) == 0) {
2!
1539
        terrno = TAOS_SYSTEM_ERROR(errno);
×
1540
        ret = terrno;
×
1541
        goto cmp_end;
×
1542
      }
1543
    }
1544
  }
1545

1546
cmp_end:
2✔
1547

1548
  if (fd >= 0) {
2!
1549
    TAOS_SKIP_ERROR(close(fd));
2✔
1550
  }
1551
  if (pSrcFile) {
2!
1552
    TAOS_SKIP_ERROR(taosCloseFile(&pSrcFile));
2✔
1553
  }
1554

1555
  if (dstFp) {
2!
1556
    TAOS_SKIP_ERROR(gzclose(dstFp));
2✔
1557
  }
1558

1559
  taosMemoryFree(data);
2!
1560

1561
  return ret;
2✔
1562
}
1563

1564
int32_t taosSetFileHandlesLimit() {
7,404✔
1565
#ifdef WINDOWS
1566
  const int max_handles = 8192;
1567
  int       res = _setmaxstdio(max_handles);
1568
  return res == max_handles ? 0 : -1;
1569
#endif
1570
  return 0;
7,404✔
1571
}
1572

1573
int32_t taosLinkFile(char *src, char *dst) {
120✔
1574
#ifndef WINDOWS
1575
  if (-1 == link(src, dst)) {
120!
1576
    terrno = TAOS_SYSTEM_ERROR(errno);
×
1577
    return terrno;
×
1578
  }
1579
#endif
1580
  return 0;
120✔
1581
}
1582

1583
FILE *taosOpenCFile(const char *filename, const char *mode) {
14,609✔
1584
  if (filename == NULL || mode == NULL) {
14,609!
1585
    terrno = TSDB_CODE_INVALID_PARA;
×
1586
    return NULL;
×
1587
  }
1588
  STUB_RAND_IO_ERR(NULL)
1589
  FILE *f = fopen(filename, mode);
14,615✔
1590
  if (NULL == f) {
14,617!
1591
    terrno = TAOS_SYSTEM_ERROR(errno);
×
1592
  }
1593
  return f;
14,617✔
1594
}
1595

1596
int taosSeekCFile(FILE *file, int64_t offset, int whence) {
14,522✔
1597
  if (NULL == file) {
14,522!
1598
    terrno = TSDB_CODE_INVALID_PARA;
×
1599
    return terrno;
×
1600
  }
1601
#ifdef WINDOWS
1602
  return _fseeki64(file, offset, whence);
1603
#else
1604
  int     code = fseeko(file, offset, whence);
14,522✔
1605
  if (-1 == code) {
14,521!
1606
    terrno = TAOS_SYSTEM_ERROR(errno);
×
1607
    code = terrno;
×
1608
  }
1609
  return code;
14,522✔
1610
#endif
1611
}
1612

1613
size_t taosReadFromCFile(void *buffer, size_t size, size_t count, FILE *stream) {
14,520✔
1614
  if (buffer == NULL || stream == NULL) {
14,520!
1615
    terrno = TSDB_CODE_INVALID_PARA;
×
1616
    return 0;
×
1617
  }
1618
  STUB_RAND_IO_ERR(terrno)
1619
  return fread(buffer, size, count, stream);
14,520✔
1620
}
1621

1622
size_t taosWriteToCFile(const void *ptr, size_t size, size_t nitems, FILE *stream) {
×
1623
  STUB_RAND_IO_ERR(terrno)
1624
  return fwrite(ptr, size, nitems, stream);
×
1625
}
1626

1627
int taosCloseCFile(FILE *f) { return fclose(f); }
14,617✔
1628

1629
int taosSetAutoDelFile(char *path) {
14,617✔
1630
#ifdef WINDOWS
1631
  bool succ = SetFileAttributes(path, FILE_ATTRIBUTE_TEMPORARY);
1632
  if (succ) {
1633
    return 0;
1634
  } else {
1635
    terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError());
1636
    return terrno;
1637
  }
1638
#else
1639
  if (-1 == unlink(path)) {
14,617!
1640
    terrno = TAOS_SYSTEM_ERROR(errno);
×
1641
    return terrno;
×
1642
  }
1643
  return 0;
14,617✔
1644
#endif
1645
}
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