~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/adfs/inode.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  linux/fs/adfs/inode.c
  3  *
  4  *  Copyright (C) 1997-1999 Russell King
  5  *
  6  * This program is free software; you can redistribute it and/or modify
  7  * it under the terms of the GNU General Public License version 2 as
  8  * published by the Free Software Foundation.
  9  */
 10 #include <linux/version.h>
 11 #include <linux/errno.h>
 12 #include <linux/fs.h>
 13 #include <linux/adfs_fs.h>
 14 #include <linux/sched.h>
 15 #include <linux/stat.h>
 16 #include <linux/string.h>
 17 #include <linux/locks.h>
 18 #include <linux/mm.h>
 19 #include <linux/smp_lock.h>
 20 
 21 #include "adfs.h"
 22 
 23 /*
 24  * Lookup/Create a block at offset 'block' into 'inode'.  We currently do
 25  * not support creation of new blocks, so we return -EIO for this case.
 26  */
 27 int
 28 adfs_get_block(struct inode *inode, long block, struct buffer_head *bh, int create)
 29 {
 30         if (block < 0)
 31                 goto abort_negative;
 32 
 33         if (!create) {
 34                 if (block >= inode->i_blocks)
 35                         goto abort_toobig;
 36 
 37                 block = __adfs_block_map(inode->i_sb, inode->i_ino, block);
 38                 if (block) {
 39                         bh->b_dev = inode->i_dev;
 40                         bh->b_blocknr = block;
 41                         bh->b_state |= (1UL << BH_Mapped);
 42                 }
 43                 return 0;
 44         }
 45         /* don't support allocation of blocks yet */
 46         return -EIO;
 47 
 48 abort_negative:
 49         adfs_error(inode->i_sb, "block %d < 0", block);
 50         return -EIO;
 51 
 52 abort_toobig:
 53         return 0;
 54 }
 55 
 56 static int adfs_writepage(struct page *page)
 57 {
 58         return block_write_full_page(page, adfs_get_block);
 59 }
 60 
 61 static int adfs_readpage(struct file *file, struct page *page)
 62 {
 63         return block_read_full_page(page, adfs_get_block);
 64 }
 65 
 66 static int adfs_prepare_write(struct file *file, struct page *page, unsigned int from, unsigned int to)
 67 {
 68         return cont_prepare_write(page, from, to, adfs_get_block,
 69                 &page->mapping->host->u.adfs_i.mmu_private);
 70 }
 71 
 72 static int _adfs_bmap(struct address_space *mapping, long block)
 73 {
 74         return generic_block_bmap(mapping, block, adfs_get_block);
 75 }
 76 
 77 static struct address_space_operations adfs_aops = {
 78         readpage:       adfs_readpage,
 79         writepage:      adfs_writepage,
 80         sync_page:      block_sync_page,
 81         prepare_write:  adfs_prepare_write,
 82         commit_write:   generic_commit_write,
 83         bmap:           _adfs_bmap
 84 };
 85 
 86 static inline unsigned int
 87 adfs_filetype(struct inode *inode)
 88 {
 89         unsigned int type;
 90 
 91         if (inode->u.adfs_i.stamped)
 92                 type = (inode->u.adfs_i.loadaddr >> 8) & 0xfff;
 93         else
 94                 type = (unsigned int) -1;
 95 
 96         return type;
 97 }
 98 
 99 /*
100  * Convert ADFS attributes and filetype to Linux permission.
101  */
102 static umode_t
103 adfs_atts2mode(struct super_block *sb, struct inode *inode)
104 {
105         unsigned int filetype, attr = inode->u.adfs_i.attr;
106         umode_t mode, rmask;
107 
108         if (attr & ADFS_NDA_DIRECTORY) {
109                 mode = S_IRUGO & sb->u.adfs_sb.s_owner_mask;
110                 return S_IFDIR | S_IXUGO | mode;
111         }
112 
113         filetype = adfs_filetype(inode);
114 
115         switch (filetype) {
116         case 0xfc0:     /* LinkFS */
117                 return S_IFLNK|S_IRWXUGO;
118 
119         case 0xfe6:     /* UnixExec */
120                 rmask = S_IRUGO | S_IXUGO;
121                 break;
122 
123         default:
124                 rmask = S_IRUGO;
125         }
126 
127         mode = S_IFREG;
128 
129         if (attr & ADFS_NDA_OWNER_READ)
130                 mode |= rmask & sb->u.adfs_sb.s_owner_mask;
131 
132         if (attr & ADFS_NDA_OWNER_WRITE)
133                 mode |= S_IWUGO & sb->u.adfs_sb.s_owner_mask;
134 
135         if (attr & ADFS_NDA_PUBLIC_READ)
136                 mode |= rmask & sb->u.adfs_sb.s_other_mask;
137 
138         if (attr & ADFS_NDA_PUBLIC_WRITE)
139                 mode |= S_IWUGO & sb->u.adfs_sb.s_other_mask;
140         return mode;
141 }
142 
143 /*
144  * Convert Linux permission to ADFS attribute.  We try to do the reverse
145  * of atts2mode, but there is not a 1:1 translation.
146  */
147 static int
148 adfs_mode2atts(struct super_block *sb, struct inode *inode)
149 {
150         umode_t mode;
151         int attr;
152 
153         /* FIXME: should we be able to alter a link? */
154         if (S_ISLNK(inode->i_mode))
155                 return inode->u.adfs_i.attr;
156 
157         if (S_ISDIR(inode->i_mode))
158                 attr = ADFS_NDA_DIRECTORY;
159         else
160                 attr = 0;
161 
162         mode = inode->i_mode & sb->u.adfs_sb.s_owner_mask;
163         if (mode & S_IRUGO)
164                 attr |= ADFS_NDA_OWNER_READ;
165         if (mode & S_IWUGO)
166                 attr |= ADFS_NDA_OWNER_WRITE;
167 
168         mode = inode->i_mode & sb->u.adfs_sb.s_other_mask;
169         mode &= ~sb->u.adfs_sb.s_owner_mask;
170         if (mode & S_IRUGO)
171                 attr |= ADFS_NDA_PUBLIC_READ;
172         if (mode & S_IWUGO)
173                 attr |= ADFS_NDA_PUBLIC_WRITE;
174 
175         return attr;
176 }
177 
178 /*
179  * Convert an ADFS time to Unix time.  ADFS has a 40-bit centi-second time
180  * referenced to 1 Jan 1900 (til 2248)
181  */
182 static unsigned int
183 adfs_adfs2unix_time(struct inode *inode)
184 {
185         unsigned int high, low;
186 
187         if (inode->u.adfs_i.stamped == 0)
188                 return CURRENT_TIME;
189 
190         high = inode->u.adfs_i.loadaddr << 24;
191         low  = inode->u.adfs_i.execaddr;
192 
193         high |= low >> 8;
194         low  &= 255;
195 
196         /* Files dated pre  01 Jan 1970 00:00:00. */
197         if (high < 0x336e996a)
198                 return 0;
199 
200         /* Files dated post 18 Jan 2038 03:14:05. */
201         if (high >= 0x656e9969)
202                 return 0x7ffffffd;
203 
204         /* discard 2208988800 (0x336e996a00) seconds of time */
205         high -= 0x336e996a;
206 
207         /* convert 40-bit centi-seconds to 32-bit seconds */
208         return (((high % 100) << 8) + low) / 100 + (high / 100 << 8);
209 }
210 
211 /*
212  * Convert an Unix time to ADFS time.  We only do this if the entry has a
213  * time/date stamp already.
214  */
215 static void
216 adfs_unix2adfs_time(struct inode *inode, unsigned int secs)
217 {
218         unsigned int high, low;
219 
220         if (inode->u.adfs_i.stamped) {
221                 /* convert 32-bit seconds to 40-bit centi-seconds */
222                 low  = (secs & 255) * 100;
223                 high = (secs / 256) * 100 + (low << 8) + 0x336e996a;
224 
225                 inode->u.adfs_i.loadaddr = (high >> 24) |
226                                 (inode->u.adfs_i.loadaddr & ~0xff);
227                 inode->u.adfs_i.execaddr = (low & 255) | (high << 8);
228         }
229 }
230 
231 /*
232  * Fill in the inode information from the object information.
233  *
234  * Note that this is an inode-less filesystem, so we can't use the inode
235  * number to reference the metadata on the media.  Instead, we use the
236  * inode number to hold the object ID, which in turn will tell us where
237  * the data is held.  We also save the parent object ID, and with these
238  * two, we can locate the metadata.
239  *
240  * This does mean that we rely on an objects parent remaining the same at
241  * all times - we cannot cope with a cross-directory rename (yet).
242  */
243 struct inode *
244 adfs_iget(struct super_block *sb, struct object_info *obj)
245 {
246         struct inode *inode;
247 
248         inode = new_inode(sb);
249         if (!inode)
250                 goto out;
251 
252         inode->i_version = ++event;
253         inode->i_uid     = sb->u.adfs_sb.s_uid;
254         inode->i_gid     = sb->u.adfs_sb.s_gid;
255         inode->i_ino     = obj->file_id;
256         inode->i_size    = obj->size;
257         inode->i_nlink   = 2;
258         inode->i_blksize = PAGE_SIZE;
259         inode->i_blocks  = (inode->i_size + sb->s_blocksize - 1) >>
260                             sb->s_blocksize_bits;
261 
262         /*
263          * we need to save the parent directory ID so that
264          * write_inode can update the directory information
265          * for this file.  This will need special handling
266          * for cross-directory renames.
267          */
268         inode->u.adfs_i.parent_id = obj->parent_id;
269         inode->u.adfs_i.loadaddr  = obj->loadaddr;
270         inode->u.adfs_i.execaddr  = obj->execaddr;
271         inode->u.adfs_i.attr      = obj->attr;
272         inode->u.adfs_i.stamped   = ((obj->loadaddr & 0xfff00000) == 0xfff00000);
273 
274         inode->i_mode    = adfs_atts2mode(sb, inode);
275         inode->i_mtime   =
276         inode->i_atime   =
277         inode->i_ctime   = adfs_adfs2unix_time(inode);
278 
279         if (S_ISDIR(inode->i_mode)) {
280                 inode->i_op     = &adfs_dir_inode_operations;
281                 inode->i_fop    = &adfs_dir_operations;
282         } else if (S_ISREG(inode->i_mode)) {
283                 inode->i_op     = &adfs_file_inode_operations;
284                 inode->i_fop    = &adfs_file_operations;
285                 inode->i_mapping->a_ops = &adfs_aops;
286                 inode->u.adfs_i.mmu_private = inode->i_size;
287         }
288 
289         insert_inode_hash(inode);
290 
291 out:
292         return inode;
293 }
294 
295 /*
296  * Validate and convert a changed access mode/time to their ADFS equivalents.
297  * adfs_write_inode will actually write the information back to the directory
298  * later.
299  */
300 int
301 adfs_notify_change(struct dentry *dentry, struct iattr *attr)
302 {
303         struct inode *inode = dentry->d_inode;
304         struct super_block *sb = inode->i_sb;
305         unsigned int ia_valid = attr->ia_valid;
306         int error;
307 
308         error = inode_change_ok(inode, attr);
309 
310         /*
311          * we can't change the UID or GID of any file -
312          * we have a global UID/GID in the superblock
313          */
314         if ((ia_valid & ATTR_UID && attr->ia_uid != sb->u.adfs_sb.s_uid) ||
315             (ia_valid & ATTR_GID && attr->ia_gid != sb->u.adfs_sb.s_gid))
316                 error = -EPERM;
317 
318         if (error)
319                 goto out;
320 
321         if (ia_valid & ATTR_SIZE)
322                 vmtruncate(inode, attr->ia_size);
323         if (ia_valid & ATTR_MTIME) {
324                 inode->i_mtime = attr->ia_mtime;
325                 adfs_unix2adfs_time(inode, attr->ia_mtime);
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->i_ctime = attr->ia_ctime;
335         if (ia_valid & ATTR_MODE) {
336                 inode->u.adfs_i.attr = adfs_mode2atts(sb, inode);
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 void adfs_write_inode(struct inode *inode, int unused)
356 {
357         struct super_block *sb = inode->i_sb;
358         struct object_info obj;
359 
360         lock_kernel();
361         obj.file_id     = inode->i_ino;
362         obj.name_len    = 0;
363         obj.parent_id   = inode->u.adfs_i.parent_id;
364         obj.loadaddr    = inode->u.adfs_i.loadaddr;
365         obj.execaddr    = inode->u.adfs_i.execaddr;
366         obj.attr        = inode->u.adfs_i.attr;
367         obj.size        = inode->i_size;
368 
369         adfs_dir_update(sb, &obj);
370         unlock_kernel();
371 }
372 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.