fs/smb/client/smb2file.c

Source file repositories/reference/linux-study-clean/fs/smb/client/smb2file.c

File Facts

System
Linux kernel
Corpus path
fs/smb/client/smb2file.c
Extension
.c
Size
12993 bytes
Lines
450
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

while ((u8 *)p + sizeof(*p) <= end) {
			if (le32_to_cpu(p->ErrorId) == SMB2_ERROR_ID_DEFAULT) {
				sym = (struct smb2_symlink_err_rsp *)p->ErrorContextData;
				break;
			}
			cifs_dbg(FYI, "%s: skipping unhandled error context: 0x%x\n",
				 __func__, le32_to_cpu(p->ErrorId));

			len = ALIGN(le32_to_cpu(p->ErrorDataLength), 8);
			if (len > end - ((u8 *)p + sizeof(*p)))
				return ERR_PTR(-EINVAL);

			p = (struct smb2_error_context_rsp *)(p->ErrorContextData + len);
		}
	} else if (le32_to_cpu(err->ByteCount) >= sizeof(*sym) &&
		   iov->iov_len >= SMB2_SYMLINK_STRUCT_SIZE) {
		sym = (struct smb2_symlink_err_rsp *)err->ErrorData;
	}

	if (!IS_ERR(sym) &&
	    ((u8 *)sym + sizeof(*sym) > end ||
	     le32_to_cpu(sym->SymLinkErrorTag) != SYMLINK_ERROR_TAG ||
	     le32_to_cpu(sym->ReparseTag) != IO_REPARSE_TAG_SYMLINK))
		sym = ERR_PTR(-EINVAL);

	return sym;
}

int smb2_fix_symlink_target_type(char **target, bool directory, struct cifs_sb_info *cifs_sb)
{
	char *buf;
	int len;

	/*
	 * POSIX server does not distinguish between symlinks to file and
	 * symlink directory. So nothing is needed to fix on the client side.
	 */
	if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_POSIX_PATHS)
		return 0;

	if (!*target)
		return smb_EIO(smb_eio_trace_null_pointers);

	len = strlen(*target);
	if (!len)
		return smb_EIO1(smb_eio_trace_sym_target_len, len);

	/*
	 * If this is directory symlink and it does not have trailing slash then
	 * append it. Trailing slash simulates Windows/SMB behavior which do not
	 * allow resolving directory symlink to file.
	 */
	if (directory && (*target)[len-1] != '/') {
		buf = krealloc(*target, len+2, GFP_KERNEL);
		if (!buf)
			return -ENOMEM;
		buf[len] = '/';
		buf[len+1] = '\0';
		*target = buf;
		len++;
	}

	/*
	 * If this is a file (non-directory) symlink and it points to path name
	 * with trailing slash then this is an invalid symlink because file name
	 * cannot contain slash character. File name with slash is invalid on
	 * both Windows and Linux systems. So return an error for such symlink.
	 */
	if (!directory && (*target)[len-1] == '/')
		return smb_EIO(smb_eio_trace_sym_slash);

	return 0;
}

int smb2_parse_symlink_response(struct cifs_sb_info *cifs_sb, const struct kvec *iov,
				const char *full_path, char **path)
{
	struct smb2_symlink_err_rsp *sym;
	unsigned int sub_offs, sub_len;
	unsigned int print_offs, print_len;

	if (!cifs_sb || !iov || !iov->iov_base || !iov->iov_len || !path)
		return -EINVAL;

	sym = symlink_data(iov);
	if (IS_ERR(sym))
		return PTR_ERR(sym);

	sub_len = le16_to_cpu(sym->SubstituteNameLength);
	sub_offs = le16_to_cpu(sym->SubstituteNameOffset);

Annotation

Implementation Notes