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