xref: /openbmc/linux/fs/adfs/inode.c (revision 02d89917)
1  // SPDX-License-Identifier: GPL-2.0-only
2  /*
3   *  linux/fs/adfs/inode.c
4   *
5   *  Copyright (C) 1997-1999 Russell King
6   */
7  #include <linux/buffer_head.h>
8  #include <linux/writeback.h>
9  #include "adfs.h"
10  
11  /*
12   * Lookup/Create a block at offset 'block' into 'inode'.  We currently do
13   * not support creation of new blocks, so we return -EIO for this case.
14   */
15  static int
16  adfs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh,
17  	       int create)
18  {
19  	if (!create) {
20  		if (block >= inode->i_blocks)
21  			goto abort_toobig;
22  
23  		block = __adfs_block_map(inode->i_sb, ADFS_I(inode)->indaddr,
24  					 block);
25  		if (block)
26  			map_bh(bh, inode->i_sb, block);
27  		return 0;
28  	}
29  	/* don't support allocation of blocks yet */
30  	return -EIO;
31  
32  abort_toobig:
33  	return 0;
34  }
35  
36  static int adfs_writepage(struct page *page, struct writeback_control *wbc)
37  {
38  	return block_write_full_page(page, adfs_get_block, wbc);
39  }
40  
41  static int adfs_read_folio(struct file *file, struct folio *folio)
42  {
43  	return block_read_full_folio(folio, adfs_get_block);
44  }
45  
46  static void adfs_write_failed(struct address_space *mapping, loff_t to)
47  {
48  	struct inode *inode = mapping->host;
49  
50  	if (to > inode->i_size)
51  		truncate_pagecache(inode, inode->i_size);
52  }
53  
54  static int adfs_write_begin(struct file *file, struct address_space *mapping,
55  			loff_t pos, unsigned len,
56  			struct page **pagep, void **fsdata)
57  {
58  	int ret;
59  
60  	*pagep = NULL;
61  	ret = cont_write_begin(file, mapping, pos, len, pagep, fsdata,
62  				adfs_get_block,
63  				&ADFS_I(mapping->host)->mmu_private);
64  	if (unlikely(ret))
65  		adfs_write_failed(mapping, pos + len);
66  
67  	return ret;
68  }
69  
70  static sector_t _adfs_bmap(struct address_space *mapping, sector_t block)
71  {
72  	return generic_block_bmap(mapping, block, adfs_get_block);
73  }
74  
75  static const struct address_space_operations adfs_aops = {
76  	.dirty_folio	= block_dirty_folio,
77  	.invalidate_folio = block_invalidate_folio,
78  	.read_folio	= adfs_read_folio,
79  	.writepage	= adfs_writepage,
80  	.write_begin	= adfs_write_begin,
81  	.write_end	= generic_write_end,
82  	.bmap		= _adfs_bmap
83  };
84  
85  /*
86   * Convert ADFS attributes and filetype to Linux permission.
87   */
88  static umode_t
89  adfs_atts2mode(struct super_block *sb, struct inode *inode)
90  {
91  	unsigned int attr = ADFS_I(inode)->attr;
92  	umode_t mode, rmask;
93  	struct adfs_sb_info *asb = ADFS_SB(sb);
94  
95  	if (attr & ADFS_NDA_DIRECTORY) {
96  		mode = S_IRUGO & asb->s_owner_mask;
97  		return S_IFDIR | S_IXUGO | mode;
98  	}
99  
100  	switch (adfs_filetype(ADFS_I(inode)->loadaddr)) {
101  	case 0xfc0:	/* LinkFS */
102  		return S_IFLNK|S_IRWXUGO;
103  
104  	case 0xfe6:	/* UnixExec */
105  		rmask = S_IRUGO | S_IXUGO;
106  		break;
107  
108  	default:
109  		rmask = S_IRUGO;
110  	}
111  
112  	mode = S_IFREG;
113  
114  	if (attr & ADFS_NDA_OWNER_READ)
115  		mode |= rmask & asb->s_owner_mask;
116  
117  	if (attr & ADFS_NDA_OWNER_WRITE)
118  		mode |= S_IWUGO & asb->s_owner_mask;
119  
120  	if (attr & ADFS_NDA_PUBLIC_READ)
121  		mode |= rmask & asb->s_other_mask;
122  
123  	if (attr & ADFS_NDA_PUBLIC_WRITE)
124  		mode |= S_IWUGO & asb->s_other_mask;
125  	return mode;
126  }
127  
128  /*
129   * Convert Linux permission to ADFS attribute.  We try to do the reverse
130   * of atts2mode, but there is not a 1:1 translation.
131   */
132  static int adfs_mode2atts(struct super_block *sb, struct inode *inode,
133  			  umode_t ia_mode)
134  {
135  	struct adfs_sb_info *asb = ADFS_SB(sb);
136  	umode_t mode;
137  	int attr;
138  
139  	/* FIXME: should we be able to alter a link? */
140  	if (S_ISLNK(inode->i_mode))
141  		return ADFS_I(inode)->attr;
142  
143  	/* Directories do not have read/write permissions on the media */
144  	if (S_ISDIR(inode->i_mode))
145  		return ADFS_NDA_DIRECTORY;
146  
147  	attr = 0;
148  	mode = ia_mode & asb->s_owner_mask;
149  	if (mode & S_IRUGO)
150  		attr |= ADFS_NDA_OWNER_READ;
151  	if (mode & S_IWUGO)
152  		attr |= ADFS_NDA_OWNER_WRITE;
153  
154  	mode = ia_mode & asb->s_other_mask;
155  	mode &= ~asb->s_owner_mask;
156  	if (mode & S_IRUGO)
157  		attr |= ADFS_NDA_PUBLIC_READ;
158  	if (mode & S_IWUGO)
159  		attr |= ADFS_NDA_PUBLIC_WRITE;
160  
161  	return attr;
162  }
163  
164  static const s64 nsec_unix_epoch_diff_risc_os_epoch = 2208988800000000000LL;
165  
166  /*
167   * Convert an ADFS time to Unix time.  ADFS has a 40-bit centi-second time
168   * referenced to 1 Jan 1900 (til 2248) so we need to discard 2208988800 seconds
169   * of time to convert from RISC OS epoch to Unix epoch.
170   */
171  static void
172  adfs_adfs2unix_time(struct timespec64 *tv, struct inode *inode)
173  {
174  	unsigned int high, low;
175  	/* 01 Jan 1970 00:00:00 (Unix epoch) as nanoseconds since
176  	 * 01 Jan 1900 00:00:00 (RISC OS epoch)
177  	 */
178  	s64 nsec;
179  
180  	if (!adfs_inode_is_stamped(inode))
181  		goto cur_time;
182  
183  	high = ADFS_I(inode)->loadaddr & 0xFF; /* top 8 bits of timestamp */
184  	low  = ADFS_I(inode)->execaddr;    /* bottom 32 bits of timestamp */
185  
186  	/* convert 40-bit centi-seconds to 32-bit seconds
187  	 * going via nanoseconds to retain precision
188  	 */
189  	nsec = (((s64) high << 32) | (s64) low) * 10000000; /* cs to ns */
190  
191  	/* Files dated pre  01 Jan 1970 00:00:00. */
192  	if (nsec < nsec_unix_epoch_diff_risc_os_epoch)
193  		goto too_early;
194  
195  	/* convert from RISC OS to Unix epoch */
196  	nsec -= nsec_unix_epoch_diff_risc_os_epoch;
197  
198  	*tv = ns_to_timespec64(nsec);
199  	return;
200  
201   cur_time:
202  	*tv = current_time(inode);
203  	return;
204  
205   too_early:
206  	tv->tv_sec = tv->tv_nsec = 0;
207  	return;
208  }
209  
210  /* Convert an Unix time to ADFS time for an entry that is already stamped. */
211  static void adfs_unix2adfs_time(struct inode *inode,
212  				const struct timespec64 *ts)
213  {
214  	s64 cs, nsec = timespec64_to_ns(ts);
215  
216  	/* convert from Unix to RISC OS epoch */
217  	nsec += nsec_unix_epoch_diff_risc_os_epoch;
218  
219  	/* convert from nanoseconds to centiseconds */
220  	cs = div_s64(nsec, 10000000);
221  
222  	cs = clamp_t(s64, cs, 0, 0xffffffffff);
223  
224  	ADFS_I(inode)->loadaddr &= ~0xff;
225  	ADFS_I(inode)->loadaddr |= (cs >> 32) & 0xff;
226  	ADFS_I(inode)->execaddr = cs;
227  }
228  
229  /*
230   * Fill in the inode information from the object information.
231   *
232   * Note that this is an inode-less filesystem, so we can't use the inode
233   * number to reference the metadata on the media.  Instead, we use the
234   * inode number to hold the object ID, which in turn will tell us where
235   * the data is held.  We also save the parent object ID, and with these
236   * two, we can locate the metadata.
237   *
238   * This does mean that we rely on an objects parent remaining the same at
239   * all times - we cannot cope with a cross-directory rename (yet).
240   */
241  struct inode *
242  adfs_iget(struct super_block *sb, struct object_info *obj)
243  {
244  	struct inode *inode;
245  
246  	inode = new_inode(sb);
247  	if (!inode)
248  		goto out;
249  
250  	inode->i_uid	 = ADFS_SB(sb)->s_uid;
251  	inode->i_gid	 = ADFS_SB(sb)->s_gid;
252  	inode->i_ino	 = obj->indaddr;
253  	inode->i_size	 = obj->size;
254  	set_nlink(inode, 2);
255  	inode->i_blocks	 = (inode->i_size + sb->s_blocksize - 1) >>
256  			    sb->s_blocksize_bits;
257  
258  	/*
259  	 * we need to save the parent directory ID so that
260  	 * write_inode can update the directory information
261  	 * for this file.  This will need special handling
262  	 * for cross-directory renames.
263  	 */
264  	ADFS_I(inode)->parent_id = obj->parent_id;
265  	ADFS_I(inode)->indaddr   = obj->indaddr;
266  	ADFS_I(inode)->loadaddr  = obj->loadaddr;
267  	ADFS_I(inode)->execaddr  = obj->execaddr;
268  	ADFS_I(inode)->attr      = obj->attr;
269  
270  	inode->i_mode	 = adfs_atts2mode(sb, inode);
271  	adfs_adfs2unix_time(&inode->i_mtime, inode);
272  	inode->i_atime = inode->i_mtime;
273  	inode_set_ctime_to_ts(inode, inode->i_mtime);
274  
275  	if (S_ISDIR(inode->i_mode)) {
276  		inode->i_op	= &adfs_dir_inode_operations;
277  		inode->i_fop	= &adfs_dir_operations;
278  	} else if (S_ISREG(inode->i_mode)) {
279  		inode->i_op	= &adfs_file_inode_operations;
280  		inode->i_fop	= &adfs_file_operations;
281  		inode->i_mapping->a_ops = &adfs_aops;
282  		ADFS_I(inode)->mmu_private = inode->i_size;
283  	}
284  
285  	inode_fake_hash(inode);
286  
287  out:
288  	return inode;
289  }
290  
291  /*
292   * Validate and convert a changed access mode/time to their ADFS equivalents.
293   * adfs_write_inode will actually write the information back to the directory
294   * later.
295   */
296  int
297  adfs_notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
298  		   struct iattr *attr)
299  {
300  	struct inode *inode = d_inode(dentry);
301  	struct super_block *sb = inode->i_sb;
302  	unsigned int ia_valid = attr->ia_valid;
303  	int error;
304  
305  	error = setattr_prepare(&nop_mnt_idmap, dentry, attr);
306  
307  	/*
308  	 * we can't change the UID or GID of any file -
309  	 * we have a global UID/GID in the superblock
310  	 */
311  	if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, ADFS_SB(sb)->s_uid)) ||
312  	    (ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, ADFS_SB(sb)->s_gid)))
313  		error = -EPERM;
314  
315  	if (error)
316  		goto out;
317  
318  	/* XXX: this is missing some actual on-disk truncation.. */
319  	if (ia_valid & ATTR_SIZE)
320  		truncate_setsize(inode, attr->ia_size);
321  
322  	if (ia_valid & ATTR_MTIME && adfs_inode_is_stamped(inode)) {
323  		adfs_unix2adfs_time(inode, &attr->ia_mtime);
324  		adfs_adfs2unix_time(&inode->i_mtime, inode);
325  	}
326  
327  	/*
328  	 * FIXME: should we make these == to i_mtime since we don't
329  	 * have the ability to represent them in our filesystem?
330  	 */
331  	if (ia_valid & ATTR_ATIME)
332  		inode->i_atime = attr->ia_atime;
333  	if (ia_valid & ATTR_CTIME)
334  		inode_set_ctime_to_ts(inode, attr->ia_ctime);
335  	if (ia_valid & ATTR_MODE) {
336  		ADFS_I(inode)->attr = adfs_mode2atts(sb, inode, attr->ia_mode);
337  		inode->i_mode = adfs_atts2mode(sb, inode);
338  	}
339  
340  	/*
341  	 * FIXME: should we be marking this inode dirty even if
342  	 * we don't have any metadata to write back?
343  	 */
344  	if (ia_valid & (ATTR_SIZE | ATTR_MTIME | ATTR_MODE))
345  		mark_inode_dirty(inode);
346  out:
347  	return error;
348  }
349  
350  /*
351   * write an existing inode back to the directory, and therefore the disk.
352   * The adfs-specific inode data has already been updated by
353   * adfs_notify_change()
354   */
355  int adfs_write_inode(struct inode *inode, struct writeback_control *wbc)
356  {
357  	struct super_block *sb = inode->i_sb;
358  	struct object_info obj;
359  
360  	obj.indaddr	= ADFS_I(inode)->indaddr;
361  	obj.name_len	= 0;
362  	obj.parent_id	= ADFS_I(inode)->parent_id;
363  	obj.loadaddr	= ADFS_I(inode)->loadaddr;
364  	obj.execaddr	= ADFS_I(inode)->execaddr;
365  	obj.attr	= ADFS_I(inode)->attr;
366  	obj.size	= inode->i_size;
367  
368  	return adfs_dir_update(sb, &obj, wbc->sync_mode == WB_SYNC_ALL);
369  }
370