2 Unix SMB/CIFS implementation.
3 System QUOTA function wrappers for LINUX
4 Copyright (C) Stefan (metze) Metzmacher 2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #define DBGC_CLASS DBGC_QUOTA
27 #ifndef HAVE_SYS_QUOTAS
28 #ifdef HAVE_QUOTACTL_LINUX
29 #undef HAVE_QUOTACTL_LINUX
33 #ifdef HAVE_QUOTACTL_LINUX
35 #include "samba_linux_quota.h"
37 /****************************************************************************
38 Abstract out the v1 Linux quota get calls.
39 ****************************************************************************/
40 static int sys_get_linux_v1_quota(const char *path
, const char *bdev
, enum SMB_QUOTA_TYPE qtype
, unid_t id
, SMB_DISK_QUOTA
*dp
)
44 struct v1_kern_dqblk D
;
45 SMB_BIG_UINT bsize
= (SMB_BIG_UINT
)QUOTABLOCK_SIZE
;
50 case SMB_USER_QUOTA_TYPE
:
51 DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
52 path
, bdev
, (unsigned)id
.uid
));
54 if ((ret
= quotactl(QCMD(Q_V1_GETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
))&&errno
!= EDQUOT
) {
59 case SMB_GROUP_QUOTA_TYPE
:
60 DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
61 path
, bdev
, (unsigned)id
.gid
));
63 if ((ret
= quotactl(QCMD(Q_V1_GETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
))&&errno
!= EDQUOT
) {
68 case SMB_USER_FS_QUOTA_TYPE
:
69 DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
70 path
, bdev
, (unsigned)id
.uid
));
72 if ((ret
= quotactl(QCMD(Q_V1_GETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
))==0) {
73 qflags
|= QUOTAS_DENY_DISK
;
77 case SMB_GROUP_FS_QUOTA_TYPE
:
78 DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
79 path
, bdev
, (unsigned)id
.gid
));
81 if ((ret
= quotactl(QCMD(Q_V1_GETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
))==0) {
82 qflags
|= QUOTAS_DENY_DISK
;
92 dp
->softlimit
= (SMB_BIG_UINT
)D
.dqb_bsoftlimit
;
93 dp
->hardlimit
= (SMB_BIG_UINT
)D
.dqb_bhardlimit
;
94 dp
->ihardlimit
= (SMB_BIG_UINT
)D
.dqb_ihardlimit
;
95 dp
->isoftlimit
= (SMB_BIG_UINT
)D
.dqb_isoftlimit
;
96 dp
->curinodes
= (SMB_BIG_UINT
)D
.dqb_curinodes
;
97 dp
->curblocks
= (SMB_BIG_UINT
)D
.dqb_curblocks
;
105 /****************************************************************************
106 Abstract out the v1 Linux quota set calls.
107 ****************************************************************************/
108 static int sys_set_linux_v1_quota(const char *path
, const char *bdev
, enum SMB_QUOTA_TYPE qtype
, unid_t id
, SMB_DISK_QUOTA
*dp
)
112 uint32 oldqflags
= 0;
113 struct v1_kern_dqblk D
;
114 SMB_BIG_UINT bsize
= (SMB_BIG_UINT
)QUOTABLOCK_SIZE
;
118 if (bsize
== dp
->bsize
) {
119 D
.dqb_bsoftlimit
= dp
->softlimit
;
120 D
.dqb_bhardlimit
= dp
->hardlimit
;
121 D
.dqb_ihardlimit
= dp
->ihardlimit
;
122 D
.dqb_isoftlimit
= dp
->isoftlimit
;
124 D
.dqb_bsoftlimit
= (dp
->softlimit
*dp
->bsize
)/bsize
;
125 D
.dqb_bhardlimit
= (dp
->hardlimit
*dp
->bsize
)/bsize
;
126 D
.dqb_ihardlimit
= (dp
->ihardlimit
*dp
->bsize
)/bsize
;
127 D
.dqb_isoftlimit
= (dp
->isoftlimit
*dp
->bsize
)/bsize
;
133 case SMB_USER_QUOTA_TYPE
:
134 DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
135 path
, bdev
, (unsigned)id
.uid
));
137 ret
= quotactl(QCMD(Q_V1_SETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
);
139 case SMB_GROUP_QUOTA_TYPE
:
140 DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
141 path
, bdev
, (unsigned)id
.gid
));
143 ret
= quotactl(QCMD(Q_V1_SETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
);
145 case SMB_USER_FS_QUOTA_TYPE
:
146 DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
147 path
, bdev
, (unsigned)id
.uid
));
149 if ((ret
= quotactl(QCMD(Q_V1_GETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
))==0) {
150 oldqflags
|= QUOTAS_DENY_DISK
;
154 case SMB_GROUP_FS_QUOTA_TYPE
:
155 DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
156 path
, bdev
, (unsigned)id
.gid
));
158 if ((ret
= quotactl(QCMD(Q_V1_GETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
))==0) {
159 oldqflags
|= QUOTAS_DENY_DISK
;
171 /****************************************************************************
172 Abstract out the v2 Linux quota get calls.
173 ****************************************************************************/
174 static int sys_get_linux_v2_quota(const char *path
, const char *bdev
, enum SMB_QUOTA_TYPE qtype
, unid_t id
, SMB_DISK_QUOTA
*dp
)
178 struct v2_kern_dqblk D
;
179 SMB_BIG_UINT bsize
= (SMB_BIG_UINT
)QUOTABLOCK_SIZE
;
184 case SMB_USER_QUOTA_TYPE
:
185 DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
186 path
, bdev
, (unsigned)id
.uid
));
188 if ((ret
= quotactl(QCMD(Q_V2_GETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
))&&errno
!= EDQUOT
) {
193 case SMB_GROUP_QUOTA_TYPE
:
194 DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
195 path
, bdev
, (unsigned)id
.gid
));
197 if ((ret
= quotactl(QCMD(Q_V2_GETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
))&&errno
!= EDQUOT
) {
202 case SMB_USER_FS_QUOTA_TYPE
:
203 DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
204 path
, bdev
, (unsigned)id
.uid
));
206 if ((ret
= quotactl(QCMD(Q_V2_GETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
))==0) {
207 qflags
|= QUOTAS_DENY_DISK
;
211 case SMB_GROUP_FS_QUOTA_TYPE
:
212 DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
213 path
, bdev
, (unsigned)id
.gid
));
215 if ((ret
= quotactl(QCMD(Q_V2_GETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
))==0) {
216 qflags
|= QUOTAS_DENY_DISK
;
226 dp
->softlimit
= (SMB_BIG_UINT
)D
.dqb_bsoftlimit
;
227 dp
->hardlimit
= (SMB_BIG_UINT
)D
.dqb_bhardlimit
;
228 dp
->ihardlimit
= (SMB_BIG_UINT
)D
.dqb_ihardlimit
;
229 dp
->isoftlimit
= (SMB_BIG_UINT
)D
.dqb_isoftlimit
;
230 dp
->curinodes
= (SMB_BIG_UINT
)D
.dqb_curinodes
;
231 dp
->curblocks
= (SMB_BIG_UINT
)D
.dqb_curspace
/bsize
;
239 /****************************************************************************
240 Abstract out the v2 Linux quota set calls.
241 ****************************************************************************/
242 static int sys_set_linux_v2_quota(const char *path
, const char *bdev
, enum SMB_QUOTA_TYPE qtype
, unid_t id
, SMB_DISK_QUOTA
*dp
)
246 uint32 oldqflags
= 0;
247 struct v2_kern_dqblk D
;
248 SMB_BIG_UINT bsize
= (SMB_BIG_UINT
)QUOTABLOCK_SIZE
;
252 if (bsize
== dp
->bsize
) {
253 D
.dqb_bsoftlimit
= dp
->softlimit
;
254 D
.dqb_bhardlimit
= dp
->hardlimit
;
255 D
.dqb_ihardlimit
= dp
->ihardlimit
;
256 D
.dqb_isoftlimit
= dp
->isoftlimit
;
258 D
.dqb_bsoftlimit
= (dp
->softlimit
*dp
->bsize
)/bsize
;
259 D
.dqb_bhardlimit
= (dp
->hardlimit
*dp
->bsize
)/bsize
;
260 D
.dqb_ihardlimit
= (dp
->ihardlimit
*dp
->bsize
)/bsize
;
261 D
.dqb_isoftlimit
= (dp
->isoftlimit
*dp
->bsize
)/bsize
;
267 case SMB_USER_QUOTA_TYPE
:
268 DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
269 path
, bdev
, (unsigned)id
.uid
));
271 ret
= quotactl(QCMD(Q_V2_SETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
);
273 case SMB_GROUP_QUOTA_TYPE
:
274 DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
275 path
, bdev
, (unsigned)id
.gid
));
277 ret
= quotactl(QCMD(Q_V2_SETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
);
279 case SMB_USER_FS_QUOTA_TYPE
:
280 DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
281 path
, bdev
, (unsigned)id
.uid
));
283 if ((ret
= quotactl(QCMD(Q_V2_GETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
))==0) {
284 oldqflags
|= QUOTAS_DENY_DISK
;
288 case SMB_GROUP_FS_QUOTA_TYPE
:
289 DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
290 path
, bdev
, (unsigned)id
.gid
));
292 if ((ret
= quotactl(QCMD(Q_V2_GETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
))==0) {
293 oldqflags
|= QUOTAS_DENY_DISK
;
305 /****************************************************************************
306 Abstract out the generic Linux quota get calls.
307 ****************************************************************************/
308 static int sys_get_linux_gen_quota(const char *path
, const char *bdev
, enum SMB_QUOTA_TYPE qtype
, unid_t id
, SMB_DISK_QUOTA
*dp
)
313 SMB_BIG_UINT bsize
= (SMB_BIG_UINT
)QUOTABLOCK_SIZE
;
318 case SMB_USER_QUOTA_TYPE
:
319 DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
320 path
, bdev
, (unsigned)id
.uid
));
322 if ((ret
= quotactl(QCMD(Q_GETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
))&&errno
!= EDQUOT
) {
327 case SMB_GROUP_QUOTA_TYPE
:
328 DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
329 path
, bdev
, (unsigned)id
.gid
));
331 if ((ret
= quotactl(QCMD(Q_GETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
))&&errno
!= EDQUOT
) {
336 case SMB_USER_FS_QUOTA_TYPE
:
337 DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
338 path
, bdev
, (unsigned)id
.uid
));
340 if ((ret
= quotactl(QCMD(Q_GETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
))==0) {
341 qflags
|= QUOTAS_DENY_DISK
;
345 case SMB_GROUP_FS_QUOTA_TYPE
:
346 DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
347 path
, bdev
, (unsigned)id
.gid
));
349 if ((ret
= quotactl(QCMD(Q_GETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
))==0) {
350 qflags
|= QUOTAS_DENY_DISK
;
360 dp
->softlimit
= (SMB_BIG_UINT
)D
.dqb_bsoftlimit
;
361 dp
->hardlimit
= (SMB_BIG_UINT
)D
.dqb_bhardlimit
;
362 dp
->ihardlimit
= (SMB_BIG_UINT
)D
.dqb_ihardlimit
;
363 dp
->isoftlimit
= (SMB_BIG_UINT
)D
.dqb_isoftlimit
;
364 dp
->curinodes
= (SMB_BIG_UINT
)D
.dqb_curinodes
;
365 dp
->curblocks
= (SMB_BIG_UINT
)D
.dqb_curspace
/bsize
;
373 /****************************************************************************
374 Abstract out the gen Linux quota set calls.
375 ****************************************************************************/
376 static int sys_set_linux_gen_quota(const char *path
, const char *bdev
, enum SMB_QUOTA_TYPE qtype
, unid_t id
, SMB_DISK_QUOTA
*dp
)
380 uint32 oldqflags
= 0;
382 SMB_BIG_UINT bsize
= (SMB_BIG_UINT
)QUOTABLOCK_SIZE
;
386 if (bsize
== dp
->bsize
) {
387 D
.dqb_bsoftlimit
= dp
->softlimit
;
388 D
.dqb_bhardlimit
= dp
->hardlimit
;
389 D
.dqb_ihardlimit
= dp
->ihardlimit
;
390 D
.dqb_isoftlimit
= dp
->isoftlimit
;
392 D
.dqb_bsoftlimit
= (dp
->softlimit
*dp
->bsize
)/bsize
;
393 D
.dqb_bhardlimit
= (dp
->hardlimit
*dp
->bsize
)/bsize
;
394 D
.dqb_ihardlimit
= (dp
->ihardlimit
*dp
->bsize
)/bsize
;
395 D
.dqb_isoftlimit
= (dp
->isoftlimit
*dp
->bsize
)/bsize
;
397 D
.dqb_valid
= QIF_LIMITS
;
402 case SMB_USER_QUOTA_TYPE
:
403 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
404 path
, bdev
, (unsigned)id
.uid
));
406 ret
= quotactl(QCMD(Q_SETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
);
408 case SMB_GROUP_QUOTA_TYPE
:
409 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
410 path
, bdev
, (unsigned)id
.gid
));
412 ret
= quotactl(QCMD(Q_SETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
);
414 case SMB_USER_FS_QUOTA_TYPE
:
415 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
416 path
, bdev
, (unsigned)id
.uid
));
418 if ((ret
= quotactl(QCMD(Q_GETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
))==0) {
419 oldqflags
|= QUOTAS_DENY_DISK
;
423 case SMB_GROUP_FS_QUOTA_TYPE
:
424 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
425 path
, bdev
, (unsigned)id
.gid
));
427 if ((ret
= quotactl(QCMD(Q_GETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
))==0) {
428 oldqflags
|= QUOTAS_DENY_DISK
;
440 /****************************************************************************
441 Abstract out the Linux quota get calls.
442 ****************************************************************************/
443 int sys_get_vfs_quota(const char *path
, const char *bdev
, enum SMB_QUOTA_TYPE qtype
, unid_t id
, SMB_DISK_QUOTA
*dp
)
447 if (!path
||!bdev
||!dp
)
448 smb_panic("sys_set_vfs_quota: called with NULL pointer");
454 case SMB_USER_QUOTA_TYPE
:
455 case SMB_GROUP_QUOTA_TYPE
:
456 if ((ret
=sys_get_linux_gen_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
457 if ((ret
=sys_get_linux_v2_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
458 if ((ret
=sys_get_linux_v1_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
464 if ((dp
->curblocks
==0)&&
466 (dp
->hardlimit
==0)) {
467 /* the upper layer functions don't want empty quota records...*/
472 case SMB_USER_FS_QUOTA_TYPE
:
475 if ((ret
=sys_get_linux_gen_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
476 if ((ret
=sys_get_linux_v2_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
477 ret
=sys_get_linux_v1_quota(path
, bdev
, qtype
, id
, dp
);
483 case SMB_GROUP_FS_QUOTA_TYPE
:
486 if ((ret
=sys_get_linux_gen_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
487 if ((ret
=sys_get_linux_v2_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
488 ret
=sys_get_linux_v1_quota(path
, bdev
, qtype
, id
, dp
);
502 /****************************************************************************
503 Abstract out the Linux quota set calls.
504 ****************************************************************************/
505 int sys_set_vfs_quota(const char *path
, const char *bdev
, enum SMB_QUOTA_TYPE qtype
, unid_t id
, SMB_DISK_QUOTA
*dp
)
508 uint32 oldqflags
= 0;
510 if (!path
||!bdev
||!dp
)
511 smb_panic("sys_set_vfs_quota: called with NULL pointer");
513 oldqflags
= dp
->qflags
;
516 case SMB_USER_QUOTA_TYPE
:
517 case SMB_GROUP_QUOTA_TYPE
:
518 if ((ret
=sys_set_linux_gen_quota(path
, bdev
, qtype
, id
, dp
))) {
519 if ((ret
=sys_set_linux_v2_quota(path
, bdev
, qtype
, id
, dp
))) {
520 if ((ret
=sys_set_linux_v1_quota(path
, bdev
, qtype
, id
, dp
))) {
526 case SMB_USER_FS_QUOTA_TYPE
:
529 if ((ret
=sys_set_linux_gen_quota(path
, bdev
, qtype
, id
, dp
))) {
530 if ((ret
=sys_set_linux_v2_quota(path
, bdev
, qtype
, id
, dp
))) {
531 ret
=sys_set_linux_v1_quota(path
, bdev
, qtype
, id
, dp
);
535 if (oldqflags
== dp
->qflags
) {
541 case SMB_GROUP_FS_QUOTA_TYPE
:
544 if ((ret
=sys_set_linux_gen_quota(path
, bdev
, qtype
, id
, dp
))) {
545 if ((ret
=sys_set_linux_v2_quota(path
, bdev
, qtype
, id
, dp
))) {
546 ret
=sys_set_linux_v1_quota(path
, bdev
, qtype
, id
, dp
);
550 if (oldqflags
== dp
->qflags
) {
565 #else /* HAVE_QUOTACTL_LINUX */
566 void dummy_sysquotas_linux(void);
568 void dummy_sysquotas_linux(void){}
569 #endif /* HAVE_QUOTACTL_LINUX */