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

wafwerar's avatar
wafwerar 已提交
20
#ifdef WINDOWS
21
#include <io.h>
wafwerar's avatar
wafwerar 已提交
22 23 24
#define F_OK 0
#define W_OK 2
#define R_OK 4
25

wafwerar's avatar
wafwerar 已提交
26 27
#define _SEND_FILE_STEP_ 1000

28
#else
29 30
#include <fcntl.h>
#include <sys/file.h>
31 32

#if !defined(_TD_DARWIN_64)
L
Liu Jicong 已提交
33
#include <sys/sendfile.h>
34
#endif
35 36 37 38
#include <sys/stat.h>
#include <unistd.h>
#define LINUX_FILE_NO_TEXT_OPTION 0
#define O_TEXT                    LINUX_FILE_NO_TEXT_OPTION
wafwerar's avatar
wafwerar 已提交
39 40

#define _SEND_FILE_STEP_ 1000
41 42
#endif

wafwerar's avatar
wafwerar 已提交
43 44 45
typedef int32_t FileFd;

typedef struct TdFile {
wafwerar's avatar
wafwerar 已提交
46
  TdThreadRwlock rwlock;
L
Liu Jicong 已提交
47 48 49
  int            refId;
  FileFd         fd;
  FILE          *fp;
50
} TdFile;
wafwerar's avatar
wafwerar 已提交
51

52 53
#define FILE_WITH_LOCK 1

54
void taosGetTmpfilePath(const char *inputTmpDir, const char *fileNamePrefix, char *dstPath) {
wafwerar's avatar
wafwerar 已提交
55
#ifdef WINDOWS
S
Shengliang Guan 已提交
56
  const char *tdengineTmpFileNamePrefix = "tdengine-";
S
TD-4088  
Shengliang Guan 已提交
57
  char        tmpPath[PATH_MAX];
S
Shengliang Guan 已提交
58

S
Shengliang Guan 已提交
59 60
  int32_t len = (int32_t)strlen(inputTmpDir);
  memcpy(tmpPath, inputTmpDir, len);
S
TD-4088  
Shengliang Guan 已提交
61 62 63

  if (tmpPath[len - 1] != '/' && tmpPath[len - 1] != '\\') {
    tmpPath[len++] = '\\';
64
  }
S
Shengliang Guan 已提交
65

66
  strcpy(tmpPath + len, tdengineTmpFileNamePrefix);
S
Shengliang Guan 已提交
67 68 69
  if (strlen(tmpPath) + strlen(fileNamePrefix) + strlen("-%d-%s") < PATH_MAX) {
    strcat(tmpPath, fileNamePrefix);
    strcat(tmpPath, "-%d-%s");
S
Shengliang Guan 已提交
70
  }
S
Shengliang Guan 已提交
71

S
TD-4088  
Shengliang Guan 已提交
72 73
  char rand[8] = {0};
  taosRandStr(rand, tListLen(rand) - 1);
S
Shengliang Guan 已提交
74
  snprintf(dstPath, PATH_MAX, tmpPath, getpid(), rand);
S
TD-1912  
Shengliang Guan 已提交
75

S
TD-4088  
Shengliang Guan 已提交
76
#else
S
Shengliang Guan 已提交
77

S
TD-4088  
Shengliang Guan 已提交
78
  const char *tdengineTmpFileNamePrefix = "tdengine-";
S
Shengliang Guan 已提交
79

80
  char    tmpPath[PATH_MAX];
S
Shengliang Guan 已提交
81 82
  int32_t len = strlen(inputTmpDir);
  memcpy(tmpPath, inputTmpDir, len);
S
TD-4088  
Shengliang Guan 已提交
83
  static uint64_t seqId = 0;
S
Shengliang Guan 已提交
84

S
TD-4088  
Shengliang Guan 已提交
85 86
  if (tmpPath[len - 1] != '/') {
    tmpPath[len++] = '/';
S
TD-1912  
Shengliang Guan 已提交
87
  }
S
Shengliang Guan 已提交
88

S
TD-4088  
Shengliang Guan 已提交
89 90 91 92
  strcpy(tmpPath + len, tdengineTmpFileNamePrefix);
  if (strlen(tmpPath) + strlen(fileNamePrefix) + strlen("-%d-%s") < PATH_MAX) {
    strcat(tmpPath, fileNamePrefix);
    strcat(tmpPath, "-%d-%s");
S
Shengliang Guan 已提交
93 94
  }

S
TD-4088  
Shengliang Guan 已提交
95 96 97
  char rand[32] = {0};

  sprintf(rand, "%" PRIu64, atomic_add_fetch_64(&seqId, 1));
S
Shengliang Guan 已提交
98

S
TD-4088  
Shengliang Guan 已提交
99
  snprintf(dstPath, PATH_MAX, tmpPath, getpid(), rand);
S
Shengliang Guan 已提交
100

S
TD-4088  
Shengliang Guan 已提交
101
#endif
S
Shengliang Guan 已提交
102
}
S
TD-4088  
Shengliang Guan 已提交
103

