1 #include "fs.h" 2 #include <sys/stat.h> 3 #include <string.h> 4 #include <minix/com.h> 5 #include "buf.h" 6 #include "inode.h" 7 #include "super.h" 8 #include <minix/vfsif.h> 9 10 static struct inode *new_node(struct inode *ldirp, char *string, mode_t 11 bits, zone_t z0); 12 13 /*===========================================================================* 14 * fs_create * 15 *===========================================================================*/ 16 int fs_create() 17 { 18 size_t len; 19 int r; 20 struct inode *ldirp; 21 struct inode *rip; 22 mode_t omode; 23 char lastc[MFS_NAME_MAX]; 24 25 /* Read request message */ 26 omode = fs_m_in.m_vfs_fs_create.mode; 27 caller_uid = fs_m_in.m_vfs_fs_create.uid; 28 caller_gid = fs_m_in.m_vfs_fs_create.gid; 29 30 /* Try to make the file. */ 31 32 /* Copy the last component (i.e., file name) */ 33 len = min(fs_m_in.m_vfs_fs_create.path_len, sizeof(lastc)); 34 err_code = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_create.grant, 35 (vir_bytes) 0, (vir_bytes) lastc, len); 36 if (err_code != OK) return err_code; 37 NUL(lastc, len, sizeof(lastc)); 38 39 /* Get last directory inode (i.e., directory that will hold the new inode) */ 40 if ((ldirp = get_inode(fs_dev, fs_m_in.m_vfs_fs_create.inode)) == NULL) 41 return(ENOENT); 42 43 /* Create a new inode by calling new_node(). */ 44 rip = new_node(ldirp, lastc, omode, NO_ZONE); 45 r = err_code; 46 47 /* If an error occurred, release inode. */ 48 if (r != OK) { 49 put_inode(ldirp); 50 put_inode(rip); 51 return(r); 52 } 53 54 /* Reply message */ 55 fs_m_out.m_fs_vfs_create.inode = rip->i_num; 56 fs_m_out.m_fs_vfs_create.mode = rip->i_mode; 57 fs_m_out.m_fs_vfs_create.file_size = rip->i_size; 58 59 /* These values are needed for the execution */ 60 fs_m_out.m_fs_vfs_create.uid = rip->i_uid; 61 fs_m_out.m_fs_vfs_create.gid = rip->i_gid; 62 63 /* Drop parent dir */ 64 put_inode(ldirp); 65 66 return(OK); 67 } 68 69 70 /*===========================================================================* 71 * fs_mknod * 72 *===========================================================================*/ 73 int fs_mknod() 74 { 75 struct inode *ip, *ldirp; 76 char lastc[MFS_NAME_MAX]; 77 phys_bytes len; 78 79 /* Copy the last component and set up caller's user and group id */ 80 len = min(fs_m_in.m_vfs_fs_mknod.path_len, sizeof(lastc)); 81 err_code = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_mknod.grant, 82 (vir_bytes) 0, (vir_bytes) lastc, (size_t) len); 83 if (err_code != OK) return err_code; 84 NUL(lastc, len, sizeof(lastc)); 85 86 caller_uid = fs_m_in.m_vfs_fs_mknod.uid; 87 caller_gid = fs_m_in.m_vfs_fs_mknod.gid; 88 89 /* Get last directory inode */ 90 if((ldirp = get_inode(fs_dev, fs_m_in.m_vfs_fs_mknod.inode)) == NULL) 91 return(ENOENT); 92 93 /* Try to create the new node */ 94 ip = new_node(ldirp, lastc, fs_m_in.m_vfs_fs_mknod.mode, 95 (zone_t) fs_m_in.m_vfs_fs_mknod.device); 96 97 put_inode(ip); 98 put_inode(ldirp); 99 return(err_code); 100 } 101 102 103 /*===========================================================================* 104 * fs_mkdir * 105 *===========================================================================*/ 106 int fs_mkdir() 107 { 108 int r1, r2; /* status codes */ 109 ino_t dot, dotdot; /* inode numbers for . and .. */ 110 struct inode *rip, *ldirp; 111 char lastc[MFS_NAME_MAX]; /* last component */ 112 phys_bytes len; 113 114 /* Copy the last component and set up caller's user and group id */ 115 len = min(fs_m_in.m_vfs_fs_mkdir.path_len, sizeof(lastc)); 116 err_code = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_mkdir.grant, 117 (vir_bytes) 0, (vir_bytes) lastc, (size_t) len); 118 if(err_code != OK) return(err_code); 119 NUL(lastc, len, sizeof(lastc)); 120 121 caller_uid = fs_m_in.m_vfs_fs_mkdir.uid; 122 caller_gid = fs_m_in.m_vfs_fs_mkdir.gid; 123 124 /* Get last directory inode */ 125 if((ldirp = get_inode(fs_dev, fs_m_in.m_vfs_fs_mkdir.inode)) == NULL) 126 return(ENOENT); 127 128 /* Next make the inode. If that fails, return error code. */ 129 rip = new_node(ldirp, lastc, fs_m_in.m_vfs_fs_mkdir.mode, (zone_t) 0); 130 131 if(rip == NULL || err_code == EEXIST) { 132 put_inode(rip); /* can't make dir: it already exists */ 133 put_inode(ldirp); 134 return(err_code); 135 } 136 137 /* Get the inode numbers for . and .. to enter in the directory. */ 138 dotdot = ldirp->i_num; /* parent's inode number */ 139 dot = rip->i_num; /* inode number of the new dir itself */ 140 141 /* Now make dir entries for . and .. unless the disk is completely full. */ 142 /* Use dot1 and dot2, so the mode of the directory isn't important. */ 143 rip->i_mode = fs_m_in.m_vfs_fs_mkdir.mode; /* set mode */ 144 r1 = search_dir(rip, dot1, &dot, ENTER, IGN_PERM);/* enter . in the new dir*/ 145 r2 = search_dir(rip, dot2, &dotdot, ENTER, IGN_PERM); /* enter .. in the new 146 dir */ 147 148 /* If both . and .. were successfully entered, increment the link counts. */ 149 if (r1 == OK && r2 == OK) { 150 /* Normal case. It was possible to enter . and .. in the new dir. */ 151 rip->i_nlinks++; /* this accounts for . */ 152 ldirp->i_nlinks++; /* this accounts for .. */ 153 IN_MARKDIRTY(ldirp); /* mark parent's inode as dirty */ 154 } else { 155 /* It was not possible to enter . or .. probably disk was full - 156 * links counts haven't been touched. */ 157 if(search_dir(ldirp, lastc, NULL, DELETE, IGN_PERM) != OK) 158 panic("Dir disappeared: %llu", rip->i_num); 159 rip->i_nlinks--; /* undo the increment done in new_node() */ 160 } 161 IN_MARKDIRTY(rip); /* either way, i_nlinks has changed */ 162 163 put_inode(ldirp); /* return the inode of the parent dir */ 164 put_inode(rip); /* return the inode of the newly made dir */ 165 return(err_code); /* new_node() always sets 'err_code' */ 166 } 167 168 169 /*===========================================================================* 170 * fs_slink * 171 *===========================================================================*/ 172 int fs_slink() 173 { 174 phys_bytes len; 175 struct inode *sip; /* inode containing symbolic link */ 176 struct inode *ldirp; /* directory containing link */ 177 register int r; /* error code */ 178 char string[MFS_NAME_MAX]; /* last component of the new dir's path name */ 179 struct buf *bp; /* disk buffer for link */ 180 181 caller_uid = fs_m_in.m_vfs_fs_slink.uid; 182 caller_gid = fs_m_in.m_vfs_fs_slink.gid; 183 184 /* Copy the link name's last component */ 185 len = min( (unsigned) fs_m_in.m_vfs_fs_slink.path_len, sizeof(string)); 186 r = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_slink.grant_path, 187 (vir_bytes) 0, (vir_bytes) string, (size_t) len); 188 if (r != OK) return(r); 189 NUL(string, len, sizeof(string)); 190 191 /* Temporarily open the dir. */ 192 if( (ldirp = get_inode(fs_dev, fs_m_in.m_vfs_fs_slink.inode)) == NULL) 193 return(EINVAL); 194 195 /* Create the inode for the symlink. */ 196 sip = new_node(ldirp, string, (I_SYMBOLIC_LINK | RWX_MODES), 0); 197 198 /* Allocate a disk block for the contents of the symlink. 199 * Copy contents of symlink (the name pointed to) into first disk block. */ 200 if( (r = err_code) == OK) { 201 size_t namelen = fs_m_in.m_vfs_fs_slink.mem_size; 202 bp = new_block(sip, (off_t) 0); 203 if (bp == NULL) 204 r = err_code; 205 else { 206 if(get_block_size(sip->i_dev) <= namelen) { 207 r = ENAMETOOLONG; 208 } else { 209 r = sys_safecopyfrom(VFS_PROC_NR, 210 fs_m_in.m_vfs_fs_slink.grant_target, 211 (vir_bytes) 0, (vir_bytes) b_data(bp), 212 namelen); 213 b_data(bp)[namelen] = '\0'; 214 } 215 } 216 217 if(bp != NULL && r == OK) { 218 sip->i_size = (off_t) strlen(b_data(bp)); 219 if(sip->i_size != fs_m_in.m_vfs_fs_slink.mem_size) { 220 /* This can happen if the user provides a buffer 221 * with a \0 in it. This can cause a lot of trouble 222 * when the symlink is used later. We could just use 223 * the strlen() value, but we want to let the user 224 * know he did something wrong. ENAMETOOLONG doesn't 225 * exactly describe the error, but there is no 226 * ENAMETOOWRONG. 227 */ 228 r = ENAMETOOLONG; 229 } 230 } 231 232 put_block(bp, DIRECTORY_BLOCK); /* put_block() accepts NULL. */ 233 234 if(r != OK) { 235 sip->i_nlinks = NO_LINK; 236 if(search_dir(ldirp, string, NULL, DELETE, IGN_PERM) != OK) 237 panic("Symbolic link vanished"); 238 } 239 } 240 241 /* put_inode() accepts NULL as a noop, so the below are safe. */ 242 put_inode(sip); 243 put_inode(ldirp); 244 245 return(r); 246 } 247 248 /*===========================================================================* 249 * new_node * 250 *===========================================================================*/ 251 static struct inode *new_node(struct inode *ldirp, 252 char *string, mode_t bits, zone_t z0) 253 { 254 /* New_node() is called by fs_open(), fs_mknod(), and fs_mkdir(). 255 * In all cases it allocates a new inode, makes a directory entry for it in 256 * the ldirp directory with string name, and initializes it. 257 * It returns a pointer to the inode if it can do this; 258 * otherwise it returns NULL. It always sets 'err_code' 259 * to an appropriate value (OK or an error code). 260 * 261 * The parsed path rest is returned in 'parsed' if parsed is nonzero. It 262 * has to hold at least MFS_NAME_MAX bytes. 263 */ 264 265 register struct inode *rip; 266 register int r; 267 268 if (ldirp->i_nlinks == NO_LINK) { /* Dir does not actually exist */ 269 err_code = ENOENT; 270 return(NULL); 271 } 272 273 /* Get final component of the path. */ 274 rip = advance(ldirp, string, IGN_PERM); 275 276 if (S_ISDIR(bits) && (ldirp->i_nlinks >= LINK_MAX)) { 277 /* New entry is a directory, alas we can't give it a ".." */ 278 put_inode(rip); 279 err_code = EMLINK; 280 return(NULL); 281 } 282 283 if ( rip == NULL && err_code == ENOENT) { 284 /* Last path component does not exist. Make new directory entry. */ 285 if ( (rip = alloc_inode((ldirp)->i_dev, bits)) == NULL) { 286 /* Can't creat new inode: out of inodes. */ 287 return(NULL); 288 } 289 290 /* Force inode to the disk before making directory entry to make 291 * the system more robust in the face of a crash: an inode with 292 * no directory entry is much better than the opposite. 293 */ 294 rip->i_nlinks++; 295 rip->i_zone[0] = z0; /* major/minor device numbers */ 296 rw_inode(rip, WRITING); /* force inode to disk now */ 297 298 /* New inode acquired. Try to make directory entry. */ 299 if((r=search_dir(ldirp, string, &rip->i_num, ENTER, IGN_PERM)) != OK) { 300 rip->i_nlinks--; /* pity, have to free disk inode */ 301 IN_MARKDIRTY(rip); /* dirty inodes are written out */ 302 put_inode(rip); /* this call frees the inode */ 303 err_code = r; 304 return(NULL); 305 } 306 307 } else if (err_code == EENTERMOUNT || err_code == ELEAVEMOUNT) { 308 r = EEXIST; 309 } else { 310 /* Either last component exists, or there is some problem. */ 311 if (rip != NULL) 312 r = EEXIST; 313 else 314 r = err_code; 315 } 316 317 /* The caller has to return the directory inode (*ldirp). */ 318 err_code = r; 319 return(rip); 320 } 321 322 323 /*===========================================================================* 324 * fs_inhibread * 325 *===========================================================================*/ 326 int fs_inhibread() 327 { 328 struct inode *rip; 329 330 if((rip = find_inode(fs_dev, fs_m_in.m_vfs_fs_inhibread.inode)) == NULL) 331 return(EINVAL); 332 333 /* inhibit read ahead */ 334 rip->i_seek = ISEEK; 335 336 return(OK); 337 } 338 339