diff a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
|
a
|
b
|
|
| 28 | 28 | #include <sys/sysmacros.h> |
| 29 | 29 | #include <sys/ddi.h> |
| 30 | 30 | #include <sys/sunddi.h> |
| | 31 | #include <sys/dirent.h> |
| 31 | 32 | #include "vboxfs_prov.h" |
| 32 | 33 | #ifdef u |
| 33 | 34 | #undef u |
| … |
… |
sfprov_rename(sfp_mount_t *mnt, char *from, char *to, uint_t is_dir)
|
| 606 | 607 | * - ENOENT - Couldn't open the directory for reading |
| 607 | 608 | * - EINVAL - Internal error of some kind |
| 608 | 609 | * |
| 609 | | * On successful return, buffer[0] is the start of an array of "char *" |
| 610 | | * pointers to the filenames. The array ends with a NULL pointer. |
| 611 | | * The remaining storage in buffer after that NULL pointer is where the |
| 612 | | * filename strings actually are. |
| 613 | | * |
| 614 | | * On input nents is the max number of filenames the requestor can handle. |
| 615 | | * On output nents is the number of entries at buff[0] |
| 616 | | * |
| 617 | | * The caller is responsible for freeing the returned buffer. |
| | 610 | * On successful return, *dirents points to a list of sffs_dirents_t; |
| | 611 | * for each dirent, all fields except the d_ino will be set appropriately. |
| | 612 | * The caller is responsible for freeing the dirents buffer. |
| 618 | 613 | */ |
| 619 | 614 | int |
| 620 | 615 | sfprov_readdir( |
| 621 | 616 | sfp_mount_t *mnt, |
| 622 | 617 | char *path, |
| 623 | | void **buffer, |
| 624 | | size_t *buffersize, |
| 625 | | uint32_t *nents) |
| | 618 | sffs_dirents_t **dirents) |
| 626 | 619 | { |
| 627 | 620 | int error; |
| 628 | 621 | char *cp; |
| … |
… |
sfprov_readdir(
|
| 630 | 623 | SHFLSTRING *mask_str = NULL; /* must be path with "/*" appended */ |
| 631 | 624 | int mask_size; |
| 632 | 625 | sfp_file_t *fp; |
| 633 | | void *buff_start = NULL; |
| 634 | | size_t buff_size; |
| 635 | 626 | static char infobuff[2 * MAXNAMELEN]; /* not on stack!! */ |
| 636 | 627 | SHFLDIRINFO *info = (SHFLDIRINFO *)&infobuff; |
| 637 | | uint32_t numbytes = sizeof (infobuff); |
| | 628 | uint32_t numbytes; |
| 638 | 629 | uint32_t justone; |
| 639 | 630 | uint32_t cnt; |
| 640 | | char **name_ptrs; |
| | 631 | sffs_dirents_t *cur_buf; |
| | 632 | struct dirent64 *dirent; |
| | 633 | unsigned short reclen; |
| | 634 | |
| | 635 | *dirents = NULL; |
| 641 | 636 | |
| 642 | | *buffer = NULL; |
| 643 | | *buffersize = 0; |
| 644 | | if (*nents == 0) |
| 645 | | return (EINVAL); |
| 646 | 637 | error = sfprov_open(mnt, path, &fp); |
| 647 | 638 | if (error != 0) |
| 648 | 639 | return (ENOENT); |
| 649 | 640 | |
| 650 | 641 | /* |
| | 642 | * Allocate the first dirents buffer. |
| | 643 | */ |
| | 644 | *dirents = kmem_alloc(SFFS_DIRENTS_SIZE, KM_SLEEP); |
| | 645 | if (*dirents == NULL) { |
| | 646 | error = (ENOSPC); |
| | 647 | goto done; |
| | 648 | } |
| | 649 | cur_buf = *dirents; |
| | 650 | cur_buf->sf_next = NULL; |
| | 651 | cur_buf->sf_len = 0; |
| | 652 | |
| | 653 | /* |
| 651 | 654 | * Create mask that VBox expects. This needs to be the directory path, |
| 652 | 655 | * plus a "*" wildcard to get all files. |
| 653 | 656 | */ |
| 654 | 657 | len = strlen(path) + 3; |
| 655 | 658 | cp = kmem_alloc(len, KM_SLEEP); |
| | 659 | if (cp == NULL) { |
| | 660 | error = (ENOSPC); |
| | 661 | goto done; |
| | 662 | } |
| 656 | 663 | strcpy(cp, path); |
| 657 | 664 | strcat(cp, "/*"); |
| 658 | 665 | mask_str = sfprov_string(cp, &mask_size); |
| 659 | 666 | kmem_free(cp, len); |
| 660 | 667 | |
| 661 | 668 | /* |
| 662 | | * Allocate the buffer to use for return values. Each entry |
| 663 | | * in the buffer will have a pointer and the string itself. |
| 664 | | * The pointers go in the front of the buffer, the strings |
| 665 | | * at the end. |
| 666 | | */ |
| 667 | | buff_size = *nents * (sizeof(char *) + MAXNAMELEN); |
| 668 | | name_ptrs = buff_start = kmem_alloc(buff_size, KM_SLEEP); |
| 669 | | cp = (char *)buff_start + buff_size; |
| 670 | | |
| 671 | | /* |
| 672 | 669 | * Now loop using vboxCallDirInfo to get one file name at a time |
| 673 | 670 | */ |
| 674 | 671 | cnt = 0; |
| … |
… |
sfprov_readdir(
|
| 690 | 687 | } |
| 691 | 688 | |
| 692 | 689 | /* |
| 693 | | * Put this name in the buffer, stop if we run out of room. |
| | 690 | * Put this name in the buffer, expand if we run out of room. |
| 694 | 691 | */ |
| 695 | | cp -= strlen(info->name.String.utf8) + 1; |
| 696 | | if (cp < (char *)(&name_ptrs[cnt + 2])) |
| 697 | | break; |
| 698 | | strcpy(cp, info->name.String.utf8); |
| 699 | | name_ptrs[cnt] = cp; |
| | 692 | reclen = DIRENT64_RECLEN(strlen(info->name.String.utf8)); |
| | 693 | if (SFFS_DIRENTS_OFF + cur_buf->sf_len + reclen > SFFS_DIRENTS_SIZE) { |
| | 694 | cur_buf->sf_next = kmem_alloc(SFFS_DIRENTS_SIZE, KM_SLEEP); |
| | 695 | if (cur_buf->sf_next == NULL) { |
| | 696 | error = ENOSPC; |
| | 697 | goto done; |
| | 698 | } |
| | 699 | cur_buf = cur_buf->sf_next; |
| | 700 | cur_buf->sf_next = NULL; |
| | 701 | cur_buf->sf_len = 0; |
| | 702 | } |
| | 703 | |
| | 704 | dirent = (dirent64_t *) |
| | 705 | (((char *) &cur_buf->sf_entries[0]) + cur_buf->sf_len); |
| | 706 | strcpy(&dirent->d_name[0], info->name.String.utf8); |
| | 707 | dirent->d_reclen = reclen; |
| | 708 | dirent->d_off = cnt; |
| | 709 | |
| | 710 | cur_buf->sf_len += reclen; |
| 700 | 711 | ++cnt; |
| 701 | 712 | } |
| 702 | 713 | error = 0; |
| 703 | | name_ptrs[cnt] = NULL; |
| 704 | | *nents = cnt; |
| 705 | | *buffer = buff_start; |
| 706 | | *buffersize = buff_size; |
| | 714 | |
| 707 | 715 | done: |
| 708 | | if (error != 0) |
| 709 | | kmem_free(buff_start, buff_size); |
| 710 | | kmem_free(mask_str, mask_size); |
| | 716 | if (error != 0) { |
| | 717 | while (*dirents) { |
| | 718 | cur_buf = (*dirents)->sf_next; |
| | 719 | kmem_free(*dirents, SFFS_DIRENTS_SIZE); |
| | 720 | *dirents = cur_buf; |
| | 721 | } |
| | 722 | } |
| | 723 | if (mask_str != NULL) |
| | 724 | kmem_free(mask_str, mask_size); |
| 711 | 725 | sfprov_close(fp); |
| 712 | 726 | return (error); |
| 713 | 727 | } |
diff a/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h b/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
|
a
|
b
|
extern int sfprov_rename(sfp_mount_t *, char *from, char *to, uint_t is_dir);
|
| 106 | 106 | /* |
| 107 | 107 | * Read directory entries. |
| 108 | 108 | */ |
| 109 | | extern int sfprov_readdir(sfp_mount_t *mnt, char *path, void **buffer, |
| 110 | | size_t *buffersize, uint32_t *nents); |
| | 109 | /* |
| | 110 | * a singly linked list of buffers, each containing an array of dirent's. |
| | 111 | * sf_len is length of the sf_entries array, in bytes. |
| | 112 | */ |
| | 113 | typedef struct sffs_dirents { |
| | 114 | struct sffs_dirents *sf_next; |
| | 115 | len_t sf_len; |
| | 116 | dirent64_t sf_entries[1]; |
| | 117 | } sffs_dirents_t; |
| | 118 | |
| | 119 | extern int sfprov_readdir(sfp_mount_t *mnt, char *path, sffs_dirents_t **dirents); |
| | 120 | |
| | 121 | #define SFFS_DIRENTS_SIZE 8192 |
| | 122 | #define SFFS_DIRENTS_OFF (offsetof(sffs_dirents_t, sf_entries[0])) |
| 111 | 123 | |
| 112 | 124 | #ifdef __cplusplus |
| 113 | 125 | } |
diff a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
|
a
|
b
|
sfnode_make(
|
| 217 | 217 | node->sf_parent = parent; |
| 218 | 218 | if (parent) |
| 219 | 219 | ++parent->sf_children; |
| | 220 | node->sf_dir_list = NULL; |
| 220 | 221 | |
| 221 | 222 | /* |
| 222 | 223 | * add the new node to our cache |
| … |
… |
sffs_readdir(
|
| 581 | 582 | sfnode_t *dir = VN2SFN(vp); |
| 582 | 583 | sfnode_t *node; |
| 583 | 584 | struct dirent64 *dirent; |
| | 585 | sffs_dirents_t *cur_buf; |
| | 586 | offset_t offset; |
| 584 | 587 | int dummy_eof; |
| 585 | 588 | int error = 0; |
| 586 | | int namelen; |
| 587 | | void *prov_buff = NULL; |
| 588 | | size_t prov_buff_size; |
| 589 | | char **names; |
| 590 | | uint32_t nents; |
| 591 | | uint32_t index; |
| 592 | 589 | |
| 593 | 590 | if (uiop->uio_iovcnt != 1) |
| 594 | 591 | return (EINVAL); |
| … |
… |
sffs_readdir(
|
| 605 | 602 | return (0); |
| 606 | 603 | } |
| 607 | 604 | |
| 608 | | dirent = kmem_zalloc(DIRENT64_RECLEN(MAXNAMELEN), KM_SLEEP); |
| 609 | | |
| 610 | 605 | /* |
| 611 | 606 | * Get the directory entry names from the host. This gets all |
| 612 | | * entries, so add in starting offset. Max the caller can expect |
| 613 | | * would be the size of the UIO buffer / sizeof of a dirent for |
| 614 | | * file with name of length 1 |
| | 607 | * entries. These are stored in a linked list of sffs_dirents_t |
| | 608 | * buffers, each of which contains a list of dirent64_t's. |
| 615 | 609 | */ |
| 616 | 610 | mutex_enter(&sffs_lock); |
| 617 | | index = uiop->uio_loffset; |
| 618 | | nents = index + (uiop->uio_resid / DIRENT64_RECLEN(1)); |
| 619 | | error = sfprov_readdir(dir->sf_sffs->sf_handle, dir->sf_path, |
| 620 | | &prov_buff, &prov_buff_size, &nents); |
| 621 | | if (error != 0) |
| 622 | | goto done; |
| 623 | | if (nents <= index) { |
| 624 | | *eofp = 1; |
| 625 | | goto done; |
| | 611 | |
| | 612 | if (dir->sf_dir_list == NULL) { |
| | 613 | error = sfprov_readdir(dir->sf_sffs->sf_handle, dir->sf_path, |
| | 614 | &dir->sf_dir_list); |
| | 615 | if (error != 0) |
| | 616 | goto done; |
| 626 | 617 | } |
| 627 | | names = (void *)prov_buff; |
| 628 | 618 | |
| 629 | 619 | /* |
| 630 | | * Lookup each of the names, so that we have ino's. |
| | 620 | * Lookup each of the names, so that we have ino's, and copy to |
| | 621 | * result buffer. |
| 631 | 622 | */ |
| 632 | | for (; index < nents; ++index) { |
| 633 | | if (strcmp(names[index], ".") == 0) { |
| | 623 | offset = 0; |
| | 624 | cur_buf = dir->sf_dir_list; |
| | 625 | while (cur_buf != NULL) { |
| | 626 | if (offset + cur_buf->sf_len <= uiop->uio_loffset) { |
| | 627 | offset += cur_buf->sf_len; |
| | 628 | cur_buf = cur_buf->sf_next; |
| | 629 | continue; |
| | 630 | } |
| | 631 | |
| | 632 | dirent = (dirent64_t *) |
| | 633 | (((char *) &cur_buf->sf_entries[0]) + |
| | 634 | (uiop->uio_loffset - offset)); |
| | 635 | if (dirent->d_reclen > uiop->uio_resid) |
| | 636 | break; |
| | 637 | |
| | 638 | if (strcmp(dirent->d_name, ".") == 0) { |
| 634 | 639 | node = dir; |
| 635 | | } else if (strcmp(names[index], "..") == 0) { |
| | 640 | } else if (strcmp(dirent->d_name, "..") == 0) { |
| 636 | 641 | node = dir->sf_parent; |
| 637 | 642 | if (node == NULL) |
| 638 | 643 | node = dir; |
| 639 | 644 | } else { |
| 640 | | node = sfnode_lookup(dir, names[index], VNON); |
| | 645 | node = sfnode_lookup(dir, dirent->d_name, VNON); |
| 641 | 646 | if (node == NULL) |
| 642 | 647 | panic("sffs_readdir() lookup failed"); |
| 643 | 648 | } |
| 644 | | namelen = strlen(names[index]); |
| 645 | | strcpy(&dirent->d_name[0], names[index]); |
| 646 | | dirent->d_reclen = DIRENT64_RECLEN(namelen); |
| 647 | | dirent->d_off = index; |
| 648 | 649 | dirent->d_ino = node->sf_ino; |
| 649 | | if (dirent->d_reclen > uiop->uio_resid) { |
| 650 | | error = ENOSPC; |
| 651 | | break; |
| 652 | | } |
| | 650 | |
| 653 | 651 | error = uiomove(dirent, dirent->d_reclen, UIO_READ, uiop); |
| 654 | 652 | if (error != 0) |
| 655 | 653 | break; |
| 656 | | bzero(&dirent->d_name[0], namelen); |
| 657 | 654 | } |
| 658 | | if (error == 0 && index >= nents) |
| | 655 | if (error == 0 && cur_buf == NULL) |
| 659 | 656 | *eofp = 1; |
| 660 | 657 | done: |
| 661 | 658 | mutex_exit(&sffs_lock); |
| 662 | | if (prov_buff != NULL) |
| 663 | | kmem_free(prov_buff, prov_buff_size); |
| 664 | | kmem_free(dirent, DIRENT64_RECLEN(MAXNAMELEN)); |
| 665 | 659 | return (error); |
| 666 | 660 | } |
| 667 | 661 | |
| … |
… |
sffs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
|
| 1418 | 1412 | } |
| 1419 | 1413 | |
| 1420 | 1414 | /* |
| | 1415 | * Free the directory entries for the node. This should normally |
| | 1416 | * have been taken care of in sffs_close(), but better safe than |
| | 1417 | * sorry. |
| | 1418 | */ |
| | 1419 | while (node->sf_dir_list != NULL) { |
| | 1420 | sffs_dirents_t *next = node->sf_dir_list->sf_next; |
| | 1421 | kmem_free(node->sf_dir_list, SFFS_DIRENTS_SIZE); |
| | 1422 | node->sf_dir_list = next; |
| | 1423 | } |
| | 1424 | |
| | 1425 | /* |
| 1421 | 1426 | * If the node is stale, we can also destroy it. |
| 1422 | 1427 | */ |
| 1423 | 1428 | if (node->sf_is_stale && node->sf_children == 0) |
| … |
… |
sffs_close(
|
| 1450 | 1455 | cred_t *cr, |
| 1451 | 1456 | caller_context_t *ct) |
| 1452 | 1457 | { |
| | 1458 | sfnode_t *node; |
| | 1459 | |
| | 1460 | mutex_enter(&sffs_lock); |
| | 1461 | node = VN2SFN(vp); |
| | 1462 | |
| | 1463 | /* |
| | 1464 | * Free the directory entries for the node. We do this on this call |
| | 1465 | * here because the directory node may not become inactive for a long |
| | 1466 | * time after the readdir is over. Case in point, if somebody cd's into |
| | 1467 | * the directory then it won't become inactive until they cd away again. |
| | 1468 | * In such a case we would end up with the directory listing not getting |
| | 1469 | * updated (i.e. the result of 'ls' always being the same) until they |
| | 1470 | * change the working directory. |
| | 1471 | */ |
| | 1472 | while (node->sf_dir_list != NULL) { |
| | 1473 | sffs_dirents_t *next = node->sf_dir_list->sf_next; |
| | 1474 | kmem_free(node->sf_dir_list, SFFS_DIRENTS_SIZE); |
| | 1475 | node->sf_dir_list = next; |
| | 1476 | } |
| | 1477 | |
| | 1478 | mutex_exit(&sffs_lock); |
| 1453 | 1479 | return (0); |
| 1454 | 1480 | } |
| 1455 | 1481 | |
diff a/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.h b/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.h
|
a
|
b
|
typedef struct sfnode {
|
| 47 | 47 | uint16_t sf_children; /* number of children sfnodes */ |
| 48 | 48 | uint8_t sf_type; /* VDIR or VREG */ |
| 49 | 49 | uint8_t sf_is_stale; /* this is stale and should be purged */ |
| | 50 | sffs_dirents_t *sf_dir_list; /* list of entries for this directory */ |
| 50 | 51 | } sfnode_t; |
| 51 | 52 | |
| 52 | 53 | #define VN2SFN(vp) ((sfnode_t *)(vp)->v_data) |