104
int64_t taosCopyFile(const char *from, const char *to) {
wafwerar's avatar
wafwerar 已提交
105
#ifdef WINDOWS
wafwerar's avatar
wafwerar 已提交
106 107 108 109 110
  if (CopyFile(from, to, 0)) {
    return 1;
  } else {
    return -1;
  }
111 112 113 114 115 116
#else
  char    buffer[4096];
  int64_t size = 0;
  int64_t bytes;

  // fidfrom = open(from, O_RDONLY);
117
  TdFilePtr pFileFrom = taosOpenFile(from, TD_FILE_READ);
118 119 120
  if (pFileFrom == NULL) goto _err;

  // fidto = open(to, O_WRONLY | O_CREAT | O_EXCL, 0755);
121
  TdFilePtr pFileTo = taosOpenFile(to, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_EXCL);
122 123 124 125 126 127 128 129 130 131 132 133 134
  if (pFileTo == NULL) goto _err;

  while (true) {
    bytes = taosReadFile(pFileFrom, buffer, sizeof(buffer));
    if (bytes < 0) goto _err;
    if (bytes == 0) break;

    size += bytes;

    if (taosWriteFile(pFileTo, (void *)buffer, bytes) < bytes) goto _err;
    if (bytes < sizeof(buffer)) break;
  }

135
  int code = taosFsyncFile(pFileTo);
136 137 138

  taosCloseFile(&pFileFrom);
  taosCloseFile(&pFileTo);
139 140 141 142

  if (code != 0) {
    return -1;
  }
143 144 145 146 147
  return size;

_err:
  if (pFileFrom != NULL) taosCloseFile(&pFileFrom);
  if (pFileTo != NULL) taosCloseFile(&pFileTo);
148
  /* coverity[+retval] */
149
  taosRemoveFile(to);
150 151 152 153
  return -1;
#endif
}

C
Cary Xu 已提交
154 155 156 157 158
TdFilePtr taosCreateFile(const char *path, int32_t tdFileOptions) {
  TdFilePtr fp = taosOpenFile(path, tdFileOptions);
  if (!fp) {
    if (errno == ENOENT) {
      // Try to create directory recursively
159
      char *s = taosStrdup(path);
C
Cary Xu 已提交
160 161 162 163 164 165 166 167 168 169 170 171 172 173
      if (taosMulMkDir(taosDirName(s)) != 0) {
        taosMemoryFree(s);
        return NULL;
      }
      taosMemoryFree(s);
      fp = taosOpenFile(path, tdFileOptions);
      if (!fp) {
        return NULL;
      }
    }
  }
  return fp;
}

174 175
int32_t taosRemoveFile(const char *path) { return remove(path); }

176
int32_t taosRenameFile(const char *oldName, const char *newName) {
wafwerar's avatar
wafwerar 已提交
177
#ifdef WINDOWS
178 179
  bool code = MoveFileEx(oldName, newName, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED);
  if (!code) {
C
Cary Xu 已提交
180
    printf("failed to rename file %s to %s, reason:%s\n", oldName, newName, strerror(errno));
181 182
  }

A
Alex Duan 已提交
183
  return code ? 0 : -1;
184 185 186
#else
  int32_t code = rename(oldName, newName);
  if (code < 0) {
C
Cary Xu 已提交
187
    printf("failed to rename file %s to %s, reason:%s\n", oldName, newName, strerror(errno));
188 189 190 191 192 193
  }

  return code;
#endif
}

194
int32_t taosStatFile(const char *path, int64_t *size, int32_t *mtime, int32_t *atime) {
wafwerar's avatar
wafwerar 已提交
195
#ifdef WINDOWS
wafwerar's avatar
wafwerar 已提交
196
  struct _stati64 fileStat;
H
Hongze Cheng 已提交
197
  int32_t         code = _stati64(path, &fileStat);
198
#else
wafwerar's avatar
wafwerar 已提交
199
  struct stat fileStat;
200
  int32_t code = stat(path, &fileStat);
201
#endif
202 203 204 205 206 207 208 209 210 211 212 213
  if (code < 0) {
    return code;
  }

  if (size != NULL) {
    *size = fileStat.st_size;
  }

  if (mtime != NULL) {
    *mtime = fileStat.st_mtime;
  }

214 215 216 217
  if (atime != NULL) {
    *atime = fileStat.st_mtime;
  }

218 219
  return 0;
}
wafwerar's avatar
wafwerar 已提交
220
int32_t taosDevInoFile(TdFilePtr pFile, int64_t *stDev, int64_t *stIno) {
X
xinsheng Ren 已提交
221 222
  if (pFile == NULL || pFile->fd < 0) {
    return -1;
wafwerar's avatar
wafwerar 已提交
223
  }
224

wafwerar's avatar
wafwerar 已提交
225
#ifdef WINDOWS
wafwerar's avatar
wafwerar 已提交
226 227

  BY_HANDLE_FILE_INFORMATION bhfi;
228
  HANDLE                     handle = (HANDLE)_get_osfhandle(pFile->fd);
wafwerar's avatar
wafwerar 已提交
229 230 231 232 233 234 235 236 237 238 239 240 241
  if (GetFileInformationByHandle(handle, &bhfi) == FALSE) {
    printf("taosFStatFile get file info fail.");
    return -1;
  }

  if (stDev != NULL) {
    *stDev = (int64_t)(bhfi.dwVolumeSerialNumber);
  }

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

242
#else
243

wafwerar's avatar
wafwerar 已提交
244
  struct stat fileStat;
245
  int32_t code = fstat(pFile->fd, &fileStat);
246
  if (code < 0) {
wafwerar's avatar
wafwerar 已提交
247
    printf("taosFStatFile run fstat fail.");
248 249 250 251 252 253 254 255 256 257
    return code;
  }

  if (stDev != NULL) {
    *stDev = fileStat.st_dev;
  }

  if (stIno != NULL) {
    *stIno = fileStat.st_ino;
  }
wafwerar's avatar
wafwerar 已提交
258
#endif
259 260 261

  return 0;
}
262

