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