shkhln / libc6-shim

Cheap glibc knockoff
MIT License
29 stars 5 forks source link

Implement statvfs64 as statvfs (same for f variant) #6

Closed monwarez closed 3 months ago

monwarez commented 1 year ago

When trying to launch dota2 under wine (I am using a too recent amd graphics cards, so I cannot have gpu acceleration on linuxulator), it will simply abort when a game is launch (at the hero selection part). Apparently just before loading the hero selection screen, dota2 inspect the base directory of the steam games folder by using statvfs64 (I guess it is wine that use it for some windows api).

Having a dummy implementation that return an error is not sufficient since dota2 will just abort, so we need to have some kind of result. I simply use the non extended variant to accomplish this goal. A more elegant way would have been to create the correct structure for statvfs and then copy it for the statvfs64, but I am too lazy and it seems to works.

Note that while it is possible to play dota2 games with wine, it may crash randomly (I get some futex error if I recall). So not really ready for competitive play (I was able to rejoin the game each time, so I guess it is some kind of ok).

monwarez commented 1 year ago

A quick search lead to this structure for statvfs64 (which is simply statfs64) on Linux

struct statfs64
  {
    __SWORD_TYPE f_type;
    __SWORD_TYPE f_bsize;
    __fsblkcnt64_t f_blocks;
    __fsblkcnt64_t f_bfree;
    __fsblkcnt64_t f_bavail;
    __fsfilcnt64_t f_files;
    __fsfilcnt64_t f_ffree;
    __fsid_t f_fsid;
    __SWORD_TYPE f_namelen;
    __SWORD_TYPE f_frsize;
    __SWORD_TYPE f_flags;
    __SWORD_TYPE f_spare[4];
  };

While on FreeBSD it is

struct statvfs {
        fsblkcnt_t      f_bavail;       /* Number of blocks */
        fsblkcnt_t      f_bfree;
        fsblkcnt_t      f_blocks;
        fsfilcnt_t      f_favail;       /* Number of files (e.g., inodes) */
        fsfilcnt_t      f_ffree;
        fsfilcnt_t      f_files;
        unsigned long   f_bsize;        /* Size of blocks counted above */
        unsigned long   f_flag;
        unsigned long   f_frsize;       /* Size of fragments */
        unsigned long   f_fsid;         /* Not meaningful */
        unsigned long   f_namemax;      /* Same as pathconf(_PC_NAME_MAX) */
};

And an exemple code for a failback with statvfs (I randomly search some repo)

/* Return information about the filesystem on which FILE resides.  */
int
__statvfs64 (const char *file, struct statvfs64 *buf)
{
  struct statfs64 fsbuf;
  int res = __statfs64 (file, &fsbuf);

#ifndef __ASSUME_STATFS64
  if (res < 0 && errno == ENOSYS)
    {
      struct statvfs buf32;

      res = statvfs (file, &buf32);
      if (res == 0)
    {
      buf->f_bsize = buf32.f_bsize;
      buf->f_frsize = buf32.f_frsize;
      buf->f_blocks = buf32.f_blocks;
      buf->f_bfree = buf32.f_bfree;
      buf->f_bavail = buf32.f_bavail;
      buf->f_files = buf32.f_files;
      buf->f_ffree = buf32.f_ffree;
      buf->f_favail = buf32.f_favail;
      buf->f_fsid = buf32.f_fsid;
      buf->f_flag = buf32.f_flag;
      buf->f_namemax = buf32.f_namemax;
      memcpy (buf->__f_spare, buf32.__f_spare, sizeof (buf32.__f_spare));
    }
    }
#endif

  if (res == 0)
    /* Convert the result.  */
    __internal_statvfs64 (file, buf, &fsbuf, -1);

  return res;
}
shkhln commented 3 months ago

statvfs64 was implemented in https://github.com/shkhln/libc6-shim/commit/0545d82d17440201c04edef4c4d0f62b2caa9493.