263
TdFilePtr taosOpenFile(const char *path, int32_t tdFileOptions) {
L
Liu Jicong 已提交
264
  int   fd = -1;
265 266 267 268 269
  FILE *fp = NULL;
  if (tdFileOptions & TD_FILE_STREAM) {
    char *mode = NULL;
    if (tdFileOptions & TD_FILE_APPEND) {
      mode = (tdFileOptions & TD_FILE_TEXT) ? "at+" : "ab+";
L
Liu Jicong 已提交
270
    } else if (tdFileOptions & TD_FILE_TRUNC) {
271
      mode = (tdFileOptions & TD_FILE_TEXT) ? "wt+" : "wb+";
L
Liu Jicong 已提交
272
    } else if ((tdFileOptions & TD_FILE_READ) && !(tdFileOptions & TD_FILE_WRITE)) {
273
      mode = (tdFileOptions & TD_FILE_TEXT) ? "rt" : "rb";
L
Liu Jicong 已提交
274
    } else {
275 276
      mode = (tdFileOptions & TD_FILE_TEXT) ? "rt+" : "rb+";
    }
X
xinsheng Ren 已提交
277 278 279 280
    ASSERT(!(tdFileOptions & TD_FILE_EXCL));
    if (tdFileOptions & TD_FILE_EXCL) {
      return NULL;
    }
281 282 283 284 285 286
    fp = fopen(path, mode);
    if (fp == NULL) {
      return NULL;
    }
  } else {
    int access = O_BINARY;
287
    access |= (tdFileOptions & TD_FILE_CREATE) ? O_CREAT : 0;
288 289 290 291 292 293 294 295 296 297 298
    if ((tdFileOptions & TD_FILE_WRITE) && (tdFileOptions & TD_FILE_READ)) {
      access |= O_RDWR;
    } else if (tdFileOptions & TD_FILE_WRITE) {
      access |= O_WRONLY;
    } else if (tdFileOptions & TD_FILE_READ) {
      access |= O_RDONLY;
    }
    access |= (tdFileOptions & TD_FILE_TRUNC) ? O_TRUNC : 0;
    access |= (tdFileOptions & TD_FILE_APPEND) ? O_APPEND : 0;
    access |= (tdFileOptions & TD_FILE_TEXT) ? O_TEXT : 0;
    access |= (tdFileOptions & TD_FILE_EXCL) ? O_EXCL : 0;
L
Liu Jicong 已提交
299
#ifdef WINDOWS
300 301 302 303 304
    int32_t pmode = _S_IREAD | _S_IWRITE;
    if (tdFileOptions & TD_FILE_AUTO_DEL) {
      pmode |= _O_TEMPORARY;
    }
    fd = _open(path, access, pmode);
L
Liu Jicong 已提交
305
#else
306
    fd = open(path, access, S_IRWXU | S_IRWXG | S_IRWXO);
L
Liu Jicong 已提交
307
#endif
308 309 310 311 312
    if (fd == -1) {
      return NULL;
    }
  }

wafwerar's avatar
wafwerar 已提交
313
  TdFilePtr pFile = (TdFilePtr)taosMemoryMalloc(sizeof(TdFile));
314
  if (pFile == NULL) {
315 316
    if (fd >= 0) close(fd);
    if (fp != NULL) fclose(fp);
317 318
    return NULL;
  }
319

320
#if FILE_WITH_LOCK
wafwerar's avatar
wafwerar 已提交
321
  taosThreadRwlockInit(&(pFile->rwlock), NULL);
322
#endif
323 324 325
  pFile->fd = fd;
  pFile->fp = fp;
  pFile->refId = 0;
326

wafwerar's avatar
wafwerar 已提交
327
  if (tdFileOptions & TD_FILE_AUTO_DEL) {
328 329 330 331 332 333 334 335
#ifdef WINDOWS
    // do nothing, since the property of pmode is set with _O_TEMPORARY; the OS will recycle
    // the file handle, as well as the space on disk.
#else
    // Remove it instantly, so when the program exits normally/abnormally, the file
    // will be automatically remove by OS.
    unlink(path);
#endif
wafwerar's avatar
wafwerar 已提交
336
  }
337

338 339 340
  return pFile;
}

L
Liu Jicong 已提交
341 342
int32_t taosCloseFile(TdFilePtr *ppFile) {
  int32_t code = 0;
343 344 345 346
  if (ppFile == NULL || *ppFile == NULL) {
    return 0;
  }
#if FILE_WITH_LOCK
wafwerar's avatar
wafwerar 已提交
347
  taosThreadRwlockWrlock(&((*ppFile)->rwlock));
348
#endif
349 350 351 352 353 354
  if ((*ppFile)->fp != NULL) {
    fflush((*ppFile)->fp);
    fclose((*ppFile)->fp);
    (*ppFile)->fp = NULL;
  }
  if ((*ppFile)->fd >= 0) {
355
#ifdef WINDOWS
356 357
    HANDLE h = (HANDLE)_get_osfhandle((*ppFile)->fd);
    !FlushFileBuffers(h);
358
#else
L
Liu Jicong 已提交
359 360
    // warning: never fsync silently in base lib
    /*fsync((*ppFile)->fd);*/
361
#endif
L
Liu Jicong 已提交
362
    code = close((*ppFile)->fd);
363 364
    (*ppFile)->fd = -1;
  }
365
  (*ppFile)->refId = 0;
366
#if FILE_WITH_LOCK
wafwerar's avatar
wafwerar 已提交
367 368
  taosThreadRwlockUnlock(&((*ppFile)->rwlock));
  taosThreadRwlockDestroy(&((*ppFile)->rwlock));
369
#endif
wafwerar's avatar
wafwerar 已提交
370
  taosMemoryFree(*ppFile);
371
  *ppFile = NULL;
L
Liu Jicong 已提交
372
  return code;
373 374 375
}

