L4Re/departure

libext2fs/lib/libsupport/quotaio.c

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