linux/fs/vboxsf/utils.c
<<
>>
Prefs
   1// SPDX-License-Identifier: MIT
   2/*
   3 * VirtualBox Guest Shared Folders support: Utility functions.
   4 * Mainly conversion from/to VirtualBox/Linux data structures.
   5 *
   6 * Copyright (C) 2006-2018 Oracle Corporation
   7 */
   8
   9#include <linux/namei.h>
  10#include <linux/nls.h>
  11#include <linux/sizes.h>
  12#include <linux/vfs.h>
  13#include "vfsmod.h"
  14
  15struct inode *vboxsf_new_inode(struct super_block *sb)
  16{
  17        struct vboxsf_sbi *sbi = VBOXSF_SBI(sb);
  18        struct inode *inode;
  19        unsigned long flags;
  20        int cursor, ret;
  21        u32 gen;
  22
  23        inode = new_inode(sb);
  24        if (!inode)
  25                return ERR_PTR(-ENOMEM);
  26
  27        idr_preload(GFP_KERNEL);
  28        spin_lock_irqsave(&sbi->ino_idr_lock, flags);
  29        cursor = idr_get_cursor(&sbi->ino_idr);
  30        ret = idr_alloc_cyclic(&sbi->ino_idr, inode, 1, 0, GFP_ATOMIC);
  31        if (ret >= 0 && ret < cursor)
  32                sbi->next_generation++;
  33        gen = sbi->next_generation;
  34        spin_unlock_irqrestore(&sbi->ino_idr_lock, flags);
  35        idr_preload_end();
  36
  37        if (ret < 0) {
  38                iput(inode);
  39                return ERR_PTR(ret);
  40        }
  41
  42        inode->i_ino = ret;
  43        inode->i_generation = gen;
  44        return inode;
  45}
  46
  47/* set [inode] attributes based on [info], uid/gid based on [sbi] */
  48void vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode,
  49                       const struct shfl_fsobjinfo *info)
  50{
  51        const struct shfl_fsobjattr *attr;
  52        s64 allocated;
  53        int mode;
  54
  55        attr = &info->attr;
  56
  57#define mode_set(r) ((attr->mode & (SHFL_UNIX_##r)) ? (S_##r) : 0)
  58
  59        mode = mode_set(IRUSR);
  60        mode |= mode_set(IWUSR);
  61        mode |= mode_set(IXUSR);
  62
  63        mode |= mode_set(IRGRP);
  64        mode |= mode_set(IWGRP);
  65        mode |= mode_set(IXGRP);
  66
  67        mode |= mode_set(IROTH);
  68        mode |= mode_set(IWOTH);
  69        mode |= mode_set(IXOTH);
  70
  71#undef mode_set
  72
  73        /* We use the host-side values for these */
  74        inode->i_flags |= S_NOATIME | S_NOCMTIME;
  75        inode->i_mapping->a_ops = &vboxsf_reg_aops;
  76
  77        if (SHFL_IS_DIRECTORY(attr->mode)) {
  78                inode->i_mode = sbi->o.dmode_set ? sbi->o.dmode : mode;
  79                inode->i_mode &= ~sbi->o.dmask;
  80                inode->i_mode |= S_IFDIR;
  81                inode->i_op = &vboxsf_dir_iops;
  82                inode->i_fop = &vboxsf_dir_fops;
  83                /*
  84                 * XXX: this probably should be set to the number of entries
  85                 * in the directory plus two (. ..)
  86                 */
  87                set_nlink(inode, 1);
  88        } else if (SHFL_IS_SYMLINK(attr->mode)) {
  89                inode->i_mode = sbi->o.fmode_set ? sbi->o.fmode : mode;
  90                inode->i_mode &= ~sbi->o.fmask;
  91                inode->i_mode |= S_IFLNK;
  92                inode->i_op = &vboxsf_lnk_iops;
  93                set_nlink(inode, 1);
  94        } else {
  95                inode->i_mode = sbi->o.fmode_set ? sbi->o.fmode : mode;
  96                inode->i_mode &= ~sbi->o.fmask;
  97                inode->i_mode |= S_IFREG;
  98                inode->i_op = &vboxsf_reg_iops;
  99                inode->i_fop = &vboxsf_reg_fops;
 100                set_nlink(inode, 1);
 101        }
 102
 103        inode->i_uid = sbi->o.uid;
 104        inode->i_gid = sbi->o.gid;
 105
 106        inode->i_size = info->size;
 107        inode->i_blkbits = 12;
 108        /* i_blocks always in units of 512 bytes! */
 109        allocated = info->allocated + 511;
 110        do_div(allocated, 512);
 111        inode->i_blocks = allocated;
 112
 113        inode->i_atime = ns_to_timespec64(
 114                                 info->access_time.ns_relative_to_unix_epoch);
 115        inode->i_ctime = ns_to_timespec64(
 116                                 info->change_time.ns_relative_to_unix_epoch);
 117        inode->i_mtime = ns_to_timespec64(
 118                           info->modification_time.ns_relative_to_unix_epoch);
 119}
 120
 121int vboxsf_create_at_dentry(struct dentry *dentry,
 122                            struct shfl_createparms *params)
 123{
 124        struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb);
 125        struct shfl_string *path;
 126        int err;
 127
 128        path = vboxsf_path_from_dentry(sbi, dentry);
 129        if (IS_ERR(path))
 130                return PTR_ERR(path);
 131
 132        err = vboxsf_create(sbi->root, path, params);
 133        __putname(path);
 134
 135        return err;
 136}
 137
 138int vboxsf_stat(struct vboxsf_sbi *sbi, struct shfl_string *path,
 139                struct shfl_fsobjinfo *info)
 140{
 141        struct shfl_createparms params = {};
 142        int err;
 143
 144        params.handle = SHFL_HANDLE_NIL;
 145        params.create_flags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW;
 146
 147        err = vboxsf_create(sbi->root, path, &params);
 148        if (err)
 149                return err;
 150
 151        if (params.result != SHFL_FILE_EXISTS)
 152                return -ENOENT;
 153
 154        if (info)
 155                *info = params.info;
 156
 157        return 0;
 158}
 159
 160int vboxsf_stat_dentry(struct dentry *dentry, struct shfl_fsobjinfo *info)
 161{
 162        struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb);
 163        struct shfl_string *path;
 164        int err;
 165
 166        path = vboxsf_path_from_dentry(sbi, dentry);
 167        if (IS_ERR(path))
 168                return PTR_ERR(path);
 169
 170        err = vboxsf_stat(sbi, path, info);
 171        __putname(path);
 172        return err;
 173}
 174
 175int vboxsf_inode_revalidate(struct dentry *dentry)
 176{
 177        struct vboxsf_sbi *sbi;
 178        struct vboxsf_inode *sf_i;
 179        struct shfl_fsobjinfo info;
 180        struct timespec64 prev_mtime;
 181        struct inode *inode;
 182        int err;
 183
 184        if (!dentry || !d_really_is_positive(dentry))
 185                return -EINVAL;
 186
 187        inode = d_inode(dentry);
 188        prev_mtime = inode->i_mtime;
 189        sf_i = VBOXSF_I(inode);
 190        sbi = VBOXSF_SBI(dentry->d_sb);
 191        if (!sf_i->force_restat) {
 192                if (time_before(jiffies, dentry->d_time + sbi->o.ttl))
 193                        return 0;
 194        }
 195
 196        err = vboxsf_stat_dentry(dentry, &info);
 197        if (err)
 198                return err;
 199
 200        dentry->d_time = jiffies;
 201        sf_i->force_restat = 0;
 202        vboxsf_init_inode(sbi, inode, &info);
 203
 204        /*
 205         * If the file was changed on the host side we need to invalidate the
 206         * page-cache for it.  Note this also gets triggered by our own writes,
 207         * this is unavoidable.
 208         */
 209        if (timespec64_compare(&inode->i_mtime, &prev_mtime) > 0)
 210                invalidate_inode_pages2(inode->i_mapping);
 211
 212        return 0;
 213}
 214
 215int vboxsf_getattr(const struct path *path, struct kstat *kstat,
 216                   u32 request_mask, unsigned int flags)
 217{
 218        int err;
 219        struct dentry *dentry = path->dentry;
 220        struct inode *inode = d_inode(dentry);
 221        struct vboxsf_inode *sf_i = VBOXSF_I(inode);
 222
 223        switch (flags & AT_STATX_SYNC_TYPE) {
 224        case AT_STATX_DONT_SYNC:
 225                err = 0;
 226                break;
 227        case AT_STATX_FORCE_SYNC:
 228                sf_i->force_restat = 1;
 229                fallthrough;
 230        default:
 231                err = vboxsf_inode_revalidate(dentry);
 232        }
 233        if (err)
 234                return err;
 235
 236        generic_fillattr(d_inode(dentry), kstat);
 237        return 0;
 238}
 239
 240int vboxsf_setattr(struct dentry *dentry, struct iattr *iattr)
 241{
 242        struct vboxsf_inode *sf_i = VBOXSF_I(d_inode(dentry));
 243        struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb);
 244        struct shfl_createparms params = {};
 245        struct shfl_fsobjinfo info = {};
 246        u32 buf_len;
 247        int err;
 248
 249        params.handle = SHFL_HANDLE_NIL;
 250        params.create_flags = SHFL_CF_ACT_OPEN_IF_EXISTS |
 251                              SHFL_CF_ACT_FAIL_IF_NEW |
 252                              SHFL_CF_ACCESS_ATTR_WRITE;
 253
 254        /* this is at least required for Posix hosts */
 255        if (iattr->ia_valid & ATTR_SIZE)
 256                params.create_flags |= SHFL_CF_ACCESS_WRITE;
 257
 258        err = vboxsf_create_at_dentry(dentry, &params);
 259        if (err || params.result != SHFL_FILE_EXISTS)
 260                return err ? err : -ENOENT;
 261
 262#define mode_set(r) ((iattr->ia_mode & (S_##r)) ? SHFL_UNIX_##r : 0)
 263
 264        /*
 265         * Setting the file size and setting the other attributes has to
 266         * be handled separately.
 267         */
 268        if (iattr->ia_valid & (ATTR_MODE | ATTR_ATIME | ATTR_MTIME)) {
 269                if (iattr->ia_valid & ATTR_MODE) {
 270                        info.attr.mode = mode_set(IRUSR);
 271                        info.attr.mode |= mode_set(IWUSR);
 272                        info.attr.mode |= mode_set(IXUSR);
 273                        info.attr.mode |= mode_set(IRGRP);
 274                        info.attr.mode |= mode_set(IWGRP);
 275                        info.attr.mode |= mode_set(IXGRP);
 276                        info.attr.mode |= mode_set(IROTH);
 277                        info.attr.mode |= mode_set(IWOTH);
 278                        info.attr.mode |= mode_set(IXOTH);
 279
 280                        if (iattr->ia_mode & S_IFDIR)
 281                                info.attr.mode |= SHFL_TYPE_DIRECTORY;
 282                        else
 283                                info.attr.mode |= SHFL_TYPE_FILE;
 284                }
 285
 286                if (iattr->ia_valid & ATTR_ATIME)
 287                        info.access_time.ns_relative_to_unix_epoch =
 288                                            timespec64_to_ns(&iattr->ia_atime);
 289
 290                if (iattr->ia_valid & ATTR_MTIME)
 291                        info.modification_time.ns_relative_to_unix_epoch =
 292                                            timespec64_to_ns(&iattr->ia_mtime);
 293
 294                /*
 295                 * Ignore ctime (inode change time) as it can't be set
 296                 * from userland anyway.
 297                 */
 298
 299                buf_len = sizeof(info);
 300                err = vboxsf_fsinfo(sbi->root, params.handle,
 301                                    SHFL_INFO_SET | SHFL_INFO_FILE, &buf_len,
 302                                    &info);
 303                if (err) {
 304                        vboxsf_close(sbi->root, params.handle);
 305                        return err;
 306                }
 307
 308                /* the host may have given us different attr then requested */
 309                sf_i->force_restat = 1;
 310        }
 311
 312#undef mode_set
 313
 314        if (iattr->ia_valid & ATTR_SIZE) {
 315                memset(&info, 0, sizeof(info));
 316                info.size = iattr->ia_size;
 317                buf_len = sizeof(info);
 318                err = vboxsf_fsinfo(sbi->root, params.handle,
 319                                    SHFL_INFO_SET | SHFL_INFO_SIZE, &buf_len,
 320                                    &info);
 321                if (err) {
 322                        vboxsf_close(sbi->root, params.handle);
 323                        return err;
 324                }
 325
 326                /* the host may have given us different attr then requested */
 327                sf_i->force_restat = 1;
 328        }
 329
 330        vboxsf_close(sbi->root, params.handle);
 331
 332        /* Update the inode with what the host has actually given us. */
 333        if (sf_i->force_restat)
 334                vboxsf_inode_revalidate(dentry);
 335
 336        return 0;
 337}
 338
 339/*
 340 * [dentry] contains string encoded in coding system that corresponds
 341 * to [sbi]->nls, we must convert it to UTF8 here.
 342 * Returns a shfl_string allocated through __getname (must be freed using
 343 * __putname), or an ERR_PTR on error.
 344 */
 345struct shfl_string *vboxsf_path_from_dentry(struct vboxsf_sbi *sbi,
 346                                            struct dentry *dentry)
 347{
 348        struct shfl_string *shfl_path;
 349        int path_len, out_len, nb;
 350        char *buf, *path;
 351        wchar_t uni;
 352        u8 *out;
 353
 354        buf = __getname();
 355        if (!buf)
 356                return ERR_PTR(-ENOMEM);
 357
 358        path = dentry_path_raw(dentry, buf, PATH_MAX);
 359        if (IS_ERR(path)) {
 360                __putname(buf);
 361                return ERR_CAST(path);
 362        }
 363        path_len = strlen(path);
 364
 365        if (sbi->nls) {
 366                shfl_path = __getname();
 367                if (!shfl_path) {
 368                        __putname(buf);
 369                        return ERR_PTR(-ENOMEM);
 370                }
 371
 372                out = shfl_path->string.utf8;
 373                out_len = PATH_MAX - SHFLSTRING_HEADER_SIZE - 1;
 374
 375                while (path_len) {
 376                        nb = sbi->nls->char2uni(path, path_len, &uni);
 377                        if (nb < 0) {
 378                                __putname(shfl_path);
 379                                __putname(buf);
 380                                return ERR_PTR(-EINVAL);
 381                        }
 382                        path += nb;
 383                        path_len -= nb;
 384
 385                        nb = utf32_to_utf8(uni, out, out_len);
 386                        if (nb < 0) {
 387                                __putname(shfl_path);
 388                                __putname(buf);
 389                                return ERR_PTR(-ENAMETOOLONG);
 390                        }
 391                        out += nb;
 392                        out_len -= nb;
 393                }
 394                *out = 0;
 395                shfl_path->length = out - shfl_path->string.utf8;
 396                shfl_path->size = shfl_path->length + 1;
 397                __putname(buf);
 398        } else {
 399                if ((SHFLSTRING_HEADER_SIZE + path_len + 1) > PATH_MAX) {
 400                        __putname(buf);
 401                        return ERR_PTR(-ENAMETOOLONG);
 402                }
 403                /*
 404                 * dentry_path stores the name at the end of buf, but the
 405                 * shfl_string string we return must be properly aligned.
 406                 */
 407                shfl_path = (struct shfl_string *)buf;
 408                memmove(shfl_path->string.utf8, path, path_len);
 409                shfl_path->string.utf8[path_len] = 0;
 410                shfl_path->length = path_len;
 411                shfl_path->size = path_len + 1;
 412        }
 413
 414        return shfl_path;
 415}
 416
 417int vboxsf_nlscpy(struct vboxsf_sbi *sbi, char *name, size_t name_bound_len,
 418                  const unsigned char *utf8_name, size_t utf8_len)
 419{
 420        const char *in;
 421        char *out;
 422        size_t out_len;
 423        size_t out_bound_len;
 424        size_t in_bound_len;
 425
 426        in = utf8_name;
 427        in_bound_len = utf8_len;
 428
 429        out = name;
 430        out_len = 0;
 431        /* Reserve space for terminating 0 */
 432        out_bound_len = name_bound_len - 1;
 433
 434        while (in_bound_len) {
 435                int nb;
 436                unicode_t uni;
 437
 438                nb = utf8_to_utf32(in, in_bound_len, &uni);
 439                if (nb < 0)
 440                        return -EINVAL;
 441
 442                in += nb;
 443                in_bound_len -= nb;
 444
 445                nb = sbi->nls->uni2char(uni, out, out_bound_len);
 446                if (nb < 0)
 447                        return nb;
 448
 449                out += nb;
 450                out_bound_len -= nb;
 451                out_len += nb;
 452        }
 453
 454        *out = 0;
 455
 456        return 0;
 457}
 458
 459static struct vboxsf_dir_buf *vboxsf_dir_buf_alloc(struct list_head *list)
 460{
 461        struct vboxsf_dir_buf *b;
 462
 463        b = kmalloc(sizeof(*b), GFP_KERNEL);
 464        if (!b)
 465                return NULL;
 466
 467        b->buf = kmalloc(DIR_BUFFER_SIZE, GFP_KERNEL);
 468        if (!b->buf) {
 469                kfree(b);
 470                return NULL;
 471        }
 472
 473        b->entries = 0;
 474        b->used = 0;
 475        b->free = DIR_BUFFER_SIZE;
 476        list_add(&b->head, list);
 477
 478        return b;
 479}
 480
 481static void vboxsf_dir_buf_free(struct vboxsf_dir_buf *b)
 482{
 483        list_del(&b->head);
 484        kfree(b->buf);
 485        kfree(b);
 486}
 487
 488struct vboxsf_dir_info *vboxsf_dir_info_alloc(void)
 489{
 490        struct vboxsf_dir_info *p;
 491
 492        p = kmalloc(sizeof(*p), GFP_KERNEL);
 493        if (!p)
 494                return NULL;
 495
 496        INIT_LIST_HEAD(&p->info_list);
 497        return p;
 498}
 499
 500void vboxsf_dir_info_free(struct vboxsf_dir_info *p)
 501{
 502        struct list_head *list, *pos, *tmp;
 503
 504        list = &p->info_list;
 505        list_for_each_safe(pos, tmp, list) {
 506                struct vboxsf_dir_buf *b;
 507
 508                b = list_entry(pos, struct vboxsf_dir_buf, head);
 509                vboxsf_dir_buf_free(b);
 510        }
 511        kfree(p);
 512}
 513
 514int vboxsf_dir_read_all(struct vboxsf_sbi *sbi, struct vboxsf_dir_info *sf_d,
 515                        u64 handle)
 516{
 517        struct vboxsf_dir_buf *b;
 518        u32 entries, size;
 519        int err = 0;
 520        void *buf;
 521
 522        /* vboxsf_dirinfo returns 1 on end of dir */
 523        while (err == 0) {
 524                b = vboxsf_dir_buf_alloc(&sf_d->info_list);
 525                if (!b) {
 526                        err = -ENOMEM;
 527                        break;
 528                }
 529
 530                buf = b->buf;
 531                size = b->free;
 532
 533                err = vboxsf_dirinfo(sbi->root, handle, NULL, 0, 0,
 534                                     &size, buf, &entries);
 535                if (err < 0)
 536                        break;
 537
 538                b->entries += entries;
 539                b->free -= size;
 540                b->used += size;
 541        }
 542
 543        if (b && b->used == 0)
 544                vboxsf_dir_buf_free(b);
 545
 546        /* -EILSEQ means the host could not translate a filename, ignore */
 547        if (err > 0 || err == -EILSEQ)
 548                err = 0;
 549
 550        return err;
 551}
 552