int64_t taosReadFile(TdFilePtr pFile, void *buf, int64_t count) {
376
#if FILE_WITH_LOCK
wafwerar's avatar
wafwerar 已提交
377
  taosThreadRwlockRdlock(&(pFile->rwlock));
378
#endif
X
xinsheng Ren 已提交
379 380
  ASSERT(pFile->fd >= 0);  // Please check if you have closed the file.
  if (pFile->fd < 0) {
381 382 383
#if FILE_WITH_LOCK
    taosThreadRwlockUnlock(&(pFile->rwlock));
#endif
X
xinsheng Ren 已提交
384 385
    return -1;
  }
S
TD-1912  
Shengliang Guan 已提交
386 387
  int64_t leftbytes = count;
  int64_t readbytes;
388
  char   *tbuf = (char *)buf;
S
Shengliang Guan 已提交
389 390

  while (leftbytes > 0) {
391
#ifdef WINDOWS
wafwerar's avatar
wafwerar 已提交
392
    readbytes = _read(pFile->fd, (void *)tbuf, (uint32_t)leftbytes);
393
#else
394
    readbytes = read(pFile->fd, (void *)tbuf, (uint32_t)leftbytes);
395
#endif
S
Shengliang Guan 已提交
396 397 398 399
    if (readbytes < 0) {
      if (errno == EINTR) {
        continue;
      } else {
400
#if FILE_WITH_LOCK
wafwerar's avatar
wafwerar 已提交
401
        taosThreadRwlockUnlock(&(pFile->rwlock));
402
#endif
S
Shengliang Guan 已提交
403 404 405
        return -1;
      }
    } else if (readbytes == 0) {
406
#if FILE_WITH_LOCK
wafwerar's avatar
wafwerar 已提交
407
      taosThreadRwlockUnlock(&(pFile->rwlock));
408
#endif
S
TD-1912  
Shengliang Guan 已提交
409
      return (int64_t)(count - leftbytes);
S
Shengliang Guan 已提交
410 411 412 413 414 415
    }

    leftbytes -= readbytes;
    tbuf += readbytes;
  }

416
#if FILE_WITH_LOCK
wafwerar's avatar
wafwerar 已提交
417
  taosThreadRwlockUnlock(&(pFile->rwlock));
418
#endif
S
TD-1912  
Shengliang Guan 已提交
419
  return count;
S
Shengliang Guan 已提交
420 421
}

422
int64_t taosPReadFile(TdFilePtr pFile, void *buf, int64_t count, int64_t offset) {
423
  if (pFile == NULL) {
424 425
    return 0;
  }
426
#if FILE_WITH_LOCK
wafwerar's avatar
wafwerar 已提交
427
  taosThreadRwlockRdlock(&(pFile->rwlock));
428
#endif
X
xinsheng Ren 已提交
429 430
  ASSERT(pFile->fd >= 0);  // Please check if you have closed the file.
  if (pFile->fd < 0) {
431 432 433
#if FILE_WITH_LOCK
    taosThreadRwlockUnlock(&(pFile->rwlock));
#endif
X
xinsheng Ren 已提交
434 435
    return -1;
  }
wafwerar's avatar
wafwerar 已提交
436
#ifdef WINDOWS
wafwerar's avatar
wafwerar 已提交
437 438
  size_t pos = _lseeki64(pFile->fd, 0, SEEK_CUR);
  _lseeki64(pFile->fd, offset, SEEK_SET);
wafwerar's avatar
wafwerar 已提交
439
  int64_t ret = _read(pFile->fd, buf, count);
wafwerar's avatar
wafwerar 已提交
440
  _lseeki64(pFile->fd, pos, SEEK_SET);
wafwerar's avatar
wafwerar 已提交
441
#else
442
  int64_t ret = pread(pFile->fd, buf, count, offset);
wafwerar's avatar
wafwerar 已提交
443
#endif
444
#if FILE_WITH_LOCK
wafwerar's avatar
wafwerar 已提交
445
  taosThreadRwlockUnlock(&(pFile->rwlock));
446 447
#endif
  return ret;
448 449 450
}

