1115
1174
ConstUnicode fileName, // IN:
1116
1175
Unicode *presult) // OUT:
1177
return File_MakeTempEx2(dir,
1179
FileMakeTempExCreateNameFunc,
1187
*----------------------------------------------------------------------
1189
* File_MakeTempEx2 --
1191
* Create a temporary file or a directory.
1192
* If a temporary file is created successfully, then return an open file
1193
* descriptor to that file.
1195
* 'dir' specifies the directory in which to create the file. It
1196
* must not end in a slash.
1198
* 'createTempFile', if TRUE, then a temporary file will be created. If
1199
* FALSE, then a temporary directory will be created.
1201
* 'createNameFunc' specifies the user-specified callback function that
1202
* will be called to construct the fileName. 'createNameFuncData' will be
1203
* passed everytime 'createNameFunc' is called. 'createNameFunc'
1204
* should return the proper fileName.
1206
* Check the documentation for File_MakeTempHelperFunc.
1209
* if a temporary file is created, then Open file descriptor or -1;
1210
* if a temporary directory is created, then 0 or -1;
1211
* If successful then presult points to a dynamically allocated
1212
* string with the pathname of the temp file.
1215
* Creates a file if successful. Errno is set on error
1217
*----------------------------------------------------------------------
1221
File_MakeTempEx2(ConstUnicode dir, // IN:
1222
Bool createTempFile, // IN:
1223
File_MakeTempCreateNameFunc *createNameFunc, // IN:
1224
void *createNameFuncData, // IN:
1225
Unicode *presult) // OUT:
1122
1231
Unicode path = NULL;
1123
Unicode basePath = NULL;
1125
if ((dir == NULL) || (fileName == NULL)) {
1233
if ((dir == NULL) || (createNameFunc == NULL)) {
1126
1234
errno = EFAULT;
1132
1240
*presult = NULL;
1134
/* construct base full pathname to use */
1135
basePath = Unicode_Join(dir, DIRSEPS, fileName, NULL);
1137
1242
for (var = 0; var < 0xFFFFFFFF; var++) {
1243
Unicode fileName = NULL;
1140
1245
/* construct suffixed pathname to use */
1141
1246
Unicode_Free(path);
1143
temp = Unicode_Format("%d", var);
1144
ASSERT_MEM_ALLOC(temp);
1145
path = Unicode_Append(basePath, temp);
1148
fd = Posix_Open(path, O_CREAT | O_EXCL | O_BINARY | O_RDWR, 0600);
1249
fileName = (*createNameFunc)(var, createNameFuncData);
1251
if (fileName == NULL) {
1252
Msg_Append(MSGID(file.maketemp.helperFuncFailed)
1253
"Failed to construct the filename.\n");
1258
/* construct base full pathname to use */
1259
path = Unicode_Join(dir, DIRSEPS, fileName, NULL);
1261
Unicode_Free(fileName);
1263
if (createTempFile) {
1264
fd = Posix_Open(path, O_CREAT | O_EXCL | O_BINARY | O_RDWR, 0600);
1267
* On windows, Posix_Open() fails with EACCES if there is any
1268
* access violation while creating the file. Also, EACCES is returned
1269
* if a directory already exists with the same name. In such case,
1270
* we need to check if a file already exists and ignore EACCES error.
1272
if ((fd == -1) && (errno == EACCES) && (File_Exists(path))) {
1277
fd = Posix_Mkdir(path, 0600);
1150
1280
if (fd != -1) {
1151
1281
*presult = path;
1468
1625
fret = FileIO_Open(&src, srcName, FILEIO_OPEN_ACCESS_READ, FILEIO_OPEN);
1469
1626
if (!FileIO_IsSuccess(fret)) {
1470
1629
Msg_Append(MSGID(File.CopyFromNameToName.open.failure)
1471
1630
"Unable to open the '%s' file for read access: %s.\n\n",
1472
1631
UTF8(srcName), FileIO_MsgError(fret));
1477
result = File_CopyFromFdToName(src, dstName, dstDispose);
1638
success = File_CopyFromFdToName(src, dstName, dstDispose);
1479
1642
if (FileIO_Close(&src) != 0) {
1643
if (success) { // Report close failure when there isn't another error
1480
1647
Msg_Append(MSGID(File.CopyFromNameToName.close.failure)
1481
1648
"Unable to close the '%s' file: %s.\n\n", UTF8(srcName),
1482
1649
Msg_ErrString());
1661
*-----------------------------------------------------------------------------
1665
* Recursively copies all files from a source path to a destination,
1666
* optionally overwriting any files. This does the actual work
1667
* for File_CopyTree.
1671
* FALSE on failure: Error messages are appended.
1676
*-----------------------------------------------------------------------------
1680
FileCopyTree(ConstUnicode srcName, // IN:
1681
ConstUnicode dstName, // IN:
1682
Bool overwriteExisting, // IN:
1683
Bool followSymlinks) // IN:
1686
Bool success = TRUE;
1689
Unicode *fileList = NULL;
1691
numFiles = File_ListDirectory(srcName, &fileList);
1693
if (numFiles == -1) {
1695
Msg_Append(MSGID(File.CopyTree.walk.failure)
1696
"Unable to access '%s' when copying files.\n\n",
1703
File_EnsureDirectory(dstName);
1705
for (i = 0; i < numFiles && success; i++) {
1708
Unicode srcFilename;
1710
name = Unicode_Alloc(fileList[i], STRING_ENCODING_DEFAULT);
1711
srcFilename = File_PathJoin(srcName, name);
1713
if (followSymlinks) {
1714
success = (Posix_Stat(srcFilename, &sb) == 0);
1716
success = (Posix_Lstat(srcFilename, &sb) == 0);
1720
Unicode dstFilename = File_PathJoin(dstName, name);
1722
switch (sb.st_mode & S_IFMT) {
1724
success = FileCopyTree(srcFilename, dstFilename, overwriteExisting,
1728
#if !defined(_WIN32)
1730
if (Posix_Symlink(Posix_ReadLink(srcFilename), dstFilename) != 0) {
1732
Msg_Append(MSGID(File.CopyTree.symlink.failure)
1733
"Unable to symlink '%s' to '%s': %s\n\n",
1734
UTF8(Posix_ReadLink(srcFilename)),
1736
Err_Errno2String(err));
1744
if (!File_Copy(srcFilename, dstFilename, overwriteExisting)) {
1746
Msg_Append(MSGID(File.CopyTree.copy.failure)
1747
"Unable to copy '%s' to '%s': %s\n\n",
1748
UTF8(srcFilename), UTF8(dstFilename),
1749
Err_Errno2String(err));
1757
Unicode_Free(dstFilename);
1760
Msg_Append(MSGID(File.CopyTree.stat.failure)
1761
"Unable to get information on '%s' when copying files.\n\n",
1766
Unicode_Free(srcFilename);
1770
for (i = 0; i < numFiles; i++) {
1771
Unicode_Free(fileList[i]);
1781
*-----------------------------------------------------------------------------
1785
* Recursively copies all files from a source path to a destination,
1786
* optionally overwriting any files.
1790
* FALSE on failure: Error messages are appended.
1795
*-----------------------------------------------------------------------------
1799
File_CopyTree(ConstUnicode srcName, // IN:
1800
ConstUnicode dstName, // IN:
1801
Bool overwriteExisting, // IN:
1802
Bool followSymlinks) // IN:
1809
if (!File_IsDirectory(srcName)) {
1811
Msg_Append(MSGID(File.CopyTree.source.notDirectory)
1812
"The source path '%s' is not a directory.\n\n",
1818
if (!File_IsDirectory(dstName)) {
1820
Msg_Append(MSGID(File.CopyTree.dest.notDirectory)
1821
"The destination path '%s' is not a directory.\n\n",
1827
return FileCopyTree(srcName, dstName, overwriteExisting, followSymlinks);
1490
1832
*----------------------------------------------------------------------
1586
1943
fret = FileIO_Open(&src, srcName, FILEIO_OPEN_ACCESS_READ, FILEIO_OPEN);
1587
1944
if (!FileIO_IsSuccess(fret)) {
1588
1947
Msg_Append(MSGID(File.Copy.open.failure)
1589
1948
"Unable to open the '%s' file for read access: %s.\n\n",
1590
1949
UTF8(srcName), FileIO_MsgError(fret));
1595
result = File_CopyFromFd(src, dstName, overwriteExisting);
1956
success = File_CopyFromFd(src, dstName, overwriteExisting);
1597
1960
if (FileIO_Close(&src) != 0) {
1961
if (success) { // Report close failure when there isn't another error
1598
1965
Msg_Append(MSGID(File.Copy.close.failure)
1599
1966
"Unable to close the '%s' file: %s.\n\n", UTF8(srcName),
1600
1967
Msg_ErrString());
1608
1979
*----------------------------------------------------------------------
1612
* Renames a source to a destination file.
1613
* Will copy the file if necessary
1983
* Moves a file from one place to the other as efficiently as possible.
1984
* This can be used to rename a file but, since file copying may be
1985
* necessary, there is no assurance of atomicity. For efficiency
1986
* purposes copying only results if the native rename ability fails.
1616
* TRUE if succeeded FALSE otherwise
1618
1992
* Side effects:
1619
1993
* src file is no more, but dst file exists
2431
2957
return msecActualSleepTime;
2433
2959
#endif // N_PLAT_NLM
2963
*----------------------------------------------------------------------
2965
* FileRotateByRename --
2967
* The oldest indexed file should be removed so that the consequent
2970
* The last dst is 'fileName' and should not be deleted.
2973
* If newFileName is non-NULL: the new path is returned to *newFileName
2974
* if the rotation succeeded, otherwise NULL is returned in *newFileName.
2975
* The caller is responsible for freeing the string returned in
2979
* Rename backup old files kept so far.
2981
*----------------------------------------------------------------------
2985
FileRotateByRename(const char *fileName, // IN: full path to file
2986
const char *baseName, // IN: filename w/o extension.
2987
const char *ext, // IN: extension
2988
int n, // IN: number of old files to keep
2989
char **newFileName) // OUT/OPT: new path to file
2996
for (i = n; i >= 0; i--) {
2997
src = (i == 0) ? (char *) fileName :
2998
Str_SafeAsprintf(NULL, "%s-%d%s", baseName, i - 1, ext);
3001
result = File_UnlinkIfExists(src);
3004
Log(LGPFX" %s: failed to remove %s: %s\n", __FUNCTION__,
3005
src, Msg_ErrString());
3008
result = Posix_Rename(src, dst);
3011
int error = Err_Errno();
3013
if (error != ENOENT) {
3014
Log(LGPFX" %s: failed to rename %s -> %s: %s\n", src, dst,
3015
__FUNCTION__, Err_Errno2String(error));
3020
if ((src == fileName) && (newFileName != NULL)) {
3021
*newFileName = result == -1 ? NULL : strdup(dst);
3024
ASSERT(dst != fileName);
3032
*----------------------------------------------------------------------
3034
* FileNumberCompare --
3036
* Helper function for comparing the contents of two
3037
* uint32 pointers a and b, suitable for use by qsort
3038
* to order an array of file numbers.
3041
* The contents of 'a' minus the contents of 'b'.
3048
FileNumberCompare(const void *a, // IN:
3049
const void *b) // IN:
3051
return *(uint32 *) a - *(uint32 *) b;
3056
*----------------------------------------------------------------------
3058
* FileRotateByRenumber --
3060
* File rotation scheme optimized for vmfs:
3061
* 1) find highest numbered file (maxNr)
3062
* 2) rename <base>.<ext> to <base>-<maxNr + 1>.<ext>
3063
* 3) delete (nFound - numToKeep) lowest numbered files.
3065
* Wrap around is handled incorrectly.
3068
* If newFilePath is non-NULL: the new path is returned to *newFilePath
3069
* if the rotation succeeded, otherwise NULL is returned in *newFilePath.
3070
* The caller is responsible for freeing the string returned in
3074
* Files renamed / deleted.
3076
*----------------------------------------------------------------------
3080
FileRotateByRenumber(const char *filePath, // IN: full path to file
3081
const char *filePathNoExt, // IN: filename w/o extension.
3082
const char *ext, // IN: extension
3083
int n, // IN: number old files to keep
3084
char **newFilePath) // OUT/OPT: new path to file
3086
char *baseDir = NULL, *fmtString = NULL, *baseName = NULL, *tmp;
3087
char *fullPathNoExt = NULL;
3089
int i, nrFiles, nFound = 0;
3090
char **fileList = NULL;
3091
uint32 *fileNumbers = NULL;
3094
fullPathNoExt = File_FullPath(filePathNoExt);
3095
if (fullPathNoExt == NULL) {
3096
Log(LGPFX" %s: failed to get full path for '%s'.\n", __FUNCTION__,
3101
File_GetPathName(fullPathNoExt, &baseDir, &baseName);
3102
if ((baseDir[0] == '\0') || (baseName[0] == '\0')) {
3103
Log(LGPFX" %s: failed to get base dir for path '%s'.\n", __FUNCTION__,
3108
fmtString = Str_SafeAsprintf(NULL, "%s-%%d%s%%n", baseName, ext);
3110
nrFiles = File_ListDirectory(baseDir, &fileList);
3111
if (nrFiles == -1) {
3112
Log(LGPFX" %s: failed to read the directory '%s'.\n", __FUNCTION__,
3117
fileNumbers = Util_SafeCalloc(nrFiles, sizeof(uint32));
3119
for (i = 0; i < nrFiles; i++) {
3121
int bytesProcessed = 0;
3124
* Make sure the whole file name matched what we expect for the file.
3127
if ((sscanf(fileList[i], fmtString, &curNr, &bytesProcessed) >= 1) &&
3128
(bytesProcessed == strlen(fileList[i]))) {
3129
fileNumbers[nFound++] = curNr;
3136
qsort(fileNumbers, nFound, sizeof(uint32), FileNumberCompare);
3137
maxNr = fileNumbers[nFound - 1];
3140
/* rename the existing file to the next number */
3141
tmp = Str_SafeAsprintf(NULL, "%s/%s-%d%s", baseDir, baseName,
3144
result = Posix_Rename(filePath, tmp);
3147
int error = Err_Errno();
3149
if (error != ENOENT) {
3150
Log(LGPFX" %s: failed to rename %s -> %s failed: %s\n", __FUNCTION__,
3151
filePath, tmp, Err_Errno2String(error));
3155
if (newFilePath != NULL) {
3157
*newFilePath = NULL;
3165
/* Delete the extra files. */
3166
for (i = 0; i <= nFound - n; i++) {
3167
tmp = Str_SafeAsprintf(NULL, "%s/%s-%d%s", baseDir, baseName,
3168
fileNumbers[i], ext);
3170
if (Posix_Unlink(tmp) == -1) {
3171
Log(LGPFX" %s: failed to remove %s: %s\n", __FUNCTION__, tmp,
3184
free(fullPathNoExt);
3189
*----------------------------------------------------------------------
3193
* Rotate old files. The 'noRename' option is useful for filesystems
3194
* where rename is hideously expensive (*cough* vmfs).
3197
* If newFileName is non-NULL: the new path is returned to
3198
* *newFileName if the rotation succeeded, otherwise NULL
3199
* is returned in *newFileName. The caller is responsible
3200
* for freeing the string returned in *newFileName.
3203
* Files are renamed / deleted.
3205
*----------------------------------------------------------------------
3209
File_Rotate(const char *fileName, // IN: original file
3210
int n, // IN: number of backup files
3211
Bool noRename, // IN: don't rename all files
3212
char **newFileName) // OUT/OPT: new path to file
3218
if ((ext = Str_Strrchr(fileName, '.')) == NULL) {
3219
ext = fileName + strlen(fileName);
3221
baseLen = ext - fileName;
3224
* Backup base of file name.
3226
* Since the Str_Asprintf(...) doesn't like format of %.*s and crashes
3227
* in Windows 2000. (Daniel Liu)
3230
baseName = Util_SafeStrdup(fileName);
3231
baseName[baseLen] = '\0';
3234
FileRotateByRenumber(fileName, baseName, ext, n, newFileName);
3236
FileRotateByRename(fileName, baseName, ext, n, newFileName);