1 /* This file contains file metadata retrieval and manipulation routines. 2 * 3 * The entry points into this file are: 4 * get_mode return a file's mode 5 * do_stat perform the STAT file system call 6 * do_chmod perform the CHMOD file system call 7 * do_utime perform the UTIME file system call 8 * 9 * Created: 10 * April 2009 (D.C. van Moolenbroek) 11 */ 12 13 #include "inc.h" 14 15 /*===========================================================================* 16 * get_mode * 17 *===========================================================================*/ 18 mode_t get_mode(struct inode *ino, int mode) 19 { 20 /* Return the mode for an inode, given the inode and the retrieved mode. 21 */ 22 23 mode &= S_IRWXU; 24 mode = mode | (mode >> 3) | (mode >> 6); 25 26 if (IS_DIR(ino)) 27 mode = S_IFDIR | (mode & sffs_params->p_dir_mask); 28 else 29 mode = S_IFREG | (mode & sffs_params->p_file_mask); 30 31 if (state.s_read_only) 32 mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); 33 34 return mode; 35 } 36 37 /*===========================================================================* 38 * do_stat * 39 *===========================================================================*/ 40 int do_stat(ino_t ino_nr, struct stat *stat) 41 { 42 /* Retrieve inode status. 43 */ 44 struct inode *ino; 45 struct sffs_attr attr; 46 char path[PATH_MAX]; 47 int r; 48 49 /* Don't increase the inode refcount: it's already open anyway */ 50 if ((ino = find_inode(ino_nr)) == NULL) 51 return EINVAL; 52 53 attr.a_mask = SFFS_ATTR_MODE | SFFS_ATTR_SIZE | SFFS_ATTR_CRTIME | 54 SFFS_ATTR_ATIME | SFFS_ATTR_MTIME | SFFS_ATTR_CTIME; 55 56 if ((r = verify_inode(ino, path, &attr)) != OK) 57 return r; 58 59 stat->st_dev = state.s_dev; 60 stat->st_ino = ino_nr; 61 stat->st_mode = get_mode(ino, attr.a_mode); 62 stat->st_uid = sffs_params->p_uid; 63 stat->st_gid = sffs_params->p_gid; 64 stat->st_rdev = NO_DEV; 65 stat->st_size = attr.a_size; 66 stat->st_atimespec = attr.a_atime; 67 stat->st_mtimespec = attr.a_mtime; 68 stat->st_ctimespec = attr.a_ctime; 69 stat->st_birthtimespec = attr.a_crtime; 70 71 stat->st_blocks = stat->st_size / S_BLKSIZE; 72 if (stat->st_size % S_BLKSIZE != 0) 73 stat->st_blocks += 1; 74 75 stat->st_blksize = BLOCK_SIZE; 76 77 /* We could make this more accurate by iterating over directory inodes' 78 * children, counting how many of those are directories as well. 79 * It's just not worth it. 80 */ 81 stat->st_nlink = 0; 82 if (ino->i_parent != NULL) stat->st_nlink++; 83 if (IS_DIR(ino)) { 84 stat->st_nlink++; 85 if (HAS_CHILDREN(ino)) stat->st_nlink++; 86 } 87 88 return OK; 89 } 90 91 /*===========================================================================* 92 * do_chmod * 93 *===========================================================================*/ 94 int do_chmod(ino_t ino_nr, mode_t *mode) 95 { 96 /* Change file mode. 97 */ 98 struct inode *ino; 99 char path[PATH_MAX]; 100 struct sffs_attr attr; 101 int r; 102 103 if (state.s_read_only) 104 return EROFS; 105 106 if ((ino = find_inode(ino_nr)) == NULL) 107 return EINVAL; 108 109 if ((r = verify_inode(ino, path, NULL)) != OK) 110 return r; 111 112 /* Set the new file mode. */ 113 attr.a_mask = SFFS_ATTR_MODE; 114 attr.a_mode = *mode; /* no need to convert in this direction */ 115 116 if ((r = sffs_table->t_setattr(path, &attr)) != OK) 117 return r; 118 119 /* We have no idea what really happened. Query for the mode again. */ 120 if ((r = verify_path(path, ino, &attr, NULL)) != OK) 121 return r; 122 123 *mode = get_mode(ino, attr.a_mode); 124 125 return OK; 126 } 127 128 /*===========================================================================* 129 * do_utime * 130 *===========================================================================*/ 131 int do_utime(ino_t ino_nr, struct timespec *atime, struct timespec *mtime) 132 { 133 /* Set file times. 134 */ 135 struct inode *ino; 136 char path[PATH_MAX]; 137 struct sffs_attr attr; 138 int r; 139 140 if (state.s_read_only) 141 return EROFS; 142 143 if ((ino = find_inode(ino_nr)) == NULL) 144 return EINVAL; 145 146 if ((r = verify_inode(ino, path, NULL)) != OK) 147 return r; 148 149 attr.a_mask = 0; 150 151 switch (atime->tv_nsec) { 152 case UTIME_OMIT: /* do not touch */ 153 break; 154 case UTIME_NOW: 155 /* XXX VFS should have time() into ACTIME, for compat; we trust it! */ 156 atime->tv_nsec = 0; 157 /*FALLTHROUGH*/ 158 default: 159 attr.a_atime = *atime; 160 attr.a_mask |= SFFS_ATTR_ATIME; 161 break; 162 } 163 164 switch (mtime->tv_nsec) { 165 case UTIME_OMIT: /* do not touch */ 166 break; 167 case UTIME_NOW: 168 /* XXX VFS should have time() into MODTIME, for compat; we trust it! */ 169 mtime->tv_nsec = 0; 170 /*FALLTHROUGH*/ 171 default: 172 attr.a_mtime = *mtime; 173 attr.a_mask |= SFFS_ATTR_MTIME; 174 break; 175 } 176 177 return sffs_table->t_setattr(path, &attr); 178 } 179