int64_t taosWriteFile(TdFilePtr pFile, const void *buf, int64_t count) {
wafwerar's avatar
wafwerar 已提交
451 452 453
  if (pFile == NULL) {
    return 0;
  }
454
#if FILE_WITH_LOCK
wafwerar's avatar
wafwerar 已提交
455
  taosThreadRwlockWrlock(&(pFile->rwlock));
456
#endif
457
  if (pFile->fd < 0) {
458 459 460
#if FILE_WITH_LOCK
    taosThreadRwlockUnlock(&(pFile->rwlock));
#endif
461 462
    return 0;
  }
463

464
  int64_t nleft = count;
S
TD-1912  
Shengliang Guan 已提交
465
  int64_t nwritten = 0;
466
  char   *tbuf = (char *)buf;
S
Shengliang Guan 已提交
467 468

  while (nleft > 0) {
469
    nwritten = write(pFile->fd, (void *)tbuf, (uint32_t)nleft);
S
Shengliang Guan 已提交
470 471 472 473
    if (nwritten < 0) {
      if (errno == EINTR) {
        continue;
      }
474
#if FILE_WITH_LOCK
wafwerar's avatar
wafwerar 已提交
475
      taosThreadRwlockUnlock(&(pFile->rwlock));
476
#endif
S
Shengliang Guan 已提交
477 478 479 480 481
      return -1;
    }
    nleft -= nwritten;
    tbuf += nwritten;
  }
482

483
#if FILE_WITH_LOCK
wafwerar's avatar
wafwerar 已提交
484
  taosThreadRwlockUnlock(&(pFile->rwlock));
485
#endif
486
  return count;
S
Shengliang Guan 已提交
487 488
}

489 490 491 492 493 494 495
int64_t taosPWriteFile(TdFilePtr pFile, const void *buf, int64_t count, int64_t offset) {
  if (pFile == NULL) {
    return 0;
  }
#if FILE_WITH_LOCK
  taosThreadRwlockWrlock(&(pFile->rwlock));
#endif
X
xinsheng Ren 已提交
496 497
  ASSERT(pFile->fd >= 0);  // Please check if you have closed the file.
  if (pFile->fd < 0) {
498 499 500
#if FILE_WITH_LOCK
    taosThreadRwlockUnlock(&(pFile->rwlock));
#endif
X
xinsheng Ren 已提交
501 502
    return 0;
  }
503 504 505 506 507 508 509 510 511 512 513 514 515 516
#ifdef WINDOWS
  size_t pos = _lseeki64(pFile->fd, 0, SEEK_CUR);
  _lseeki64(pFile->fd, offset, SEEK_SET);
  int64_t ret = _write(pFile->fd, buf, count);
  _lseeki64(pFile->fd, pos, SEEK_SET);
#else
  int64_t ret = pwrite(pFile->fd, buf, count, offset);
#endif
#if FILE_WITH_LOCK
  taosThreadRwlockUnlock(&(pFile->rwlock));
#endif
  return ret;
}

517
int64_t taosLSeekFile(TdFilePtr pFile, int64_t offset, int32_t whence) {
518 519 520
  if (pFile == NULL || pFile->fd < 0) {
    return -1;
  }
521
#if FILE_WITH_LOCK
wafwerar's avatar
wafwerar 已提交
522
  taosThreadRwlockRdlock(&(pFile->rwlock));
523
#endif
X
xinsheng Ren 已提交
524
  ASSERT(pFile->fd >= 0);  // Please check if you have closed the file.
wafwerar's avatar
wafwerar 已提交
525
#ifdef WINDOWS
wafwerar's avatar
wafwerar 已提交
526
  int64_t ret = _lseeki64(pFile->fd, offset, whence);
wafwerar's avatar
wafwerar 已提交
527
#else
L
Liu Jicong 已提交
528
  int64_t ret = lseek(pFile->fd, offset, whence);
wafwerar's avatar
wafwerar 已提交
529
#endif
530
#if FILE_WITH_LOCK
wafwerar's avatar
wafwerar 已提交
531
  taosThreadRwlockUnlock(&(pFile->rwlock));
532 533
#endif
  return ret;
534
}
S
Shengliang Guan 已提交
535

536
int32_t taosFStatFile(TdFilePtr pFile, int64_t *size, int32_t *mtime) {
537 538 539
  if (pFile == NULL) {
    return 0;
  }
X
xinsheng Ren 已提交
540 541 542 543
  ASSERT(pFile->fd >= 0);  // Please check if you have closed the file.
  if (pFile->fd < 0) {
    return -1;
  }
544

545
#ifdef WINDOWS
546
  struct __stat64 fileStat;
547
  int32_t         code = _fstat64(pFile->fd, &fileStat);
548
#else
549
  struct stat fileStat;
550
  int32_t code = fstat(pFile->fd, &fileStat);
551
#endif
552 553 554
  if (code < 0) {
    return code;
  }
H
Hongze Cheng 已提交
555

556 557 558
  if (size != NULL) {
    *size = fileStat.st_size;
  }
H
Hongze Cheng 已提交
559

560 561 562
  if (mtime != NULL) {
    *mtime = fileStat.st_mtime;
  }
H
Hongze Cheng 已提交
563

564 565
  return 0;
}
H
Hongze Cheng 已提交
566

567
int32_t taosLockFile(TdFilePtr pFile) {
X
xinsheng Ren 已提交
568
  ASSERT(pFile->fd >= 0);  // Please check if you have closed the file.
569
  if (pFile->fd < 0) {
X
xinsheng Ren 已提交
570 571
    return -1;
  }
wafwerar's avatar
wafwerar 已提交
572
#ifdef WINDOWS
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
  BOOL          fSuccess = FALSE;
  LARGE_INTEGER fileSize;
  OVERLAPPED    overlapped = {0};

  HANDLE hFile = (HANDLE)_get_osfhandle(pFile->fd);

  fSuccess = LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY,
                        0,           // reserved
                        ~0,          // number of bytes to lock low
                        ~0,          // number of bytes to lock high
                        &overlapped  // overlapped structure
  );
  if (!fSuccess) {
    return GetLastError();
  }
