/* * nwfs_close(struct vnode *a_vp, int a_fflag) */ static int nwfs_close(struct vop_close_args *ap) { thread_t td = curthread; /* XXX */ struct vnode *vp = ap->a_vp; struct nwnode *np = VTONW(vp); int error; NCPVNDEBUG("name=%s,td=%p,c=%d\n",np->n_name,ap->a_td,np->opened); vn_lock(vp, LK_UPGRADE | LK_RETRY); error = 0; if (vp->v_type == VDIR) goto done; if (np->opened == 0) goto done; error = nwfs_vinvalbuf(vp, V_SAVE, 1); if (np->opened == 0) { error = 0; /* huh? */ goto done; } if (--np->opened == 0) { error = ncp_close_file(NWFSTOCONN(VTONWFS(vp)), &np->n_fh, td, proc0.p_ucred); } np->n_atime = 0; done: vop_stdclose(ap); return (error); }
/* * Defer release of inode_info and file_info structures until the inode * has been cleared. This avoids a race condition allowing the inode to * be put back in use before being cleared. Also, temporarily increment * i_count after clear_inode() so that the inode can't be reused. */ static void ncp_put_inode(struct inode *inode) { struct super_block *sb = inode->i_sb; struct ncp_server *server = NCP_SERVER(inode); struct ncp_inode_info *iinfo = NCP_INOP(inode); struct nw_file_info *finfo = NCP_FINFO(inode); /* * This operation may block, so we lock before checking the count. */ lock_super(sb); if (inode->i_count > 1) { printk("ncp_put_inode: inode in use device %s, inode %ld, count=%ld\n", kdevname(inode->i_dev), inode->i_ino, inode->i_count); goto unlock; } DDPRINTK("ncp_put_inode: put %s\n", finfo->i.entryName); /* * This operation should never block. */ if (S_ISDIR(inode->i_mode)) { DDPRINTK("ncp_put_inode: put directory %ld\n", inode->i_ino); ncp_invalid_dir_cache(inode); } clear_inode(inode); /* * After clearing the inode i_count will be 0 in 2.0.xx kernels. * To keep the inode from being reused as free if we block while * closing the file, increment i_count temporarily. */ inode->i_count++; if (finfo->opened != 0) { if (ncp_close_file(server, finfo->file_handle) != 0) { /* We can't do anything but complain. */ printk("ncp_put_inode: could not close %s\n", finfo->i.entryName); } } ncp_free_inode_info(iinfo); inode->i_count--; unlock: unlock_super(sb); }
/* * nwfs_create call * Create a regular file. On entry the directory to contain the file being * created is locked. We must release before we return. * * nwfs_create(struct vnode *a_dvp, struct vnode **a_vpp, * struct componentname *a_cnpl, struct vattr *a_vap) */ static int nwfs_create(struct vop_old_create_args *ap) { struct vnode *dvp = ap->a_dvp; struct vattr *vap = ap->a_vap; struct vnode **vpp=ap->a_vpp; struct componentname *cnp = ap->a_cnp; struct vnode *vp = NULL; int error = 0, fmode; struct vattr vattr; struct nwnode *np; struct ncp_open_info no; struct nwmount *nmp=VTONWFS(dvp); ncpfid fid; NCPVNDEBUG("\n"); *vpp = NULL; if (vap->va_type == VSOCK) return (EOPNOTSUPP); if ((error = VOP_GETATTR(dvp, &vattr))) { return (error); } fmode = AR_READ | AR_WRITE; /* if (vap->va_vaflags & VA_EXCLUSIVE) fmode |= AR_DENY_READ | AR_DENY_WRITE;*/ error = ncp_open_create_file_or_subdir(nmp,dvp,cnp->cn_namelen,cnp->cn_nameptr, OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE, 0, fmode, &no, cnp->cn_td, cnp->cn_cred); if (!error) { error = ncp_close_file(NWFSTOCONN(nmp), &no.fh, cnp->cn_td,cnp->cn_cred); fid.f_parent = VTONW(dvp)->n_fid.f_id; fid.f_id = no.fattr.dirEntNum; error = nwfs_nget(VTOVFS(dvp), fid, &no.fattr, dvp, &vp); if (!error) { np = VTONW(vp); np->opened = 0; *vpp = vp; } } return (error); }
static int ncp_notify_change(struct inode *inode, struct iattr *attr) { int result = 0; int info_mask; struct nw_modify_dos_info info; if (!ncp_conn_valid(NCP_SERVER(inode))) { return -EIO; } if ((result = inode_change_ok(inode, attr)) < 0) return result; if (((attr->ia_valid & ATTR_UID) && (attr->ia_uid != NCP_SERVER(inode)->m.uid))) return -EPERM; if (((attr->ia_valid & ATTR_GID) && (attr->ia_uid != NCP_SERVER(inode)->m.gid))) return -EPERM; if (((attr->ia_valid & ATTR_MODE) && (attr->ia_mode & ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO)))) return -EPERM; info_mask = 0; memset(&info, 0, sizeof(info)); if ((attr->ia_valid & ATTR_CTIME) != 0) { info_mask |= (DM_CREATE_TIME|DM_CREATE_DATE); ncp_date_unix2dos(attr->ia_ctime, &(info.creationTime), &(info.creationDate)); } if ((attr->ia_valid & ATTR_MTIME) != 0) { info_mask |= (DM_MODIFY_TIME|DM_MODIFY_DATE); ncp_date_unix2dos(attr->ia_mtime, &(info.modifyTime), &(info.modifyDate)); } if ((attr->ia_valid & ATTR_ATIME) != 0) { __u16 dummy; info_mask |= (DM_LAST_ACCESS_DATE); ncp_date_unix2dos(attr->ia_ctime, &(dummy), &(info.lastAccessDate)); } if (info_mask != 0) { if ((result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode), NCP_ISTRUCT(inode), info_mask, &info)) != 0) { result = -EACCES; if (info_mask == (DM_CREATE_TIME|DM_CREATE_DATE)) { /* NetWare seems not to allow this. I do not know why. So, just tell the user everything went fine. This is a terrible hack, but I do not know how to do this correctly. */ result = 0; } } } if ((attr->ia_valid & ATTR_SIZE) != 0) { int written; DPRINTK("ncpfs: trying to change size of %s to %ld\n", NCP_ISTRUCT(inode)->entryName, attr->ia_size); if ((result = ncp_make_open(inode, O_RDWR)) < 0) { return -EACCES; } ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, attr->ia_size, 0, "", &written); /* According to ndir, the changes only take effect after closing the file */ ncp_close_file(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle); NCP_FINFO(inode)->opened = 0; result = 0; } ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode); return result; }
int main(int argc, char *argv[]) { NWDSCCODE dserr; NWCONN_HANDLE conn; char volume[1000]; char volpath[1000]; int opt; u_int32_t rim = 0; u_int32_t destns = NW_NS_DOS; u_int32_t searchattr = 0x8006; char* s = NULL; setlocale(LC_ALL, ""); bindtextdomain(NCPFS_PACKAGE, LOCALEDIR); textdomain(NCPFS_PACKAGE); progname = argv[0]; NWCallsInit(NULL, NULL); // NWDSInitRequester(); while ((opt = getopt(argc, argv, "h?r:n:s:p:")) != EOF) { switch (opt) { case 'r': rim = strtoul(optarg, NULL, 0); break; case 'n': destns = strtoul(optarg, NULL, 0); break; case 's': searchattr = strtoul(optarg, NULL, 0); break; case 'p': s = optarg; break; case 'h': case '?': help(); goto finished; default: usage(); goto finished; } } dserr = NWParsePath(argv[optind++], NULL, &conn, volume, volpath); if (dserr) { fprintf(stderr, "NWParsePath failed: %s\n", strnwerror(dserr)); return 123; } if (!conn) { fprintf(stderr, "Path is not remote\n"); return 124; } strcpy(volume + 2, s); volume[0] = 1; volume[1] = strlen(s); { struct nw_info_struct2 iii; u_int8_t fh[10]; memset(&iii, 0xCC, sizeof(iii)); dserr = ncp_ns_open_create_entry(conn, destns, searchattr, NCP_DIRSTYLE_DIRBASE, 3, rim, volume, strlen(s) + 2, -1, 0x0B, 0, 0, 0xFF, &iii, sizeof(iii), NULL, NULL, fh); if (dserr) { fprintf(stderr, "Cannot obtain info: %s\n", strnwerror(dserr)); } else { printstruct2(0xFF, &iii); } ncp_close_file(conn, fh); } ncp_close(conn); finished:; return 0; }