X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=blobdiff_plain;f=etc%2Fafpd%2Fquota.c;h=f4d6d273a5e6fca2b984cf290d62830b65b39b39;hp=0596d7c74ca3fa48e83d993844609b654aebe93a;hb=1b20936596f89b2706f1122ca2fabad6ffe00c98;hpb=538fd6d476e4f3e00bc9d6149e12e1851b60e9d8 diff --git a/etc/afpd/quota.c b/etc/afpd/quota.c index 0596d7c7..f4d6d273 100644 --- a/etc/afpd/quota.c +++ b/etc/afpd/quota.c @@ -1,5 +1,5 @@ /* - * $Id: quota.c,v 1.19 2002-02-03 05:01:09 jmarcus Exp $ + * $Id: quota.c,v 1.32.2.1 2010-01-02 10:22:32 franklahm Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -9,11 +9,12 @@ #include "config.h" #endif /* HAVE_CONFIG_H */ +#ifndef NO_QUOTA_SUPPORT #include #include #include #include - +#include /* STDC check */ #if STDC_HEADERS #include @@ -28,7 +29,6 @@ char *strchr (), *strrchr (); #define memmove(d,s,n) bcopy ((s), (d), (n)) #endif /* ! HAVE_MEMCPY */ #endif /* STDC_HEADERS */ - #include #include #include @@ -38,15 +38,21 @@ char *strchr (), *strrchr (); #ifdef HAVE_FCNTL_H #include #endif /* HAVE_FCNTL_H */ -#include +#include #include #include "auth.h" #include "volume.h" #include "unix.h" -#ifndef NO_QUOTA_SUPPORT +/* +#define DEBUG_QUOTA 0 +*/ + +#define WANT_USER_QUOTA 0 +#define WANT_GROUP_QUOTA 1 + #ifdef NEED_QUOTACTL_WRAPPER int quotactl(int cmd, const char *special, int id, caddr_t addr) { @@ -54,6 +60,228 @@ int quotactl(int cmd, const char *special, int id, caddr_t addr) } #endif /* NEED_QUOTACTL_WRAPPER */ +static int overquota( struct dqblk *); + +#ifdef linux + +#ifdef HAVE_LINUX_XQM_H +#include +#else +#ifdef HAVE_XFS_XQM_H +#include +#define HAVE_LINUX_XQM_H +#else +#ifdef HAVE_LINUX_DQBLK_XFS_H +#include +#define HAVE_LINUX_XQM_H +#endif /* HAVE_LINUX_DQBLK_XFS_H */ +#endif /* HAVE_XFS_XQM_H */ +#endif /* HAVE_LINUX_XQM_H */ + +#include + +static int is_xfs = 0; + +static int get_linux_xfs_quota(int, char*, uid_t, struct dqblk *); +static int get_linux_fs_quota(int, char*, uid_t, struct dqblk *); + +/* format supported by current kernel */ +static int kernel_iface = IFACE_UNSET; + +/* +** Check kernel quota version +** Taken from quota-tools 3.08 by Jan Kara +*/ +static void linuxquota_get_api( void ) +{ +#ifndef LINUX_API_VERSION + struct stat st; + + if (stat("/proc/sys/fs/quota", &st) == 0) { + kernel_iface = IFACE_GENERIC; + } + else { + struct dqstats_v2 v2_stats; + struct sigaction sig; + struct sigaction oldsig; + + /* This signal handling is needed because old kernels send us SIGSEGV as they try to resolve the device */ + sig.sa_handler = SIG_IGN; + sig.sa_sigaction = NULL; + sig.sa_flags = 0; + sigemptyset(&sig.sa_mask); + if (sigaction(SIGSEGV, &sig, &oldsig) < 0) { + LOG( log_error, logtype_afpd, "cannot set SEGV signal handler: %s", strerror(errno)); + goto failure; + } + if (quotactl(QCMD(Q_V2_GETSTATS, 0), NULL, 0, (void *)&v2_stats) >= 0) { + kernel_iface = IFACE_VFSV0; + } + else if (errno != ENOSYS && errno != ENOTSUP) { + /* RedHat 7.1 (2.4.2-2) newquota check + * Q_V2_GETSTATS in it's old place, Q_GETQUOTA in the new place + * (they haven't moved Q_GETSTATS to its new value) */ + int err_stat = 0; + int err_quota = 0; + char tmp[1024]; /* Just temporary buffer */ + + if (quotactl(QCMD(Q_V1_GETSTATS, 0), NULL, 0, tmp)) + err_stat = errno; + if (quotactl(QCMD(Q_V1_GETQUOTA, 0), "/dev/null", 0, tmp)) + err_quota = errno; + + /* On a RedHat 2.4.2-2 we expect 0, EINVAL + * On a 2.4.x we expect 0, ENOENT + * On a 2.4.x-ac we wont get here */ + if (err_stat == 0 && err_quota == EINVAL) { + kernel_iface = IFACE_VFSV0; + } + else { + kernel_iface = IFACE_VFSOLD; + } + } + else { + /* This branch is *not* in quota-tools 3.08 + ** but without it quota version is not correctly + ** identified for the original SuSE 8.0 kernel */ + unsigned int vers_no; + FILE * qf; + + if ((qf = fopen("/proc/fs/quota", "r"))) { + if (fscanf(qf, "Version %u", &vers_no) == 1) { + if ( (vers_no == (6*10000 + 5*100 + 0)) || + (vers_no == (6*10000 + 5*100 + 1)) ) { + kernel_iface = IFACE_VFSV0; + } + } + fclose(qf); + } + } + if (sigaction(SIGSEGV, &oldsig, NULL) < 0) { + LOG(log_error, logtype_afpd, "cannot reset signal handler: %s", strerror(errno)); + goto failure; + } + } + +failure: + if (kernel_iface == IFACE_UNSET) + kernel_iface = IFACE_VFSOLD; + +#else /* defined LINUX_API_VERSION */ + kernel_iface = LINUX_API_VERSION; +#endif +} + +/****************************************************************************/ + +static int get_linux_quota(int what, char *path, uid_t euser_id, struct dqblk *dp) +{ + int r; /* result */ + + if ( is_xfs ) + r=get_linux_xfs_quota(what, path, euser_id, dp); + else + r=get_linux_fs_quota(what, path, euser_id, dp); + + return r; +} + +/**************************************************************************** + Abstract out the XFS Quota Manager quota get call. +****************************************************************************/ + +static int get_linux_xfs_quota(int what, char *path, uid_t euser_id, struct dqblk *dqb) +{ + int ret = -1; +#ifdef HAVE_LINUX_XQM_H + struct fs_disk_quota D; + + memset (&D, 0, sizeof(D)); + + if ((ret = quotactl(QCMD(Q_XGETQUOTA,(what ? GRPQUOTA : USRQUOTA)), path, euser_id, (caddr_t)&D))) + return ret; + + dqb->bsize = (u_int64_t)512; + dqb->dqb_bsoftlimit = (u_int64_t)D.d_blk_softlimit; + dqb->dqb_bhardlimit = (u_int64_t)D.d_blk_hardlimit; + dqb->dqb_ihardlimit = (u_int64_t)D.d_ino_hardlimit; + dqb->dqb_isoftlimit = (u_int64_t)D.d_ino_softlimit; + dqb->dqb_curinodes = (u_int64_t)D.d_icount; + dqb->dqb_curblocks = (u_int64_t)D.d_bcount; +#endif + return ret; +} + +/* +** Wrapper for the quotactl(GETQUOTA) call. +** For API v2 the results are copied back into a v1 structure. +** Taken from quota-1.4.8 perl module +*/ +static int get_linux_fs_quota(int what, char *path, uid_t euser_id, struct dqblk *dqb) +{ + int ret; + + if (kernel_iface == IFACE_UNSET) + linuxquota_get_api(); + + if (kernel_iface == IFACE_GENERIC) + { + struct dqblk_v3 dqb3; + + ret = quotactl(QCMD(Q_V3_GETQUOTA, (what ? GRPQUOTA : USRQUOTA)), path, euser_id, (caddr_t) &dqb3); + if (ret == 0) + { + dqb->dqb_bhardlimit = dqb3.dqb_bhardlimit; + dqb->dqb_bsoftlimit = dqb3.dqb_bsoftlimit; + dqb->dqb_curblocks = dqb3.dqb_curspace / DEV_QBSIZE; + dqb->dqb_ihardlimit = dqb3.dqb_ihardlimit; + dqb->dqb_isoftlimit = dqb3.dqb_isoftlimit; + dqb->dqb_curinodes = dqb3.dqb_curinodes; + dqb->dqb_btime = dqb3.dqb_btime; + dqb->dqb_itime = dqb3.dqb_itime; + dqb->bsize = DEV_QBSIZE; + } + } + else if (kernel_iface == IFACE_VFSV0) + { + struct dqblk_v2 dqb2; + + ret = quotactl(QCMD(Q_V2_GETQUOTA, (what ? GRPQUOTA : USRQUOTA)), path, euser_id, (caddr_t) &dqb2); + if (ret == 0) + { + dqb->dqb_bhardlimit = dqb2.dqb_bhardlimit; + dqb->dqb_bsoftlimit = dqb2.dqb_bsoftlimit; + dqb->dqb_curblocks = dqb2.dqb_curspace / DEV_QBSIZE; + dqb->dqb_ihardlimit = dqb2.dqb_ihardlimit; + dqb->dqb_isoftlimit = dqb2.dqb_isoftlimit; + dqb->dqb_curinodes = dqb2.dqb_curinodes; + dqb->dqb_btime = dqb2.dqb_btime; + dqb->dqb_itime = dqb2.dqb_itime; + dqb->bsize = DEV_QBSIZE; + } + } + else /* if (kernel_iface == IFACE_VFSOLD) */ + { + struct dqblk_v1 dqb1; + + ret = quotactl(QCMD(Q_V1_GETQUOTA, (what ? GRPQUOTA : USRQUOTA)), path, euser_id, (caddr_t) &dqb1); + if (ret == 0) + { + dqb->dqb_bhardlimit = dqb1.dqb_bhardlimit; + dqb->dqb_bsoftlimit = dqb1.dqb_bsoftlimit; + dqb->dqb_curblocks = dqb1.dqb_curblocks; + dqb->dqb_ihardlimit = dqb1.dqb_ihardlimit; + dqb->dqb_isoftlimit = dqb1.dqb_isoftlimit; + dqb->dqb_curinodes = dqb1.dqb_curinodes; + dqb->dqb_btime = dqb1.dqb_btime; + dqb->dqb_itime = dqb1.dqb_itime; + dqb->bsize = DEV_QBSIZE; + } + } + return ret; +} + +#endif /* linux */ #if defined(HAVE_SYS_MNTTAB_H) || defined(__svr4__) /* @@ -61,16 +289,14 @@ int quotactl(int cmd, const char *special, int id, caddr_t addr) * on which "file" resides. Returns NULL on failure. */ static char * -mountp( file, nfs) -char *file; -int *nfs; +mountp( char *file, int *nfs) { struct stat sb; FILE *mtab; dev_t devno; static struct mnttab mnt; - if ( stat( file, &sb ) < 0 ) { + if ( lstat( file, &sb ) < 0 ) { return( NULL ); } devno = sb.st_dev; @@ -81,14 +307,14 @@ int *nfs; while ( getmntent( mtab, &mnt ) == 0 ) { /* local fs */ - if ( (stat( mnt.mnt_special, &sb ) == 0) && (devno == sb.st_rdev)) { + if ( (lstat( mnt.mnt_special, &sb ) == 0) && (devno == sb.st_rdev)) { fclose( mtab ); return mnt.mnt_mountp; } /* check for nfs. we probably should use * strcmp(mnt.mnt_fstype, MNTTYPE_NFS), but that's not as fast. */ - if ((stat(mnt.mnt_mountp, &sb) == 0) && (devno == sb.st_dev) && + if ((lstat(mnt.mnt_mountp, &sb) == 0) && (devno == sb.st_dev) && strchr(mnt.mnt_special, ':')) { *nfs = 1; fclose( mtab ); @@ -108,14 +334,12 @@ int *nfs; */ static char * -special( file, nfs ) -char *file; -int *nfs; +special( char *file, int *nfs) { static struct fs_data fsd; if ( getmnt(0, &fsd, 0, STAT_ONE, file ) < 0 ) { - LOG(log_info, logtype_default, "special: getmnt %s: %m", file ); + LOG(log_info, logtype_afpd, "special: getmnt %s: %s", file, strerror(errno) ); return( NULL ); } @@ -129,9 +353,7 @@ int *nfs; #if (defined(HAVE_SYS_MOUNT_H) && !defined(__linux__)) || defined(BSD4_4) || defined(_IBMR2) static char * -special( file, nfs ) -char *file; -int *nfs; +special(char *file, int *nfs) { static struct statfs sfs; @@ -139,8 +361,14 @@ int *nfs; return( NULL ); } +#ifdef TRU64 + /* Digital UNIX: The struct sfs contains a field sfs.f_type, + * the MOUNT_* constants are defined in */ + if ((sfs.f_type == MOUNT_NFS)||(sfs.f_type == MOUNT_NFS3)) +#else /* TRU64 */ /* XXX: make sure this really detects an nfs mounted fs */ if (strchr(sfs.f_mntfromname, ':')) +#endif /* TRU64 */ *nfs = 1; return( sfs.f_mntfromname ); } @@ -148,16 +376,15 @@ int *nfs; #else /* BSD4_4 */ static char * -special( file, nfs ) -char *file; -int *nfs; +special(char *file, int *nfs) { struct stat sb; FILE *mtab; dev_t devno; struct mntent *mnt; + int found=0; - if ( stat( file, &sb ) < 0 ) { + if ( lstat( file, &sb ) < 0 ) { return( NULL ); } devno = sb.st_dev; @@ -168,23 +395,31 @@ int *nfs; while (( mnt = getmntent( mtab )) != NULL ) { /* check for local fs */ - if ( (stat( mnt->mnt_fsname, &sb ) == 0) && devno == sb.st_rdev) { - endmntent( mtab ); - return( mnt->mnt_fsname ); + if ( (lstat( mnt->mnt_fsname, &sb ) == 0) && devno == sb.st_rdev) { + found = 1; + break; } /* check for an nfs mount entry. the alternative is to use * strcmp(mnt->mnt_type, MNTTYPE_NFS) instead of the strchr. */ - if ((stat(mnt->mnt_dir, &sb) == 0) && (devno == sb.st_dev) && + if ((lstat(mnt->mnt_dir, &sb) == 0) && (devno == sb.st_dev) && strchr(mnt->mnt_fsname, ':')) { *nfs = 1; - endmntent( mtab ); - return( mnt->mnt_fsname ); + found = 1; + break; } } endmntent( mtab ); - return( NULL ); + + if (!found) + return (NULL); +#ifdef linux + if (strcmp(mnt->mnt_type, "xfs") == 0) + is_xfs = 1; +#endif + + return( mnt->mnt_fsname ); } #endif /* BSD4_4 */ @@ -192,14 +427,18 @@ int *nfs; #endif /* __svr4__ */ -static int getfsquota(vol, uid, dq) -struct vol *vol; -const int uid; -struct dqblk *dq; +static int getfsquota(struct vol *vol, const int uid, struct dqblk *dq) + { + struct dqblk dqg; + #ifdef __svr4__ - struct quotctl qc; + struct quotctl qc; +#endif + memset(&dqg, 0, sizeof(dqg)); + +#ifdef __svr4__ qc.op = Q_GETQUOTA; qc.uid = uid; qc.addr = (caddr_t)dq; @@ -225,9 +464,6 @@ struct dqblk *dq; #ifndef TRU64 /* for group quotas. we only use these if the user belongs * to one group. */ - struct dqblk dqg; - - memset(&dqg, 0, sizeof(dqg)); #endif /* TRU64 */ #ifdef BSD4_4 @@ -257,37 +493,44 @@ struct dqblk *dq; } #else /* BSD4_4 */ - if ( quotactl(QCMD(Q_GETQUOTA, USRQUOTA), vol->v_gvs, uid, - (caddr_t) dq ) != 0 ) { + if (get_linux_quota (WANT_USER_QUOTA, vol->v_gvs, uid, dq) !=0) { return( AFPERR_PARAM ); } - if (ngroups >= 1) - quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), vol->v_gvs, - groups[0], (char *) &dqg); + if (get_linux_quota(WANT_GROUP_QUOTA, vol->v_gvs, getegid(), &dqg) != 0) { +#ifdef DEBUG_QUOTA + LOG(log_debug, logtype_afpd, "group quota did not work!" ); +#endif /* DEBUG_QUOTA */ + + return AFP_OK; /* no need to check user vs group quota */ + } #endif /* BSD4_4 */ -#ifndef TRU64 - /* set stuff up for group quotas if necessary */ - /* max(user blocks, group blocks) */ - if (dqg.dqb_curblocks && (dq->dqb_curblocks < dqg.dqb_curblocks)) +#ifndef TRU64 + /* return either the group quota entry or user quota entry, + whichever has the least amount of space remaining + */ + + /* if user space remaining > group space remaining */ + if( + /* if overquota, free space is 0 otherwise hard-current */ + ( overquota( dq ) ? 0 : ( dq->dqb_bhardlimit ? dq->dqb_bhardlimit - + dq->dqb_curblocks : ~((u_int64_t) 0) ) ) + + > + + ( overquota( &dqg ) ? 0 : ( dqg.dqb_bhardlimit ? dqg.dqb_bhardlimit - + dqg.dqb_curblocks : ~((u_int64_t) 0) ) ) + + ) /* if */ + { + /* use group quota limits rather than user limits */ dq->dqb_curblocks = dqg.dqb_curblocks; - - /* min(user limit, group limit) */ - if (dqg.dqb_bhardlimit && (!dq->dqb_bhardlimit || - (dq->dqb_bhardlimit > dqg.dqb_bhardlimit))) dq->dqb_bhardlimit = dqg.dqb_bhardlimit; - - /* ditto */ - if (dqg.dqb_bsoftlimit && (!dq->dqb_bsoftlimit || - (dq->dqb_bsoftlimit > dqg.dqb_bsoftlimit))) dq->dqb_bsoftlimit = dqg.dqb_bsoftlimit; - - /* ditto */ - if (dqg.dqb_btimelimit && (!dq->dqb_btimelimit || - (dq->dqb_btimelimit > dqg.dqb_btimelimit))) dq->dqb_btimelimit = dqg.dqb_btimelimit; + } /* if */ #endif /* TRU64 */ @@ -298,10 +541,7 @@ struct dqblk *dq; } -static int getquota( vol, dq, bsize) -struct vol *vol; -struct dqblk *dq; -const u_int32_t bsize; +static int getquota( struct vol *vol, struct dqblk *dq, const u_int32_t bsize) { char *p; @@ -310,13 +550,13 @@ const u_int32_t bsize; if ( vol->v_qfd == -1 && vol->v_gvs == NULL) { if (( p = mountp( vol->v_path, &vol->v_nfs)) == NULL ) { - LOG(log_info, logtype_default, "getquota: mountp %s fails", vol->v_path ); + LOG(log_info, logtype_afpd, "getquota: mountp %s fails", vol->v_path ); return( AFPERR_PARAM ); } if (vol->v_nfs) { if (( vol->v_gvs = (char *)malloc( strlen( p ) + 1 )) == NULL ) { - LOG(log_error, logtype_default, "getquota: malloc: %m" ); + LOG(log_error, logtype_afpd, "getquota: malloc: %s", strerror(errno) ); return AFPERR_MISC; } strcpy( vol->v_gvs, p ); @@ -324,7 +564,7 @@ const u_int32_t bsize; } else { sprintf( buf, "%s/quotas", p ); if (( vol->v_qfd = open( buf, O_RDONLY, 0 )) < 0 ) { - LOG(log_info, logtype_default, "open %s: %m", buf ); + LOG(log_info, logtype_afpd, "open %s: %s", buf, strerror(errno) ); return( AFPERR_PARAM ); } } @@ -333,28 +573,68 @@ const u_int32_t bsize; #else if ( vol->v_gvs == NULL ) { if (( p = special( vol->v_path, &vol->v_nfs )) == NULL ) { - LOG(log_info, logtype_default, "getquota: special %s fails", vol->v_path ); + LOG(log_info, logtype_afpd, "getquota: special %s fails", vol->v_path ); return( AFPERR_PARAM ); } if (( vol->v_gvs = (char *)malloc( strlen( p ) + 1 )) == NULL ) { - LOG(log_error, logtype_default, "getquota: malloc: %s", strerror(errno) ); + LOG(log_error, logtype_afpd, "getquota: malloc: %s", strerror(errno) ); return AFPERR_MISC; } strcpy( vol->v_gvs, p ); } #endif +#ifdef TRU64 + /* Digital UNIX: Two forms of specifying an NFS filesystem are possible, + either 'hostname:path' or 'path@hostname' (Ultrix heritage) */ + if (vol->v_nfs) { + char *hostpath; + char pathstring[MNAMELEN]; + /* MNAMELEN ist defined in */ + int result; + + if ((hostpath = strchr(vol->v_gvs,'@')) != NULL ) { + /* convert 'path@hostname' to 'hostname:path', + * call getnfsquota(), + * convert 'hostname:path' back to 'path@hostname' */ + *hostpath = '\0'; + sprintf(pathstring,"%s:%s",hostpath+1,vol->v_gvs); + strcpy(vol->v_gvs,pathstring); + + result = getnfsquota(vol, uuid, bsize, dq); + + hostpath = strchr(vol->v_gvs,':'); + *hostpath = '\0'; + sprintf(pathstring,"%s@%s",hostpath+1,vol->v_gvs); + strcpy(vol->v_gvs,pathstring); + + return result; + } + else + /* vol->v_gvs is of the form 'hostname:path' */ + return getnfsquota(vol, uuid, bsize, dq); + } else + /* local filesystem */ + return getfsquota(vol, uuid, dq); + +#else /* TRU64 */ return vol->v_nfs ? getnfsquota(vol, uuid, bsize, dq) : getfsquota(vol, uuid, dq); +#endif /* TRU64 */ } -static int overquota( dqblk ) -struct dqblk *dqblk; +static int overquota( struct dqblk *dqblk) { struct timeval tv; - if ( dqblk->dqb_curblocks < dqblk->dqb_bsoftlimit ) { + if ( dqblk->dqb_curblocks > dqblk->dqb_bhardlimit && + dqblk->dqb_bhardlimit != 0 ) { + return( 1 ); + } + + if ( dqblk->dqb_curblocks < dqblk->dqb_bsoftlimit || + dqblk->dqb_bsoftlimit == 0 ) { return( 0 ); } #ifdef ultrix @@ -362,8 +642,8 @@ struct dqblk *dqblk; return( 0 ); } #else /* ultrix */ - if ( gettimeofday( &tv, 0 ) < 0 ) { - LOG(log_error, logtype_default, "overquota: gettimeofday: %s", strerror(errno) ); + if ( gettimeofday( &tv, NULL ) < 0 ) { + LOG(log_error, logtype_afpd, "overquota: gettimeofday: %s", strerror(errno) ); return( AFPERR_PARAM ); } if ( dqblk->dqb_btimelimit && dqblk->dqb_btimelimit > tv.tv_sec ) { @@ -398,36 +678,64 @@ struct dqblk *dqblk; #else #define tobytes(a, b) dbtob((VolSpace) (a)) #endif -int uquota_getvolspace( vol, bfree, btotal, bsize) -const struct vol *vol; -VolSpace *bfree, *btotal; -const u_int32_t bsize; + +int uquota_getvolspace( struct vol *vol, VolSpace *bfree, VolSpace *btotal, const u_int32_t bsize) { - struct dqblk dqblk; + u_int64_t this_bsize; + struct dqblk dqblk; - if (getquota( vol, &dqblk, bsize) != 0 ) { - return( AFPERR_PARAM ); - } + this_bsize = bsize; + + if (getquota( vol, &dqblk, bsize) != 0 ) { + return( AFPERR_PARAM ); + } - /* no limit set for this user. it might be set in the future. */ - if (dqblk.dqb_bsoftlimit == 0 && dqblk.dqb_bhardlimit == 0) { - *btotal = *bfree = ~((VolSpace) 0); - } else if ( overquota( &dqblk )) { - if ( tobytes( dqblk.dqb_curblocks, bsize ) > tobytes( dqblk.dqb_bhardlimit, bsize ) ) { - *btotal = tobytes( dqblk.dqb_curblocks, bsize ); - *bfree = 0; - } - else { - *btotal = tobytes( dqblk.dqb_bhardlimit, bsize ); - *bfree = tobytes( dqblk.dqb_bhardlimit, bsize ) - - tobytes( dqblk.dqb_curblocks, bsize ); - } - } else { - *btotal = tobytes( dqblk.dqb_bsoftlimit, bsize ); - *bfree = tobytes( dqblk.dqb_bsoftlimit, bsize ) - - tobytes( dqblk.dqb_curblocks, bsize ); - } +#ifdef linux + this_bsize = dqblk.bsize; +#endif + +#ifdef DEBUG_QUOTA + LOG(log_info, logtype_afpd, "after calling getquota in uquota_getvolspace!" ); + LOG(log_info, logtype_afpd, "dqb_ihardlimit: %u", dqblk.dqb_ihardlimit ); + LOG(log_info, logtype_afpd, "dqb_isoftlimit: %u", dqblk.dqb_isoftlimit ); + LOG(log_info, logtype_afpd, "dqb_curinodes : %u", dqblk.dqb_curinodes ); + LOG(log_info, logtype_afpd, "dqb_bhardlimit: %u", dqblk.dqb_bhardlimit ); + LOG(log_info, logtype_afpd, "dqb_bsoftlimit: %u", dqblk.dqb_bsoftlimit ); + LOG(log_info, logtype_afpd, "dqb_curblocks : %u", dqblk.dqb_curblocks ); + LOG(log_info, logtype_afpd, "dqb_btime : %u", dqblk.dqb_btime ); + LOG(log_info, logtype_afpd, "dqb_itime : %u", dqblk.dqb_itime ); + LOG(log_info, logtype_afpd, "bsize/this_bsize : %u/%u", bsize, this_bsize ); + LOG(log_info, logtype_afpd, "dqblk.dqb_bhardlimit size: %u", tobytes( dqblk.dqb_bhardlimit, this_bsize )); + LOG(log_info, logtype_afpd, "dqblk.dqb_bsoftlimit size: %u", tobytes( dqblk.dqb_bsoftlimit, this_bsize )); + LOG(log_info, logtype_afpd, "dqblk.dqb_curblocks size: %u", tobytes( dqblk.dqb_curblocks, this_bsize )); +#endif /* DEBUG_QUOTA */ + + /* no limit set for this user. it might be set in the future. */ + if (dqblk.dqb_bsoftlimit == 0 && dqblk.dqb_bhardlimit == 0) { + *btotal = *bfree = ~((VolSpace) 0); + } else if ( overquota( &dqblk )) { + if ( tobytes( dqblk.dqb_curblocks, this_bsize ) > tobytes( dqblk.dqb_bsoftlimit, this_bsize ) ) { + *btotal = tobytes( dqblk.dqb_curblocks, this_bsize ); + *bfree = 0; + } + else { + *btotal = tobytes( dqblk.dqb_bsoftlimit, this_bsize ); + *bfree = tobytes( dqblk.dqb_bsoftlimit, this_bsize ) - + tobytes( dqblk.dqb_curblocks, this_bsize ); + } + } else { + *btotal = tobytes( dqblk.dqb_bhardlimit, this_bsize ); + *bfree = tobytes( dqblk.dqb_bhardlimit, this_bsize ) - + tobytes( dqblk.dqb_curblocks, this_bsize ); + } + +#ifdef DEBUG_QUOTA + LOG(log_info, logtype_afpd, "bfree : %u", *bfree ); + LOG(log_info, logtype_afpd, "btotal : %u", *btotal ); + LOG(log_info, logtype_afpd, "bfree : %uKB", *bfree/1024 ); + LOG(log_info, logtype_afpd, "btotal : %uKB", *btotal/1024 ); +#endif - return( AFP_OK ); + return( AFP_OK ); } #endif