588 589 590 591 592
  return 0;
#else
  return (int32_t)flock(pFile->fd, LOCK_EX | LOCK_NB);
#endif
}
H
Hongze Cheng 已提交
593

594
int32_t taosUnLockFile(TdFilePtr pFile) {
X
xinsheng Ren 已提交
595
  ASSERT(pFile->fd >= 0);
596
  if (pFile->fd < 0) {
X
xinsheng Ren 已提交
597 598
    return 0;
  }
wafwerar's avatar
wafwerar 已提交
599
#ifdef WINDOWS
600 601 602
  BOOL       fSuccess = FALSE;
  OVERLAPPED overlapped = {0};
  HANDLE     hFile = (HANDLE)_get_osfhandle(pFile->fd);
603 604 605 606 607

  fSuccess = UnlockFileEx(hFile, 0, ~0, ~0, &overlapped);
  if (!fSuccess) {
    return GetLastError();
  }
608 609 610 611 612 613 614
  return 0;
#else
  return (int32_t)flock(pFile->fd, LOCK_UN | LOCK_NB);
#endif
}

int32_t taosFtruncateFile(TdFilePtr pFile, int64_t l_size) {
X
xinsheng Ren 已提交
615 616 617
  if (pFile == NULL) {
    return 0;
  }
618
  if (pFile->fd < 0) {
619
    printf("Ftruncate file error, fd arg was negative\n");
620
    return -1;
H
Hongze Cheng 已提交
621
  }
X
xinsheng Ren 已提交
622
#ifdef WINDOWS
H
Hongze Cheng 已提交
623

624
  HANDLE h = (HANDLE)_get_osfhandle(pFile->fd);
H
Hongze Cheng 已提交
625

626 627 628 629
  LARGE_INTEGER li_0;
  li_0.QuadPart = (int64_t)0;
  BOOL cur = SetFilePointerEx(h, li_0, NULL, FILE_CURRENT);
  if (!cur) {
wafwerar's avatar
wafwerar 已提交
630
    printf("SetFilePointerEx Error getting current position in file.\n");
631 632
    return -1;
  }
H
Hongze Cheng 已提交
633

634 635 636 637 638
  LARGE_INTEGER li_size;
  li_size.QuadPart = l_size;
  BOOL cur2 = SetFilePointerEx(h, li_size, NULL, FILE_BEGIN);
  if (cur2 == 0) {
    int error = GetLastError();
wafwerar's avatar
wafwerar 已提交
639
    printf("SetFilePointerEx GetLastError is: %d\n", error);
640 641 642 643 644 645 646 647 648 649 650 651 652
    switch (error) {
      case ERROR_INVALID_HANDLE:
        errno = EBADF;
        break;
      default:
        errno = EIO;
        break;
    }
    return -1;
  }

  if (!SetEndOfFile(h)) {
    int error = GetLastError();
wafwerar's avatar
wafwerar 已提交
653
    printf("SetEndOfFile GetLastError is:%d", error);
654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
    switch (error) {
      case ERROR_INVALID_HANDLE:
        errno = EBADF;
        break;
      default:
        errno = EIO;
        break;
    }
    return -1;
  }

  return 0;
#else
  return ftruncate(pFile->fd, l_size);
#endif
}

int32_t taosFsyncFile(TdFilePtr pFile) {
672 673 674 675
  if (pFile == NULL) {
    return 0;
  }

L
Liu Jicong 已提交
676 677
  // this implementation is WRONG
  // fflush is not a replacement of fsync
678
  if (pFile->fp != NULL) return fflush(pFile->fp);
679
  if (pFile->fd >= 0) {
680
#ifdef WINDOWS
681 682
    HANDLE h = (HANDLE)_get_osfhandle(pFile->fd);
    return !FlushFileBuffers(h);
683
#else
684
    return fsync(pFile->fd);
685
#endif
686
  }
687
  return 0;
H
Hongze Cheng 已提交
688 689
}

