1*6a54128fSAndroid Build Coastguard Worker /** quotaio.c
2*6a54128fSAndroid Build Coastguard Worker *
3*6a54128fSAndroid Build Coastguard Worker * Generic IO operations on quotafiles
4*6a54128fSAndroid Build Coastguard Worker * Jan Kara <[email protected]> - sponsored by SuSE CR
5*6a54128fSAndroid Build Coastguard Worker * Aditya Kali <[email protected]> - Ported to e2fsprogs
6*6a54128fSAndroid Build Coastguard Worker */
7*6a54128fSAndroid Build Coastguard Worker
8*6a54128fSAndroid Build Coastguard Worker #include "config.h"
9*6a54128fSAndroid Build Coastguard Worker #include <stdio.h>
10*6a54128fSAndroid Build Coastguard Worker #include <errno.h>
11*6a54128fSAndroid Build Coastguard Worker #include <string.h>
12*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
13*6a54128fSAndroid Build Coastguard Worker #include <stdlib.h>
14*6a54128fSAndroid Build Coastguard Worker #include <time.h>
15*6a54128fSAndroid Build Coastguard Worker #include <sys/types.h>
16*6a54128fSAndroid Build Coastguard Worker #include <sys/stat.h>
17*6a54128fSAndroid Build Coastguard Worker #include <sys/file.h>
18*6a54128fSAndroid Build Coastguard Worker #include <assert.h>
19*6a54128fSAndroid Build Coastguard Worker
20*6a54128fSAndroid Build Coastguard Worker #include "common.h"
21*6a54128fSAndroid Build Coastguard Worker #include "quotaio.h"
22*6a54128fSAndroid Build Coastguard Worker
23*6a54128fSAndroid Build Coastguard Worker static const char * const extensions[MAXQUOTAS] = {
24*6a54128fSAndroid Build Coastguard Worker [USRQUOTA] = "user",
25*6a54128fSAndroid Build Coastguard Worker [GRPQUOTA] = "group",
26*6a54128fSAndroid Build Coastguard Worker [PRJQUOTA] = "project",
27*6a54128fSAndroid Build Coastguard Worker };
28*6a54128fSAndroid Build Coastguard Worker static const char * const basenames[] = {
29*6a54128fSAndroid Build Coastguard Worker "", /* undefined */
30*6a54128fSAndroid Build Coastguard Worker "quota", /* QFMT_VFS_OLD */
31*6a54128fSAndroid Build Coastguard Worker "aquota", /* QFMT_VFS_V0 */
32*6a54128fSAndroid Build Coastguard Worker "", /* QFMT_OCFS2 */
33*6a54128fSAndroid Build Coastguard Worker "aquota" /* QFMT_VFS_V1 */
34*6a54128fSAndroid Build Coastguard Worker };
35*6a54128fSAndroid Build Coastguard Worker
36*6a54128fSAndroid Build Coastguard Worker /* Header in all newer quotafiles */
37*6a54128fSAndroid Build Coastguard Worker struct disk_dqheader {
38*6a54128fSAndroid Build Coastguard Worker __le32 dqh_magic;
39*6a54128fSAndroid Build Coastguard Worker __le32 dqh_version;
40*6a54128fSAndroid Build Coastguard Worker } __attribute__ ((packed));
41*6a54128fSAndroid Build Coastguard Worker
42*6a54128fSAndroid Build Coastguard Worker /**
43*6a54128fSAndroid Build Coastguard Worker * Convert type of quota to written representation
44*6a54128fSAndroid Build Coastguard Worker */
quota_type2name(enum quota_type qtype)45*6a54128fSAndroid Build Coastguard Worker const char *quota_type2name(enum quota_type qtype)
46*6a54128fSAndroid Build Coastguard Worker {
47*6a54128fSAndroid Build Coastguard Worker if (qtype >= MAXQUOTAS)
48*6a54128fSAndroid Build Coastguard Worker return "unknown";
49*6a54128fSAndroid Build Coastguard Worker return extensions[qtype];
50*6a54128fSAndroid Build Coastguard Worker }
51*6a54128fSAndroid Build Coastguard Worker
quota_type2inum(enum quota_type qtype,struct ext2_super_block * sb)52*6a54128fSAndroid Build Coastguard Worker ext2_ino_t quota_type2inum(enum quota_type qtype,
53*6a54128fSAndroid Build Coastguard Worker struct ext2_super_block *sb)
54*6a54128fSAndroid Build Coastguard Worker {
55*6a54128fSAndroid Build Coastguard Worker switch (qtype) {
56*6a54128fSAndroid Build Coastguard Worker case USRQUOTA:
57*6a54128fSAndroid Build Coastguard Worker return EXT4_USR_QUOTA_INO;
58*6a54128fSAndroid Build Coastguard Worker case GRPQUOTA:
59*6a54128fSAndroid Build Coastguard Worker return EXT4_GRP_QUOTA_INO;
60*6a54128fSAndroid Build Coastguard Worker case PRJQUOTA:
61*6a54128fSAndroid Build Coastguard Worker return sb->s_prj_quota_inum;
62*6a54128fSAndroid Build Coastguard Worker default:
63*6a54128fSAndroid Build Coastguard Worker return 0;
64*6a54128fSAndroid Build Coastguard Worker }
65*6a54128fSAndroid Build Coastguard Worker return 0;
66*6a54128fSAndroid Build Coastguard Worker }
67*6a54128fSAndroid Build Coastguard Worker
68*6a54128fSAndroid Build Coastguard Worker /**
69*6a54128fSAndroid Build Coastguard Worker * Creates a quota file name for given type and format.
70*6a54128fSAndroid Build Coastguard Worker */
quota_get_qf_name(enum quota_type type,int fmt,char * buf)71*6a54128fSAndroid Build Coastguard Worker const char *quota_get_qf_name(enum quota_type type, int fmt, char *buf)
72*6a54128fSAndroid Build Coastguard Worker {
73*6a54128fSAndroid Build Coastguard Worker if (!buf)
74*6a54128fSAndroid Build Coastguard Worker return NULL;
75*6a54128fSAndroid Build Coastguard Worker snprintf(buf, QUOTA_NAME_LEN, "%s.%s",
76*6a54128fSAndroid Build Coastguard Worker basenames[fmt], extensions[type]);
77*6a54128fSAndroid Build Coastguard Worker
78*6a54128fSAndroid Build Coastguard Worker return buf;
79*6a54128fSAndroid Build Coastguard Worker }
80*6a54128fSAndroid Build Coastguard Worker
81*6a54128fSAndroid Build Coastguard Worker /*
82*6a54128fSAndroid Build Coastguard Worker * Set grace time if needed
83*6a54128fSAndroid Build Coastguard Worker */
update_grace_times(struct dquot * q)84*6a54128fSAndroid Build Coastguard Worker void update_grace_times(struct dquot *q)
85*6a54128fSAndroid Build Coastguard Worker {
86*6a54128fSAndroid Build Coastguard Worker time_t now;
87*6a54128fSAndroid Build Coastguard Worker
88*6a54128fSAndroid Build Coastguard Worker time(&now);
89*6a54128fSAndroid Build Coastguard Worker if (q->dq_dqb.dqb_bsoftlimit && toqb(q->dq_dqb.dqb_curspace) >
90*6a54128fSAndroid Build Coastguard Worker q->dq_dqb.dqb_bsoftlimit) {
91*6a54128fSAndroid Build Coastguard Worker if (!q->dq_dqb.dqb_btime)
92*6a54128fSAndroid Build Coastguard Worker q->dq_dqb.dqb_btime =
93*6a54128fSAndroid Build Coastguard Worker now + q->dq_h->qh_info.dqi_bgrace;
94*6a54128fSAndroid Build Coastguard Worker } else {
95*6a54128fSAndroid Build Coastguard Worker q->dq_dqb.dqb_btime = 0;
96*6a54128fSAndroid Build Coastguard Worker }
97*6a54128fSAndroid Build Coastguard Worker
98*6a54128fSAndroid Build Coastguard Worker if (q->dq_dqb.dqb_isoftlimit && q->dq_dqb.dqb_curinodes >
99*6a54128fSAndroid Build Coastguard Worker q->dq_dqb.dqb_isoftlimit) {
100*6a54128fSAndroid Build Coastguard Worker if (!q->dq_dqb.dqb_itime)
101*6a54128fSAndroid Build Coastguard Worker q->dq_dqb.dqb_itime =
102*6a54128fSAndroid Build Coastguard Worker now + q->dq_h->qh_info.dqi_igrace;
103*6a54128fSAndroid Build Coastguard Worker } else {
104*6a54128fSAndroid Build Coastguard Worker q->dq_dqb.dqb_itime = 0;
105*6a54128fSAndroid Build Coastguard Worker }
106*6a54128fSAndroid Build Coastguard Worker }
107*6a54128fSAndroid Build Coastguard Worker
quota_inode_truncate(ext2_filsys fs,ext2_ino_t ino)108*6a54128fSAndroid Build Coastguard Worker errcode_t quota_inode_truncate(ext2_filsys fs, ext2_ino_t ino)
109*6a54128fSAndroid Build Coastguard Worker {
110*6a54128fSAndroid Build Coastguard Worker struct ext2_inode inode;
111*6a54128fSAndroid Build Coastguard Worker errcode_t err;
112*6a54128fSAndroid Build Coastguard Worker enum quota_type qtype;
113*6a54128fSAndroid Build Coastguard Worker
114*6a54128fSAndroid Build Coastguard Worker if ((err = ext2fs_read_inode(fs, ino, &inode)))
115*6a54128fSAndroid Build Coastguard Worker return err;
116*6a54128fSAndroid Build Coastguard Worker
117*6a54128fSAndroid Build Coastguard Worker for (qtype = 0; qtype < MAXQUOTAS; qtype++)
118*6a54128fSAndroid Build Coastguard Worker if (ino == quota_type2inum(qtype, fs->super))
119*6a54128fSAndroid Build Coastguard Worker break;
120*6a54128fSAndroid Build Coastguard Worker
121*6a54128fSAndroid Build Coastguard Worker if (qtype != MAXQUOTAS) {
122*6a54128fSAndroid Build Coastguard Worker inode.i_dtime = fs->now ? fs->now : time(0);
123*6a54128fSAndroid Build Coastguard Worker if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
124*6a54128fSAndroid Build Coastguard Worker return 0;
125*6a54128fSAndroid Build Coastguard Worker err = ext2fs_punch(fs, ino, &inode, NULL, 0, ~0ULL);
126*6a54128fSAndroid Build Coastguard Worker if (err)
127*6a54128fSAndroid Build Coastguard Worker return err;
128*6a54128fSAndroid Build Coastguard Worker fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
129*6a54128fSAndroid Build Coastguard Worker memset(&inode, 0, sizeof(struct ext2_inode));
130*6a54128fSAndroid Build Coastguard Worker } else {
131*6a54128fSAndroid Build Coastguard Worker inode.i_flags &= ~EXT2_IMMUTABLE_FL;
132*6a54128fSAndroid Build Coastguard Worker }
133*6a54128fSAndroid Build Coastguard Worker err = ext2fs_write_inode(fs, ino, &inode);
134*6a54128fSAndroid Build Coastguard Worker return err;
135*6a54128fSAndroid Build Coastguard Worker }
136*6a54128fSAndroid Build Coastguard Worker
137*6a54128fSAndroid Build Coastguard Worker /* Functions to read/write quota file. */
quota_write_nomount(struct quota_file * qf,ext2_loff_t offset,void * buf,unsigned int size)138*6a54128fSAndroid Build Coastguard Worker static unsigned int quota_write_nomount(struct quota_file *qf,
139*6a54128fSAndroid Build Coastguard Worker ext2_loff_t offset,
140*6a54128fSAndroid Build Coastguard Worker void *buf, unsigned int size)
141*6a54128fSAndroid Build Coastguard Worker {
142*6a54128fSAndroid Build Coastguard Worker ext2_file_t e2_file = qf->e2_file;
143*6a54128fSAndroid Build Coastguard Worker unsigned int bytes_written = 0;
144*6a54128fSAndroid Build Coastguard Worker errcode_t err;
145*6a54128fSAndroid Build Coastguard Worker
146*6a54128fSAndroid Build Coastguard Worker err = ext2fs_file_llseek(e2_file, offset, EXT2_SEEK_SET, NULL);
147*6a54128fSAndroid Build Coastguard Worker if (err) {
148*6a54128fSAndroid Build Coastguard Worker log_err("ext2fs_file_llseek failed: %ld", err);
149*6a54128fSAndroid Build Coastguard Worker return 0;
150*6a54128fSAndroid Build Coastguard Worker }
151*6a54128fSAndroid Build Coastguard Worker
152*6a54128fSAndroid Build Coastguard Worker err = ext2fs_file_write(e2_file, buf, size, &bytes_written);
153*6a54128fSAndroid Build Coastguard Worker if (err) {
154*6a54128fSAndroid Build Coastguard Worker log_err("ext2fs_file_write failed: %ld", err);
155*6a54128fSAndroid Build Coastguard Worker return 0;
156*6a54128fSAndroid Build Coastguard Worker }
157*6a54128fSAndroid Build Coastguard Worker
158*6a54128fSAndroid Build Coastguard Worker /* Correct inode.i_size is set in end_io. */
159*6a54128fSAndroid Build Coastguard Worker return bytes_written;
160*6a54128fSAndroid Build Coastguard Worker }
161*6a54128fSAndroid Build Coastguard Worker
quota_read_nomount(struct quota_file * qf,ext2_loff_t offset,void * buf,unsigned int size)162*6a54128fSAndroid Build Coastguard Worker static unsigned int quota_read_nomount(struct quota_file *qf,
163*6a54128fSAndroid Build Coastguard Worker ext2_loff_t offset,
164*6a54128fSAndroid Build Coastguard Worker void *buf, unsigned int size)
165*6a54128fSAndroid Build Coastguard Worker {
166*6a54128fSAndroid Build Coastguard Worker ext2_file_t e2_file = qf->e2_file;
167*6a54128fSAndroid Build Coastguard Worker unsigned int bytes_read = 0;
168*6a54128fSAndroid Build Coastguard Worker errcode_t err;
169*6a54128fSAndroid Build Coastguard Worker
170*6a54128fSAndroid Build Coastguard Worker err = ext2fs_file_llseek(e2_file, offset, EXT2_SEEK_SET, NULL);
171*6a54128fSAndroid Build Coastguard Worker if (err) {
172*6a54128fSAndroid Build Coastguard Worker log_err("ext2fs_file_llseek failed: %ld", err);
173*6a54128fSAndroid Build Coastguard Worker return 0;
174*6a54128fSAndroid Build Coastguard Worker }
175*6a54128fSAndroid Build Coastguard Worker
176*6a54128fSAndroid Build Coastguard Worker err = ext2fs_file_read(e2_file, buf, size, &bytes_read);
177*6a54128fSAndroid Build Coastguard Worker if (err) {
178*6a54128fSAndroid Build Coastguard Worker log_err("ext2fs_file_read failed: %ld", err);
179*6a54128fSAndroid Build Coastguard Worker return 0;
180*6a54128fSAndroid Build Coastguard Worker }
181*6a54128fSAndroid Build Coastguard Worker
182*6a54128fSAndroid Build Coastguard Worker return bytes_read;
183*6a54128fSAndroid Build Coastguard Worker }
184*6a54128fSAndroid Build Coastguard Worker
185*6a54128fSAndroid Build Coastguard Worker /*
186*6a54128fSAndroid Build Coastguard Worker * Detect quota format and initialize quota IO
187*6a54128fSAndroid Build Coastguard Worker */
quota_file_open(quota_ctx_t qctx,struct quota_handle * h,ext2_ino_t qf_ino,enum quota_type qtype,int fmt,int flags)188*6a54128fSAndroid Build Coastguard Worker errcode_t quota_file_open(quota_ctx_t qctx, struct quota_handle *h,
189*6a54128fSAndroid Build Coastguard Worker ext2_ino_t qf_ino, enum quota_type qtype,
190*6a54128fSAndroid Build Coastguard Worker int fmt, int flags)
191*6a54128fSAndroid Build Coastguard Worker {
192*6a54128fSAndroid Build Coastguard Worker ext2_filsys fs = qctx->fs;
193*6a54128fSAndroid Build Coastguard Worker ext2_file_t e2_file;
194*6a54128fSAndroid Build Coastguard Worker errcode_t err;
195*6a54128fSAndroid Build Coastguard Worker int allocated_handle = 0;
196*6a54128fSAndroid Build Coastguard Worker
197*6a54128fSAndroid Build Coastguard Worker if (qtype >= MAXQUOTAS)
198*6a54128fSAndroid Build Coastguard Worker return EINVAL;
199*6a54128fSAndroid Build Coastguard Worker
200*6a54128fSAndroid Build Coastguard Worker if (fmt == -1)
201*6a54128fSAndroid Build Coastguard Worker fmt = QFMT_VFS_V1;
202*6a54128fSAndroid Build Coastguard Worker
203*6a54128fSAndroid Build Coastguard Worker err = ext2fs_read_bitmaps(fs);
204*6a54128fSAndroid Build Coastguard Worker if (err)
205*6a54128fSAndroid Build Coastguard Worker return err;
206*6a54128fSAndroid Build Coastguard Worker
207*6a54128fSAndroid Build Coastguard Worker if (qf_ino == 0)
208*6a54128fSAndroid Build Coastguard Worker qf_ino = *quota_sb_inump(fs->super, qtype);
209*6a54128fSAndroid Build Coastguard Worker
210*6a54128fSAndroid Build Coastguard Worker log_debug("Opening quota ino=%u, type=%d", qf_ino, qtype);
211*6a54128fSAndroid Build Coastguard Worker err = ext2fs_file_open(fs, qf_ino, flags, &e2_file);
212*6a54128fSAndroid Build Coastguard Worker if (err) {
213*6a54128fSAndroid Build Coastguard Worker log_err("ext2fs_file_open failed: %s", error_message(err));
214*6a54128fSAndroid Build Coastguard Worker return err;
215*6a54128fSAndroid Build Coastguard Worker }
216*6a54128fSAndroid Build Coastguard Worker
217*6a54128fSAndroid Build Coastguard Worker if (!h) {
218*6a54128fSAndroid Build Coastguard Worker if (qctx->quota_file[qtype]) {
219*6a54128fSAndroid Build Coastguard Worker h = qctx->quota_file[qtype];
220*6a54128fSAndroid Build Coastguard Worker if (((flags & EXT2_FILE_WRITE) == 0) ||
221*6a54128fSAndroid Build Coastguard Worker (h->qh_file_flags & EXT2_FILE_WRITE)) {
222*6a54128fSAndroid Build Coastguard Worker ext2fs_file_close(e2_file);
223*6a54128fSAndroid Build Coastguard Worker return 0;
224*6a54128fSAndroid Build Coastguard Worker }
225*6a54128fSAndroid Build Coastguard Worker (void) quota_file_close(qctx, h);
226*6a54128fSAndroid Build Coastguard Worker }
227*6a54128fSAndroid Build Coastguard Worker err = ext2fs_get_mem(sizeof(struct quota_handle), &h);
228*6a54128fSAndroid Build Coastguard Worker if (err) {
229*6a54128fSAndroid Build Coastguard Worker log_err("Unable to allocate quota handle");
230*6a54128fSAndroid Build Coastguard Worker ext2fs_file_close(e2_file);
231*6a54128fSAndroid Build Coastguard Worker return err;
232*6a54128fSAndroid Build Coastguard Worker }
233*6a54128fSAndroid Build Coastguard Worker allocated_handle = 1;
234*6a54128fSAndroid Build Coastguard Worker }
235*6a54128fSAndroid Build Coastguard Worker
236*6a54128fSAndroid Build Coastguard Worker h->qh_qf.e2_file = e2_file;
237*6a54128fSAndroid Build Coastguard Worker h->qh_qf.fs = fs;
238*6a54128fSAndroid Build Coastguard Worker h->qh_qf.ino = qf_ino;
239*6a54128fSAndroid Build Coastguard Worker h->e2fs_write = quota_write_nomount;
240*6a54128fSAndroid Build Coastguard Worker h->e2fs_read = quota_read_nomount;
241*6a54128fSAndroid Build Coastguard Worker h->qh_file_flags = flags;
242*6a54128fSAndroid Build Coastguard Worker h->qh_io_flags = 0;
243*6a54128fSAndroid Build Coastguard Worker h->qh_type = qtype;
244*6a54128fSAndroid Build Coastguard Worker h->qh_fmt = fmt;
245*6a54128fSAndroid Build Coastguard Worker memset(&h->qh_info, 0, sizeof(h->qh_info));
246*6a54128fSAndroid Build Coastguard Worker h->qh_ops = "afile_ops_2;
247*6a54128fSAndroid Build Coastguard Worker
248*6a54128fSAndroid Build Coastguard Worker if (h->qh_ops->check_file &&
249*6a54128fSAndroid Build Coastguard Worker (h->qh_ops->check_file(h, qtype, fmt) == 0)) {
250*6a54128fSAndroid Build Coastguard Worker log_err("qh_ops->check_file failed");
251*6a54128fSAndroid Build Coastguard Worker err = EIO;
252*6a54128fSAndroid Build Coastguard Worker goto errout;
253*6a54128fSAndroid Build Coastguard Worker }
254*6a54128fSAndroid Build Coastguard Worker
255*6a54128fSAndroid Build Coastguard Worker if (h->qh_ops->init_io && (h->qh_ops->init_io(h) < 0)) {
256*6a54128fSAndroid Build Coastguard Worker log_err("qh_ops->init_io failed");
257*6a54128fSAndroid Build Coastguard Worker err = EIO;
258*6a54128fSAndroid Build Coastguard Worker goto errout;
259*6a54128fSAndroid Build Coastguard Worker }
260*6a54128fSAndroid Build Coastguard Worker if (allocated_handle)
261*6a54128fSAndroid Build Coastguard Worker qctx->quota_file[qtype] = h;
262*6a54128fSAndroid Build Coastguard Worker
263*6a54128fSAndroid Build Coastguard Worker return 0;
264*6a54128fSAndroid Build Coastguard Worker errout:
265*6a54128fSAndroid Build Coastguard Worker ext2fs_file_close(e2_file);
266*6a54128fSAndroid Build Coastguard Worker if (allocated_handle)
267*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&h);
268*6a54128fSAndroid Build Coastguard Worker return err;
269*6a54128fSAndroid Build Coastguard Worker }
270*6a54128fSAndroid Build Coastguard Worker
quota_inode_init_new(ext2_filsys fs,ext2_ino_t ino)271*6a54128fSAndroid Build Coastguard Worker static errcode_t quota_inode_init_new(ext2_filsys fs, ext2_ino_t ino)
272*6a54128fSAndroid Build Coastguard Worker {
273*6a54128fSAndroid Build Coastguard Worker struct ext2_inode inode;
274*6a54128fSAndroid Build Coastguard Worker errcode_t err = 0;
275*6a54128fSAndroid Build Coastguard Worker
276*6a54128fSAndroid Build Coastguard Worker err = ext2fs_read_inode(fs, ino, &inode);
277*6a54128fSAndroid Build Coastguard Worker if (err) {
278*6a54128fSAndroid Build Coastguard Worker log_err("ex2fs_read_inode failed");
279*6a54128fSAndroid Build Coastguard Worker return err;
280*6a54128fSAndroid Build Coastguard Worker }
281*6a54128fSAndroid Build Coastguard Worker
282*6a54128fSAndroid Build Coastguard Worker if (EXT2_I_SIZE(&inode)) {
283*6a54128fSAndroid Build Coastguard Worker err = quota_inode_truncate(fs, ino);
284*6a54128fSAndroid Build Coastguard Worker if (err)
285*6a54128fSAndroid Build Coastguard Worker return err;
286*6a54128fSAndroid Build Coastguard Worker }
287*6a54128fSAndroid Build Coastguard Worker
288*6a54128fSAndroid Build Coastguard Worker memset(&inode, 0, sizeof(struct ext2_inode));
289*6a54128fSAndroid Build Coastguard Worker ext2fs_iblk_set(fs, &inode, 0);
290*6a54128fSAndroid Build Coastguard Worker inode.i_atime = inode.i_mtime =
291*6a54128fSAndroid Build Coastguard Worker inode.i_ctime = fs->now ? fs->now : time(0);
292*6a54128fSAndroid Build Coastguard Worker inode.i_links_count = 1;
293*6a54128fSAndroid Build Coastguard Worker inode.i_mode = LINUX_S_IFREG | 0600;
294*6a54128fSAndroid Build Coastguard Worker inode.i_flags |= EXT2_IMMUTABLE_FL;
295*6a54128fSAndroid Build Coastguard Worker if (ext2fs_has_feature_extents(fs->super))
296*6a54128fSAndroid Build Coastguard Worker inode.i_flags |= EXT4_EXTENTS_FL;
297*6a54128fSAndroid Build Coastguard Worker
298*6a54128fSAndroid Build Coastguard Worker err = ext2fs_write_new_inode(fs, ino, &inode);
299*6a54128fSAndroid Build Coastguard Worker if (err) {
300*6a54128fSAndroid Build Coastguard Worker log_err("ext2fs_write_new_inode failed: %ld", err);
301*6a54128fSAndroid Build Coastguard Worker return err;
302*6a54128fSAndroid Build Coastguard Worker }
303*6a54128fSAndroid Build Coastguard Worker return err;
304*6a54128fSAndroid Build Coastguard Worker }
305*6a54128fSAndroid Build Coastguard Worker
306*6a54128fSAndroid Build Coastguard Worker /*
307*6a54128fSAndroid Build Coastguard Worker * Create new quotafile of specified format on given filesystem
308*6a54128fSAndroid Build Coastguard Worker */
quota_file_create(struct quota_handle * h,ext2_filsys fs,enum quota_type qtype,int fmt)309*6a54128fSAndroid Build Coastguard Worker errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs,
310*6a54128fSAndroid Build Coastguard Worker enum quota_type qtype, int fmt)
311*6a54128fSAndroid Build Coastguard Worker {
312*6a54128fSAndroid Build Coastguard Worker ext2_file_t e2_file;
313*6a54128fSAndroid Build Coastguard Worker errcode_t err;
314*6a54128fSAndroid Build Coastguard Worker ext2_ino_t qf_inum = 0;
315*6a54128fSAndroid Build Coastguard Worker
316*6a54128fSAndroid Build Coastguard Worker if (fmt == -1)
317*6a54128fSAndroid Build Coastguard Worker fmt = QFMT_VFS_V1;
318*6a54128fSAndroid Build Coastguard Worker
319*6a54128fSAndroid Build Coastguard Worker h->qh_qf.fs = fs;
320*6a54128fSAndroid Build Coastguard Worker qf_inum = quota_type2inum(qtype, fs->super);
321*6a54128fSAndroid Build Coastguard Worker if (qf_inum == 0 && qtype == PRJQUOTA) {
322*6a54128fSAndroid Build Coastguard Worker err = ext2fs_new_inode(fs, EXT2_ROOT_INO, LINUX_S_IFREG | 0600,
323*6a54128fSAndroid Build Coastguard Worker 0, &qf_inum);
324*6a54128fSAndroid Build Coastguard Worker if (err)
325*6a54128fSAndroid Build Coastguard Worker return err;
326*6a54128fSAndroid Build Coastguard Worker ext2fs_inode_alloc_stats2(fs, qf_inum, +1, 0);
327*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_ib_dirty(fs);
328*6a54128fSAndroid Build Coastguard Worker } else if (qf_inum == 0) {
329*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_BAD_INODE_NUM;
330*6a54128fSAndroid Build Coastguard Worker }
331*6a54128fSAndroid Build Coastguard Worker
332*6a54128fSAndroid Build Coastguard Worker err = ext2fs_read_bitmaps(fs);
333*6a54128fSAndroid Build Coastguard Worker if (err)
334*6a54128fSAndroid Build Coastguard Worker goto out_err;
335*6a54128fSAndroid Build Coastguard Worker
336*6a54128fSAndroid Build Coastguard Worker err = quota_inode_init_new(fs, qf_inum);
337*6a54128fSAndroid Build Coastguard Worker if (err) {
338*6a54128fSAndroid Build Coastguard Worker log_err("init_new_quota_inode failed");
339*6a54128fSAndroid Build Coastguard Worker goto out_err;
340*6a54128fSAndroid Build Coastguard Worker }
341*6a54128fSAndroid Build Coastguard Worker h->qh_qf.ino = qf_inum;
342*6a54128fSAndroid Build Coastguard Worker h->qh_file_flags = EXT2_FILE_WRITE | EXT2_FILE_CREATE;
343*6a54128fSAndroid Build Coastguard Worker h->e2fs_write = quota_write_nomount;
344*6a54128fSAndroid Build Coastguard Worker h->e2fs_read = quota_read_nomount;
345*6a54128fSAndroid Build Coastguard Worker
346*6a54128fSAndroid Build Coastguard Worker log_debug("Creating quota ino=%u, type=%d", qf_inum, qtype);
347*6a54128fSAndroid Build Coastguard Worker err = ext2fs_file_open(fs, qf_inum, h->qh_file_flags, &e2_file);
348*6a54128fSAndroid Build Coastguard Worker if (err) {
349*6a54128fSAndroid Build Coastguard Worker log_err("ext2fs_file_open failed: %ld", err);
350*6a54128fSAndroid Build Coastguard Worker goto out_err;
351*6a54128fSAndroid Build Coastguard Worker }
352*6a54128fSAndroid Build Coastguard Worker h->qh_qf.e2_file = e2_file;
353*6a54128fSAndroid Build Coastguard Worker
354*6a54128fSAndroid Build Coastguard Worker h->qh_io_flags = 0;
355*6a54128fSAndroid Build Coastguard Worker h->qh_type = qtype;
356*6a54128fSAndroid Build Coastguard Worker h->qh_fmt = fmt;
357*6a54128fSAndroid Build Coastguard Worker memset(&h->qh_info, 0, sizeof(h->qh_info));
358*6a54128fSAndroid Build Coastguard Worker h->qh_ops = "afile_ops_2;
359*6a54128fSAndroid Build Coastguard Worker
360*6a54128fSAndroid Build Coastguard Worker if (h->qh_ops->new_io && (h->qh_ops->new_io(h) < 0)) {
361*6a54128fSAndroid Build Coastguard Worker log_err("qh_ops->new_io failed");
362*6a54128fSAndroid Build Coastguard Worker err = EIO;
363*6a54128fSAndroid Build Coastguard Worker goto out_err1;
364*6a54128fSAndroid Build Coastguard Worker }
365*6a54128fSAndroid Build Coastguard Worker
366*6a54128fSAndroid Build Coastguard Worker return 0;
367*6a54128fSAndroid Build Coastguard Worker
368*6a54128fSAndroid Build Coastguard Worker out_err1:
369*6a54128fSAndroid Build Coastguard Worker ext2fs_file_close(e2_file);
370*6a54128fSAndroid Build Coastguard Worker out_err:
371*6a54128fSAndroid Build Coastguard Worker
372*6a54128fSAndroid Build Coastguard Worker if (qf_inum)
373*6a54128fSAndroid Build Coastguard Worker quota_inode_truncate(fs, qf_inum);
374*6a54128fSAndroid Build Coastguard Worker
375*6a54128fSAndroid Build Coastguard Worker return err;
376*6a54128fSAndroid Build Coastguard Worker }
377*6a54128fSAndroid Build Coastguard Worker
378*6a54128fSAndroid Build Coastguard Worker /*
379*6a54128fSAndroid Build Coastguard Worker * Close quotafile and release handle
380*6a54128fSAndroid Build Coastguard Worker */
quota_file_close(quota_ctx_t qctx,struct quota_handle * h)381*6a54128fSAndroid Build Coastguard Worker errcode_t quota_file_close(quota_ctx_t qctx, struct quota_handle *h)
382*6a54128fSAndroid Build Coastguard Worker {
383*6a54128fSAndroid Build Coastguard Worker if (h->qh_io_flags & IOFL_INFODIRTY) {
384*6a54128fSAndroid Build Coastguard Worker if (h->qh_ops->write_info && h->qh_ops->write_info(h) < 0)
385*6a54128fSAndroid Build Coastguard Worker return EIO;
386*6a54128fSAndroid Build Coastguard Worker h->qh_io_flags &= ~IOFL_INFODIRTY;
387*6a54128fSAndroid Build Coastguard Worker }
388*6a54128fSAndroid Build Coastguard Worker
389*6a54128fSAndroid Build Coastguard Worker if (h->qh_ops->end_io && h->qh_ops->end_io(h) < 0)
390*6a54128fSAndroid Build Coastguard Worker return EIO;
391*6a54128fSAndroid Build Coastguard Worker if (h->qh_qf.e2_file)
392*6a54128fSAndroid Build Coastguard Worker ext2fs_file_close(h->qh_qf.e2_file);
393*6a54128fSAndroid Build Coastguard Worker if (qctx->quota_file[h->qh_type] == h)
394*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&qctx->quota_file[h->qh_type]);
395*6a54128fSAndroid Build Coastguard Worker return 0;
396*6a54128fSAndroid Build Coastguard Worker }
397*6a54128fSAndroid Build Coastguard Worker
398*6a54128fSAndroid Build Coastguard Worker /*
399*6a54128fSAndroid Build Coastguard Worker * Create empty quota structure
400*6a54128fSAndroid Build Coastguard Worker */
get_empty_dquot(void)401*6a54128fSAndroid Build Coastguard Worker struct dquot *get_empty_dquot(void)
402*6a54128fSAndroid Build Coastguard Worker {
403*6a54128fSAndroid Build Coastguard Worker struct dquot *dquot;
404*6a54128fSAndroid Build Coastguard Worker
405*6a54128fSAndroid Build Coastguard Worker if (ext2fs_get_memzero(sizeof(struct dquot), &dquot)) {
406*6a54128fSAndroid Build Coastguard Worker log_err("Failed to allocate dquot");
407*6a54128fSAndroid Build Coastguard Worker return NULL;
408*6a54128fSAndroid Build Coastguard Worker }
409*6a54128fSAndroid Build Coastguard Worker
410*6a54128fSAndroid Build Coastguard Worker dquot->dq_id = -1;
411*6a54128fSAndroid Build Coastguard Worker return dquot;
412*6a54128fSAndroid Build Coastguard Worker }
413