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
;
401 case SMB_USER_QUOTA_TYPE
:
402 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
403 path
, bdev
, (unsigned)id
.uid
));
405 ret
= quotactl(QCMD(Q_SETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
);
407 case SMB_GROUP_QUOTA_TYPE
:
408 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
409 path
, bdev
, (unsigned)id
.gid
));
411 ret
= quotactl(QCMD(Q_SETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
);
413 case SMB_USER_FS_QUOTA_TYPE
:
414 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
415 path
, bdev
, (unsigned)id
.uid
));
417 if ((ret
= quotactl(QCMD(Q_GETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
))==0) {
418 oldqflags
|= QUOTAS_DENY_DISK
;
422 case SMB_GROUP_FS_QUOTA_TYPE
:
423 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
424 path
, bdev
, (unsigned)id
.gid
));
426 if ((ret
= quotactl(QCMD(Q_GETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
))==0) {
427 oldqflags
|= QUOTAS_DENY_DISK
;
439 /****************************************************************************
440 Abstract out the Linux quota get calls.
441 ****************************************************************************/
442 int sys_get_vfs_quota(const char *path
, const char *bdev
, enum SMB_QUOTA_TYPE qtype
, unid_t id
, SMB_DISK_QUOTA
*dp
)
446 if (!path
||!bdev
||!dp
)
447 smb_panic("sys_set_vfs_quota: called with NULL pointer");
453 case SMB_USER_QUOTA_TYPE
:
454 case SMB_GROUP_QUOTA_TYPE
:
455 if ((ret
=sys_get_linux_gen_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
456 if ((ret
=sys_get_linux_v2_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
457 if ((ret
=sys_get_linux_v1_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
463 if ((dp
->curblocks
==0)&&
465 (dp
->hardlimit
==0)) {
466 /* the upper layer functions don't want empty quota records...*/
471 case SMB_USER_FS_QUOTA_TYPE
:
474 if ((ret
=sys_get_linux_gen_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
475 if ((ret
=sys_get_linux_v2_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
476 ret
=sys_get_linux_v1_quota(path
, bdev
, qtype
, id
, dp
);
482 case SMB_GROUP_FS_QUOTA_TYPE
:
485 if ((ret
=sys_get_linux_gen_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
486 if ((ret
=sys_get_linux_v2_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
487 ret
=sys_get_linux_v1_quota(path
, bdev
, qtype
, id
, dp
);
501 /****************************************************************************
502 Abstract out the Linux quota set calls.
503 ****************************************************************************/
504 int sys_set_vfs_quota(const char *path
, const char *bdev
, enum SMB_QUOTA_TYPE qtype
, unid_t id
, SMB_DISK_QUOTA
*dp
)
507 uint32 oldqflags
= 0;
509 if (!path
||!bdev
||!dp
)
510 smb_panic("sys_set_vfs_quota: called with NULL pointer");
512 oldqflags
= dp
->qflags
;
515 case SMB_USER_QUOTA_TYPE
:
516 case SMB_GROUP_QUOTA_TYPE
:
517 if ((ret
=sys_set_linux_gen_quota(path
, bdev
, qtype
, id
, dp
))) {
518 if ((ret
=sys_set_linux_v2_quota(path
, bdev
, qtype
, id
, dp
))) {
519 if ((ret
=sys_set_linux_v1_quota(path
, bdev
, qtype
, id
, dp
))) {
525 case SMB_USER_FS_QUOTA_TYPE
:
528 if ((ret
=sys_get_linux_gen_quota(path
, bdev
, qtype
, id
, dp
))) {
529 if ((ret
=sys_get_linux_v2_quota(path
, bdev
, qtype
, id
, dp
))) {
530 ret
=sys_get_linux_v1_quota(path
, bdev
, qtype
, id
, dp
);
534 if (oldqflags
== dp
->qflags
) {
540 case SMB_GROUP_FS_QUOTA_TYPE
:
543 if ((ret
=sys_get_linux_gen_quota(path
, bdev
, qtype
, id
, dp
))) {
544 if ((ret
=sys_get_linux_v2_quota(path
, bdev
, qtype
, id
, dp
))) {
545 ret
=sys_get_linux_v1_quota(path
, bdev
, qtype
, id
, dp
);
549 if (oldqflags
== dp
->qflags
) {
564 #else /* HAVE_QUOTACTL_LINUX */
565 void dummy_sysquotas_linux(void);
567 void dummy_sysquotas_linux(void){}
568 #endif /* HAVE_QUOTACTL_LINUX */