wafwerar's avatar
wafwerar 已提交
690 691 692
int64_t taosFSendFile(TdFilePtr pFileOut, TdFilePtr pFileIn, int64_t *offset, int64_t size) {
  if (pFileOut == NULL || pFileIn == NULL) {
    return 0;
S
TD-4088  
Shengliang Guan 已提交
693
  }
X
xinsheng Ren 已提交
694
  ASSERT(pFileIn->fd >= 0 && pFileOut->fd >= 0);
695
  if (pFileIn->fd < 0 || pFileOut->fd < 0) {
X
xinsheng Ren 已提交
696 697
    return 0;
  }
S
TD-4088  
Shengliang Guan 已提交
698

wafwerar's avatar
wafwerar 已提交
699
#ifdef WINDOWS
S
TD-4088  
Shengliang Guan 已提交
700

wafwerar's avatar
wafwerar 已提交
701
  _lseeki64(pFileIn->fd, *offset, 0);
S
TD-4088  
Shengliang Guan 已提交
702 703 704
  int64_t writeLen = 0;
  uint8_t buffer[_SEND_FILE_STEP_] = {0};

wafwerar's avatar
wafwerar 已提交
705
  for (int64_t len = 0; len < (size - _SEND_FILE_STEP_); len += _SEND_FILE_STEP_) {
wafwerar's avatar
wafwerar 已提交
706
    size_t rlen = _read(pFileIn->fd, (void *)buffer, _SEND_FILE_STEP_);
S
TD-4088  
Shengliang Guan 已提交
707 708 709
    if (rlen <= 0) {
      return writeLen;
    } else if (rlen < _SEND_FILE_STEP_) {
wafwerar's avatar
wafwerar 已提交
710
      write(pFileOut->fd, (void *)buffer, (uint32_t)rlen);
S
TD-4088  
Shengliang Guan 已提交
711 712
      return (int64_t)(writeLen + rlen);
    } else {
wafwerar's avatar
wafwerar 已提交
713
      write(pFileOut->fd, (void *)buffer, _SEND_FILE_STEP_);
S
TD-4088  
Shengliang Guan 已提交
714 715 716 717
      writeLen += _SEND_FILE_STEP_;
    }
  }

wafwerar's avatar
wafwerar 已提交
718
  int64_t remain = size - writeLen;
S
TD-4088  
Shengliang Guan 已提交
719
  if (remain > 0) {
wafwerar's avatar
wafwerar 已提交
720
    size_t rlen = _read(pFileIn->fd, (void *)buffer, (size_t)remain);
S
TD-4088  
Shengliang Guan 已提交
721 722 723
    if (rlen <= 0) {
      return writeLen;
    } else {
wafwerar's avatar
wafwerar 已提交
724
      write(pFileOut->fd, (void *)buffer, (uint32_t)remain);
S
TD-4088  
Shengliang Guan 已提交
725 726 727 728 729 730
      writeLen += remain;
    }
  }
  return writeLen;

#elif defined(_TD_DARWIN_64)
S
TD-1912  
Shengliang Guan 已提交
731

wafwerar's avatar
wafwerar 已提交
732 733 734 735 736 737 738 739 740 741 742 743 744 745
  lseek(pFileIn->fd, (int32_t)(*offset), 0);
  int64_t writeLen = 0;
  uint8_t buffer[_SEND_FILE_STEP_] = {0};

  for (int64_t len = 0; len < (size - _SEND_FILE_STEP_); len += _SEND_FILE_STEP_) {
    size_t rlen = read(pFileIn->fd, (void *)buffer, _SEND_FILE_STEP_);
    if (rlen <= 0) {
      return writeLen;
    } else if (rlen < _SEND_FILE_STEP_) {
      write(pFileOut->fd, (void *)buffer, (uint32_t)rlen);
      return (int64_t)(writeLen + rlen);
    } else {
      write(pFileOut->fd, (void *)buffer, _SEND_FILE_STEP_);
      writeLen += _SEND_FILE_STEP_;
S
TD-4088  
Shengliang Guan 已提交
746
    }
wafwerar's avatar
wafwerar 已提交
747 748 749 750 751 752 753 754 755 756
  }

  int64_t remain = size - writeLen;
  if (remain > 0) {
    size_t rlen = read(pFileIn->fd, (void *)buffer, (size_t)remain);
    if (rlen <= 0) {
      return writeLen;
    } else {
      write(pFileOut->fd, (void *)buffer, (uint32_t)remain);
      writeLen += remain;
S
TD-4088  
Shengliang Guan 已提交
757 758
    }
  }
wafwerar's avatar
wafwerar 已提交
759
  return writeLen;
S
TD-4088  
Shengliang Guan 已提交
760 761 762

#else

S
TD-1912  
Shengliang Guan 已提交
763 764
  int64_t leftbytes = size;
  int64_t sentbytes;
S
Shengliang Guan 已提交
765 766

  while (leftbytes > 0) {
H
Hongze Cheng 已提交
767 768 769
#ifdef _TD_ARM_32
    sentbytes = sendfile(pFileOut->fd, pFileIn->fd, (long int *)offset, leftbytes);
#else
770
    sentbytes = sendfile(pFileOut->fd, pFileIn->fd, offset, leftbytes);
H
Hongze Cheng 已提交
771
#endif
S
Shengliang Guan 已提交
772
    if (sentbytes == -1) {
S
TD-1985  
Shengliang Guan 已提交
773
      if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
S
Shengliang Guan 已提交
774 775 776 777 778
        continue;
      } else {
        return -1;
      }
    } else if (sentbytes == 0) {
S
TD-1912  
Shengliang Guan 已提交
779
      return (int64_t)(size - leftbytes);
S
Shengliang Guan 已提交
780 781 782 783 784 785
    }

    leftbytes -= sentbytes;
  }

  return size;
S
Shengliang Guan 已提交
786
#endif
wafwerar's avatar
wafwerar 已提交
787
}
S
Shengliang Guan 已提交
788

789
void taosFprintfFile(TdFilePtr pFile, const char *format, ...) {
X
xinsheng Ren 已提交
790
  if (pFile == NULL || pFile->fp == NULL) {
791 792
    return;
  }
793
  va_list ap;
794
  va_start(ap, format);
795
  vfprintf(pFile->fp, format, ap);
796
  va_end(ap);
S
Shengliang Guan 已提交
797 798
}

799
bool taosValidFile(TdFilePtr pFile) { return pFile != NULL && pFile->fd > 0; }
S
Shengliang Guan 已提交
800

