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