188
#if defined(sun) || defined(linux) || (defined(__FreeBSD__) && BSD_VERSION < 49)
195
#if defined(sun) || defined(linux) || \
196
(defined(__FreeBSD_version) && __FreeBSD_version < 490000)
190
198
* Implements futimes(), which was introduced in glibc 2.3.3. FreeBSD 3.2
191
199
* doesn't have it, but 4.9 does. Unfortunately, these early FreeBSD versions
902
911
static HgfsInternalStatus
903
912
HgfsValidateOpen(HgfsFileOpenInfo *openInfo, // IN: Open info struct
913
int followSymlinks, // IN: followSymlinks config option
904
914
HgfsLocalId *localId, // OUT: Local unique file ID
905
915
int *fileDesc) // OUT: Handle to the file
949
959
openInfo->otherPerms : (openPerms & S_IRWXU) >> 6;
962
* By default we don't follow symlinks, O_NOFOLLOW is always set.
963
* Unset it if followSymlinks config option is specified.
965
if (followSymlinks) {
966
openFlags &= ~O_NOFOLLOW;
952
970
* Try to open the file with the requested mode, flags and permissions.
954
972
fd = Posix_Open(openInfo->utf8Name,
1352
* Unicode_CompareIgnoreCase crashes with invalid unicode strings,
1353
* validate it before passing it to Unicode_* functions.
1355
if (!Unicode_IsBufferValid(currentComponent, -1, STRING_ENCODING_UTF8)) {
1356
/* Invalid unicode string, return failure. */
1334
1362
* Read all of the directory entries. For each one, convert the name
1335
1363
* to lower case and then compare it to the lower case component.
1337
1365
while ((dirent = readdir(dir))) {
1366
Unicode dentryNameU;
1338
1369
dentryName = dirent->d_name;
1339
1370
dentryNameLen = strlen(dentryName);
1341
if (Unicode_CompareIgnoreCase(currentComponent, dentryName) == 0) {
1373
* Unicode_CompareIgnoreCase crashes with invalid unicode strings,
1374
* validate and convert it appropriately before passing it to Unicode_* functions.
1376
if (!Unicode_IsBufferValid(dentryName, dentryNameLen, STRING_ENCODING_DEFAULT)) {
1377
/* Invalid unicode string, skip the entry. */
1381
dentryNameU = Unicode_Alloc(dentryName, STRING_ENCODING_DEFAULT);
1383
cmpResult = Unicode_CompareIgnoreCase(currentComponent, dentryNameU);
1384
Unicode_Free(dentryNameU);
1386
if (cmpResult == 0) {
1343
1388
* The current directory entry is a case insensitive match to
1344
1389
* the specified component. Malloc and copy the current directory entry.
1703
1748
static HgfsInternalStatus
1704
HgfsGetattrFromName(char *fileName, // IN/OUT: Input filename
1705
HgfsFileAttrInfo *attr, // OUT: Struct to copy into
1706
char **targetName) // OUT: Symlink target filename
1749
HgfsGetattrFromName(char *fileName, // IN/OUT: Input filename
1750
HgfsShareOptions configOptions, // IN: Share config options
1751
HgfsFileAttrInfo *attr, // OUT: Struct to copy into
1752
char **targetName) // OUT: Symlink target filename
1708
1754
HgfsInternalStatus status = 0;
1709
1755
struct stat stats;
1711
1757
char *myTargetName = NULL;
1714
1762
LOG(4, ("HgfsGetattrFromName: getting attrs for \"%s\"\n", fileName));
1717
error = Posix_Lstat(fileName, &stats);
1764
/* Check the config option to determine if we should follow symlinks. */
1765
if (HgfsServerPolicy_IsShareOptionSet(configOptions, HGFS_SHARE_FOLLOW_SYMLINKS)) {
1767
error = Posix_Stat(fileName, &stats);
1770
error = Posix_Lstat(fileName, &stats);
1719
1774
status = errno;
1720
1775
LOG(4, ("HgfsGetattrFromName: error stating file: %s\n",
1983
2038
* FreeBSD: All supported versions have timestamps with nanosecond resolution.
1984
2039
* FreeBSD 5+ has also file creation time.
1986
# if BSD_VERSION >= 50
2041
# if __IS_FREEBSD_VER__(500043)
1987
2042
attr->creationTime = HgfsConvertTimeSpecToNtTime(&stats->st_birthtimespec);
1989
2044
attr->creationTime = HgfsConvertTimeSpecToNtTime(&stats->st_atimespec);
2031
2086
attr->specialPerms, attr->ownerPerms, attr->groupPerms,
2032
2087
attr->otherPerms, attr->size));
2033
2088
#ifdef __FreeBSD__
2034
# if !defined(VM_X86_64) && BSD_VERSION >= 50
2089
# if !defined(VM_X86_64) && __FreeBSD_version >= 500043
2035
2090
# define FMTTIMET ""
2037
2092
# define FMTTIMET "l"
2048
2103
attr->userId = stats->st_uid;
2049
2104
attr->groupId = stats->st_gid;
2050
2105
attr->hostFileId = stats->st_ino;
2106
attr->volumeId = stats->st_dev;
2051
2107
attr->mask = HGFS_ATTR_VALID_TYPE |
2052
2108
HGFS_ATTR_VALID_SIZE |
2053
2109
HGFS_ATTR_VALID_CREATE_TIME |
2482
2539
size_t cpNameSize, // IN: Name length
2483
2540
HgfsFileAttrInfo *attr, // IN: attrs to set
2484
2541
HgfsAttrHint hints, // IN: attr hints
2485
uint32 caseFlags) // IN: case-sensitivity flags
2542
uint32 caseFlags) // IN: case-sensitivity flags
2487
2544
HgfsInternalStatus status = 0, timesStatus;
2488
2545
HgfsNameStatus nameStatus;
2497
2554
Bool timesChanged = FALSE;
2498
2555
Bool idChanged = FALSE;
2499
2556
HgfsServerLock serverLock;
2557
HgfsShareOptions configOptions;
2501
2559
nameStatus = HgfsServerGetAccess(cpName,
2513
2571
ASSERT(localName);
2516
* Verify that the pathname isn't a symlink. Some of the following
2517
* syscalls (chmod, for example) will follow a link. So we need to
2518
* verify the final component too. The parent has already been verified
2519
* in HgfsServerGetAccess.
2521
* XXX: This is racy. But clients interested in preventing a race should
2522
* have sent us a Setattr packet with a valid HGFS handle.
2524
if (File_IsSymLink(localName)) {
2525
LOG(4, ("HgfsSetattrFromName: pathname contains a symlink\n"));
2573
/* Get the config options. */
2574
nameStatus = HgfsServerPolicy_GetShareOptions(cpName, cpNameSize,
2576
if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
2577
LOG(4, ("HgfsSetattrFromName: no matching share: %s.\n", cpName));
2581
if (!HgfsServerPolicy_IsShareOptionSet(configOptions, HGFS_SHARE_FOLLOW_SYMLINKS)) {
2583
* If followSymlink option is not set, verify that the pathname isn't a
2584
* symlink. Some of the following syscalls (chmod, for example) will follow
2585
* a link. So we need to verify the final component too. The parent has
2586
* already been verified in HgfsServerGetAccess.
2588
* XXX: This is racy. But clients interested in preventing a race should
2589
* have sent us a Setattr packet with a valid HGFS handle.
2591
if (File_IsSymLink(localName)) {
2592
LOG(4, ("HgfsSetattrFromName: pathname contains a symlink\n"));
2530
2598
LOG(4, ("HgfsSetattrFromName: setting attrs for \"%s\"\n", localName));
2647
2715
HgfsInternalStatus
2648
2716
HgfsServerScandir(char const *baseDir, // IN: Directory to search in
2649
2717
size_t baseDirLen, // IN: Ignored
2718
Bool followSymlinks, // IN: followSymlinks config option
2650
2719
DirectoryEntry ***dents, // OUT: Array of DirectoryEntrys
2651
2720
int *numDents) // OUT: Number of DirectoryEntrys
2662
2732
char buffer[8192];
2664
/* We want a directory. No FIFOs and no symlinks. */
2665
result = Posix_Open(baseDir, O_NONBLOCK | O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
2734
/* Follow symlinks if config option is set. */
2735
if (followSymlinks) {
2736
openFlags &= ~O_NOFOLLOW;
2739
/* We want a directory. No FIFOs. Symlinks only if config option is set. */
2740
result = Posix_Open(baseDir, openFlags);
2666
2741
if (result < 0) {
2667
2742
status = errno;
2668
2743
LOG(4, ("HgfsServerScandir: error in open: %d (%s)\n", status,
2962
/* Get the config options. */
2963
nameStatus = HgfsServerPolicy_GetShareOptions(openInfo.cpName,
2964
openInfo.cpNameSize,
2966
if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
2967
LOG(4, ("HgfsServerSearchRead: no matching share: %s.\n", openInfo.cpName));
2972
followSymlinks = HgfsServerPolicy_IsShareOptionSet(configOptions,
2973
HGFS_SHARE_FOLLOW_SYMLINKS);
2885
2975
/* See if the name is valid, and if so add it and return the handle. */
2886
status = HgfsValidateOpen(&openInfo, &localId, &newFd);
2976
status = HgfsValidateOpen(&openInfo, followSymlinks, &localId, &newFd);
2887
2977
if (status == 0) {
2888
2978
ASSERT(newFd >= 0);
3319
3409
switch (nameStatus) {
3320
3410
case HGFS_NAME_STATUS_COMPLETE:
3321
3416
ASSERT(baseDir);
3323
LOG(4, ("HgfsServerSearchOpen: searching in \"%s\"\n", baseDir));
3417
LOG(4, ("HgfsServerSearchOpen: searching in \"%s\", %s.\n", baseDir, dirName));
3419
inEnd = dirName + dirNameLength;
3421
/* Get the first component. */
3422
len = CPName_GetComponentGeneric(dirName, inEnd, "", (char const **) &next);
3424
LOG(4, ("HgfsServerSearchOpen: get first component failed\n"));
3429
LOG(4, ("HgfsServerSearchOpen: dirName: %s.\n", dirName));
3324
3430
status = HgfsServerSearchRealDir(baseDir,
3326
3432
DIRECTORY_SEARCH_TYPE_DIR,
3329
3436
if (status != 0) {
3531
/* Get the config options. */
3532
if (search.utf8ShareNameLen != 0) {
3533
nameStatus = HgfsServerPolicy_GetShareOptions(search.utf8ShareName,
3534
search.utf8ShareNameLen,
3536
if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
3537
LOG(4, ("HgfsServerSearchRead: no matching share: %s.\n", search.utf8ShareName));
3538
free(search.utf8Dir);
3539
free(search.utf8ShareName);
3422
3544
while ((dent = HgfsGetSearchResult(hgfsSearchHandle,
3423
3545
requestedOffset, FALSE)) != NULL) {
3424
3546
unsigned int length;
3443
3568
LOG(4, ("HgfsServerSearchRead: could not allocate space for "
3444
3569
"\"%s\\%s\"\n", search.utf8Dir, dent->d_name));
3445
3570
free(search.utf8Dir);
3571
free(search.utf8ShareName);
3451
3577
memcpy(&fullName[search.utf8DirLen + 1], dent->d_name, length + 1);
3453
3579
LOG(4, ("HgfsServerSearchRead: about to stat \"%s\"\n", fullName));
3454
status = HgfsGetattrFromName(fullName, &attr, NULL);
3581
status = HgfsGetattrFromName(fullName, configOptions, &attr, NULL);
3455
3582
free(fullName);
3457
3584
if (status != 0) {
3591
#if defined(__APPLE__)
3593
* HGFS clients receive names in unicode normal form C,
3594
* (precomposed) so Mac hosts must convert from normal form D
3597
if (!CodeSet_Utf8FormDToUtf8FormC((const char *)dent->d_name,
3601
LOG(4, ("HgfsServerSearchRead: Unable to normalize form C \"%s\"\n",
3603
/* Skip this entry and continue. */
3608
freeEntryName = TRUE;
3609
#else /* defined(__APPLE__) */
3610
entryName = dent->d_name;
3611
entryNameLen = length;
3612
#endif /* defined(__APPLE__) */
3464
3614
case DIRECTORY_SEARCH_TYPE_BASE:
3486
3636
LOG(4, ("HgfsServerSearchRead: No such share or access denied\n"));
3488
3638
free(search.utf8Dir);
3639
free(search.utf8ShareName);
3489
3640
return HgfsConvertFromNameStatus(nameStatus);
3491
status = HgfsGetattrFromName(sharePath, &attr, NULL);
3643
status = HgfsGetattrFromName(sharePath, configOptions, &attr, NULL);
3492
3644
if (status != 0) {
3494
3646
* The dent no longer exists. Remove it from the search and get
3518
3677
free(search.utf8Dir);
3521
size_t entryNameLen;
3522
char *entryName = NULL;
3523
Bool freeEntryName = FALSE;
3525
#if defined(__APPLE__)
3528
* HGFS clients receive names in unicode normal form C,
3529
* (precomposed) so Mac hosts must convert from normal form D
3532
if (!CodeSet_Utf8FormDToUtf8FormC((const char *)dent->d_name,
3536
LOG(4, ("HgfsServerSearchRead: Unable to normalize form C \"%s\"\n",
3538
/* Skip this entry and continue. */
3543
freeEntryName = TRUE;
3544
#else /* defined(__APPLE__) */
3545
entryName = dent->d_name;
3546
entryNameLen = length;
3547
#endif /* defined(__APPLE__) */
3549
LOG(4, ("HgfsServerSearchRead: dent name is \"%s\" len = %"FMTSZ"u\n",
3550
entryName, entryNameLen));
3553
* XXX: HgfsPackSearchReadReply will error out if the dent we
3554
* give it is too large for the packet. Prior to
3555
* HgfsPackSearchReadReply, we'd skip the dent and return the next
3556
* one with success. Now we return an error. This may be a non-issue
3557
* since what filesystems allow dent lengths as high as 6144 bytes?
3559
status = HgfsPackSearchReadReply(entryName, entryNameLen, &attr,
3560
packetOut, packetSize) ? 0 : EPROTO;
3562
if (freeEntryName) {
3678
free(search.utf8ShareName);
3680
LOG(4, ("HgfsServerSearchRead: dent name is \"%s\" len = %"FMTSZ"u\n",
3681
entryName, entryNameLen));
3684
* XXX: HgfsPackSearchReadReply will error out if the dent we
3685
* give it is too large for the packet. Prior to
3686
* HgfsPackSearchReadReply, we'd skip the dent and return the next
3687
* one with success. Now we return an error. This may be a non-issue
3688
* since what filesystems allow dent lengths as high as 6144 bytes?
3690
status = HgfsPackSearchReadReply(entryName, entryNameLen, &attr,
3691
packetOut, packetSize) ? 0 : EPROTO;
3693
if (freeEntryName) {
3571
3701
/* No entry at this offset */
3572
3702
free(search.utf8Dir);
3703
free(search.utf8ShareName);
3573
3704
LOG(4, ("HgfsServerSearchRead: no entry\n"));
3574
3705
return HgfsPackSearchReadReply(NULL, 0, &attr, packetOut, packetSize) ?
3662
3795
/* This is a regular lookup; proceed as usual */
3663
3796
ASSERT(localName);
3665
status = HgfsGetattrFromName(localName, &attr, &targetName);
3798
/* Get the config options. */
3799
nameStatus = HgfsServerPolicy_GetShareOptions(cpName, cpNameSize,
3801
if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
3802
LOG(4, ("HgfsServerGetattr: no matching share: %s.\n", cpName));
3808
status = HgfsGetattrFromName(localName, configOptions, &attr, &targetName);
3666
3809
free(localName);
3667
3810
if (status != 0) {
3825
3970
LOG(4, ("HgfsServerCreateDir: error: %s\n", strerror(error)));
3828
return HgfsPackCreateDirReply(packetOut, packetSize) ? 0 : EPROTO;
3973
return HgfsPackCreateDirReply(((HgfsRequest *)packetIn)->op,
3974
packetOut, packetSize) ?
4138
4289
if (hints & HGFS_RENAME_HINT_NO_REPLACE_EXISTING) {
4139
4290
HgfsFileAttrInfo attr;
4291
HgfsShareOptions configOptions;
4293
/* Get the config options. */
4294
nameStatus = HgfsServerPolicy_GetShareOptions(cpNewName, cpNewNameLen,
4296
if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
4297
LOG(4, ("HgfsServerRename: no matching share: %s.\n", cpNewName));
4142
4303
* We were asked to avoid replacing an existing file,
4143
4304
* so fail if the target exists.
4145
status = HgfsGetattrFromName(localNewName, &attr, NULL);
4306
status = HgfsGetattrFromName(localNewName, configOptions, &attr, NULL);
4146
4307
if (status == 0) {
4147
4308
/* The target exists, and so must fail the rename. */
4148
4309
LOG(4, ("HgfsServerRename: error: target %s exists\n", localNewName));
4168
4329
* the client to see success anyway, because the rename succeeded.
4170
4331
HgfsUpdateNodeNames(localOldName, localNewName);
4171
status = HgfsPackRenameReply(packetOut, packetSize) ?
4332
status = HgfsPackRenameReply(((HgfsRequest *)packetIn)->op,
4333
packetOut, packetSize) ?
4248
4410
* Clients should retry using the file name.
4250
4412
if (requestV3->fileName.flags & HGFS_FILE_NAME_USE_FILE_DESC) {
4251
LOG(4, ("HgfsServerSearchOpen: Doesn't support file handle.\n"));
4413
LOG(4, ("HgfsServerQueryVolume: Doesn't support file handle.\n"));
4252
4414
return EPARAMETERNOTSUPPORTED;
4264
4426
fileName = requestV3->fileName.name;
4265
4427
fileNameLength = requestV3->fileName.length;
4266
4428
*packetSize = HGFS_REP_PAYLOAD_SIZE_V3(replyV3);
4267
LOG(4, ("HgfsServerSearchOpen: HGFS_OP_SEARCH_OPEN_V3\n"));
4429
LOG(4, ("HgfsServerQueryVolume: HGFS_OP_QUERY_VOLUME_INFO_V3\n"));
4269
4431
HgfsRequestQueryVolume *request = (HgfsRequestQueryVolume *)packetIn;
4270
4432
HgfsReplyQueryVolume *reply = (HgfsReplyQueryVolume *)packetOut;
4588
4751
/* It is now safe to read the target file name */
4753
/* Get the config options. */
4754
nameStatus = HgfsServerPolicy_GetShareOptions(symlinkName, symlinkNameLength,
4756
if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
4757
LOG(4, ("HgfsServerSymlinkCreate: no matching share: %s.\n", symlinkName));
4758
return HgfsConvertFromNameStatus(nameStatus);
4590
4761
/* Convert from CPName-lite to normal and NUL-terminate. */
4591
4762
memcpy(localTargetName, targetName, targetNameLength);
4592
4763
CPNameLite_ConvertFrom(localTargetName, targetNameLength, DIRSEPC);
4593
4764
localTargetName[targetNameLength] = '\0';
4766
/* Prohibit symlink ceation if symlink following is enabled. */
4767
if (HgfsServerPolicy_IsShareOptionSet(configOptions, HGFS_SHARE_FOLLOW_SYMLINKS)) {
4595
4771
LOG(4, ("HgfsServerSymlinkCreate: creating \"%s\" linked to \"%s\"\n",
4596
4772
localSymlinkName, localTargetName));