801
int32_t taosUmaskFile(int32_t maskVal) {
wafwerar's avatar
wafwerar 已提交
802
#ifdef WINDOWS
S
Shengliang Guan 已提交
803 804
  return 0;
#else
805
  return umask(maskVal);
S
TD-4088  
Shengliang Guan 已提交
806
#endif
807 808
}

809
int32_t taosGetErrorFile(TdFilePtr pFile) { return errno; }
wafwerar's avatar
wafwerar 已提交
810
int64_t taosGetLineFile(TdFilePtr pFile, char **__restrict ptrBuf) {
L
Liu Jicong 已提交
811
  if (pFile == NULL || ptrBuf == NULL) {
812 813
    return -1;
  }
wafwerar's avatar
wafwerar 已提交
814 815 816
  if (*ptrBuf != NULL) {
    taosMemoryFreeClear(*ptrBuf);
  }
X
xinsheng Ren 已提交
817 818 819 820
  ASSERT(pFile->fp != NULL);
  if (pFile->fp == NULL) {
    return -1;
  }
wafwerar's avatar
wafwerar 已提交
821 822 823 824 825 826 827 828 829 830
#ifdef WINDOWS
  *ptrBuf = taosMemoryMalloc(1024);
  if (*ptrBuf == NULL) return -1;
  if (fgets(*ptrBuf, 1023, pFile->fp) == NULL) {
    taosMemoryFreeClear(*ptrBuf);
    return -1;
  }
  (*ptrBuf)[1023] = 0;
  return strlen(*ptrBuf);
#else
831 832
  size_t len = 0;
  return getline(ptrBuf, &len, pFile->fp);
wafwerar's avatar
wafwerar 已提交
833
#endif
834
}
H
Haojun Liao 已提交
835

wafwerar's avatar
wafwerar 已提交
836
int64_t taosGetsFile(TdFilePtr pFile, int32_t maxSize, char *__restrict buf) {
L
Liu Jicong 已提交
837
  if (pFile == NULL || buf == NULL) {
wafwerar's avatar
wafwerar 已提交
838 839
    return -1;
  }
X
xinsheng Ren 已提交
840 841 842 843
  ASSERT(pFile->fp != NULL);
  if (pFile->fp == NULL) {
    return -1;
  }
wafwerar's avatar
wafwerar 已提交
844 845 846 847 848
  if (fgets(buf, maxSize, pFile->fp) == NULL) {
    return -1;
  }
  return strlen(buf);
}
H
Haojun Liao 已提交
849

L
Liu Jicong 已提交
850
int32_t taosEOFFile(TdFilePtr pFile) {
851
  if (pFile == NULL) {
X
xinsheng Ren 已提交
852 853 854
    return -1;
  }
  ASSERT(pFile->fp != NULL);
855
  if (pFile->fp == NULL) {
X
xinsheng Ren 已提交
856
    return -1;
857 858
  }

L
Liu Jicong 已提交
859
  return feof(pFile->fp);
L
fix  
Liu Jicong 已提交
860
}
861

862 863 864 865 866 867 868 869 870 871 872 873 874 875
bool taosCheckAccessFile(const char *pathname, int32_t tdFileAccessOptions) {
  int flags = 0;

  if (tdFileAccessOptions & TD_FILE_ACCESS_EXIST_OK) {
    flags |= F_OK;
  }

  if (tdFileAccessOptions & TD_FILE_ACCESS_READ_OK) {
    flags |= R_OK;
  }

  if (tdFileAccessOptions & TD_FILE_ACCESS_WRITE_OK) {
    flags |= W_OK;
  }
wafwerar's avatar
wafwerar 已提交
876 877 878
#ifdef WINDOWS
  return _access(pathname, flags) == 0;
#else
879
  return access(pathname, flags) == 0;
wafwerar's avatar
wafwerar 已提交
880
#endif
881
}
882 883

bool taosCheckExistFile(const char *pathname) { return taosCheckAccessFile(pathname, TD_FILE_ACCESS_EXIST_OK); };
884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903

int32_t taosCompressFile(char *srcFileName, char *destFileName) {
  int32_t compressSize = 163840;
  int32_t ret = 0;
  int32_t len = 0;
  char   *data = taosMemoryMalloc(compressSize);
  gzFile  dstFp = NULL;

  TdFilePtr pSrcFile = taosOpenFile(srcFileName, TD_FILE_READ | TD_FILE_STREAM);
  if (pSrcFile == NULL) {
    ret = -1;
    goto cmp_end;
  }

  TdFilePtr pFile = taosOpenFile(destFileName, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC);
  if (pFile == NULL) {
    ret = -2;
    goto cmp_end;
  }

904 905 906 907 908 909
  dstFp = gzdopen(pFile->fd, "wb6f");
  if (dstFp == NULL) {
    ret = -3;
    taosCloseFile(&pFile);
    goto cmp_end;
  }
910

911 912 913 914
  while (!feof(pSrcFile->fp)) {
    len = (int32_t)fread(data, 1, compressSize, pSrcFile->fp);
    (void)gzwrite(dstFp, data, len);
  }
915 916 917 918 919 920 921 922 923 924 925 926 927 928

cmp_end:
  if (pSrcFile) {
    taosCloseFile(&pSrcFile);
  }

  if (dstFp) {
    gzclose(dstFp);
  }

  taosMemoryFree(data);

  return ret;
}